guix_mirror_bot pushed a commit to branch master
in repository guix.

commit 7d488fec76c8fc36b2d6d058e172fc37f72f9787
Author: Yelninei <[email protected]>
AuthorDate: Fri Oct 17 18:57:58 2025 +0100

    gnu: glibc/hurd: Add patches from glibc 2.42.
    
    * gnu/packages/base.scm (glibc/hurd): Remove intr-msg-clobber.patch, add
    signal-fpe-exception.patch and xstate.patch.
    gnu/packages/patches/glibc-hurd-signal-fpe-exception.patch, 
gnu/packages/patches/glibc-hurd-xstate.patch : New patches
    * gnu/local.mk (dist_patch_DATA): Register them.
    
    Change-Id: Ib5b38f1fb8b43d76ec236232be8ff7552dad7422
    Signed-off-by: Ludovic Courtès <[email protected]>
---
 gnu/local.mk                                       |   2 +
 gnu/packages/base.scm                              |  13 +-
 .../patches/glibc-hurd-signal-fpe-exception.patch  |  67 ++
 gnu/packages/patches/glibc-hurd-xstate.patch       | 813 +++++++++++++++++++++
 4 files changed, 894 insertions(+), 1 deletion(-)

diff --git a/gnu/local.mk b/gnu/local.mk
index ec0efb1a0a..82a6577562 100644
--- a/gnu/local.mk
+++ b/gnu/local.mk
@@ -1465,10 +1465,12 @@ dist_patch_DATA =                                       
        \
   %D%/packages/patches/glibc-hurd-gettyent.patch               \
   %D%/packages/patches/glibc-hurd-mach-print.patch             \
   %D%/packages/patches/glibc-hurd-pthread_setcancelstate.patch \
+  %D%/packages/patches/glibc-hurd-signal-fpe-exception.patch   \
   %D%/packages/patches/glibc-hurd-signal-sa-siginfo.patch      \
   %D%/packages/patches/glibc-hurd-2.41-pthread-once.patch      \
   %D%/packages/patches/glibc-hurd-2.41-pthread-sigmask.patch   \
   %D%/packages/patches/glibc-hurd-2.41-symlink.patch           \
+  %D%/packages/patches/glibc-hurd-xstate.patch                 \
   %D%/packages/patches/glibc-hurd64-gcc-14.2-tls-bug.patch     \
   %D%/packages/patches/glibc-hurd64-intr-msg-clobber.patch     \
   %D%/packages/patches/glibc-ldd-powerpc.patch                 \
diff --git a/gnu/packages/base.scm b/gnu/packages/base.scm
index 2609674319..79810bccd1 100644
--- a/gnu/packages/base.scm
+++ b/gnu/packages/base.scm
@@ -1548,7 +1548,18 @@ variety of options.  It is an alternative to the shell 
\"type\" built-in
 command.")
     (license gpl3+))) ; some files are under GPLv2+
 
