[Crash-utility] [PATCH v2] x86_64_exception_frame only performs EFRAME_VERIFY if it is the only flag

David Mair dmair at suse.com
Thu Sep 3 05:06:19 UTC 2020


x86_64_exception_frame() called with combined flags including
EFRAME_VERIFY does not perform the verify. It's only done when
EFRAME_VERIFY is the only flag set.

Correct the condition to EFRAME_VERIFY if the flag is set. Verify
requests are always performed. Fixes stack overrun "seek errors" seen on
an x86_64 core when backtracing a PID at an IRQ stack where the
interrupt handler doesn't save a pt_regs. Higher layers than the top
frame on the IRQ stack were not displayed. Fixed by this change.

But it breaks bt -e and bt -E for exceptions on userspace stacks. Those
use the constant 0 as the kvaddr argument to x86_64_exception_frame()
and pass the userspace stack position in the local argument.
x86_64_exception_frame() only verifies the kvaddr argument. Zero is not
accessible and EFRAME_VERIFY always fails for those cases.

Modify the EFRAME_VERIFY block in x86_64_exception_frame() to choose
kvaddr or local to verify using the same condition used to assign one of
them to pt_regs_buf later in the same function. Add verify_addr to
locals to hold the choice. Modify the accessible tests to use it instead
of kvaddr. Type of the new variable is the same as the type of kvaddr.

If verifying local argument, translate to a kernel address range using
the stackbuf and stackbase members of the bt argument the same way used
for EFRAME_SEARCH later in x86_64_exception_frame(). local and
bt->stackbuf are char *, the assignment destination and bt->stackbase
are ulong. Cast the char * variables to uintptr_t for the assignment
arithmetic using the local argument to prevent gcc 10.2 errors assigning
char * to ulong...the sum is okay without casts in the uses for function
arguments later.

Signed-off-by: David Mair <dmair at suse.com>
---
diff --git a/x86_64.c b/x86_64.c
index fc05e8a..9f4b5c7 100644
--- a/x86_64.c
+++ b/x86_64.c
@@ -4412,15 +4412,20 @@ x86_64_exception_frame(ulong flags, ulong
kvaddr, char *local,
         long r8, r9, r10, r11, r12, r13, r14, r15;
 	struct machine_specific *ms;
 	struct syment *sp;
-	ulong offset;
+	ulong offset, verify_addr;
 	char *pt_regs_buf;
 	long verified;
 	long err;
 	char buf[BUFSIZE];

-	if (flags == EFRAME_VERIFY) {
-		if (!accessible(kvaddr) ||
-		    !accessible(kvaddr + SIZE(pt_regs) - sizeof(long)))
+	if (flags & EFRAME_VERIFY) {
+		if (kvaddr)
+			verify_addr = kvaddr;
+		else
+			verify_addr = ((uintptr_t)local - (uintptr_t)bt->stackbuf) +
bt->stackbase;
+
+		if (!accessible(verify_addr) ||
+		    !accessible(verify_addr + SIZE(pt_regs) - sizeof(long)))
 			return FALSE;
 	}




More information about the Crash-utility mailing list