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


Reply via email to