Skip to content

Commit ac5cecc

Browse files
thejhKAGA-KOKO
authored andcommitted
x86/unwind: Add hardcoded ORC entry for NULL
When the ORC unwinder is invoked for an oops caused by IP==0, it currently has no idea what to do because there is no debug information for the stack frame of NULL. But if RIP is NULL, it is very likely that the last successfully executed instruction was an indirect CALL/JMP, and it is possible to unwind out in the same way as for the first instruction of a normal function. Hardcode a corresponding ORC entry. With an artificially-added NULL call in prctl_set_seccomp(), before this patch, the trace is: Call Trace: ? __x64_sys_prctl+0x402/0x680 ? __ia32_sys_prctl+0x6e0/0x6e0 ? __do_page_fault+0x457/0x620 ? do_syscall_64+0x6d/0x160 ? entry_SYSCALL_64_after_hwframe+0x44/0xa9 After this patch, the trace looks like this: Call Trace: __x64_sys_prctl+0x402/0x680 ? __ia32_sys_prctl+0x6e0/0x6e0 ? __do_page_fault+0x457/0x620 do_syscall_64+0x6d/0x160 entry_SYSCALL_64_after_hwframe+0x44/0xa9 prctl_set_seccomp() still doesn't show up in the trace because for some reason, tail call optimization is only disabled in builds that use the frame pointer unwinder. Signed-off-by: Jann Horn <[email protected]> Signed-off-by: Thomas Gleixner <[email protected]> Acked-by: Josh Poimboeuf <[email protected]> Cc: Borislav Petkov <[email protected]> Cc: Andrew Morton <[email protected]> Cc: syzbot <[email protected]> Cc: "H. Peter Anvin" <[email protected]> Cc: Masahiro Yamada <[email protected]> Cc: Michal Marek <[email protected]> Cc: [email protected] Link: https://lkml.kernel.org/r/[email protected]
1 parent f4f34e1 commit ac5cecc

File tree

1 file changed

+17
-0
lines changed

1 file changed

+17
-0
lines changed

arch/x86/kernel/unwind_orc.c

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,13 +113,30 @@ static struct orc_entry *orc_ftrace_find(unsigned long ip)
113113
}
114114
#endif
115115

116+
/*
117+
* If we crash with IP==0, the last successfully executed instruction
118+
* was probably an indirect function call with a NULL function pointer,
119+
* and we don't have unwind information for NULL.
120+
* This hardcoded ORC entry for IP==0 allows us to unwind from a NULL function
121+
* pointer into its parent and then continue normally from there.
122+
*/
123+
static struct orc_entry null_orc_entry = {
124+
.sp_offset = sizeof(long),
125+
.sp_reg = ORC_REG_SP,
126+
.bp_reg = ORC_REG_UNDEFINED,
127+
.type = ORC_TYPE_CALL
128+
};
129+
116130
static struct orc_entry *orc_find(unsigned long ip)
117131
{
118132
static struct orc_entry *orc;
119133

120134
if (!orc_init)
121135
return NULL;
122136

137+
if (ip == 0)
138+
return &null_orc_entry;
139+
123140
/* For non-init vmlinux addresses, use the fast lookup table: */
124141
if (ip >= LOOKUP_START_IP && ip < LOOKUP_STOP_IP) {
125142
unsigned int idx, start, stop;

0 commit comments

Comments
 (0)