From e0f0ce88eb9e526cf8271f124478143fc3ae388a Mon Sep 17 00:00:00 2001 From: Matt Turner Date: Wed, 3 Jun 2026 12:18:51 -0400 Subject: [PATCH] linux-user/sparc: call block_signals() before set_sigmask() in setcontext sparc64_set_context() emulates the kernel's `ta 0x6f` trap by calling set_sigmask() to install the mask supplied via the user's ucontext_t. The contract of set_sigmask() (see its comment in linux-user/signal.c) is that the caller must have first called block_signals(), which sets TaskState::signal_pending. Without block_signals(), if a guest signal is pending-and-blocked at the time setcontext is invoked and the new mask unblocks it, signal_pending stays 0 and the post-trap process_pending_signals() call in linux-user/sparc/cpu_loop.c never enters its while loop, so the now-deliverable signal is left undelivered indefinitely. This affects programs that use getcontext/setcontext to swap signal masks, including libunwind's unw_resume() out of a signal handler: without this fix, the test program below loops forever printing "calling setcontext" instead of delivering the pending SIGUSR2. #define _GNU_SOURCE #include #include #include #include static int got; static void h(int s) { got = 1; } int main(void) { signal(SIGUSR2, h); sigset_t m; sigemptyset(&m); sigaddset(&m, SIGUSR2); sigprocmask(SIG_BLOCK, &m, NULL); kill(getpid(), SIGUSR2); ucontext_t uc; getcontext(&uc); if (got) return 0; uc.uc_sigmask.__val[0] = 0; setcontext(&uc); return 1; } The 32-bit sparc do_sigreturn / do_rt_sigreturn paths already get block_signals() from the rt_sigreturn syscall wrapper in linux-user/syscall.c, so only sparc64_set_context (invoked directly from cpu_loop) needs the addition. Signed-off-by: Matt Turner Cc: Mark Cave-Ayland Signed-off-by: Helge Deller --- linux-user/sparc/signal.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/linux-user/sparc/signal.c b/linux-user/sparc/signal.c index fda5508c48..ba692c3123 100644 --- a/linux-user/sparc/signal.c +++ b/linux-user/sparc/signal.c @@ -619,6 +619,15 @@ void sparc64_set_context(CPUSPARCState *env) } } target_to_host_sigset_internal(&set, &target_set); + /* + * set_sigmask() requires the caller to have first called + * block_signals() so that process_pending_signals() is guaranteed + * to run after the mask change. Without this, a guest signal that + * is pending-and-blocked at setcontext time is left undelivered + * even after its mask bit is cleared, because signal_pending stays + * 0 and the post-trap process_pending_signals() loop never enters. + */ + block_signals(); set_sigmask(&set); } env->pc = pc;