Kernel/x86: Use iretq instead of sysretq for sys$sigreturn

Using sysretq clobbers rcx and r11 as this instruction loads the rip and
rflags from those registers. This is fine for normal syscalls.

Signal dispatching works like this:
The kernel makes userspace jump to the signal trampoline when a signal
is dispatched. That trampoline then executes the sigreturn syscall after
calling the signal handler to continue executing the code before the
signal was dispatched.

Since e71c320154 the sigreturn syscall is done via the syscall
instruction (and int 0x82 support was removed in the next commit),
which causes the kernel to currently use sysretq to return to userspace.
But signals can happen at any time, not just during syscalls, so the
sigreturn syscall shouldn't clobber the contents of those registers when
returning to userspace.
This commit is contained in:
Sönke Holz 2024-08-03 14:05:03 +02:00 committed by Nico Weber
parent b806c52bd3
commit d9c098f103

View file

@ -52,12 +52,19 @@ extern "C" NO_SANITIZE_COVERAGE [[gnu::naked]] void syscall_entry()
" pushq %%rsi \n"
" pushq %%rdi \n"
" movq %%rax, %%rbx \n" // Move the syscall function to a callee-saved register.
" pushq %%rsp \n" // TrapFrame::regs
" subq $" __STRINGIFY(TRAP_FRAME_SIZE - 8) ", %%rsp \n"
" movq %%rsp, %%rdi \n"
" call enter_trap_no_irq \n"
" movq %%rsp, %%rdi \n"
" call syscall_handler \n"
// We have to use iretq for sys$sigreturn, as signals would otherwise clobber rcx and r11 when using sysretq.
" cmpq %[sc_sigreturn], %%rbx \n"
" je common_trap_exit \n"
" movq %%rsp, %%rdi \n"
" call exit_trap \n"
" addq $" __STRINGIFY(TRAP_FRAME_SIZE) ", %%rsp \n" // Pop TrapFrame
@ -88,6 +95,6 @@ extern "C" NO_SANITIZE_COVERAGE [[gnu::naked]] void syscall_entry()
" cli \n"
" popq %%rsp \n"
" sysretq \n"
:: [user_stack] "i"(Kernel::Processor::user_stack_offset()), [kernel_stack] "i"(Kernel::Processor::kernel_stack_offset()));
:: [user_stack] "i"(Kernel::Processor::user_stack_offset()), [kernel_stack] "i"(Kernel::Processor::kernel_stack_offset()), [sc_sigreturn] "i"(SC_sigreturn));
// clang-format on
}