From patchwork Wed Feb 4 07:16:38 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Samuel Thibault X-Patchwork-Id: 129539 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from vm01.sourceware.org (localhost [127.0.0.1]) by sourceware.org (Postfix) with ESMTP id 18D7A4BA2E0A for ; Wed, 4 Feb 2026 07:17:12 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 18D7A4BA2E0A X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from sonata.ens-lyon.org (sonata.ens-lyon.org [140.77.166.138]) by sourceware.org (Postfix) with ESMTPS id 7F1CF4BA543C for ; Wed, 4 Feb 2026 07:16:41 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 7F1CF4BA543C Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=ens-lyon.org Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=bounce.ens-lyon.org ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 7F1CF4BA543C Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=140.77.166.138 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1770189401; cv=none; b=delxFvsn10VilHLIvMSqYpmMM+21WEyw0PB9czVFGvJGxP3XeCAJlC+ScHlArgarfJRX0jbK3v4eGW3rykuLEy7xc2ghS0xDhvzUFT6jufQbdJhYqCKa88i2V2wfMnW7qTpX4IW+9MRctge2B2a4T0gbmDqhBUvX0WQtiHINwjQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1770189401; c=relaxed/simple; bh=VKK6LC/sXPUAdpBrZsiKuE2A8vcejg/wuelhQCw8x1k=; h=From:To:Subject:Date:Message-ID:MIME-Version; b=hi4HCRLTtoM/Sa3DUXN+UGg0meStW0K5jv2H9v1hLMKuWSy7rF2A0nw0dhhUiy2lCfJ3U+3SrReEVqufJ4gBU27M2y2vFL+tC+26gCxX1vda2HRy1NwMYCC361Z3X+SPrzb+Jjsdq92Y58H8eviXnOWB3fRmGt61A+tCoiroHK0= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 7F1CF4BA543C Received: from localhost (localhost [127.0.0.1]) by sonata.ens-lyon.org (Postfix) with ESMTP id 6D4CCA73B9; Wed, 4 Feb 2026 08:16:40 +0100 (CET) Received: from sonata.ens-lyon.org ([127.0.0.1]) by localhost (sonata.ens-lyon.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id 5PdVe8294Bdu; Wed, 4 Feb 2026 08:16:40 +0100 (CET) Received: from end (aamiens-653-1-40-48.w83-192.abo.wanadoo.fr [83.192.199.48]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange ECDHE (P-256) server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by sonata.ens-lyon.org (Postfix) with ESMTPSA id 31455A1B6B; Wed, 4 Feb 2026 08:16:40 +0100 (CET) Received: from samy by end with local (Exim 4.99.1) (envelope-from ) id 1vnX7v-00000003RCY-2qod; Wed, 04 Feb 2026 08:16:39 +0100 From: Samuel Thibault To: libc-alpha@sourceware.org Cc: Mike Kelly , commit-hurd@gnu.org Subject: [hurd, commited] hurd: handling pending signals could result in corruption of FPU state Date: Wed, 4 Feb 2026 08:16:38 +0100 Message-ID: <20260204071638.819539-1-samuel.thibault@ens-lyon.org> X-Mailer: git-send-email 2.51.0 MIME-Version: 1.0 X-Spam-Status: No, score=-13.0 required=5.0 tests=BAYES_00, GIT_PATCH_0, JMQ_SPF_NEUTRAL, KAM_DMARC_STATUS, RCVD_IN_VALIDITY_RPBL_BLOCKED, RCVD_IN_VALIDITY_SAFE_BLOCKED, SPF_HELO_PASS, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on sourceware.org X-BeenThere: libc-alpha@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Libc-alpha mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libc-alpha-bounces~patchwork=sourceware.org@sourceware.org From: Mike Kelly Handling a pending signal calls _hurd_setup_sighandler() once again after the initial signal handling. In this case a pointer to the previous sigcontext is available to supply the interrupted thread's original basic state, fpu state and fpu XSTATE. The original XSTATE was not being preserved by the pending signal but instead overwritten with the active XSTATE. XSTATE register values modified by the signal handling code could therefore be wrongly propogated back to the interrupted user code. --- sysdeps/mach/hurd/i386/bits/sigcontext.h | 1 + sysdeps/mach/hurd/x86/trampoline.c | 81 +++++++++++++--------- sysdeps/mach/hurd/x86_64/bits/sigcontext.h | 1 + 3 files changed, 52 insertions(+), 31 deletions(-) diff --git a/sysdeps/mach/hurd/i386/bits/sigcontext.h b/sysdeps/mach/hurd/i386/bits/sigcontext.h index eefc5bbeb8..0e12e26da9 100644 --- a/sysdeps/mach/hurd/i386/bits/sigcontext.h +++ b/sysdeps/mach/hurd/i386/bits/sigcontext.h @@ -90,6 +90,7 @@ struct sigcontext int sc_fpexcsr; /* FPSR including exception bits. */ struct i386_xfloat_state *xstate; + size_t xstate_size; }; /* Traditional BSD names for some members. */ diff --git a/sysdeps/mach/hurd/x86/trampoline.c b/sysdeps/mach/hurd/x86/trampoline.c index d1c30fbb49..e511481b48 100644 --- a/sysdeps/mach/hurd/x86/trampoline.c +++ b/sysdeps/mach/hurd/x86/trampoline.c @@ -151,9 +151,9 @@ _hurd_setup_sighandler (struct hurd_sigstate *ss, const struct sigaction *action ucontext_t ucontext; siginfo_t siginfo; #ifdef __x86_64__ - char _pad2[56]; + char _pad2[48]; #else - char _pad2[20]; + char _pad2[16]; #endif char xstate[]; /* Don't add anything after xstate, as it's dynamically @@ -170,29 +170,30 @@ _hurd_setup_sighandler (struct hurd_sigstate *ss, const struct sigaction *action /* We have a previous sigcontext that sigreturn was about to restore when another signal arrived. We will just base our setup on that. */ - if (! _hurdsig_catch_memory_fault (ss->context)) - { - memcpy (&state->basic, &ss->context->sc_i386_thread_state, - sizeof (state->basic)); - memcpy (&state->fpu, &ss->context->sc_i386_float_state, - sizeof (state->fpu)); - state->set |= (1 << i386_REGS_SEGS_STATE) | (1 << i386_FLOAT_STATE); - } - } - - if (! machine_get_basic_state (ss->thread, state)) - return NULL; + memcpy (&state->basic, &ss->context->sc_i386_thread_state, + sizeof (state->basic)); + memcpy (&state->fpu, &ss->context->sc_i386_float_state, + sizeof (state->fpu)); + state->set |= (1 << i386_REGS_SEGS_STATE) | (1 << i386_FLOAT_STATE); - /* Initialize the size of the CPU extended state, to be saved during - * signal handling */ + xstate_size = ss->context->xstate_size; + } + else + { + /* Initialize the size of the CPU extended state, to be saved during + * signal handling */ #ifdef i386_XFLOAT_STATE - _Static_assert ((sizeof(*stackframe) + sizeof(struct i386_xfloat_state)) % 64 == 0, - "stackframe size must be multiple of 64-byte minus " - "sizeof(struct i386_xfloat_state), please adjust _pad2"); + _Static_assert ((sizeof(*stackframe) + sizeof(struct i386_xfloat_state)) % 64 == 0, + "stackframe size must be multiple of 64-byte minus " + "sizeof(struct i386_xfloat_state), please adjust _pad2"); - if (__i386_get_xstate_size(__mach_host_self(), &xstate_size)) + if (__i386_get_xstate_size(__mach_host_self(), &xstate_size)) #endif - xstate_size = 0; + xstate_size = 0; + } + + if (! machine_get_basic_state (ss->thread, state)) + return NULL; /* Save the original SP in the gratuitous `esp' slot. We may need to reset the SP (the `uesp' slot) to avoid clobbering an @@ -279,33 +280,51 @@ _hurd_setup_sighandler (struct hurd_sigstate *ss, const struct sigaction *action memcpy (&scp->sc_i386_thread_state, &state->basic, sizeof (state->basic)); + scp->xstate_size = 0; scp->xstate = NULL; #ifdef i386_XFLOAT_STATE if (xstate_size > 0) { - mach_msg_type_number_t got = (xstate_size / sizeof (int)); + if (ss->context != NULL) + { + assert (ss->context->xstate != NULL); - ok = (! __thread_get_state (ss->thread, i386_XFLOAT_STATE, - (thread_state_t) stackframe->xstate, &got) - && got == (xstate_size / sizeof (int))); + /* Copy the xstate preserved at the time of handling the first + signal rather than that currently in the FPU. */ + memcpy (stackframe->xstate, ss->context->xstate, xstate_size); + ok = 1; + } + else + { + mach_msg_type_number_t got = (xstate_size / sizeof (int)); - if (ok && ((struct i386_xfloat_state*) stackframe->xstate)->fp_save_kind > 5) - /* We support up to XSAVES */ - ok = 0; + ok = (! __thread_get_state (ss->thread, i386_XFLOAT_STATE, + (thread_state_t) stackframe->xstate, &got) + && got == (xstate_size / sizeof (int))); - if (ok) + if (ok && ((struct i386_xfloat_state*) stackframe->xstate)->fp_save_kind > 5) + /* We support up to XSAVES */ + ok = 0; + } + + if (ok) { scp->xstate = (struct i386_xfloat_state*) stackframe->xstate; + scp->xstate_size = xstate_size; assert((uintptr_t)scp->xstate->hw_state % 64 == 0); } - } + } else #endif ok = 0; if (!ok) { /* struct sigcontext is laid out so that starting at sc_fpkind mimics - a struct i386_float_state. */ + a struct i386_float_state. In the event that we are processing a + previous sigcontext (ss->context != NULL) 'state' correctly contains + the FPU state saved from the previous handler (see memcpy above) + rather than that currently in the FPU */ + _Static_assert (offsetof (struct sigcontext, sc_i386_float_state) % __alignof__ (struct i386_float_state) == 0, "sc_i386_float_state layout mismatch"); diff --git a/sysdeps/mach/hurd/x86_64/bits/sigcontext.h b/sysdeps/mach/hurd/x86_64/bits/sigcontext.h index 94061e7a91..770523949c 100644 --- a/sysdeps/mach/hurd/x86_64/bits/sigcontext.h +++ b/sysdeps/mach/hurd/x86_64/bits/sigcontext.h @@ -98,6 +98,7 @@ struct sigcontext int sc_fpexcsr; /* FPSR including exception bits. */ struct i386_xfloat_state *xstate; + size_t xstate_size; }; /* Traditional BSD names for some members. */