SFrame may represent an undefined return address (RA) as SFrame FRE without any offsets as indication for an outermost frame.
Cc: Steven Rostedt <[email protected]> Cc: Josh Poimboeuf <[email protected]> Cc: Masami Hiramatsu <[email protected]> Cc: Mathieu Desnoyers <[email protected]> Cc: Peter Zijlstra <[email protected]> Cc: Ingo Molnar <[email protected]> Cc: Jiri Olsa <[email protected]> Cc: Arnaldo Carvalho de Melo <[email protected]> Cc: Namhyung Kim <[email protected]> Cc: Thomas Gleixner <[email protected]> Cc: Andrii Nakryiko <[email protected]> Cc: Indu Bhagat <[email protected]> Cc: "Jose E. Marchesi" <[email protected]> Cc: Beau Belgrave <[email protected]> Cc: Jens Remus <[email protected]> Cc: Linus Torvalds <[email protected]> Cc: Andrew Morton <[email protected]> Cc: Florian Weimer <[email protected]> Cc: Sam James <[email protected]> Cc: Kees Cook <[email protected]> Cc: "Carlos O'Donell" <[email protected]> Signed-off-by: Jens Remus <[email protected]> --- 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
