Control: tags -1 confirmed On 2025-05-12 20:07:15 +0200, Aurelien Jarno wrote: > Package: release.debian.org > Severity: normal > X-Debbugs-Cc: [email protected] > Control: affects -1 + src:glibc > User: [email protected] > Usertags: unblock > > Please pre-approve unblocking of package glibc/2.41-8
ACK from RT. Adding d-boot for the d-i ACK. It might make sense to wait until after the next RC from d-i with the upload. Cheers > > [ Reason ] > * The upstream stable branch got a few fixes since the last upload > and this update pulls them into the debian package. From the > changelog: > > - Fix elf/tst-audit10 test failure on x86 systems without AVX. Closes: > #1103303. > => This fixes an issue reported by the reproducible builds team, > basically the testsuite doesn't run anymore on a host without > AVX. This is relatively recent so it went unnoticed, and has been > introduced by GCC changes. This comes with additional tests. > > - Fix pthread_getattr_np failure when executable stack tunable is set. > => This fix an issue introduced with the recently added tunable > option to make the stack executable. This issue has been reported > upstream from a Debian system: > https://sourceware.org/bugzilla/show_bug.cgi?id=32897 > > * In addition to the upstream changes there is also a debconf > translation update, and a small change to the debhelper.mk to fix the > content of the NEWS.Debian.gz (#1104099). > > * Finally there are also some Hurd related changes, but they only > touches code that is not built on Linux. > > [ Impact ] > If the unblock isn't granted: > - Users will get the wrong documentation to make the stack executable > - Difference with the upstream stable branch will increase, which might > make future updates more complicated (e.g. for a security fix). > > [ Tests ] > The pthread_getattr_np changes comes with additional upstream tests. > > [ Risks ] > I believe the risks are quite low, the changes only affect the ld.so > binary, and the version number in the libc.so binary. Other binaries are > bit to bit identical to the previous version. The changes to ld.so are > only executed with GLIBC_TUNABLES=glibc.rtld.execstack=2. > > [ Checklist ] > [x] all changes are documented in the d/changelog > [x] I reviewed all changes and I approve them > [x] attach debdiff against the package in testing > > [ Other info ] > It took me some time to prepare this request, and in the meantime the > d-i udeb freeze email arrived. I am fine with any ordering. > > unblock glibc/2.41-8 > diff --git a/debian/changelog b/debian/changelog > index bbc1004d..fe504c81 100644 > --- a/debian/changelog > +++ b/debian/changelog > @@ -1,3 +1,34 @@ > +glibc (2.41-8) unstable; urgency=medium > + > + [ Samuel Thibault ] > + * debian/testsuite-xfail-debian.mk: xfail tst-execstack-prog-static-tunable > + on hurd-any. Drop duplicate unsupported stances commited uptream. > + * debian/patches/hurd-i386/git-dup-refcnt.diff: Fix detecting too many > dups. > + * debian/patches/hurd-i386/git-xstate.diff: Fix restoring SSE state on > + signals. > + * debian/patches/hurd-i386/local-intr-msg-clobber.diff: Drop now-useless > + patch. > + * debian/patches/hurd-i386/git-utime-EINVAL.diff: Make *utime*s catch > invalid > + times. > + * debian/patches/hurd-i386/git-xstate-initialized.diff: Fix crash in dash. > + * debian/patches/hurd-i386/git-signal-fpe-exceptions.diff: Fix crash in FPE > + handlers. > + * debian/patches/hurd-i386/git-symlink-eexist.diff: Fix gnulib testsuite. > + > + [ Adriano Rafael Gomes ] > + * Update Brazilian Portuguese debconf translation. Closes: #1103446. > + > + [ Aurelien Jarno ] > + * debian/rules.d/debhelper.mk: do not replace LIBC in debhelper.in files. > + This was used for lintian overrides, but it is not used anymore. Closes: > + #1104099. > + * debian/patches/git-updates.diff: update from upstream stable branch: > + - Fix elf/tst-audit10 test failure on x86 systems without AVX. Closes: > + #1103303. > + - Fix pthread_getattr_np failure when executable stack tunable is set. > + > + -- Aurelien Jarno <[email protected]> Sat, 10 May 2025 12:45:57 +0200 > + > glibc (2.41-7) unstable; urgency=medium > > [ Samuel Thibault ] > diff --git a/debian/patches/git-updates.diff b/debian/patches/git-updates.diff > index 80295b6a..ea94532b 100644 > --- a/debian/patches/git-updates.diff > +++ b/debian/patches/git-updates.diff > @@ -22,10 +22,10 @@ index d0108d2caa..aa547a443f 100644 > $(common-objdir):$(subst $(empty) ,:,$(patsubst > ../$(subdir),.,$(rpath-dirs:%=$(common-objpfx)%))) > else # build-static > diff --git a/NEWS b/NEWS > -index b11422b060..8740f5956a 100644 > +index b11422b060..51586aaad7 100644 > --- a/NEWS > +++ b/NEWS > -@@ -5,6 +5,28 @@ See the end for copying conditions. > +@@ -5,6 +5,31 @@ See the end for copying conditions. > Please send GNU C library bug reports via <https://sourceware.org/bugzilla/> > using `glibc' in the "product" field. > > @@ -50,6 +50,9 @@ index b11422b060..8740f5956a 100644 > + [32782] nptl: Race conditions in pthread cancellation causing crash > + [32786] nptl: PTHREAD_COND_INITIALIZER compatibility with pre-2.41 > versions > + [32810] Crash on x86-64 if XSAVEC disable via tunable > ++ [32882] tst-audit10 fails with SIGILL on CPUs without AVX > ++ [32897] dynamic-link: pthread_getattr_np fails when executable stack > ++ tunable is set > + > Version 2.41 > > @@ -986,7 +989,7 @@ index 4b1d0d8741..3a3ae56a24 100644 > $(objpfx)tst-piemod1.so: $(libsupport) > diff --git a/elf/dl-execstack-tunable.c b/elf/dl-execstack-tunable.c > new file mode 100644 > -index 0000000000..6cef1a3036 > +index 0000000000..e3b638aeaa > --- /dev/null > +++ b/elf/dl-execstack-tunable.c > @@ -0,0 +1,39 @@ > @@ -1023,12 +1026,47 @@ index 0000000000..6cef1a3036 > + break; > + > + case stack_tunable_mode_force: > -+ if (_dl_make_stack_executable (&__libc_stack_end) != 0) > ++ if (_dl_make_stack_executable (__libc_stack_end) != 0) > + _dl_fatal_printf ( > +"Fatal glibc error: cannot enable executable stack as tunable requires"); > + break; > + } > +} > +diff --git a/elf/dl-execstack.c b/elf/dl-execstack.c > +index e4d7dbe7f8..ceec5b2def 100644 > +--- a/elf/dl-execstack.c > ++++ b/elf/dl-execstack.c > +@@ -23,7 +23,7 @@ > + so as to mprotect it. */ > + > + int > +-_dl_make_stack_executable (void **stack_endp) > ++_dl_make_stack_executable (const void *stack_endp) > + { > + return ENOSYS; > + } > +diff --git a/elf/dl-load.c b/elf/dl-load.c > +index f905578a65..945dd8a231 100644 > +--- a/elf/dl-load.c > ++++ b/elf/dl-load.c > +@@ -945,7 +945,7 @@ struct link_map * > + _dl_map_object_from_fd (const char *name, const char *origname, int fd, > + struct filebuf *fbp, char *realname, > + struct link_map *loader, int l_type, int mode, > +- void **stack_endp, Lmid_t nsid) > ++ const void *stack_endp, Lmid_t nsid) > + { > + struct link_map *l = NULL; > + const ElfW(Ehdr) *header; > +@@ -2180,7 +2180,7 @@ _dl_map_object (struct link_map *loader, const char > *name, > + > + void *stack_end = __libc_stack_end; > + return _dl_map_object_from_fd (name, origname, fd, &fb, realname, loader, > +- type, mode, &stack_end, nsid); > ++ type, mode, stack_end, nsid); > + } > + > + struct add_path_state > diff --git a/elf/dl-reloc-static-pie.c b/elf/dl-reloc-static-pie.c > index e34bf5f7ce..758bf9893e 100644 > --- a/elf/dl-reloc-static-pie.c > @@ -2784,10 +2822,10 @@ index 0000000000..7fb40fdd9e > +END (__memset_sve_zva64) > +#endif > diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h > -index e871f27ff2..4b44beb3f4 100644 > +index e871f27ff2..ddb34a1588 100644 > --- a/sysdeps/generic/ldsodefs.h > +++ b/sysdeps/generic/ldsodefs.h > -@@ -695,6 +695,19 @@ extern const ElfW(Phdr) *_dl_phdr; > +@@ -695,10 +695,23 @@ extern const ElfW(Phdr) *_dl_phdr; > extern size_t _dl_phnum; > #endif > > @@ -2807,6 +2845,11 @@ index e871f27ff2..4b44beb3f4 100644 > /* This function changes the permission of the memory region pointed > by STACK_ENDP to executable and update the internal memory protection > flags for future thread stack creation. */ > +-int _dl_make_stack_executable (void **stack_endp) attribute_hidden; > ++int _dl_make_stack_executable (const void *stack_endp) attribute_hidden; > + > + /* Variable pointing to the end of the stack (or close to it). This value > + must be constant over the runtime of the application. Some programs > diff --git a/sysdeps/ieee754/dbl-64/e_atanh.c > b/sysdeps/ieee754/dbl-64/e_atanh.c > index 1e09e46f0f..d1c71b2aa4 100644 > --- a/sysdeps/ieee754/dbl-64/e_atanh.c > @@ -2949,6 +2992,25 @@ index dfe56fc2a0..5ee1d6f35e 100644 > { > if (sgn) > return -st[j].rh - st[j].rl; > +diff --git a/sysdeps/mach/hurd/dl-execstack.c > b/sysdeps/mach/hurd/dl-execstack.c > +index 0617d3a161..dc4719bd38 100644 > +--- a/sysdeps/mach/hurd/dl-execstack.c > ++++ b/sysdeps/mach/hurd/dl-execstack.c > +@@ -26,12 +26,11 @@ extern struct hurd_startup_data *_dl_hurd_data > attribute_hidden; > + so as to mprotect it. */ > + > + int > +-_dl_make_stack_executable (void **stack_endp) > ++_dl_make_stack_executable (const void *stack_endp) > + { > + /* Challenge the caller. */ > +- if (__builtin_expect (*stack_endp != __libc_stack_end, 0)) > ++ if (__glibc_unlikely (stack_endp != __libc_stack_end)) > + return EPERM; > +- *stack_endp = NULL; > + > + #if IS_IN (rtld) > + if (__mprotect ((void *)_dl_hurd_data->stack_base, > _dl_hurd_data->stack_size, > diff --git a/sysdeps/nptl/bits/thread-shared-types.h > b/sysdeps/nptl/bits/thread-shared-types.h > index 7c24c0a6be..e614c7f3c9 100644 > --- a/sysdeps/nptl/bits/thread-shared-types.h > @@ -2988,7 +3050,7 @@ index 050b4ab8d1..9ad36cabe9 100644 > > /* Cleanup buffers */ > diff --git a/sysdeps/pthread/Makefile b/sysdeps/pthread/Makefile > -index a123e28a57..2e0ce773a0 100644 > +index a123e28a57..7fcbc72bc0 100644 > --- a/sysdeps/pthread/Makefile > +++ b/sysdeps/pthread/Makefile > @@ -106,6 +106,7 @@ tests += \ > @@ -2999,6 +3061,35 @@ index a123e28a57..2e0ce773a0 100644 > tst-cleanup0 \ > tst-cleanup1 \ > tst-cleanup2 \ > +@@ -271,6 +272,7 @@ tests += \ > + tst-spin4 \ > + tst-spin5 \ > + tst-stack1 \ > ++ tst-stack2 \ > + tst-stdio1 \ > + tst-stdio2 \ > + tst-thrd-detach \ > +@@ -366,6 +368,7 @@ modules-names += \ > + tst-atfork4mod \ > + tst-create1mod \ > + tst-fini1mod \ > ++ tst-stack2-mod \ > + tst-tls4moda \ > + tst-tls4modb \ > + # modules-names > +@@ -539,4 +542,12 @@ LDFLAGS-tst-create1 = -Wl,-export-dynamic > + $(objpfx)tst-create1: $(shared-thread-library) > + $(objpfx)tst-create1.out: $(objpfx)tst-create1mod.so > + > ++$(objpfx)tst-stack2.out: $(objpfx)tst-stack2-mod.so > ++$(objpfx)tst-stack2-mod.so: $(shared-thread-library) > ++LDFLAGS-tst-stack2-mod.so = -Wl,-z,execstack > ++ifeq ($(have-no-error-execstack),yes) > ++LDFLAGS-tst-stack2-mod.so += -Wl,--no-error-execstack > ++endif > ++tst-stack2-ENV = GLIBC_TUNABLES=glibc.rtld.execstack=2 > ++ > + endif > diff --git a/sysdeps/pthread/tst-cancel32.c b/sysdeps/pthread/tst-cancel32.c > new file mode 100644 > index 0000000000..ab550c16bf > @@ -3078,6 +3169,104 @@ index 0000000000..ab550c16bf > +} > + > +#include <support/test-driver.c> > +diff --git a/sysdeps/pthread/tst-stack2-mod.c > b/sysdeps/pthread/tst-stack2-mod.c > +new file mode 100644 > +index 0000000000..806fdbcd8d > +--- /dev/null > ++++ b/sysdeps/pthread/tst-stack2-mod.c > +@@ -0,0 +1,39 @@ > ++/* Check if pthread_getattr_np works within modules with non-exectuble > ++ stacks (BZ 32897). > ++ 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 <pthread.h> > ++ > ++bool init_result; > ++ > ++void > ++__attribute__ ((constructor)) > ++init (void) > ++{ > ++ pthread_t me = pthread_self (); > ++ pthread_attr_t attr; > ++ init_result = pthread_getattr_np (me, &attr) == 0; > ++} > ++ > ++int > ++mod_func (void) > ++{ > ++ pthread_t me = pthread_self (); > ++ pthread_attr_t attr; > ++ return pthread_getattr_np (me, &attr); > ++} > +diff --git a/sysdeps/pthread/tst-stack2.c b/sysdeps/pthread/tst-stack2.c > +new file mode 100644 > +index 0000000000..20ab5af166 > +--- /dev/null > ++++ b/sysdeps/pthread/tst-stack2.c > +@@ -0,0 +1,47 @@ > ++/* Check if pthread_getattr_np works within modules with non-exectuble > ++ stacks (BZ 32897). > ++ 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 <pthread.h> > ++#include <stdbool.h> > ++#include <support/xdlfcn.h> > ++#include <support/check.h> > ++ > ++static int > ++do_test (void) > ++{ > ++ { > ++ pthread_t me = pthread_self (); > ++ pthread_attr_t attr; > ++ TEST_COMPARE (pthread_getattr_np (me, &attr), 0); > ++ } > ++ > ++ void *h = xdlopen ("tst-stack2-mod.so", RTLD_NOW); > ++ > ++ bool *init_result = xdlsym (h, "init_result"); > ++ TEST_COMPARE (*init_result, true); > ++ > ++ int (*mod_func)(void) = xdlsym (h, "mod_func"); > ++ TEST_COMPARE (mod_func (), 0); > ++ > ++ xdlclose (h); > ++ > ++ return 0; > ++} > ++ > ++#include <support/test-driver.c> > diff --git a/sysdeps/riscv/dl-machine.h b/sysdeps/riscv/dl-machine.h > index a30892f080..dcc3e0883b 100644 > --- a/sysdeps/riscv/dl-machine.h > @@ -3905,6 +4094,33 @@ index 3656e98eda..39b0b3d19c 100644 > > #endif > > +diff --git a/sysdeps/unix/sysv/linux/dl-execstack.c > b/sysdeps/unix/sysv/linux/dl-execstack.c > +index 9791b339ca..6db9601656 100644 > +--- a/sysdeps/unix/sysv/linux/dl-execstack.c > ++++ b/sysdeps/unix/sysv/linux/dl-execstack.c > +@@ -19,10 +19,10 @@ > + #include <ldsodefs.h> > + > + int > +-_dl_make_stack_executable (void **stack_endp) > ++_dl_make_stack_executable (const void *stack_endp) > + { > + /* This gives us the highest/lowest page that needs to be changed. */ > +- uintptr_t page = ((uintptr_t) *stack_endp > ++ uintptr_t page = ((uintptr_t) stack_endp > + & -(intptr_t) GLRO(dl_pagesize)); > + > + if (__mprotect ((void *) page, GLRO(dl_pagesize), > +@@ -35,9 +35,6 @@ _dl_make_stack_executable (void **stack_endp) > + ) != 0) > + return errno; > + > +- /* Clear the address. */ > +- *stack_endp = NULL; > +- > + /* Remember that we changed the permission. */ > + GL(dl_stack_flags) |= PF_X; > + > diff --git a/sysdeps/unix/sysv/linux/rseq-internal.h > b/sysdeps/unix/sysv/linux/rseq-internal.h > index f89e784243..d2ab4cb829 100644 > --- a/sysdeps/unix/sysv/linux/rseq-internal.h > @@ -4642,6 +4858,18 @@ index 0000000000..f0024c143d > +++ b/sysdeps/x86/tst-gnu2-tls2-x86-noxsavexsavec.c > @@ -0,0 +1 @@ > +#include <elf/tst-gnu2-tls2.c> > +diff --git a/sysdeps/x86_64/Makefile b/sysdeps/x86_64/Makefile > +index 9d31685e02..5723ec1847 100644 > +--- a/sysdeps/x86_64/Makefile > ++++ b/sysdeps/x86_64/Makefile > +@@ -142,7 +142,6 @@ CFLAGS-tst-avxmod.c += $(AVX-CFLAGS) > + AVX512-CFLAGS = -mavx512f > + CFLAGS-tst-audit10-aux.c += $(AVX512-CFLAGS) > + CFLAGS-tst-auditmod10a.c += $(AVX512-CFLAGS) > +-CFLAGS-tst-auditmod10b.c += $(AVX512-CFLAGS) > + CFLAGS-tst-avx512-aux.c += $(AVX512-CFLAGS) > + CFLAGS-tst-avx512mod.c += $(AVX512-CFLAGS) > + > diff --git a/sysdeps/x86_64/dl-tlsdesc-dynamic.h > b/sysdeps/x86_64/dl-tlsdesc-dynamic.h > index 9965ddd2c0..4f496de8c8 100644 > --- a/sysdeps/x86_64/dl-tlsdesc-dynamic.h > @@ -4867,3 +5095,149 @@ index 0000000000..5539b6c61c > +# define __tanh __tanh_sse2 > +#endif > +#include <sysdeps/ieee754/dbl-64/s_tanh.c> > +diff --git a/sysdeps/x86_64/tst-auditmod10b.c > b/sysdeps/x86_64/tst-auditmod10b.c > +index 6eb21b6f06..0b994ef0f0 100644 > +--- a/sysdeps/x86_64/tst-auditmod10b.c > ++++ b/sysdeps/x86_64/tst-auditmod10b.c > +@@ -125,7 +125,6 @@ la_symbind64 (Elf64_Sym *sym, unsigned int ndx, > uintptr_t *refcook, > + > + #include <tst-audit.h> > + > +-#ifdef __AVX512F__ > + #include <immintrin.h> > + #include <cpuid.h> > + > +@@ -148,9 +147,37 @@ check_avx512 (void) > + return (eax & 0xe6) == 0xe6; > + } > + > +-#else > +-#include <emmintrin.h> > +-#endif > ++void > ++__attribute__ ((target ("avx512f"))) > ++pltenter_avx512f (La_regs *regs, long int *framesizep) > ++{ > ++ __m512i zero = _mm512_setzero_si512 (); > ++ if (memcmp (®s->lr_vector[0], &zero, sizeof (zero)) > ++ || memcmp (®s->lr_vector[1], &zero, sizeof (zero)) > ++ || memcmp (®s->lr_vector[2], &zero, sizeof (zero)) > ++ || memcmp (®s->lr_vector[3], &zero, sizeof (zero)) > ++ || memcmp (®s->lr_vector[4], &zero, sizeof (zero)) > ++ || memcmp (®s->lr_vector[5], &zero, sizeof (zero)) > ++ || memcmp (®s->lr_vector[6], &zero, sizeof (zero)) > ++ || memcmp (®s->lr_vector[7], &zero, sizeof (zero))) > ++ abort (); > ++ > ++ for (int i = 0; i < 8; i++) > ++ regs->lr_vector[i].zmm[0] > ++ = (La_x86_64_zmm) _mm512_set1_epi64 (i + 1); > ++ > ++ __m512i zmm = _mm512_set1_epi64 (-1); > ++ asm volatile ("vmovdqa64 %0, %%zmm0" : : "x" (zmm) : "xmm0" ); > ++ asm volatile ("vmovdqa64 %0, %%zmm1" : : "x" (zmm) : "xmm1" ); > ++ asm volatile ("vmovdqa64 %0, %%zmm2" : : "x" (zmm) : "xmm2" ); > ++ asm volatile ("vmovdqa64 %0, %%zmm3" : : "x" (zmm) : "xmm3" ); > ++ asm volatile ("vmovdqa64 %0, %%zmm4" : : "x" (zmm) : "xmm4" ); > ++ asm volatile ("vmovdqa64 %0, %%zmm5" : : "x" (zmm) : "xmm5" ); > ++ asm volatile ("vmovdqa64 %0, %%zmm6" : : "x" (zmm) : "xmm6" ); > ++ asm volatile ("vmovdqa64 %0, %%zmm7" : : "x" (zmm) : "xmm7" ); > ++ > ++ *framesizep = 1024; > ++} > + > + ElfW(Addr) > + pltenter (ElfW(Sym) *sym, unsigned int ndx, uintptr_t *refcook, > +@@ -160,39 +187,33 @@ pltenter (ElfW(Sym) *sym, unsigned int ndx, uintptr_t > *refcook, > + printf ("pltenter: symname=%s, st_value=%#lx, ndx=%u, flags=%u\n", > + symname, (long int) sym->st_value, ndx, *flags); > + > +-#ifdef __AVX512F__ > + if (check_avx512 () && strcmp (symname, "audit_test") == 0) > ++ pltenter_avx512f (regs, framesizep); > ++ > ++ return sym->st_value; > ++} > ++ > ++void > ++__attribute__ ((target ("avx512f"))) > ++pltexit_avx512f (const La_regs *inregs, La_retval *outregs) > ++{ > ++ __m512i zero = _mm512_setzero_si512 (); > ++ if (memcmp (&outregs->lrv_vector0, &zero, sizeof (zero))) > ++ abort (); > ++ > ++ for (int i = 0; i < 8; i++) > + { > +- __m512i zero = _mm512_setzero_si512 (); > +- if (memcmp (®s->lr_vector[0], &zero, sizeof (zero)) > +- || memcmp (®s->lr_vector[1], &zero, sizeof (zero)) > +- || memcmp (®s->lr_vector[2], &zero, sizeof (zero)) > +- || memcmp (®s->lr_vector[3], &zero, sizeof (zero)) > +- || memcmp (®s->lr_vector[4], &zero, sizeof (zero)) > +- || memcmp (®s->lr_vector[5], &zero, sizeof (zero)) > +- || memcmp (®s->lr_vector[6], &zero, sizeof (zero)) > +- || memcmp (®s->lr_vector[7], &zero, sizeof (zero))) > +- abort (); > +- > +- for (int i = 0; i < 8; i++) > +- regs->lr_vector[i].zmm[0] > +- = (La_x86_64_zmm) _mm512_set1_epi64 (i + 1); > +- > +- __m512i zmm = _mm512_set1_epi64 (-1); > +- asm volatile ("vmovdqa64 %0, %%zmm0" : : "x" (zmm) : "xmm0" ); > +- asm volatile ("vmovdqa64 %0, %%zmm1" : : "x" (zmm) : "xmm1" ); > +- asm volatile ("vmovdqa64 %0, %%zmm2" : : "x" (zmm) : "xmm2" ); > +- asm volatile ("vmovdqa64 %0, %%zmm3" : : "x" (zmm) : "xmm3" ); > +- asm volatile ("vmovdqa64 %0, %%zmm4" : : "x" (zmm) : "xmm4" ); > +- asm volatile ("vmovdqa64 %0, %%zmm5" : : "x" (zmm) : "xmm5" ); > +- asm volatile ("vmovdqa64 %0, %%zmm6" : : "x" (zmm) : "xmm6" ); > +- asm volatile ("vmovdqa64 %0, %%zmm7" : : "x" (zmm) : "xmm7" ); > +- > +- *framesizep = 1024; > ++ __m512i zmm = _mm512_set1_epi64 (i + 1); > ++ if (memcmp (&inregs->lr_vector[i], &zmm, sizeof (zmm)) != 0) > ++ abort (); > + } > +-#endif > + > +- return sym->st_value; > ++ outregs->lrv_vector0.zmm[0] > ++ = (La_x86_64_zmm) _mm512_set1_epi64 (0x12349876); > ++ > ++ __m512i zmm = _mm512_set1_epi64 (-1); > ++ asm volatile ("vmovdqa64 %0, %%zmm0" : : "x" (zmm) : "xmm0" ); > ++ asm volatile ("vmovdqa64 %0, %%zmm1" : : "x" (zmm) : "xmm1" ); > + } > + > + unsigned int > +@@ -204,28 +225,8 @@ pltexit (ElfW(Sym) *sym, unsigned int ndx, uintptr_t > *refcook, > + symname, (long int) sym->st_value, ndx, > + (ptrdiff_t) outregs->int_retval); > + > +-#ifdef __AVX512F__ > + if (check_avx512 () && strcmp (symname, "audit_test") == 0) > +- { > +- __m512i zero = _mm512_setzero_si512 (); > +- if (memcmp (&outregs->lrv_vector0, &zero, sizeof (zero))) > +- abort (); > +- > +- for (int i = 0; i < 8; i++) > +- { > +- __m512i zmm = _mm512_set1_epi64 (i + 1); > +- if (memcmp (&inregs->lr_vector[i], &zmm, sizeof (zmm)) != 0) > +- abort (); > +- } > +- > +- outregs->lrv_vector0.zmm[0] > +- = (La_x86_64_zmm) _mm512_set1_epi64 (0x12349876); > +- > +- __m512i zmm = _mm512_set1_epi64 (-1); > +- asm volatile ("vmovdqa64 %0, %%zmm0" : : "x" (zmm) : "xmm0" ); > +- asm volatile ("vmovdqa64 %0, %%zmm1" : : "x" (zmm) : "xmm1" ); > +- } > +-#endif > ++ pltexit_avx512f (inregs, outregs); > + > + return 0; > + } > diff --git a/debian/patches/hurd-i386/git-dup-refcnt.diff > b/debian/patches/hurd-i386/git-dup-refcnt.diff > new file mode 100644 > index 00000000..d50ff690 > --- /dev/null > +++ b/debian/patches/hurd-i386/git-dup-refcnt.diff > @@ -0,0 +1,152 @@ > +commit e150ee870907e1c5ded4aad8d22a92a98f59d243 > +Author: Zhaoming Luo <[email protected]> > +Date: Mon Mar 10 16:44:09 2025 +0800 > + > + hurd: Check return value of mach_port_mod_refs() in the dup routine of > fcntl() > + > + Message-ID: <[email protected]> > + > +diff --git a/sysdeps/mach/hurd/dup3.c b/sysdeps/mach/hurd/dup3.c > +index 22af45b491..49545ae63a 100644 > +--- a/sysdeps/mach/hurd/dup3.c > ++++ b/sysdeps/mach/hurd/dup3.c > +@@ -69,6 +69,7 @@ __dup3 (int fd, int fd2, int flags) > + { > + /* Get a hold of the destination descriptor. */ > + struct hurd_fd *d2; > ++ error_t err; > + > + __mutex_lock (&_hurd_dtable_lock); > + > +@@ -107,22 +108,51 @@ __dup3 (int fd, int fd2, int flags) > + } > + else > + { > +- /* Give the ports each a user ref for the new descriptor. */ > +- __mach_port_mod_refs (__mach_task_self (), port, > +- MACH_PORT_RIGHT_SEND, 1); > +- if (ctty != MACH_PORT_NULL) > +- __mach_port_mod_refs (__mach_task_self (), ctty, > +- MACH_PORT_RIGHT_SEND, 1); > +- > +- /* Install the ports and flags in the new descriptor slot. */ > +- __spin_lock (&d2->port.lock); > +- if (flags & O_CLOEXEC) > +- d2->flags = d_flags | FD_CLOEXEC; > +- else > +- /* dup clears FD_CLOEXEC. */ > +- d2->flags = d_flags & ~FD_CLOEXEC; > +- _hurd_port_set (&d2->ctty, ctty); > +- _hurd_port_locked_set (&d2->port, port); /* Unlocks D2. */ > ++ /* Give the io server port a user ref for the new descriptor. */ > ++ err = __mach_port_mod_refs (__mach_task_self (), port, > ++ MACH_PORT_RIGHT_SEND, 1); > ++ > ++ if (err == KERN_UREFS_OVERFLOW) > ++ fd2 = __hurd_fail (EMFILE); > ++ else if (err) > ++ fd2 = __hurd_fail (EINVAL); > ++ else if (ctty != MACH_PORT_NULL) > ++ { > ++ /* We have confirmed the io server port has got a user ref > ++ count, now give ctty port a user ref for the new > ++ descriptor. */ > ++ err = __mach_port_mod_refs (__mach_task_self (), ctty, > ++ MACH_PORT_RIGHT_SEND, 1); > ++ > ++ if (err) > ++ { > ++ /* In this case the io server port has got a ref count > ++ but the ctty port failed to get one, so we need to > ++ clean the ref count we just assigned. */ > ++ __mach_port_mod_refs (__mach_task_self (), port, > ++ MACH_PORT_RIGHT_SEND, -1); > ++ > ++ if (err == KERN_UREFS_OVERFLOW) > ++ fd2 = __hurd_fail (EMFILE); > ++ else > ++ fd2 = __hurd_fail (EINVAL); > ++ } > ++ } > ++ > ++ if (!err) > ++ { > ++ /* The ref counts of the ports are incremented > ++ successfully. */ > ++ /* Install the ports and flags in the new descriptor slot. */ > ++ __spin_lock (&d2->port.lock); > ++ if (flags & O_CLOEXEC) > ++ d2->flags = d_flags | FD_CLOEXEC; > ++ else > ++ /* dup clears FD_CLOEXEC. */ > ++ d2->flags = d_flags & ~FD_CLOEXEC; > ++ _hurd_port_set (&d2->ctty, ctty); > ++ _hurd_port_locked_set (&d2->port, port); /* Unlocks D2. */ > ++ } > + } > + } > + > +diff --git a/sysdeps/mach/hurd/fcntl.c b/sysdeps/mach/hurd/fcntl.c > +index a65c190cac..de576af1b7 100644 > +--- a/sysdeps/mach/hurd/fcntl.c > ++++ b/sysdeps/mach/hurd/fcntl.c > +@@ -83,18 +83,47 @@ __libc_fcntl (int fd, int cmd, ...) > + result = -1; > + else > + { > +- /* Give the ports each a user ref for the new descriptor. */ > +- __mach_port_mod_refs (__mach_task_self (), port, > +- MACH_PORT_RIGHT_SEND, 1); > +- if (ctty != MACH_PORT_NULL) > +- __mach_port_mod_refs (__mach_task_self (), ctty, > +- MACH_PORT_RIGHT_SEND, 1); > +- > +- /* Install the ports and flags in the new descriptor. */ > +- if (ctty != MACH_PORT_NULL) > +- _hurd_port_set (&new->ctty, ctty); > +- new->flags = flags; > +- _hurd_port_locked_set (&new->port, port); /* Unlocks NEW. */ > ++ /* Give the io server port a user ref for the new descriptor. */ > ++ err = __mach_port_mod_refs (__mach_task_self (), port, > ++ MACH_PORT_RIGHT_SEND, 1); > ++ > ++ if (err == KERN_UREFS_OVERFLOW) > ++ result = __hurd_fail (EMFILE); > ++ else if (err) > ++ result = __hurd_fail (EINVAL); > ++ else if (ctty != MACH_PORT_NULL) > ++ { > ++ /* We have confirmed the io server port has got a user ref > ++ count, now give ctty port a user ref for the new > ++ descriptor. */ > ++ err = __mach_port_mod_refs (__mach_task_self (), ctty, > ++ MACH_PORT_RIGHT_SEND, 1); > ++ > ++ if (err) > ++ { > ++ /* In this case the io server port has got a ref count > ++ but the ctty port fails to get one, so we need to clean > ++ the ref count we just assigned. */ > ++ __mach_port_mod_refs (__mach_task_self (), port, > ++ MACH_PORT_RIGHT_SEND, -1); > ++ > ++ if (err == KERN_UREFS_OVERFLOW) > ++ result = __hurd_fail (EMFILE); > ++ else > ++ result = __hurd_fail (EINVAL); > ++ } > ++ } > ++ > ++ if (!err) > ++ { > ++ /* The ref counts of the ports are incremented successfully. */ > ++ /* Install the ports and flags in the new descriptor. */ > ++ if (ctty != MACH_PORT_NULL) > ++ _hurd_port_set (&new->ctty, ctty); > ++ new->flags = flags; > ++ /* Unlocks NEW. */ > ++ _hurd_port_locked_set (&new->port, port); > ++ } > + } > + > + HURD_CRITICAL_END; > diff --git a/debian/patches/hurd-i386/git-signal-fpe-exceptions.diff > b/debian/patches/hurd-i386/git-signal-fpe-exceptions.diff > new file mode 100644 > index 00000000..68468271 > --- /dev/null > +++ b/debian/patches/hurd-i386/git-signal-fpe-exceptions.diff > @@ -0,0 +1,46 @@ > +Index: glibc-2.41/sysdeps/mach/hurd/x86/trampoline.c > +=================================================================== > +--- glibc-2.41.orig/sysdeps/mach/hurd/x86/trampoline.c > ++++ glibc-2.41/sysdeps/mach/hurd/x86/trampoline.c > +@@ -461,7 +461,10 @@ _hurd_setup_sighandler (struct hurd_sigs > + - 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 s > + /* 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: > + > diff --git a/debian/patches/hurd-i386/git-symlink-eexist.diff > b/debian/patches/hurd-i386/git-symlink-eexist.diff > new file mode 100644 > index 00000000..5e7324fd > --- /dev/null > +++ b/debian/patches/hurd-i386/git-symlink-eexist.diff > @@ -0,0 +1,22 @@ > +commit 1eb32c5788a59b821087f971821536a22a3b65de > +Author: Samuel Thibault <[email protected]> > +Date: Mon Apr 21 22:21:17 2025 +0200 > + > + hurd: Make symlink return EEXIST on existing target directory > + > + The gnulib testsuite does not recognize ENOTDIR for such a situation, > + and this error is indeed more comprehensible to users. > + > +diff --git a/sysdeps/mach/hurd/symlinkat.c b/sysdeps/mach/hurd/symlinkat.c > +index e7dfb673df..cb6250e6f0 100644 > +--- a/sysdeps/mach/hurd/symlinkat.c > ++++ b/sysdeps/mach/hurd/symlinkat.c > +@@ -47,7 +47,7 @@ __symlinkat (const char *from, int fd, const char *to) > + > + if (! *name) > + /* Can't link to the existing directory itself. */ > +- err = ENOTDIR; > ++ err = EEXIST; > + else > + /* Create a new, unlinked node in the target directory. */ > + err = __dir_mkfile (dir, O_WRITE, 0777 & ~_hurd_umask, &node); > diff --git a/debian/patches/hurd-i386/git-utime-EINVAL.diff > b/debian/patches/hurd-i386/git-utime-EINVAL.diff > new file mode 100644 > index 00000000..5fe9d2d8 > --- /dev/null > +++ b/debian/patches/hurd-i386/git-utime-EINVAL.diff > @@ -0,0 +1,220 @@ > +commit 8a0200c833f261e8eb456bbc4f0f5449e1a5e367 > +Author: Samuel Thibault <[email protected]> > +Date: Tue Mar 18 18:49:21 2025 +0100 > + > + hurd: Make *utime*s catch invalid times [BZ #32802] > + > +diff --git a/sysdeps/mach/hurd/futimens.c b/sysdeps/mach/hurd/futimens.c > +index 30ef0a6493..12125299c4 100644 > +--- a/sysdeps/mach/hurd/futimens.c > ++++ b/sysdeps/mach/hurd/futimens.c > +@@ -32,7 +32,9 @@ __futimens (int fd, const struct timespec tsp[2]) > + struct timespec atime, mtime; > + error_t err; > + > +- utime_ts_from_tspec (tsp, &atime, &mtime); > ++ err = utime_ts_from_tspec (tsp, &atime, &mtime); > ++ if (err) > ++ return err; > + > + err = HURD_DPORT_USE (fd, __file_utimens (port, atime, mtime)); > + > +@@ -40,7 +42,9 @@ __futimens (int fd, const struct timespec tsp[2]) > + { > + time_value_t atim, mtim; > + > +- utime_tvalue_from_tspec (tsp, &atim, &mtim); > ++ err = utime_tvalue_from_tspec (tsp, &atim, &mtim); > ++ if (err) > ++ return err; > + > + err = HURD_DPORT_USE (fd, __file_utimes (port, atim, mtim)); > + } > +diff --git a/sysdeps/mach/hurd/futimes.c b/sysdeps/mach/hurd/futimes.c > +index 20f47f3d28..97385d7dd0 100644 > +--- a/sysdeps/mach/hurd/futimes.c > ++++ b/sysdeps/mach/hurd/futimes.c > +@@ -32,7 +32,9 @@ __futimes (int fd, const struct timeval tvp[2]) > + struct timespec atime, mtime; > + error_t err; > + > +- utime_ts_from_tval (tvp, &atime, &mtime); > ++ err = utime_ts_from_tval (tvp, &atime, &mtime); > ++ if (err) > ++ return err; > + > + err = HURD_DPORT_USE (fd, __file_utimens (port, atime, mtime)); > + > +@@ -40,7 +42,9 @@ __futimes (int fd, const struct timeval tvp[2]) > + { > + time_value_t atim, mtim; > + > +- utime_tvalue_from_tval (tvp, &atim, &mtim); > ++ err = utime_tvalue_from_tval (tvp, &atim, &mtim); > ++ if (err) > ++ return err; > + > + err = HURD_DPORT_USE (fd, __file_utimes (port, atim, mtim)); > + } > +diff --git a/sysdeps/mach/hurd/utime-helper.c > b/sysdeps/mach/hurd/utime-helper.c > +index d88bccd786..6afa871197 100644 > +--- a/sysdeps/mach/hurd/utime-helper.c > ++++ b/sysdeps/mach/hurd/utime-helper.c > +@@ -21,8 +21,14 @@ > + #include <stddef.h> > + #include <sys/time.h> > + > ++static inline bool > ++check_tval (const struct timeval *tvp) > ++{ > ++ return tvp->tv_usec >= 0 && tvp->tv_usec < USEC_PER_SEC; > ++} > ++ > + /* Initializes atime/mtime timespec structures from an array of timeval. */ > +-static inline void > ++static inline error_t > + utime_ts_from_tval (const struct timeval tvp[2], > + struct timespec *atime, struct timespec *mtime) > + { > +@@ -37,13 +43,19 @@ utime_ts_from_tval (const struct timeval tvp[2], > + } > + else > + { > ++ if (!check_tval (&tvp[0])) > ++ return EINVAL; > ++ if (!check_tval (&tvp[1])) > ++ return EINVAL; > ++ > + TIMEVAL_TO_TIMESPEC (&tvp[0], atime); > + TIMEVAL_TO_TIMESPEC (&tvp[1], mtime); > + } > ++ return 0; > + } > + > + /* Initializes atime/mtime time_value_t structures from an array of > timeval. */ > +-static inline void > ++static inline error_t > + utime_tvalue_from_tval (const struct timeval tvp[2], > + time_value_t *atime, time_value_t *mtime) > + { > +@@ -53,11 +65,17 @@ utime_tvalue_from_tval (const struct timeval tvp[2], > + atime->microseconds = mtime->microseconds = -1; > + else > + { > ++ if (!check_tval (&tvp[0])) > ++ return EINVAL; > ++ if (!check_tval (&tvp[1])) > ++ return EINVAL; > ++ > + atime->seconds = tvp[0].tv_sec; > + atime->microseconds = tvp[0].tv_usec; > + mtime->seconds = tvp[1].tv_sec; > + mtime->microseconds = tvp[1].tv_usec; > + } > ++ return 0; > + } > + > + /* Changes the access time of the file behind PORT using a timeval array. > */ > +@@ -67,7 +85,9 @@ hurd_futimes (const file_t port, const struct timeval > tvp[2]) > + error_t err; > + struct timespec atime, mtime; > + > +- utime_ts_from_tval (tvp, &atime, &mtime); > ++ err = utime_ts_from_tval (tvp, &atime, &mtime); > ++ if (err) > ++ return err; > + > + err = __file_utimens (port, atime, mtime); > + > +@@ -75,7 +95,9 @@ hurd_futimes (const file_t port, const struct timeval > tvp[2]) > + { > + time_value_t atim, mtim; > + > +- utime_tvalue_from_tval (tvp, &atim, &mtim); > ++ err = utime_tvalue_from_tval (tvp, &atim, &mtim); > ++ if (err) > ++ return err; > + > + err = __file_utimes (port, atim, mtim); > + } > +@@ -83,8 +105,16 @@ hurd_futimes (const file_t port, const struct timeval > tvp[2]) > + return err; > + } > + > ++static inline bool > ++check_tspec (const struct timespec *tsp) > ++{ > ++ return tsp->tv_nsec == UTIME_NOW > ++ || tsp->tv_nsec == UTIME_OMIT > ++ || tsp->tv_nsec >= 0 && tsp->tv_nsec < NSEC_PER_SEC; > ++} > ++ > + /* Initializes atime/mtime timespec structures from an array of timespec. > */ > +-static inline void > ++static inline error_t > + utime_ts_from_tspec (const struct timespec tsp[2], > + struct timespec *atime, struct timespec *mtime) > + { > +@@ -99,13 +129,19 @@ utime_ts_from_tspec (const struct timespec tsp[2], > + } > + else > + { > ++ if (!check_tspec (&tsp[0])) > ++ return EINVAL; > ++ if (!check_tspec (&tsp[1])) > ++ return EINVAL; > ++ > + *atime = tsp[0]; > + *mtime = tsp[1]; > + } > ++ return 0; > + } > + > + /* Initializes atime/mtime time_value_t structures from an array of > timespec. */ > +-static inline void > ++static inline error_t > + utime_tvalue_from_tspec (const struct timespec tsp[2], > + time_value_t *atime, time_value_t *mtime) > + { > +@@ -115,6 +151,11 @@ utime_tvalue_from_tspec (const struct timespec tsp[2], > + atime->microseconds = mtime->microseconds = -1; > + else > + { > ++ if (!check_tspec (&tsp[0])) > ++ return EINVAL; > ++ if (!check_tspec (&tsp[1])) > ++ return EINVAL; > ++ > + if (tsp[0].tv_nsec == UTIME_NOW) > + atime->microseconds = -1; > + else if (tsp[0].tv_nsec == UTIME_OMIT) > +@@ -128,6 +169,7 @@ utime_tvalue_from_tspec (const struct timespec tsp[2], > + else > + TIMESPEC_TO_TIME_VALUE (mtime, &(tsp[1])); > + } > ++ return 0; > + } > + > + /* Changes the access time of the file behind PORT using a timespec array. > */ > +@@ -137,7 +179,9 @@ hurd_futimens (const file_t port, const struct timespec > tsp[2]) > + error_t err; > + struct timespec atime, mtime; > + > +- utime_ts_from_tspec (tsp, &atime, &mtime); > ++ err = utime_ts_from_tspec (tsp, &atime, &mtime); > ++ if (err) > ++ return err; > + > + err = __file_utimens (port, atime, mtime); > + > +@@ -145,7 +189,9 @@ hurd_futimens (const file_t port, const struct timespec > tsp[2]) > + { > + time_value_t atim, mtim; > + > +- utime_tvalue_from_tspec (tsp, &atim, &mtim); > ++ err = utime_tvalue_from_tspec (tsp, &atim, &mtim); > ++ if (err) > ++ return err; > + > + err = __file_utimes (port, atim, mtim); > + } > diff --git a/debian/patches/hurd-i386/git-xstate-initialized.diff > b/debian/patches/hurd-i386/git-xstate-initialized.diff > new file mode 100644 > index 00000000..65f6d31d > --- /dev/null > +++ b/debian/patches/hurd-i386/git-xstate-initialized.diff > @@ -0,0 +1,108 @@ > +commit 8d54b428cfe98c21049f94c8af3bf302e44091e9 > +Author: Samuel Thibault <[email protected]> > +Date: Mon Apr 21 19:42:27 2025 +0200 > + > + 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. > + > +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 > diff --git a/debian/patches/hurd-i386/git-xstate.diff > b/debian/patches/hurd-i386/git-xstate.diff > new file mode 100644 > index 00000000..d2caa989 > --- /dev/null > +++ b/debian/patches/hurd-i386/git-xstate.diff > @@ -0,0 +1,648 @@ > +commit 6d6a6e2dd2133908e3f5cb8a2ed817ccb2a0bb06 > +Author: Luca Dariz <[email protected]> > +Date: Wed Mar 19 18:11:18 2025 +0100 > + > + 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]> > + > +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, > diff --git a/debian/patches/hurd-i386/local-intr-msg-clobber.diff > b/debian/patches/hurd-i386/local-intr-msg-clobber.diff > deleted file mode 100644 > index d4a946fc..00000000 > --- a/debian/patches/hurd-i386/local-intr-msg-clobber.diff > +++ /dev/null > @@ -1,23 +0,0 @@ > -Force putting save_data on the stack rather than in SSE register > - > -The signal management does not yet properly save SSE state, so that save_data > -would get overwritten by signal handlers, notably leading to `` shell > -replacement getting empty content because then the io_read RPC retry gets an > -MIG_BAD_ARGUMENTS error. > - > -XXX: This is only temporary to fix the common shll replacement issue, and is > -waiting for proper SSE state restoration. > - > -Index: glibc-2.38/hurd/intr-msg.c > -=================================================================== > ---- glibc-2.38.orig/hurd/intr-msg.c > -+++ glibc-2.38/hurd/intr-msg.c > -@@ -79,7 +79,7 @@ _hurd_intr_rpc_mach_msg (mach_msg_header > - mach_msg_bits_t msgh_bits; > - mach_port_t remote_port; > - mach_msg_id_t msgid; > -- struct clobber save_data; > -+ volatile struct clobber save_data; > - > - if ((option & (MACH_SEND_MSG|MACH_RCV_MSG)) != > (MACH_SEND_MSG|MACH_RCV_MSG) > - || _hurd_msgport_thread == MACH_PORT_NULL) > diff --git a/debian/patches/series b/debian/patches/series > index f82a08aa..f45c42a2 100644 > --- a/debian/patches/series > +++ b/debian/patches/series > @@ -25,15 +25,19 @@ arm/local-arm-futex.diff > > # Commited for 2.42 > hurd-i386/git-proc_reauth.diff > - > -# Commited for 2.42 > hurd-i386/git-mig-strncpy.diff > -hurd-i386/local-pthread_once.diff > hurd-i386/git-pthread_sigmask_nothread.diff > hurd-i386/git-rt-timedwait-realtime.diff > hurd-i386/git-pthread_setcancel.diff > +hurd-i386/git-dup-refcnt.diff > +hurd-i386/git-xstate.diff > +hurd-i386/git-utime-EINVAL.diff > +hurd-i386/git-xstate-initialized.diff > +hurd-i386/git-signal-fpe-exceptions.diff > +hurd-i386/git-symlink-eexist.diff > + > +hurd-i386/local-pthread_once.diff > > -hurd-i386/local-intr-msg-clobber.diff > hurd-i386/local-enable-ldconfig.diff > hurd-i386/tg-sysvshm.diff > hurd-i386/tg-thread-cancel.diff > diff --git a/debian/po/pt_BR.po b/debian/po/pt_BR.po > index a9a29128..a13d5709 100644 > --- a/debian/po/pt_BR.po > +++ b/debian/po/pt_BR.po > @@ -3,17 +3,16 @@ > # This file is distributed under the same license as the glibc package. > # Felipe Augusto van de Wiel (faw) <[email protected]>, 2007-2008. > # Fernando Ike de Oliveira (fike) <[email protected]>, 2013. > -# Adriano Rafael Gomes <[email protected]>, 2014-2023. > +# Adriano Rafael Gomes <[email protected]>, 2014-2025. > # > msgid "" > msgstr "" > "Project-Id-Version: glibc\n" > "Report-Msgid-Bugs-To: [email protected]\n" > "POT-Creation-Date: 2025-01-02 16:30+0000\n" > -"PO-Revision-Date: 2023-01-08 13:21-0300\n" > +"PO-Revision-Date: 2025-03-21 14:35-0300\n" > "Last-Translator: Adriano Rafael Gomes <[email protected]>\n" > -"Language-Team: Brazilian Portuguese <debian-l10n-" > -"[email protected]>\n" > +"Language-Team: pt_BR <[email protected]>\n" > "Language: pt_BR\n" > "MIME-Version: 1.0\n" > "Content-Type: text/plain; charset=UTF-8\n" > @@ -62,6 +61,8 @@ msgid "" > "Please note that the C, C.UTF-8 and POSIX locales are always available and " > "do not need to be generated." > msgstr "" > +"Por favor, note que os locales C, C.UTF-8 e POSIX sempre estão disponíveis > e " > +"não precisam ser gerados." > > #. Type: select > #. Choices > diff --git a/debian/rules.d/debhelper.mk b/debian/rules.d/debhelper.mk > index 5440e4ce..6da52d6e 100644 > --- a/debian/rules.d/debhelper.mk > +++ b/debian/rules.d/debhelper.mk > @@ -130,7 +130,6 @@ $(stamp)debhelper-common: > -e 'BEGIN {open(IN, "debian/tmp/usr/share/i18n/SUPPORTED"); $$l = > join("", grep { !/^C\.UTF-8/ } grep { /UTF-8/ } <IN>);} > s/__PROVIDED_LOCALES__/$$l/g;' \ > -e 's#DEB_VERSION_UPSTREAM#$(DEB_VERSION_UPSTREAM)#g;' \ > -e 's#CURRENT_VER#$(DEB_VERSION)#g;' \ > - -e 's#LIBC#$(libc)#g;' \ > $$x > $$y ; \ > case $$y in \ > *.install) \ > diff --git a/debian/testsuite-xfail-debian.mk > b/debian/testsuite-xfail-debian.mk > index 60191e83..99fd1224 100644 > --- a/debian/testsuite-xfail-debian.mk > +++ b/debian/testsuite-xfail-debian.mk > @@ -306,17 +306,6 @@ test-xfail-tst-open-tmpfile = yes > test-xfail-tst-closedir-leaks = yes > test-xfail-tst-closedir-leaks-mem = yes > > -# Missing RLIMIT_AS/overcommit enforcement > -tests-unsupported += tst-basic7 > -tests-unsupported += test-lfs > -tests-unsupported += tst-asprintf-null > -tests-unsupported += bug18240 > -tests-unsupported += tst-vfprintf-width-prec > -tests-unsupported += tst-vfprintf-width-prec-mem > -tests-unsupported += tst-vfprintf-width-prec-alloc > -tests-unsupported += test-bz22786 tst-strtod-overflow > -tests-unsupported += tst-tzset > - > # new in 2.22 > test-xfail-tst-prelink = yes > > @@ -443,6 +432,7 @@ test-xfail-tst-execstack-prog-noexecstack = yes > test-xfail-tst-support-process_state = yes > test-xfail-tst-audit12 = yes > test-xfail-tst-audit28 = yes > +test-xfail-tst-execstack-prog-static-tunable = yes > > # actually never succeded > test-xfail-tst-create_format1 = yes -- Sebastian Ramacher

