]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
s390/stacktrace: Do not fallback to RA register
authorJens Remus <jremus@linux.ibm.com>
Thu, 11 Dec 2025 11:24:50 +0000 (12:24 +0100)
committerHeiko Carstens <hca@linux.ibm.com>
Sun, 14 Dec 2025 10:03:58 +0000 (11:03 +0100)
The logic to fallback to the return address (RA) register value in
the topmost frame when stack tracing using back chain is broken in
multiple ways:

When assuming the RA register 14 has not been saved yet one must assume
that a new user stack frame has not been allocated either.  Therefore
the back chain would not contain the stack pointer (SP) at entry, but
the caller's SP at its entry instead.

Therefore when falling back to the RA register 14 value it would also be
necessary to fallback to the SP register 15 value.  Otherwise an invalid
combination of RA register 14 and caller's SP at its entry (from the
back chain) is used.

In the topmost frame the back chain contains either the caller's SP at
its entry (before having allocated a new stack frame in the prologue),
the SP at entry (after having allocated a new stack frame), or an
uninitialized value (during static/dynamic stack allocation).  In both
cases where the back chain is valid either the caller or prologue must
have saved its respective RA to the respective frame.  Therefore, if the
RA obtained from the frame pointed to by the back chain is invalid, this
does not indicate that the IP in the topmost frame is still early in the
prologue and the RA has not been saved.

Reviewed-by: Heiko Carstens <hca@linux.ibm.com>
Signed-off-by: Jens Remus <jremus@linux.ibm.com>
Signed-off-by: Heiko Carstens <hca@linux.ibm.com>
arch/s390/kernel/stacktrace.c

index 3aae7f70e6ab1293991685230717fd6eccdc521c..18520d33305818fa5399e944080d405a90c426e4 100644 (file)
@@ -104,7 +104,6 @@ void arch_stack_walk_user_common(stack_trace_consume_fn consume_entry, void *coo
        struct stack_frame_vdso_wrapper __user *sf_vdso;
        struct stack_frame_user __user *sf;
        unsigned long ip, sp;
-       bool first = true;
 
        if (!current->mm)
                return;
@@ -133,24 +132,11 @@ void arch_stack_walk_user_common(stack_trace_consume_fn consume_entry, void *coo
                        if (__get_user(ip, &sf->gprs[8]))
                                break;
                }
-               /* Sanity check: ABI requires SP to be 8 byte aligned. */
-               if (sp & 0x7)
+               /* Validate SP and RA (ABI requires SP to be 8 byte aligned). */
+               if (sp & 0x7 || ip_invalid(ip))
                        break;
-               if (ip_invalid(ip)) {
-                       /*
-                        * If the instruction address is invalid, and this
-                        * is the first stack frame, assume r14 has not
-                        * been written to the stack yet. Otherwise exit.
-                        */
-                       if (!first)
-                               break;
-                       ip = regs->gprs[14];
-                       if (ip_invalid(ip))
-                               break;
-               }
                if (!store_ip(consume_entry, cookie, entry, perf, ip))
                        break;
-               first = false;
        }
        pagefault_enable();
 }