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

David Mair dmair at suse.com
Sun Aug 30 01:41:00 UTC 2020


Calls to x86_64_exception_frame() with combined items set in the flags
argument that include EFRAME_VERIFY do not have the EFRAME_VERIFY
operation performed. I have some cores where multiple cases of
attempting to read a not-present pt_regs end a single PID backtrace with
a failure. One instance has the pt_regs read overrunning stacktop
because the pt_regs is not present and the level's stack position is
closer to stacktop than the size of a pt_regs. That results in a
backtrace failing before complete with a "seek error" at the start of
page after stacktop:

crash> bt 7456
PID: 7456   TASK: ffff933fdb960000  CPU: 0   COMMAND: "sh"
 #0 [fffffe0000009e58] crash_nmi_callback at ffffffff93260e93
...
 #9 [ffffaea5c0003f80] hrtimer_interrupt at ffffffff933313d5
bt: seek error: kernel virtual address: ffffaea5c0004000  type: "pt_regs"
crash>

The correct backtrace would reach level #12 with no seek error.

The condition to perform the EFRAME_VERIFY operation tests if the flags
value equals EFRAME_VERIFY, not if the value includes EFRAME_VERIFY. The
call to x86_64_exception_frame() in x86_64_print_stack_entry() performed
when eframe_check >= 0 supplies a flags value of EFRAME_PRINT |
EFRAME_VERIFY.

In the bt example above backtrace reaches level #9, 128 bytes from the
top of the current stack's pages in an IRQ stack and with a function
name ending in "_interrupt". This leads to x86_64_print_stack_entry()
setting eframe_check to zero and x86_64_exception_frame() being called
with flags EFRAME_PRINT | EFRAME_VERIFY. x86_64_exception_frame()
doesn't perform the verify because flags is not just EFRAME_VERIFY. An
attempt is made to read 168 bytes (SIZE(pt_regs) - 8 bytes) from a
position 128 bytes from the top of the stack. The stack in question is
followed by a not-present page and the read fails attempting to read
from the page following stacktop.

Signed-off-by: David Mair <dmair at suse.com>
---
diff --git a/x86_64.c b/x86_64.c
index fc05e8a..cc870e0 100644
--- a/x86_64.c
+++ b/x86_64.c
@@ -4418,7 +4418,7 @@ x86_64_exception_frame(ulong flags, ulong kvaddr,
char *local,
        long err;
        char buf[BUFSIZE];

-       if (flags == EFRAME_VERIFY) {
+       if (flags & EFRAME_VERIFY) {
                if (!accessible(kvaddr) ||
                    !accessible(kvaddr + SIZE(pt_regs) - sizeof(long)))
                        return FALSE;




More information about the Crash-utility mailing list