-(define-public glibc/hurd glibc)
+(define-public glibc/hurd
+  (hidden-package
+   (package/inherit glibc
+     (source
+      (origin
+        (inherit (package-source glibc))
+        (patches
+         (append (map search-patch
+                      (delete "glibc-hurd64-intr-msg-clobber.patch" 
%glibc-patches))
+                 (search-patches
+                 "glibc-hurd-signal-fpe-exception.patch"
+                 "glibc-hurd-xstate.patch"))))))))
 
 (define-public glibc/hurd-headers
   (package/inherit glibc/hurd
diff --git a/gnu/packages/patches/glibc-hurd-signal-fpe-exception.patch 
b/gnu/packages/patches/glibc-hurd-signal-fpe-exception.patch
new file mode 100644
index 0000000000..fefd9f693c
--- /dev/null
+++ b/gnu/packages/patches/glibc-hurd-signal-fpe-exception.patch
@@ -0,0 +1,67 @@
+Cherry picked from glibc-2.42
+
+0d99714680 * hurd: Clear FP exceptions before calling signal handler
+
+From 0d9971468087c77e8727638123ae4aa60724e0ff Mon Sep 17 00:00:00 2001
+From: Samuel Thibault <[email protected]>
+Date: Mon, 21 Apr 2025 19:58:04 +0200
+Subject: [PATCH] hurd: Clear FP exceptions before calling signal handler
+
+This avoids SIGFPE handlers (or code longjmp-ed to) getting disturbed by the
+exception that generated it.
+
+Note: gcc's unwinding depends on the rpc_wait_trampoline/trampoline exact
+code, so we here avoid breaking it.
+---
+ sysdeps/mach/hurd/x86/trampoline.c | 14 ++++++++++----
+ 1 file changed, 10 insertions(+), 4 deletions(-)
+
+diff --git a/sysdeps/mach/hurd/x86/trampoline.c 
b/sysdeps/mach/hurd/x86/trampoline.c
+index 02510b178c..6f23c567da 100644
+--- a/sysdeps/mach/hurd/x86/trampoline.c
++++ b/sysdeps/mach/hurd/x86/trampoline.c
+@@ -461,7 +461,10 @@ _hurd_setup_sighandler (struct hurd_sigstate *ss, const 
struct sigaction *action
+    - in gdb: gdb/i386-gnu-tdep.c gnu_sigtramp_code.  */
+ 
+ #ifdef __x86_64__
+-asm ("rpc_wait_trampoline:\n"
++asm ("trampoline:\n"
++     "fnclex\n"                       /* Clear any pending exception.  */
++     "jmp _trampoline\n"
++     "rpc_wait_trampoline:\n"
+   /* This is the entry point when we have an RPC reply message to receive
+      before running the handler.  The MACH_MSG_SEND bit has already been
+      cleared in the OPTION argument in our %rsi.  The interrupted user
+@@ -480,7 +483,7 @@ asm ("rpc_wait_trampoline:\n"
+      /* Switch to the signal stack.  */
+      "movq %rbx, %rsp\n"
+ 
+-     "trampoline:\n"
++     "_trampoline:\n"
+      /* Entry point for running the handler normally.  The arguments to the
+         handler function are on the top of the stack, same as in the i386
+         version:
+@@ -506,7 +509,10 @@ asm ("rpc_wait_trampoline:\n"
+      "movq 16(%rsp), %rdi\n"
+      "ret");
+ #else
+-asm ("rpc_wait_trampoline:\n");
++asm ("trampoline:\n"
++     "fnclex\n"                       /* Clear any pending exception.  */
++     "jmp _trampoline\n"
++     "rpc_wait_trampoline:\n");
+   /* This is the entry point when we have an RPC reply message to receive
+      before running the handler.  The MACH_MSG_SEND bit has already been
+      cleared in the OPTION argument on our stack.  The interrupted user
+@@ -526,7 +532,7 @@ asm (/* Retry the interrupted mach_msg system call.  */
+      /* Switch to the signal stack.  */
+      "movl %ebx, %esp\n");
+ 
+- asm ("trampoline:\n");
++asm ("_trampoline:\n");
+   /* Entry point for running the handler normally.  The arguments to the
+      handler function are already on the top of the stack:
+ 
+-- 
+2.51.0
+
diff --git a/gnu/packages/patches/glibc-hurd-xstate.patch 
b/gnu/packages/patches/glibc-hurd-xstate.patch
new file mode 100644
index 0000000000..f46a84adb2
--- /dev/null
+++ b/gnu/packages/patches/glibc-hurd-xstate.patch
@@ -0,0 +1,813 @@
+Cherry picked from glibc 2.42
+
+6d6a6e2dd2 * hurd: save xstate during signal handling
+8d54b428cf * hurd: Do not restore xstate when it is not initialized
+0f2df19d95 * hurd: Do not check for xstate level if it was not initialized
+
+From 6d6a6e2dd2133908e3f5cb8a2ed817ccb2a0bb06 Mon Sep 17 00:00:00 2001
+From: Luca Dariz <[email protected]>
+Date: Wed, 19 Mar 2025 18:11:18 +0100
+Subject: [PATCH] hurd: save xstate during signal handling
+
+* hurd/Makefile: add new tests
+* hurd/test-sig-rpc-interrupted.c: check xstate save and restore in
+  the case where a signal is delivered to a thread which is waiting
+  for an rpc. This test implements the rpc interruption protocol used
+  by the hurd servers. It was so far passing on Debian thanks to the
+  local-intr-msg-clobber.diff patch, which is now obsolete.
+* hurd/test-sig-xstate.c: check xstate save and restore in the case
+  where a signal is delivered to a running thread, making sure that
+  the xstate is modified in the signal handler.
+* hurd/test-xstate.h: add helpers to test xstate
+* sysdeps/mach/hurd/i386/bits/sigcontext.h: add xstate to the
+  sigcontext structure.
++ sysdeps/mach/hurd/i386/sigreturn.c: restore xstate from the saved
+  context
+* sysdeps/mach/hurd/x86/trampoline.c: save xstate if
+  supported. Otherwise we fall back to the previous behaviour of
+  ignoring xstate.
+* sysdeps/mach/hurd/x86_64/bits/sigcontext.h: add xstate to the
+  sigcontext structure.
+* sysdeps/mach/hurd/x86_64/sigreturn.c: restore xstate from the saved
+  context
+
+Signed-off-by: Luca Dariz <[email protected]>
+Signed-off-by: Samuel Thibault <[email protected]>
+Message-ID: <[email protected]>
+---
+ hurd/Makefile                              |   5 +
+ hurd/test-sig-rpc-interrupted.c            | 185 +++++++++++++++++++++
+ hurd/test-sig-xstate.c                     |  94 +++++++++++
+ hurd/test-xstate.h                         |  40 +++++
+ sysdeps/mach/hurd/i386/bits/sigcontext.h   |   2 +
+ sysdeps/mach/hurd/i386/sigreturn.c         |  32 +++-
+ sysdeps/mach/hurd/x86/trampoline.c         |  91 ++++++++--
+ sysdeps/mach/hurd/x86_64/bits/sigcontext.h |   2 +
+ sysdeps/mach/hurd/x86_64/sigreturn.c       |  32 +++-
+ 9 files changed, 458 insertions(+), 25 deletions(-)
+ create mode 100644 hurd/test-sig-rpc-interrupted.c
+ create mode 100644 hurd/test-sig-xstate.c
+ create mode 100644 hurd/test-xstate.h
+
+diff --git a/hurd/Makefile b/hurd/Makefile
+index cf70b8c65c..cbc3c23b1f 100644
+--- a/hurd/Makefile
++++ b/hurd/Makefile
+@@ -19,6 +19,11 @@ subdir := hurd
+ 
+ include ../Makeconfig
+ 
++tests := test-sig-xstate \
++      test-sig-rpc-interrupted
++$(objpfx)test-sig-xstate: $(shared-thread-library)
++$(objpfx)test-sig-rpc-interrupted: $(shared-thread-library) 
$(objdir)/hurd/libhurduser.so
++
+ headers = \
+   $(interface-headers) \
+   hurd.h \
+diff --git a/hurd/test-sig-rpc-interrupted.c b/hurd/test-sig-rpc-interrupted.c
+new file mode 100644
+index 0000000000..a89d70e5a4
+--- /dev/null
++++ b/hurd/test-sig-rpc-interrupted.c
+@@ -0,0 +1,185 @@
++/* Test the state save/restore procedures during signal handling when an
++   interruptible RPC is restarted.
++
++   Copyright (C) 2024 Free Software Foundation, Inc.
++   This file is part of the GNU C Library.
++
++   The GNU C Library is free software; you can redistribute it and/or
++   modify it under the terms of the GNU Lesser General Public
++   License as published by the Free Software Foundation; either
++   version 2.1 of the License, or (at your option) any later version.
++
++   The GNU C Library is distributed in the hope that it will be useful,
++   but WITHOUT ANY WARRANTY; without even the implied warranty of
++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++   Lesser General Public License for more details.
++
++   You should have received a copy of the GNU Lesser General Public
++   License along with the GNU C Library; if not, see
++   <https://www.gnu.org/licenses/>.  */
++
++
++#include <assert.h>
++#include <pthread.h>
++#include <signal.h>
++#include <stdbool.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include <unistd.h>
++
++#include <mach/message.h>
++#include <mach/gnumach.h>
++#include <mach/mach_traps.h>
++#include <mach/mig_errors.h>
++#include <mach-shortcuts.h>
++#include <mach_init.h>
++#include <hurd/io.h>
++#include <hurd/io_reply.h>
++
++#include <support/check.h>
++#include <support/xthread.h>
++
++#include "test-xstate.h"
++
++void handler (int signum, siginfo_t *info, void *context)
++{
++  printf ("signal %d setting a different CPU state\n", signum);
++  char buf3[XSTATE_BUFFER_SIZE];
++  memset (buf3, 0x77, XSTATE_BUFFER_SIZE);
++  SET_XSTATE (buf3);
++}
++
++static const mach_msg_type_t RetCodeCheck = {
++  .msgt_name =            (unsigned char) MACH_MSG_TYPE_INTEGER_32,
++  .msgt_size =            32,
++  .msgt_number =          1,
++  .msgt_inline =          TRUE,
++  .msgt_longform =        FALSE,
++  .msgt_deallocate =      FALSE,
++  .msgt_unused =          0
++};
++
++
++/* Helper thread to simulate a proper RPC interruption during dignal handling 
*/
++void* fake_interruptor (void *arg)
++{
++  int err;
++  sigset_t ss;
++  TEST_COMPARE (sigemptyset (&ss), 0);
++  TEST_COMPARE (sigaddset (&ss, SIGUSR1), 0);
++  TEST_COMPARE (sigprocmask (SIG_BLOCK, &ss, NULL), 0);
++
++  struct {
++    mach_msg_header_t Head;
++  } request;
++  mach_port_t rxport = *((mach_port_t*)arg);
++  err = mach_msg (&request.Head, MACH_RCV_MSG, 0, sizeof (request), rxport,
++                  MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
++  TEST_COMPARE (err, MACH_MSG_SUCCESS);
++  TEST_COMPARE (request.Head.msgh_bits, 0x1112);
++  TEST_COMPARE (request.Head.msgh_size, sizeof (request.Head));
++  TEST_COMPARE (request.Head.msgh_id, 33000);
++
++  mig_reply_header_t reply;
++  reply.Head = request.Head;
++  reply.Head.msgh_id += 100;
++  reply.RetCodeType = RetCodeCheck;
++  reply.RetCode = KERN_SUCCESS;
++  err = mach_msg (&reply.Head, MACH_SEND_MSG, sizeof (reply), 0, 
MACH_PORT_NULL,
++                  MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
++  TEST_COMPARE (err, MACH_MSG_SUCCESS);
++
++  return NULL;
++}
++
++
++/* Helper thread to send a signal to the main thread in the middle of
++ * an interruptible rpc */
++void* signal_sender (void *arg)
++{
++  int err;
++  sigset_t ss;
++  TEST_COMPARE (sigemptyset (&ss), 0);
++  TEST_COMPARE (sigaddset (&ss, SIGUSR1), 0);
++  TEST_COMPARE (sigprocmask (SIG_BLOCK, &ss, NULL), 0);
++
++  /* Receive the first request, we won't answer to this. */
++  struct {
++    mach_msg_header_t head;
++    char data[64];
++  } m1, m2;
++  mach_port_t rxport = *((mach_port_t*)arg);
++  memset (&m1, 0, sizeof (m1));
++  memset (&m2, 0, sizeof (m2));
++  err = mach_msg (&m1.head, MACH_RCV_MSG, 0, sizeof (m1), rxport,
++                  MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
++  TEST_COMPARE (err, MACH_MSG_SUCCESS);
++
++  /* interrupt the ongoing rpc with a signal, using the
++   * interruptible rpc protocol */
++  pthread_t thintr = xpthread_create (NULL, fake_interruptor, arg);
++  TEST_COMPARE (kill (getpid (), SIGUSR1), 0);
++  xpthread_join (thintr);
++
++  /* Complete the interruption by sending EINTR */
++  mig_reply_header_t reply;
++  reply.Head = m1.head;
++  reply.Head.msgh_id += 100;
++  reply.RetCodeType = RetCodeCheck;
++  reply.RetCode = EINTR;
++  err = mach_msg (&reply.Head, MACH_SEND_MSG, sizeof (reply), 0, 
MACH_PORT_NULL,
++                  MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
++  TEST_COMPARE (err, MACH_MSG_SUCCESS);
++
++  /* Receive the retried rpc, and check that it has the same payload
++   * as the first one. Port names might still be different. */
++  err = mach_msg (&m2.head, MACH_RCV_MSG, 0, sizeof (m2), rxport,
++                  MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
++  TEST_COMPARE (m1.head.msgh_bits, m2.head.msgh_bits);
++  TEST_COMPARE (m1.head.msgh_size, m2.head.msgh_size);
++  TEST_COMPARE (m1.head.msgh_id, m2.head.msgh_id);
++  TEST_COMPARE_BLOB (m1.data, sizeof (m1.data), m2.data, sizeof (m2.data));
++
++  /* And finally make the rpc succeed by sending a valid reply */
++  err = io_read_reply (m2.head.msgh_remote_port, MACH_MSG_TYPE_MOVE_SEND_ONCE,
++                       KERN_SUCCESS, NULL, 0);
++  TEST_COMPARE (err, MACH_MSG_SUCCESS);
++
++  return NULL;
++}
++
++
++static int do_test (void)
++{
++#if ! XSTATE_HELPERS_SUPPORTED
++  FAIL_UNSUPPORTED ("Test not supported on this arch.");
++#endif
++
++  /* Setup signal handling; we need to handle the signal in the main
++   * thread, the other ones will explicitely block SIGUSR1. */
++  struct sigaction act = { 0 };
++  act.sa_flags = SA_RESTART;
++  act.sa_sigaction = &handler;
++  TEST_COMPARE (sigaction (SIGUSR1, &act, NULL), 0);
++
++  mach_port_t fakeio;
++  int err;
++  err = mach_port_allocate (mach_task_self (), MACH_PORT_RIGHT_RECEIVE, 
&fakeio);
++  TEST_COMPARE (err, MACH_MSG_SUCCESS);
++
++  err = mach_port_insert_right (mach_task_self (), fakeio, fakeio,
++                                MACH_MSG_TYPE_MAKE_SEND);
++  TEST_COMPARE (err, MACH_MSG_SUCCESS);
++
++  pthread_t thsender = xpthread_create (NULL, signal_sender, &fakeio);
++
++  char *buf;
++  mach_msg_type_number_t n;
++  TEST_COMPARE (io_read (fakeio, &buf, &n, 1, 2), 0);
++
++  xpthread_join (thsender);
++  return EXIT_SUCCESS;
++}
++
++#include <support/test-driver.c>
+diff --git a/hurd/test-sig-xstate.c b/hurd/test-sig-xstate.c
+new file mode 100644
+index 0000000000..0a68a44fd7
+--- /dev/null
++++ b/hurd/test-sig-xstate.c
+@@ -0,0 +1,94 @@
++/* Test the state save/restore procedures during signal handling.
++
++   Copyright (C) 2025 Free Software Foundation, Inc.
++   This file is part of the GNU C Library.
++
++   The GNU C Library is free software; you can redistribute it and/or
++   modify it under the terms of the GNU Lesser General Public
++   License as published by the Free Software Foundation; either
++   version 2.1 of the License, or (at your option) any later version.
++
++   The GNU C Library is distributed in the hope that it will be useful,
++   but WITHOUT ANY WARRANTY; without even the implied warranty of
++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++   Lesser General Public License for more details.
++
++   You should have received a copy of the GNU Lesser General Public
++   License along with the GNU C Library; if not, see
++   <https://www.gnu.org/licenses/>.  */
++
++
++#include <assert.h>
++#include <pthread.h>
++#include <signal.h>
++#include <stdbool.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include <unistd.h>
++
++#include <mach/message.h>
++#include <mach/gnumach.h>
++#include <mach/mach_traps.h>
++#include <mach-shortcuts.h>
++#include <mach_init.h>
++#include <hurd/io.h>
++#include <hurd/io_reply.h>
++
++#include <support/check.h>
++#include <support/xthread.h>
++
++#include "test-xstate.h"
++
++static volatile bool loopflag = true;
++
++void handler (int signum, siginfo_t *info, void *context)
++{
++  char buf3[XSTATE_BUFFER_SIZE];
++  memset (buf3, 0x77, XSTATE_BUFFER_SIZE);
++  SET_XSTATE (buf3);
++  printf ("signal %d setting a different CPU state\n", signum);
++  loopflag = false;
++}
++
++/* Helper thread to send a signal to the main thread  */
++void* signal_sender (void *arg)
++{
++  sigset_t ss;
++  assert (! sigemptyset (&ss));
++  assert (! sigaddset (&ss, SIGUSR1));
++  assert (! sigprocmask (SIG_BLOCK, &ss, NULL));
++
++  TEST_COMPARE (kill (getpid (), SIGUSR1), 0);
++
++  return NULL;
++}
++
++static int do_test (void)
++{
++#if ! XSTATE_HELPERS_SUPPORTED
++  FAIL_UNSUPPORTED ("Test not supported on this arch.");
++#endif
++
++  struct sigaction act = { 0 };
++  act.sa_sigaction = &handler;
++  TEST_COMPARE (sigaction (SIGUSR1, &act, NULL), 0);
++
++  pthread_t thsender = xpthread_create (NULL, signal_sender, NULL);
++
++  char buf1[XSTATE_BUFFER_SIZE], buf2[XSTATE_BUFFER_SIZE];
++  memset (buf1, 0x33, XSTATE_BUFFER_SIZE);
++
++  SET_XSTATE (buf1);
++
++  while (loopflag)
++    ;
++
++  GET_XSTATE (buf2);
++  TEST_COMPARE_BLOB (buf1, sizeof (buf1), buf2, sizeof (buf2));
++
++  xpthread_join (thsender);
++  return EXIT_SUCCESS;
++}
++
++#include <support/test-driver.c>
+diff --git a/hurd/test-xstate.h b/hurd/test-xstate.h
+new file mode 100644
+index 0000000000..a8185dcb07
+--- /dev/null
++++ b/hurd/test-xstate.h
+@@ -0,0 +1,40 @@
++/* Helpers to test XSTATE during signal handling
++
++   Copyright (C) 2025 Free Software Foundation, Inc.
++   This file is part of the GNU C Library.
++
++   The GNU C Library is free software; you can redistribute it and/or
++   modify it under the terms of the GNU Lesser General Public
++   License as published by the Free Software Foundation; either
++   version 2.1 of the License, or (at your option) any later version.
++
++   The GNU C Library is distributed in the hope that it will be useful,
++   but WITHOUT ANY WARRANTY; without even the implied warranty of
++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++   Lesser General Public License for more details.
++
++   You should have received a copy of the GNU Lesser General Public
++   License along with the GNU C Library; if not, see
++   <https://www.gnu.org/licenses/>.  */
++
++#ifndef _TEST_XSTATE_H
++#define _TEST_XSTATE_H
++
++#if defined __x86_64__ || defined __i386__
++#define XSTATE_HELPERS_SUPPORTED 1
++#define XSTATE_BUFFER_SIZE 16
++#define SET_XSTATE(b) do {                                    \
++    asm volatile ("movups (%0),%%xmm0" :: "r" (b));           \
++  } while (0)
++
++#define GET_XSTATE(b) do {                                    \
++    asm volatile ("movups %%xmm0,(%0)" :: "r" (b));           \
++  } while (0)
++
++#else
++#define XSTATE_HELPERS_SUPPORTED 0
++#define XSTATE_BUFFER_SIZE 1
++#define SET_XSTATE(b)
++#endif
++
++#endif /* _TEST_XSTATE_H */
+diff --git a/sysdeps/mach/hurd/i386/bits/sigcontext.h 
b/sysdeps/mach/hurd/i386/bits/sigcontext.h
+index 6e5e220e9d..c44e4deac6 100644
+--- a/sysdeps/mach/hurd/i386/bits/sigcontext.h
++++ b/sysdeps/mach/hurd/i386/bits/sigcontext.h
+@@ -88,6 +88,8 @@ struct sigcontext
+     struct i386_fp_save sc_fpsave;
+     struct i386_fp_regs sc_fpregs;
+     int sc_fpexcsr;           /* FPSR including exception bits.  */
++
++    struct i386_xfloat_state *xstate;
+   };
+ 
+ /* Traditional BSD names for some members.  */
+diff --git a/sysdeps/mach/hurd/i386/sigreturn.c 
b/sysdeps/mach/hurd/i386/sigreturn.c
+index ce8df8d02b..37fa984070 100644
+--- a/sysdeps/mach/hurd/i386/sigreturn.c
++++ b/sysdeps/mach/hurd/i386/sigreturn.c
+@@ -21,6 +21,8 @@
+ #include <stdlib.h>
+ #include <string.h>
+ 
++#include <cpuid.h>
++
+ /* This is run on the thread stack after restoring it, to be able to
+    unlock SS off sigstack.  */
+ static void
+@@ -123,10 +125,32 @@ __sigreturn (struct sigcontext *scp)
+   if (scp->sc_onstack)
+     ss->sigaltstack.ss_flags &= ~SS_ONSTACK;
+ 
+-  if (scp->sc_fpused)
+-    /* Restore the FPU state.  Mach conveniently stores the state
+-       in the format the i387 `frstor' instruction uses to restore it.  */
+-    asm volatile ("frstor %0" : : "m" (scp->sc_fpsave));
++#ifdef i386_XFLOAT_STATE
++  if ((scp->xstate) && (scp->xstate->initialized))
++    {
++      unsigned eax, ebx, ecx, edx;
++      __cpuid_count(0xd, 0, eax, ebx, ecx, edx);
++      switch (scp->xstate->fp_save_kind)
++        {
++        case 0: // FNSAVE
++          asm volatile("frstor %0" : : "m" (scp->xstate->hw_state));
++          break;
++        case 1: // FXSAVE
++          asm volatile("fxrstor %0" : : "m" (scp->xstate->hw_state),    \
++                       "a" (eax), "d" (edx));
++          break;
++        default: // XSAVE, XSAVEOPT, XSAVEC, XSAVES
++          asm volatile("xrstor %0" : : "m" (scp->xstate->hw_state),     \
++                       "a" (eax), "d" (edx));
++          break;
++        }
++    }
++  else
++#endif
++    if (scp->sc_fpused)
++      /* Restore the FPU state.  Mach conveniently stores the state
++         in the format the i387 `frstor' instruction uses to restore it.  */
++      asm volatile ("frstor %0" : : "m" (scp->sc_fpsave));
+ 
+   {
+     /* There are convenient instructions to pop state off the stack, so we
+diff --git a/sysdeps/mach/hurd/x86/trampoline.c 
b/sysdeps/mach/hurd/x86/trampoline.c
+index 8e2890f8c5..db756e8a1f 100644
+--- a/sysdeps/mach/hurd/x86/trampoline.c
++++ b/sysdeps/mach/hurd/x86/trampoline.c
+@@ -26,7 +26,11 @@
+ #include "hurdfault.h"
+ #include <intr-msg.h>
+ #include <sys/ucontext.h>
+-
++#ifdef __x86_64__
++#include <mach/x86_64/mach_i386.h>
++#else
++#include <mach/i386/mach_i386.h>
++#endif
+ 
+ /* Fill in a siginfo_t structure for SA_SIGINFO-enabled handlers.  */
+ static void fill_siginfo (siginfo_t *si, int signo,
+@@ -106,6 +110,7 @@ _hurd_setup_sighandler (struct hurd_sigstate *ss, const 
struct sigaction *action
+   void firewall (void);
+   void *sigsp;
+   struct sigcontext *scp;
++  vm_size_t xstate_size;
+   struct
+     {
+       union
+@@ -145,6 +150,14 @@ _hurd_setup_sighandler (struct hurd_sigstate *ss, const 
struct sigaction *action
+       struct hurd_userlink link;
+       ucontext_t ucontext;
+       siginfo_t siginfo;
++#ifdef __x86_64__
++      char _pad2[56];
++#else
++      char _pad2[20];
++#endif
++      char xstate[];
++      /* Don't add anything after xstate, as it's dynamically
++         sized. */
+     } *stackframe;
+ 
+ #ifdef __x86_64__
+@@ -170,6 +183,17 @@ _hurd_setup_sighandler (struct hurd_sigstate *ss, const 
struct sigaction *action
+   if (! machine_get_basic_state (ss->thread, state))
+     return NULL;
+ 
++  /* 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");
++
++  if (__i386_get_xstate_size(__mach_host_self(), &xstate_size))
++#endif
++    xstate_size = 0;
++
+   /* Save the original SP in the gratuitous `esp' slot.
+      We may need to reset the SP (the `uesp' slot) to avoid clobbering an
+      interrupted RPC frame.  */
+@@ -196,14 +220,21 @@ _hurd_setup_sighandler (struct hurd_sigstate *ss, const 
struct sigaction *action
+ #endif
+     }
+ 
+-  /* Push the arguments to call `trampoline' on the stack.  */
+-  sigsp -= sizeof (*stackframe);
+-#ifdef __x86_64__
+-  /* Align SP at 16 bytes.  Coupled with the fact that sigreturn_addr is
+-     16-byte aligned within the stackframe struct, this ensures that it ends
+-     up on a 16-byte aligned address, as required by the ABI.  */
+-  sigsp = (void *) ((uintptr_t) sigsp & ~15UL);
+-#endif
++  /* Push the arguments to call `trampoline' on the stack.
++   * The extended state might have a variable size depending on the platform,
++   * so we dynamically allocate it on the stack frame.*/
++  sigsp -= sizeof (*stackframe) + xstate_size;
++
++  /* Align SP at 64 bytes. This is needed for two reasons:
++   * - sigreturn_addr is 16-byte aligned within the stackframe
++   *   struct, and this ensures that it ends up on a 16-byte aligned
++   *   address, as required by the ABI.
++   * - the XSAVE state needs to be aligned at 64 bytes (on both i386 and
++   *   x86_64), so we align the stackframe also at 64 bytes and add the
++   *   required padding at the end, see the _pad2 field.
++   */
++  sigsp = (void *) ((uintptr_t) sigsp & ~63UL);
++
+   stackframe = sigsp;
+ 
+   if (_hurdsig_catch_memory_fault (stackframe))
+@@ -248,14 +279,40 @@ _hurd_setup_sighandler (struct hurd_sigstate *ss, const 
struct sigaction *action
+       memcpy (&scp->sc_i386_thread_state,
+             &state->basic, sizeof (state->basic));
+ 
+-      /* struct sigcontext is laid out so that starting at sc_fpkind mimics
+-       a struct i386_float_state.  */
+-      _Static_assert (offsetof (struct sigcontext, sc_i386_float_state)
+-                    % __alignof__ (struct i386_float_state) == 0,
+-                    "sc_i386_float_state layout mismatch");
+-      ok = machine_get_state (ss->thread, state, i386_FLOAT_STATE,
+-                            &state->fpu, &scp->sc_i386_float_state,
+-                            sizeof (state->fpu));
++      scp->xstate = NULL;
++#ifdef i386_XFLOAT_STATE
++      if (xstate_size > 0)
++        {
++          mach_msg_type_number_t got = (xstate_size / sizeof (int));
++
++          ok = (! __thread_get_state (ss->thread, i386_XFLOAT_STATE,
++                                      (thread_state_t) stackframe->xstate, 
&got)
++                && got == (xstate_size / sizeof (int)));
++
++        if (((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;
++            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.  */
++          _Static_assert (offsetof (struct sigcontext, sc_i386_float_state)
++                         % __alignof__ (struct i386_float_state) == 0,
++                         "sc_i386_float_state layout mismatch");
++          ok = machine_get_state (ss->thread, state, i386_FLOAT_STATE,
++                                 &state->fpu, &scp->sc_i386_float_state,
++                                 sizeof (state->fpu));
++        }
+ 
+       /* Set up the arguments for the signal handler.  */
+       stackframe->signo = signo;
+diff --git a/sysdeps/mach/hurd/x86_64/bits/sigcontext.h 
b/sysdeps/mach/hurd/x86_64/bits/sigcontext.h
+index 7bac881176..d83795fcbc 100644
+--- a/sysdeps/mach/hurd/x86_64/bits/sigcontext.h
++++ b/sysdeps/mach/hurd/x86_64/bits/sigcontext.h
+@@ -96,6 +96,8 @@ struct sigcontext
+     struct i386_fp_save sc_fpsave;
+     struct i386_fp_regs sc_fpregs;
+     int sc_fpexcsr;           /* FPSR including exception bits.  */
++
++    struct i386_xfloat_state *xstate;
+   };
+ 
+ /* Traditional BSD names for some members.  */
+diff --git a/sysdeps/mach/hurd/x86_64/sigreturn.c 
b/sysdeps/mach/hurd/x86_64/sigreturn.c
+index 81a2d3ba74..dff8e76dc8 100644
+--- a/sysdeps/mach/hurd/x86_64/sigreturn.c
++++ b/sysdeps/mach/hurd/x86_64/sigreturn.c
+@@ -20,6 +20,8 @@
+ #include <hurd/msg.h>
+ #include <stdlib.h>
+ 
++#include <cpuid.h>
++
+ /* This is run on the thread stack after restoring it, to be able to
+    unlock SS off sigstack.  */
+ void
+@@ -116,10 +118,32 @@ __sigreturn (struct sigcontext *scp)
+   if (scp->sc_onstack)
+     ss->sigaltstack.ss_flags &= ~SS_ONSTACK;
+ 
+-  if (scp->sc_fpused)
+-    /* Restore the FPU state.  Mach conveniently stores the state
+-       in the format the i387 `frstor' instruction uses to restore it.  */
+-    asm volatile ("frstor %0" : : "m" (scp->sc_fpsave));
++#ifdef i386_XFLOAT_STATE
++  if ((scp->xstate) && (scp->xstate->initialized))
++    {
++      unsigned eax, ebx, ecx, edx;
++      __cpuid_count(0xd, 0, eax, ebx, ecx, edx);
++      switch (scp->xstate->fp_save_kind)
++        {
++        case 0: // FNSAVE
++          asm volatile("frstor %0" : : "m" (scp->xstate->hw_state));
++          break;
++        case 1: // FXSAVE
++          asm volatile("fxrstor %0" : : "m" (scp->xstate->hw_state),    \
++                       "a" (eax), "d" (edx));
++          break;
++        default: // XSAVE, XSAVEOPT, XSAVEC, XSAVES
++          asm volatile("xrstor %0" : : "m" (scp->xstate->hw_state),     \
++                       "a" (eax), "d" (edx));
++          break;
++        }
++    }
++  else
++#endif
++    if (scp->sc_fpused)
++      /* Restore the FPU state.  Mach conveniently stores the state
++         in the format the i387 `frstor' instruction uses to restore it.  */
++      asm volatile ("frstor %0" : : "m" (scp->sc_fpsave));
+ 
+   /* Copy the registers onto the user's stack, to be able to release the
+      altstack (by unlocking sigstate).  Note that unless an altstack is used,
+-- 
+2.51.0
+
+From 8d54b428cfe98c21049f94c8af3bf302e44091e9 Mon Sep 17 00:00:00 2001
+From: Samuel Thibault <[email protected]>
+Date: Mon, 21 Apr 2025 19:42:27 +0200
+Subject: [PATCH] hurd: Do not restore xstate when it is not initialized
+
+If the process has never used fp before getting a signal, xstate is set
+(and thus the x87 state is not initialized) but xstate->initialized is still
+0, and we should not restore anything.
+---
+ sysdeps/mach/hurd/i386/sigreturn.c   | 37 +++++++++++++++-------------
+ sysdeps/mach/hurd/x86_64/sigreturn.c | 37 +++++++++++++++-------------
+ 2 files changed, 40 insertions(+), 34 deletions(-)
+
+diff --git a/sysdeps/mach/hurd/i386/sigreturn.c 
b/sysdeps/mach/hurd/i386/sigreturn.c
+index 37fa984070..dc57d6122c 100644
+--- a/sysdeps/mach/hurd/i386/sigreturn.c
++++ b/sysdeps/mach/hurd/i386/sigreturn.c
+@@ -126,24 +126,27 @@ __sigreturn (struct sigcontext *scp)
+     ss->sigaltstack.ss_flags &= ~SS_ONSTACK;
+ 
+ #ifdef i386_XFLOAT_STATE
+-  if ((scp->xstate) && (scp->xstate->initialized))
++  if (scp->xstate)
+     {
+-      unsigned eax, ebx, ecx, edx;
+-      __cpuid_count(0xd, 0, eax, ebx, ecx, edx);
+-      switch (scp->xstate->fp_save_kind)
+-        {
+-        case 0: // FNSAVE
+-          asm volatile("frstor %0" : : "m" (scp->xstate->hw_state));
+-          break;
+-        case 1: // FXSAVE
+-          asm volatile("fxrstor %0" : : "m" (scp->xstate->hw_state),    \
+-                       "a" (eax), "d" (edx));
+-          break;
+-        default: // XSAVE, XSAVEOPT, XSAVEC, XSAVES
+-          asm volatile("xrstor %0" : : "m" (scp->xstate->hw_state),     \
+-                       "a" (eax), "d" (edx));
+-          break;
+-        }
++      if (scp->xstate->initialized)
++      {
++        unsigned eax, ebx, ecx, edx;
++        __cpuid_count(0xd, 0, eax, ebx, ecx, edx);
++        switch (scp->xstate->fp_save_kind)
++          {
++          case 0: // FNSAVE
++            asm volatile("frstor %0" : : "m" (scp->xstate->hw_state));
++            break;
++          case 1: // FXSAVE
++            asm volatile("fxrstor %0" : : "m" (scp->xstate->hw_state),    \
++                         "a" (eax), "d" (edx));
++            break;
++          default: // XSAVE, XSAVEOPT, XSAVEC, XSAVES
++            asm volatile("xrstor %0" : : "m" (scp->xstate->hw_state),     \
++                         "a" (eax), "d" (edx));
++            break;
++          }
++      }
+     }
+   else
+ #endif
+diff --git a/sysdeps/mach/hurd/x86_64/sigreturn.c 
b/sysdeps/mach/hurd/x86_64/sigreturn.c
+index dff8e76dc8..773c00f86d 100644
+--- a/sysdeps/mach/hurd/x86_64/sigreturn.c
++++ b/sysdeps/mach/hurd/x86_64/sigreturn.c
+@@ -119,24 +119,27 @@ __sigreturn (struct sigcontext *scp)
+     ss->sigaltstack.ss_flags &= ~SS_ONSTACK;
+ 
+ #ifdef i386_XFLOAT_STATE
+-  if ((scp->xstate) && (scp->xstate->initialized))
++  if (scp->xstate)
+     {
+-      unsigned eax, ebx, ecx, edx;
+-      __cpuid_count(0xd, 0, eax, ebx, ecx, edx);
+-      switch (scp->xstate->fp_save_kind)
+-        {
+-        case 0: // FNSAVE
+-          asm volatile("frstor %0" : : "m" (scp->xstate->hw_state));
+-          break;
+-        case 1: // FXSAVE
+-          asm volatile("fxrstor %0" : : "m" (scp->xstate->hw_state),    \
+-                       "a" (eax), "d" (edx));
+-          break;
+-        default: // XSAVE, XSAVEOPT, XSAVEC, XSAVES
+-          asm volatile("xrstor %0" : : "m" (scp->xstate->hw_state),     \
+-                       "a" (eax), "d" (edx));
+-          break;
+-        }
++      if (scp->xstate->initialized)
++      {
++        unsigned eax, ebx, ecx, edx;
++        __cpuid_count(0xd, 0, eax, ebx, ecx, edx);
++        switch (scp->xstate->fp_save_kind)
++          {
++          case 0: // FNSAVE
++            asm volatile("frstor %0" : : "m" (scp->xstate->hw_state));
++            break;
++          case 1: // FXSAVE
++            asm volatile("fxrstor %0" : : "m" (scp->xstate->hw_state),    \
++                         "a" (eax), "d" (edx));
++            break;
++          default: // XSAVE, XSAVEOPT, XSAVEC, XSAVES
++            asm volatile("xrstor %0" : : "m" (scp->xstate->hw_state),     \
++                         "a" (eax), "d" (edx));
++            break;
++          }
++      }
+     }
+   else
+ #endif
+-- 
+2.51.0
+
+From 0f2df19d9535d234b31c65f84a6c67ac2e0bd027 Mon Sep 17 00:00:00 2001
+From: Samuel Thibault <[email protected]>
+Date: Mon, 21 Apr 2025 19:45:02 +0200
+Subject: [PATCH] hurd: Do not check for xstate level if it was not
+ initialized
+
+If __thread_get_state failed, there is no xstate level to check.
+ok is 0 already and the memory exists, but better not read uninitialized
+memory.
+---
+ sysdeps/mach/hurd/x86/trampoline.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/sysdeps/mach/hurd/x86/trampoline.c 
b/sysdeps/mach/hurd/x86/trampoline.c
+index db756e8a1f..02510b178c 100644
+--- a/sysdeps/mach/hurd/x86/trampoline.c
++++ b/sysdeps/mach/hurd/x86/trampoline.c
+@@ -289,7 +289,7 @@ _hurd_setup_sighandler (struct hurd_sigstate *ss, const 
struct sigaction *action
+                                       (thread_state_t) stackframe->xstate, 
&got)
+                 && got == (xstate_size / sizeof (int)));
+ 
+-        if (((struct i386_xfloat_state*) stackframe->xstate)->fp_save_kind > 
5)
++        if (ok && ((struct i386_xfloat_state*) 
stackframe->xstate)->fp_save_kind > 5)
+           /* We support up to XSAVES */
+           ok = 0;
+ 
+-- 
+2.51.0
+


Reply via email to