--- zzzz-none-000/linux-2.6.39.4/arch/x86/kernel/dumpstack_32.c 2011-08-03 19:43:28.000000000 +0000 +++ puma6-arm-6490-729/linux-2.6.39.4/arch/x86/kernel/dumpstack_32.c 2021-11-10 13:23:10.000000000 +0000 @@ -13,6 +13,7 @@ #include #include #include +#include #include @@ -81,8 +82,20 @@ show_trace_log_lvl(task, regs, sp, bp, log_lvl); } +/* + * On old kernels (pre-v3.3 at least), nested NMIs are not handled correctly. + * In an NMI handler, triggering a page fault allows nested NMIs to happen, so + * this must be avoided. Since vmalloc'ed memory can go away anytime, we + * better not access it from nmi context. + */ +#define probe_kernel_address_nmisafe(addr, c) \ + ({ \ + in_nmi() && !virt_addr_valid(addr) ? \ + -EFAULT : \ + probe_kernel_address((addr), c); \ + }) -void show_registers(struct pt_regs *regs) +void show_regs(struct pt_regs *regs) { int i; @@ -108,15 +121,21 @@ printk(KERN_EMERG "Code: "); ip = (u8 *)regs->ip - code_prologue; - if (ip < (u8 *)PAGE_OFFSET || probe_kernel_address(ip, c)) { + if (ip < (u8 *)PAGE_OFFSET || + probe_kernel_address_nmisafe(ip, c)) { /* try starting at IP */ ip = (u8 *)regs->ip; code_len = code_len - code_prologue + 1; } for (i = 0; i < code_len; i++, ip++) { + bool bad_probe = false; + if (ip < (u8 *)PAGE_OFFSET || - probe_kernel_address(ip, c)) { - printk(" Bad EIP value."); + (bad_probe = probe_kernel_address_nmisafe(ip, c))) { + if (bad_probe && in_nmi()) + printk(" Unsafe EIP address."); + else + printk(" Bad EIP value."); break; } if (ip == (u8 *)regs->ip)