Messages in this thread | | | Date | Sat, 2 Sep 2023 20:28:20 +0800 | From | Chen Zhongjin <> | Subject | [BUG] x86/entry: ORC stack unwinding error on error_entry |
| |
My KASAN reported a stack-out-of-bounds BUG in unwind_next_frame I found there was a wrong stack unwinding on error_entry and the stack was like:
<NMI> ... exc_nmi end_repeat_nmi RIP: 0010:error_entry+0x17 RSP: 0018:ffff88de81889928 EFLAGS: 00000082 RAX: 0000000000000000 RBX: ffff88de81889a98 RCX: ffffffff9cec64a9 RDX: dffffc0000000000 RSI: ffffffff9e400cfa RDI: ffffffff9e400d01 RBP: 1ffff11bd031133c R08: ffffffff9cec6406 R09: ffff88de81889acc R10: fffffbfff40bb517 R11: 0000000000000001 R12: 0000000000000001 R13: ffff88de81889ae0 R14: ffffffff9f2ee640 R15: 0000000000000000 </NMI> <IRQ> asm_sysvec_apic_timer_interrupt+0x11 RIP: 9e2d0a66:unwind_next_frame+0x0 RSP: 81889ab8:ffff88de81889ab8 EFLAGS: ffff88b11727fd48 ORIG_RAX: ffffffff9eecdff0 RAX: ffff88b11727fd48 RBX: 0000000000000018 RCX: ffff88de81889acd RDX: ffffffff9e400d02 RSI: ffff88b11727fd40 RDI: 0000000041b58ab3 RBP: ffff88de818899a0 R08: ffffffff9e400d02 R09: ffff88de81889ae8 R10: ffff88de81889ad0 R11: ffffffff9cec64bf R12: 0000000000000282 R13: 0000000000000010 R14: ffffffff9cec6150 R15: ffffffffffffffff (orc unwinding stopped here)
It's because in error_entry the return address is changed. When asm_sysvec_apic_timer_interrupt calls error_entry, the stack looks like:
asm_sysvec_apic_timer_interrupt+0xa ffffffffffffffff (IRET_REGS) <- idtentry unwind stack by IRET_REGS
Then error_entry enters PUSH_AND_CLEAR_REGS save_ret=1, which will change the return address:
pushq %rsi movq 8(%rsp), %rsi movq %rdi, 8(%rsp) (push other regs) UNWIND_HINT_REGS
And the stack is changed to:
(other regs) %rsi %rdi (asm_sysvec_apic_timer_interrupt+0x11, in this case) ffffffffffffffff (IRET_REGS)
If there is a NMI happens before all regs are pushed and unwinding hint changed to UNWIND_HINT_REGS, the unwinding in error_entry is wrong. It find %rdi as the return address and search the next orc_entry, which makes unwinding fail.
I guess this can be fixed if it keeps the pt_regs->di slot as return address until all regs are pushed to stack and unwind hint changed to UNWIND_HINT_REGS, then overwrite the return address to %rdi.
UNWIND_HINT_REGS
.if \save_ret movq 0x70(%rsp), %rsi movq %rdi, 0x70(%rsp) pushq %rsi .endif
However I'm not sure if it works or there is any side affect (at lease it looks not so graceful). Does anyone has some advise for this bug or this fix? I'll test this after I can reproduce the bug stably.
Thanks.
| |