]> git.ipfire.org Git - thirdparty/glibc.git/commitdiff
x86: Use separate variable for TLSDESC XSAVE/XSAVEC state size (bug 32810)
authorFlorian Weimer <fweimer@redhat.com>
Fri, 28 Mar 2025 08:26:59 +0000 (09:26 +0100)
committerH.J. Lu <hjl.tools@gmail.com>
Wed, 20 Aug 2025 13:14:48 +0000 (06:14 -0700)
Previously, the initialization code reused the xsave_state_full_size
member of struct cpu_features for the TLSDESC state size.  However,
the tunable processing code assumes that this member has the
original XSAVE (non-compact) state size, so that it can use its
value if XSAVEC is disabled via tunable.

This change uses a separate variable and not a struct member because
the value is only needed in ld.so and the static libc, but not in
libc.so.  As a result, struct cpu_features layout does not change,
helping a future backport of this change.

Fixes commit 9b7091415af47082664717210ac49d51551456ab ("x86-64:
Update _dl_tlsdesc_dynamic to preserve AMX registers").

Reviewed-by: H.J. Lu <hjl.tools@gmail.com>
(cherry picked from commit 145097dff170507fe73190e8e41194f5b5f7e6bf)

NEWS
sysdeps/x86/Makefile
sysdeps/x86/cpu-features.c
sysdeps/x86/cpu-tunables.c
sysdeps/x86/dl-diagnostics-cpu.c
sysdeps/x86/include/cpu-features.h
sysdeps/x86/tst-gnu2-tls2-x86-noxsave.c [new file with mode: 0644]
sysdeps/x86/tst-gnu2-tls2-x86-noxsavec.c [new file with mode: 0644]
sysdeps/x86/tst-gnu2-tls2-x86-noxsavexsavec.c [new file with mode: 0644]
sysdeps/x86_64/dl-tlsdesc-dynamic.h

diff --git a/NEWS b/NEWS
index 77e89c96195be01c5534a79e37a2607d83df9df0..7f3049367fd5f37c78e49779486f9a5ed4dc0047 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -10,6 +10,10 @@ Version 2.38.1
 * Sync with Linux kernel 6.6 shadow stack interface.  The --enable-cet
   configure option in only supported on x86-64.
 
+The following bugs are resolved with this release:
+
+  [32810] Crash on x86-64 if XSAVEC disable via tunable
+
 Deprecated and removed features, and other changes affecting compatibility:
 
 * __rseq_size now denotes the size of the active rseq area (20 bytes
index 02ecfbf146eb9fc8ecf357c15eeeed8508efd049..e4286a7acd1c7faceafb586f1165e3ceb20893e2 100644 (file)
@@ -21,6 +21,9 @@ tests += \
   tst-cpu-features-supports-static \
   tst-get-cpu-features \
   tst-get-cpu-features-static \
+  tst-gnu2-tls2-x86-noxsave \
+  tst-gnu2-tls2-x86-noxsavec \
+  tst-gnu2-tls2-x86-noxsavexsavec \
 # tests
 tests-static += \
   tst-cpu-features-cpuinfo-static \
@@ -89,6 +92,22 @@ CFLAGS-tst-gnu2-tls2.c += -msse
 CFLAGS-tst-gnu2-tls2mod0.c += -msse2 -mtune=haswell
 CFLAGS-tst-gnu2-tls2mod1.c += -msse2 -mtune=haswell
 CFLAGS-tst-gnu2-tls2mod2.c += -msse2 -mtune=haswell
+
+LDFLAGS-tst-gnu2-tls2-x86-noxsave += -Wl,-z,lazy
+LDFLAGS-tst-gnu2-tls2-x86-noxsavec += -Wl,-z,lazy
+LDFLAGS-tst-gnu2-tls2-x86-noxsavexsavec += -Wl,-z,lazy
+
+# Test for bug 32810: incorrect XSAVE state size if XSAVEC is disabled
+# via tunable.
+tst-gnu2-tls2-x86-noxsave-ENV = GLIBC_TUNABLES=glibc.cpu.hwcaps=-XSAVE
+tst-gnu2-tls2-x86-noxsavec-ENV = GLIBC_TUNABLES=glibc.cpu.hwcaps=-XSAVEC
+tst-gnu2-tls2-x86-noxsavexsavec-ENV = GLIBC_TUNABLES=glibc.cpu.hwcaps=-XSAVE,-XSAVEC
+$(objpfx)tst-gnu2-tls2-x86-noxsave.out \
+$(objpfx)tst-gnu2-tls2-x86-noxsavec.out \
+$(objpfx)tst-gnu2-tls2-x86-noxsavexsavec.out: \
+  $(objpfx)tst-gnu2-tls2mod0.so \
+  $(objpfx)tst-gnu2-tls2mod1.so \
+  $(objpfx)tst-gnu2-tls2mod2.so
 endif
 
 ifeq ($(subdir),math)
index 4b75d3bcf2b05bdc20ebb526f794f3c0a9b23686..b9ae482429d90ac717329e3798dd42bbce7765dc 100644 (file)
@@ -62,6 +62,8 @@ extern void TUNABLE_CALLBACK (set_x86_shstk) (tunable_val_t *)
 # include <dl-cet.h>
 #endif
 
+unsigned long int _dl_x86_features_tlsdesc_state_size;
+
 static void
 update_active (struct cpu_features *cpu_features)
 {
@@ -271,6 +273,7 @@ update_active (struct cpu_features *cpu_features)
                = xsave_state_full_size;
              cpu_features->xsave_state_full_size
                = xsave_state_full_size;
+             _dl_x86_features_tlsdesc_state_size = xsave_state_full_size;
 
              /* Check if XSAVEC is available.  */
              if (CPU_FEATURES_CPU_P (cpu_features, XSAVEC))
@@ -359,11 +362,9 @@ update_active (struct cpu_features *cpu_features)
                        = ALIGN_UP ((amx_size
                                     + TLSDESC_CALL_REGISTER_SAVE_AREA),
                                    64);
-                     /* Set xsave_state_full_size to the compact AMX
-                        state size for XSAVEC.  NB: xsave_state_full_size
-                        is only used in _dl_tlsdesc_dynamic_xsave and
-                        _dl_tlsdesc_dynamic_xsavec.  */
-                     cpu_features->xsave_state_full_size = amx_size;
+                     /* Set TLSDESC state size to the compact AMX
+                        state size for XSAVEC.  */
+                     _dl_x86_features_tlsdesc_state_size = amx_size;
 #endif
                      cpu_features->xsave_state_size
                        = ALIGN_UP (size + TLSDESC_CALL_REGISTER_SAVE_AREA,
index c1441241427eb071e27b48770a6422bf21b583b4..7cd2899b405308beac447790aff637a5d7217d03 100644 (file)
@@ -196,6 +196,8 @@ TUNABLE_CALLBACK (set_hwcaps) (tunable_val_t *valp)
                  /* Update xsave_state_size to XSAVE state size.  */
                  cpu_features->xsave_state_size
                    = cpu_features->xsave_state_full_size;
+                 _dl_x86_features_tlsdesc_state_size
+                   = cpu_features->xsave_state_full_size;
                  CPU_FEATURE_UNSET (cpu_features, XSAVEC);
                }
            }
index 5aab63e53211062abf9e15533918792862e9b5a6..3b32056362d11f1e893d0b60e85f46bdfc68068a 100644 (file)
@@ -78,6 +78,8 @@ _dl_diagnostics_cpu (void)
                             cpu_features->xsave_state_size);
   print_cpu_features_value ("xsave_state_full_size",
                             cpu_features->xsave_state_full_size);
+  print_cpu_features_value ("tlsdesc_state_full_size",
+                            _dl_x86_features_tlsdesc_state_size);
   print_cpu_features_value ("data_cache_size", cpu_features->data_cache_size);
   print_cpu_features_value ("shared_cache_size",
                             cpu_features->shared_cache_size);
index bedea77167aa3ccf1c5d85c6edad5d3e0a92b814..3a786a12d928609184b4f5e8ae905fbea5f50156 100644 (file)
@@ -909,8 +909,6 @@ struct cpu_features
   /* The full state size for XSAVE when XSAVEC is disabled by
 
      GLIBC_TUNABLES=glibc.cpu.hwcaps=-XSAVEC
-
-     and the AMX state size when XSAVEC is available.
    */
   unsigned int xsave_state_full_size;
   /* Data cache size for use in memory and string routines, typically
@@ -962,6 +960,13 @@ extern const struct cpu_features *_dl_x86_get_cpu_features (void)
 
 #define __get_cpu_features() _dl_x86_get_cpu_features()
 
+#if IS_IN (rtld) || IS_IN (libc)
+/* XSAVE/XSAVEC state size used by TLS descriptors.  Compared to
+   xsave_state_size from struct cpu_features, this includes additional
+   registers.  */
+extern unsigned long int _dl_x86_features_tlsdesc_state_size attribute_hidden;
+#endif
+
 #if defined (_LIBC) && !IS_IN (nonlib)
 /* Unused for x86.  */
 # define INIT_ARCH()
diff --git a/sysdeps/x86/tst-gnu2-tls2-x86-noxsave.c b/sysdeps/x86/tst-gnu2-tls2-x86-noxsave.c
new file mode 100644 (file)
index 0000000..f0024c1
--- /dev/null
@@ -0,0 +1 @@
+#include <elf/tst-gnu2-tls2.c>
diff --git a/sysdeps/x86/tst-gnu2-tls2-x86-noxsavec.c b/sysdeps/x86/tst-gnu2-tls2-x86-noxsavec.c
new file mode 100644 (file)
index 0000000..f0024c1
--- /dev/null
@@ -0,0 +1 @@
+#include <elf/tst-gnu2-tls2.c>
diff --git a/sysdeps/x86/tst-gnu2-tls2-x86-noxsavexsavec.c b/sysdeps/x86/tst-gnu2-tls2-x86-noxsavexsavec.c
new file mode 100644 (file)
index 0000000..f0024c1
--- /dev/null
@@ -0,0 +1 @@
+#include <elf/tst-gnu2-tls2.c>
index 9f02cfc3eb297ed23a9c33f83f1d96acb164c6dc..44d948696fbe44af91a383487179dfb17d3fa861 100644 (file)
@@ -99,7 +99,7 @@ _dl_tlsdesc_dynamic:
 # endif
 #else
        /* Allocate stack space of the required size to save the state.  */
-       sub     _rtld_local_ro+RTLD_GLOBAL_RO_DL_X86_CPU_FEATURES_OFFSET+XSAVE_STATE_FULL_SIZE_OFFSET(%rip), %RSP_LP
+       sub     _dl_x86_features_tlsdesc_state_size(%rip), %RSP_LP
 #endif
        /* Besides rdi and rsi, saved above, save rcx, rdx, r8, r9,
           r10 and r11.  */