Skip to content

Commit 6f2601c

Browse files
jpoimboeKernel Patches Daemon
authored andcommitted
x86/unwind/orc: Support reliable unwinding through BPF stack frames
BPF JIT programs and trampolines use a frame pointer, so the current ORC unwinder strategy of falling back to frame pointers (when an ORC entry is missing) usually works in practice when unwinding through BPF JIT stack frames. However, that frame pointer fallback is just a guess, so the unwind gets marked unreliable for live patching, which can cause livepatch transition stalls. Make the common case reliable by calling the bpf_has_frame_pointer() helper to detect the valid frame pointer region of BPF JIT programs and trampolines. Fixes: ee9f8fc ("x86/unwind: Add the ORC unwinder") Reported-by: Andrey Grodzovsky <[email protected]> Closes: https://lore.kernel.org/[email protected] Signed-off-by: Josh Poimboeuf <[email protected]> Acked-by: Song Liu <[email protected]>
1 parent 8e2e296 commit 6f2601c

File tree

1 file changed

+27
-12
lines changed

1 file changed

+27
-12
lines changed

arch/x86/kernel/unwind_orc.c

Lines changed: 27 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
#include <linux/objtool.h>
33
#include <linux/module.h>
44
#include <linux/sort.h>
5+
#include <linux/bpf.h>
56
#include <asm/ptrace.h>
67
#include <asm/stacktrace.h>
78
#include <asm/unwind.h>
@@ -172,6 +173,25 @@ static struct orc_entry *orc_ftrace_find(unsigned long ip)
172173
}
173174
#endif
174175

176+
/* Fake frame pointer entry -- used as a fallback for generated code */
177+
static struct orc_entry orc_fp_entry = {
178+
.type = ORC_TYPE_CALL,
179+
.sp_reg = ORC_REG_BP,
180+
.sp_offset = 16,
181+
.bp_reg = ORC_REG_PREV_SP,
182+
.bp_offset = -16,
183+
};
184+
185+
static struct orc_entry *orc_bpf_find(unsigned long ip)
186+
{
187+
#ifdef CONFIG_BPF_JIT
188+
if (bpf_has_frame_pointer(ip))
189+
return &orc_fp_entry;
190+
#endif
191+
192+
return NULL;
193+
}
194+
175195
/*
176196
* If we crash with IP==0, the last successfully executed instruction
177197
* was probably an indirect function call with a NULL function pointer,
@@ -186,15 +206,6 @@ static struct orc_entry null_orc_entry = {
186206
.type = ORC_TYPE_CALL
187207
};
188208

189-
/* Fake frame pointer entry -- used as a fallback for generated code */
190-
static struct orc_entry orc_fp_entry = {
191-
.type = ORC_TYPE_CALL,
192-
.sp_reg = ORC_REG_BP,
193-
.sp_offset = 16,
194-
.bp_reg = ORC_REG_PREV_SP,
195-
.bp_offset = -16,
196-
};
197-
198209
static struct orc_entry *orc_find(unsigned long ip)
199210
{
200211
static struct orc_entry *orc;
@@ -238,6 +249,11 @@ static struct orc_entry *orc_find(unsigned long ip)
238249
if (orc)
239250
return orc;
240251

252+
/* BPF lookup: */
253+
orc = orc_bpf_find(ip);
254+
if (orc)
255+
return orc;
256+
241257
return orc_ftrace_find(ip);
242258
}
243259

@@ -495,9 +511,8 @@ bool unwind_next_frame(struct unwind_state *state)
495511
if (!orc) {
496512
/*
497513
* As a fallback, try to assume this code uses a frame pointer.
498-
* This is useful for generated code, like BPF, which ORC
499-
* doesn't know about. This is just a guess, so the rest of
500-
* the unwind is no longer considered reliable.
514+
* This is just a guess, so the rest of the unwind is no longer
515+
* considered reliable.
501516
*/
502517
orc = &orc_fp_entry;
503518
state->error = true;

0 commit comments

Comments
 (0)