[PATCH v12 08/13] unwind_user/sframe: Add support for outermost frame indication
From: Jens Remus <hidden>
Date: 2025-11-19 13:24:56
Also in:
bpf, linux-mm, lkml
Subsystem:
the rest, userspace stack unwinding · Maintainers:
Linus Torvalds, Josh Poimboeuf, Steven Rostedt
SFrame may represent an undefined return address (RA) as SFrame FRE
without any offsets as indication for an outermost frame.
Cc: Steven Rostedt <rostedt@kernel.org>
Cc: Josh Poimboeuf <jpoimboe@kernel.org>
Cc: Masami Hiramatsu <mhiramat@kernel.org>
Cc: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Ingo Molnar <mingo@kernel.org>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Arnaldo Carvalho de Melo <acme@kernel.org>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Thomas Gleixner <redacted>
Cc: Andrii Nakryiko <andrii@kernel.org>
Cc: Indu Bhagat <redacted>
Cc: "Jose E. Marchesi" <redacted>
Cc: Beau Belgrave <redacted>
Cc: Jens Remus <redacted>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Florian Weimer <redacted>
Cc: Sam James <redacted>
Cc: Kees Cook <kees@kernel.org>
Cc: "Carlos O'Donell" <redacted>
Signed-off-by: Jens Remus <redacted>
---
Notes (jremus):
Changes in v11:
- New patch.
kernel/unwind/sframe.c | 15 ++++++++++++++-
1 file changed, 14 insertions(+), 1 deletion(-)
diff --git a/kernel/unwind/sframe.c b/kernel/unwind/sframe.c
index d4ef825b1cbc..1e877c3e5417 100644
--- a/kernel/unwind/sframe.c
+++ b/kernel/unwind/sframe.c@@ -33,6 +33,7 @@ struct sframe_fre_internal { s32 ra_off; s32 fp_off; u8 info; + bool ra_undefined; }; DEFINE_STATIC_SRCU(sframe_srcu);
@@ -187,6 +188,7 @@ static __always_inline int __read_fre(struct sframe_section *sec, unsigned char offset_count, offset_size; s32 cfa_off, ra_off, fp_off; unsigned long cur = fre_addr; + bool ra_undefined = false; unsigned char addr_size; u32 ip_off; u8 info;
@@ -205,7 +207,7 @@ static __always_inline int __read_fre(struct sframe_section *sec, UNSAFE_GET_USER_INC(info, cur, 1, Efault); offset_count = SFRAME_FRE_OFFSET_COUNT(info); offset_size = offset_size_enum_to_size(SFRAME_FRE_OFFSET_SIZE(info)); - if (!offset_count || !offset_size) + if (!offset_size) return -EFAULT; if (cur + (offset_count * offset_size) > sec->fres_end)
@@ -213,6 +215,14 @@ static __always_inline int __read_fre(struct sframe_section *sec, fre->size = addr_size + 1 + (offset_count * offset_size); + if (!offset_count) { + cfa_off = 0; + ra_off = 0; + fp_off = 0; + ra_undefined = true; + goto done; + } + UNSAFE_GET_USER_INC(cfa_off, cur, offset_size, Efault); offset_count--;
@@ -233,11 +243,13 @@ static __always_inline int __read_fre(struct sframe_section *sec, if (offset_count) return -EFAULT; +done: fre->ip_off = ip_off; fre->cfa_off = cfa_off; fre->ra_off = ra_off; fre->fp_off = fp_off; fre->info = info; + fre->ra_undefined = ra_undefined; return 0;
@@ -298,6 +310,7 @@ static __always_inline int __find_fre(struct sframe_section *sec, frame->ra_off = fre->ra_off; frame->fp_off = fre->fp_off; frame->use_fp = SFRAME_FRE_CFA_BASE_REG_ID(fre->info) == SFRAME_BASE_REG_FP; + frame->outermost = fre->ra_undefined; return 0; }
--
2.48.1