From 7d8483662a7986fe174bac69531d238097890342 Mon Sep 17 00:00:00 2001 From: raiden00pl Date: Mon, 10 Aug 2026 12:19:27 +0200 Subject: [PATCH 1/3] arch/x86_64: restore the kernel stack when a signal handler returns SYS_signal_handler_return restored RSP from saved_rsp, which is not written when a task signals itself: synchronous dispatch skips up_schedule_sigaction(), so the kernel stack pointer was set to zero and the next push faulted. Save the kernel stack pointer at dispatch in xcp.kstkptr, as risc-v does, and restore that. Signed-off-by: raiden00pl Assisted-by: Claude Code --- arch/x86_64/src/common/x86_64_syscall.c | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/arch/x86_64/src/common/x86_64_syscall.c b/arch/x86_64/src/common/x86_64_syscall.c index 196453f5d6ae8..b9111b3033a04 100644 --- a/arch/x86_64/src/common/x86_64_syscall.c +++ b/arch/x86_64/src/common/x86_64_syscall.c @@ -247,6 +247,12 @@ uint64_t *x86_64_syscall(uint64_t *regs) { uint64_t usp; + /* Save the kernel stack pointer to restore on handler + * return + */ + + rtcb->xcp.kstkptr = (uintptr_t *)regs[REG_RSP]; + /* Copy "info" into user stack */ usp = rtcb->xcp.saved_ursp - 8; @@ -290,12 +296,21 @@ uint64_t *x86_64_syscall(uint64_t *regs) DEBUGASSERT(rtcb->xcp.sigreturn != 0); regs[REG_RCX] = rtcb->xcp.sigreturn; - regs[REG_RSP] = rtcb->xcp.saved_rsp; rtcb->xcp.sigreturn = 0; - /* For kernel mode, we should be already on a correct kernel stack - * which was recovered in x86_64_syscall_entry. - */ +#ifdef CONFIG_ARCH_KERNEL_STACK + if (rtcb->xcp.kstack != NULL) + { + /* Return to the kernel stack saved at dispatch */ + + regs[REG_RSP] = (uint64_t)rtcb->xcp.kstkptr; + rtcb->xcp.kstkptr = rtcb->xcp.ktopstk; + } + else +#endif + { + regs[REG_RSP] = rtcb->xcp.saved_rsp; + } break; } From 4b4a0756a750792a82067a8f6d3b77ad4ee9a510 Mon Sep 17 00:00:00 2001 From: raiden00pl Date: Mon, 10 Aug 2026 12:35:23 +0200 Subject: [PATCH 2/3] arch/x86_64: run the signal trampoline on the thread kernel stack For a thread interrupted in user mode the trampoline ran on the user stack, where the signal handler then grows over its frame. Run it on the thread kernel stack, unused while the thread is in user mode. The stack cannot be selected from the saved CS: up_initial_state() records the caller CS, a kernel selector even for user threads. Signed-off-by: raiden00pl Assisted-by: Claude Code --- .../src/intel64/intel64_schedulesigaction.c | 21 +++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/arch/x86_64/src/intel64/intel64_schedulesigaction.c b/arch/x86_64/src/intel64/intel64_schedulesigaction.c index 2bd5cc52e53f7..7b8fae360b5eb 100644 --- a/arch/x86_64/src/intel64/intel64_schedulesigaction.c +++ b/arch/x86_64/src/intel64/intel64_schedulesigaction.c @@ -74,6 +74,8 @@ void up_schedule_sigaction(struct tcb_s *tcb) { + uint64_t sp = tcb->xcp.regs[REG_RSP]; + sinfo("tcb=%p, rtcb=%p current_regs=%p\n", tcb, this_task(), this_task()->xcp.regs); @@ -83,7 +85,7 @@ void up_schedule_sigaction(struct tcb_s *tcb) */ tcb->xcp.saved_rip = tcb->xcp.regs[REG_RIP]; - tcb->xcp.saved_rsp = tcb->xcp.regs[REG_RSP]; + tcb->xcp.saved_rsp = sp; tcb->xcp.saved_rflags = tcb->xcp.regs[REG_RFLAGS]; /* Then set up to vector to the trampoline with interrupts @@ -91,6 +93,21 @@ void up_schedule_sigaction(struct tcb_s *tcb) */ tcb->xcp.regs[REG_RIP] = (uint64_t)x86_64_sigdeliver; - tcb->xcp.regs[REG_RSP] = tcb->xcp.regs[REG_RSP] - 8; tcb->xcp.regs[REG_RFLAGS] = 0; + +#ifdef CONFIG_ARCH_KERNEL_STACK + /* Run the trampoline on the thread kernel stack when the thread was + * interrupted in user mode: the signal handler runs on the user + * stack and would overwrite the trampoline frame there. + */ + + if (tcb->xcp.kstack != NULL && + (sp < (uint64_t)tcb->xcp.kstack || sp > (uint64_t)tcb->xcp.ktopstk)) + { + tcb->xcp.saved_ursp = sp; + sp = (uint64_t)tcb->xcp.ktopstk; + } +#endif + + tcb->xcp.regs[REG_RSP] = sp - 8; } From 0f8f4b236880bff0df3a7578dfa3ed166eeb3c65 Mon Sep 17 00:00:00 2001 From: raiden00pl Date: Mon, 10 Aug 2026 15:58:58 +0200 Subject: [PATCH 3/3] arch/x86_64: align the user signal frame and skip the ABI red zone The signal frame was built inside the 128 byte red zone of the interrupted user code and inherited its stack alignment, so a leaf function could lose live data to the siginfo copy and the handler could fault on an SSE access. Build the frame below the red zone, 16 byte aligned; the naked trampoline calls the handler itself and its call provides the return address slot. Signed-off-by: raiden00pl Assisted-by: Claude Code --- arch/x86_64/src/common/x86_64_syscall.c | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/arch/x86_64/src/common/x86_64_syscall.c b/arch/x86_64/src/common/x86_64_syscall.c index b9111b3033a04..a3a7f26f448ac 100644 --- a/arch/x86_64/src/common/x86_64_syscall.c +++ b/arch/x86_64/src/common/x86_64_syscall.c @@ -39,6 +39,14 @@ #include "x86_64_internal.h" +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Red zone the System V AMD64 ABI reserves below the user stack pointer */ + +#define X86_64_ABI_RED_ZONE 128 + /**************************************************************************** * Private Types ****************************************************************************/ @@ -253,16 +261,18 @@ uint64_t *x86_64_syscall(uint64_t *regs) rtcb->xcp.kstkptr = (uintptr_t *)regs[REG_RSP]; - /* Copy "info" into user stack */ - - usp = rtcb->xcp.saved_ursp - 8; - - /* Create a frame for info and copy the kernel info */ + /* Create a 16 byte aligned frame for info below the red + * zone of the interrupted user code + */ - usp = usp - sizeof(siginfo_t); + usp = (rtcb->xcp.saved_ursp - X86_64_ABI_RED_ZONE - + sizeof(siginfo_t)) & ~0x0f; memcpy((void *)usp, (void *)regs[REG_RSI], sizeof(siginfo_t)); - /* Now set the updated SP and user copy of "info" to RSI */ + /* Set the new SP and the user copy of "info" to RSI. + * The naked trampoline is entered with SP 16 byte + * aligned; its call provides the return address slot. + */ regs[REG_RSP] = usp; regs[REG_RSI] = usp;