6 Commits

Author SHA256 Message Date
11bdce59fa +- nss-missing-checks.patch: nss: Missing checks in __nss_configure_lookup,
+  __nss_database_get (bsc#1258319, BZ #28940)
2026-02-17 16:55:56 +01:00
0e0a97f21b - s390-z17.patch: S390: Add new s390 platform z17 (jsc#PED-14685) 2026-01-26 13:01:17 +01:00
045836fcce +- memalign-overflow-check.patch: memalign: reinstate alignment overflow
+  check (CVE-2026-0861, bsc#1256766, BZ #33796)
+- nss-dns-getnetbyaddr.patch: resolv: Fix NSS DNS backend for getnetbyaddr
+  (CVE-2026-0915, bsc#1256822, BZ #33802)
+- nptl-optimize-trylock.patch: nptl: Optimize trylock for high cache
+  contention workloads (bsc#1256436, BZ #33704)
+- wordexp-wrde-reuse.patch: posix: Reset wordexp_t fields with WRDE_REUSE
+  (CVE-2025-15281, bsc#1257005, BZ #33814)
2026-01-26 13:01:17 +01:00
a78eec5d8a Don't use %tmpfiles_create 2026-01-26 13:01:17 +01:00
29991678d3 - Manage files in /var with systemd-tmpfiles (bsc#1253139) 2026-01-07 14:23:42 +01:00
a6b3163cca foo 2025-10-07 13:47:15 +02:00
9 changed files with 1223 additions and 13 deletions

View File

@@ -0,0 +1,63 @@
From 7d4b6bcae91f29d7b4daf15bab06b66cf1d2217c Mon Sep 17 00:00:00 2001
From: Siddhesh Poyarekar <siddhesh@sourceware.org>
Date: Tue, 21 Jan 2025 16:11:06 -0500
Subject: [PATCH] Fix underallocation of abort_msg_s struct (CVE-2025-0395)
Include the space needed to store the length of the message itself, in
addition to the message string. This resolves BZ #32582.
Signed-off-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
Reviewed: Adhemerval Zanella <adhemerval.zanella@linaro.org>
(cherry picked from commit 68ee0f704cb81e9ad0a78c644a83e1e9cd2ee578)
---
assert/assert.c | 4 +++-
sysdeps/posix/libc_fatal.c | 4 +++-
2 files changed, 6 insertions(+), 2 deletions(-)
diff --git a/assert/assert.c b/assert/assert.c
index c29629f5f6..b6e37d694c 100644
--- a/assert/assert.c
+++ b/assert/assert.c
@@ -18,6 +18,7 @@
#include <assert.h>
#include <atomic.h>
#include <ldsodefs.h>
+#include <libc-pointer-arith.h>
#include <libintl.h>
#include <stdio.h>
#include <stdlib.h>
@@ -65,7 +66,8 @@ __assert_fail_base (const char *fmt, const char *assertion, const char *file,
(void) __fxprintf (NULL, "%s", str);
(void) fflush (stderr);
- total = (total + 1 + GLRO(dl_pagesize) - 1) & ~(GLRO(dl_pagesize) - 1);
+ total = ALIGN_UP (total + sizeof (struct abort_msg_s) + 1,
+ GLRO(dl_pagesize));
struct abort_msg_s *buf = __mmap (NULL, total, PROT_READ | PROT_WRITE,
MAP_ANON | MAP_PRIVATE, -1, 0);
if (__glibc_likely (buf != MAP_FAILED))
diff --git a/sysdeps/posix/libc_fatal.c b/sysdeps/posix/libc_fatal.c
index f9e3425e04..089c47b04b 100644
--- a/sysdeps/posix/libc_fatal.c
+++ b/sysdeps/posix/libc_fatal.c
@@ -20,6 +20,7 @@
#include <errno.h>
#include <fcntl.h>
#include <ldsodefs.h>
+#include <libc-pointer-arith.h>
#include <paths.h>
#include <stdarg.h>
#include <stdbool.h>
@@ -105,7 +106,8 @@ __libc_message_impl (const char *fmt, ...)
{
WRITEV_FOR_FATAL (fd, iov, iovcnt, total);
- total = (total + 1 + GLRO(dl_pagesize) - 1) & ~(GLRO(dl_pagesize) - 1);
+ total = ALIGN_UP (total + sizeof (struct abort_msg_s) + 1,
+ GLRO(dl_pagesize));
struct abort_msg_s *buf = __mmap (NULL, total,
PROT_READ | PROT_WRITE,
MAP_ANON | MAP_PRIVATE, -1, 0);
--
2.51.0

View File

@@ -1,3 +1,37 @@
-------------------------------------------------------------------
Tue Feb 17 15:00:29 UTC 2026 - Andreas Schwab <schwab@suse.de>
- nss-missing-checks.patch: nss: Missing checks in __nss_configure_lookup,
__nss_database_get (bsc#1258319, BZ #28940)
-------------------------------------------------------------------
Mon Jan 26 11:56:25 UTC 2026 - Andreas Schwab <schwab@suse.de>
- s390-z17.patch: S390: Add new s390 platform z17 (jsc#PED-14685)
-------------------------------------------------------------------
Tue Jan 20 10:13:43 UTC 2026 - Andreas Schwab <schwab@suse.de>
- memalign-overflow-check.patch: memalign: reinstate alignment overflow
check (CVE-2026-0861, bsc#1256766, BZ #33796)
- nss-dns-getnetbyaddr.patch: resolv: Fix NSS DNS backend for getnetbyaddr
(CVE-2026-0915, bsc#1256822, BZ #33802)
- nptl-optimize-trylock.patch: nptl: Optimize trylock for high cache
contention workloads (bsc#1256436, BZ #33704)
- wordexp-wrde-reuse.patch: posix: Reset wordexp_t fields with WRDE_REUSE
(CVE-2025-15281, bsc#1257005, BZ #33814)
-------------------------------------------------------------------
Wed Jan 7 13:22:30 UTC 2026 - Andreas Schwab <schwab@suse.de>
- Manage files in /var with systemd-tmpfiles (bsc#1253139)
-------------------------------------------------------------------
Tue Oct 7 10:33:16 UTC 2025 - Andreas Schwab <schwab@suse.de>
- abort-msg-s-underallocation.patch: Fix underallocation of abort_msg_s
struct (CVE-2025-0395, bsc#1236282, BZ #32582)
-------------------------------------------------------------------
Thu Jul 24 10:14:52 UTC 2025 - Andreas Schwab <schwab@suse.de>

View File

@@ -325,6 +325,7 @@ Patch306: glibc-fix-double-loopback.diff
%if %{without snapshot}
###
# Patches from upstream
###
# PATCH-FIX-UPSTREAM Fix missing randomness in __gen_tempname (BZ #32214)
Patch1000: gen-tempname-randomness.patch
# PATCH-FIX-UPSTREAM pthreads NPTL: lost wakeup fix 2 (BZ #25847)
@@ -335,7 +336,20 @@ Patch1006: ppc64le-revert-power10-strcmp.patch
Patch1007: ppc64le-revert-power10-memcmp.patch
# PATCH-FIX-UPSTREAM posix: Fix double-free after allocation failure in regcomp (BZ #33185)
Patch1008: regcomp-double-free.patch
###
# PATCH-FIX-UPSTREAM Fix underallocation of abort_msg_s struct (CVE-2025-0395, BZ #32582)
Patch1009: abort-msg-s-underallocation.patch
# PATCH-FIX-UPSTREAM memalign: reinstate alignment overflow check (CVE-2026-0861, BZ #33796)
Patch1010: memalign-overflow-check.patch
# PATCH-FIX-UPSTREAM resolv: Fix NSS DNS backend for getnetbyaddr (CVE-2026-0915, BZ #33802)
Patch1011: nss-dns-getnetbyaddr.patch
# PATCH-FIX-UPSTREAM nptl: Optimize trylock for high cache contention workloads (BZ #33704)
Patch1012: nptl-optimize-trylock.patch
# PATCH-FIX-UPSTREAM posix: Reset wordexp_t fields with WRDE_REUSE (CVE-2025-15281, BZ #33814)
Patch1013: wordexp-wrde-reuse.patch
# PATCH-FIX-UPSTREAM S390: Add new s390 platform z17
Patch1014: s390-z17.patch
# PATCH-FIX-UPSTREAM nss: Missing checks in __nss_configure_lookup, __nss_database_get (BZ #28940)
Patch1015: nss-missing-checks.patch
%endif
###
@@ -1042,6 +1056,9 @@ include /etc/ld.so.conf.d/*.conf
EOF
# Add ldconfig cache directory for directory ownership
mkdir -p %{buildroot}/var/cache/ldconfig
mkdir -p %{buildroot}%{_tmpfilesdir}
echo 'd /var/cache/ldconfig 0700 root root' > %{buildroot}%{_tmpfilesdir}/glibc.conf
# Empty the ld.so.cache:
rm -f %{buildroot}/etc/ld.so.cache
touch %{buildroot}/etc/ld.so.cache
@@ -1057,12 +1074,12 @@ rm -f %{buildroot}%{slibdir}/libnsl.so.1
%if %{with nscd}
%ifnarch i686
mkdir -p %{buildroot}/usr/lib/tmpfiles.d/
install -m 644 %{SOURCE20} %{buildroot}/usr/lib/tmpfiles.d/
mkdir -p %{buildroot}%{_tmpfilesdir}
install -m 644 %{SOURCE20} %{buildroot}%{_tmpfilesdir}/
mkdir -p %{buildroot}/usr/lib/systemd/system
install -m 644 %{SOURCE21} %{buildroot}/usr/lib/systemd/system
mkdir -p %{buildroot}/usr/lib/sysusers.d/
install -m 644 %{SOURCE22} %{buildroot}/usr/lib/sysusers.d/nscd.conf
mkdir -p %{buildroot}%{_sysusersdir}/
install -m 644 %{SOURCE22} %{buildroot}%{_sysusersdir}/nscd.conf
%endif
%endif
@@ -1101,6 +1118,8 @@ rm -f %{buildroot}%{_sbindir}/nscd
mkdir %{buildroot}%{_prefix}/share/misc
mv %{buildroot}/var/lib/misc/Makefile %{buildroot}%{_prefix}/share/misc/Makefile.makedb
ln -s %{_prefix}/share/misc/Makefile.makedb %{buildroot}/var/lib/misc/Makefile
mkdir -p %{buildroot}%{_tmpfilesdir}/
echo 'L /var/lib/misc/Makefile - - - - /usr/share/misc/Makefile.makedb' > %{buildroot}%{_tmpfilesdir}/glibc-extra.conf
%endif
%endif
@@ -1266,7 +1285,6 @@ end
%post -n nscd
%service_add_post nscd.service
%tmpfiles_create /usr/lib/tmpfiles.d/nscd.conf
# Previously we had nscd.socket, remove it
test -x /usr/bin/systemctl && /usr/bin/systemctl stop nscd.socket 2>/dev/null || :
test -x /usr/bin/systemctl && /usr/bin/systemctl disable nscd.socket 2>/dev/null || :
@@ -1338,7 +1356,7 @@ exit 0
%ifarch %libutil_archs
%{slibdir}/libutil.so.1
%endif
%dir %attr(0700,root,root) /var/cache/ldconfig
%dir %attr(0700,root,root) %ghost /var/cache/ldconfig
%{rootsbindir}/ldconfig
%{_bindir}/gencat
%{_bindir}/getconf
@@ -1369,6 +1387,7 @@ exit 0
%{_libdir}/gconv/UTF8_UTF16_Z9.so
%endif
%attr(0644,root,root) %verify(not md5 size mtime) %ghost %{_libdir}/gconv/gconv-modules.cache
%{_tmpfilesdir}/glibc.conf
%files gconv-modules-extra
%dir %{_libdir}/gconv
@@ -1482,14 +1501,14 @@ exit 0
%{_sbindir}/nscd
%{_sbindir}/rcnscd
/usr/lib/systemd/system/nscd.service
%dir /usr/lib/tmpfiles.d
/usr/lib/tmpfiles.d/nscd.conf
%dir /usr/lib/sysusers.d
/usr/lib/sysusers.d/nscd.conf
%dir %{_tmpfilesdir}
%{_tmpfilesdir}/nscd.conf
%dir %{_sysusersdir}
%{_sysusersdir}/nscd.conf
%dir %attr(0755,root,root) %ghost /run/nscd
%attr(0644,root,root) %verify(not md5 size mtime) %ghost %config(missingok,noreplace) /run/nscd/nscd.pid
%attr(0666,root,root) %verify(not md5 size mtime) %ghost %config(missingok,noreplace) /run/nscd/socket
%dir %attr(0755,root,root) /var/lib/nscd
%dir %attr(0755,root,root) %ghost /var/lib/nscd
%attr(0600,root,root) %verify(not md5 size mtime) %ghost %config(missingok,noreplace) /var/lib/nscd/passwd
%attr(0600,root,root) %verify(not md5 size mtime) %ghost %config(missingok,noreplace) /var/lib/nscd/group
%attr(0600,root,root) %verify(not md5 size mtime) %ghost %config(missingok,noreplace) /var/lib/nscd/hosts
@@ -1524,7 +1543,8 @@ exit 0
%defattr(-,root,root)
%{_bindir}/makedb
%{_prefix}/share/misc/Makefile.makedb
/var/lib/misc/Makefile
%ghost /var/lib/misc/Makefile
%{_tmpfilesdir}/glibc-extra.conf
%files lang -f libc.lang
%endif

View File

@@ -0,0 +1,88 @@
From bfc4dd9e526eacf3017dd8864ba0848e9d045dd4 Mon Sep 17 00:00:00 2001
From: Siddhesh Poyarekar <siddhesh@gotplt.org>
Date: Thu, 15 Jan 2026 06:06:40 -0500
Subject: [PATCH] memalign: reinstate alignment overflow check (CVE-2026-0861)
The change to cap valid sizes to PTRDIFF_MAX inadvertently dropped the
overflow check for alignment in memalign functions, _mid_memalign and
_int_memalign. Reinstate the overflow check in _int_memalign, aligned
with the PTRDIFF_MAX change since that is directly responsible for the
CVE. The missing _mid_memalign check is not relevant (and does not have
a security impact) and may need a different approach to fully resolve,
so it has been omitted.
CVE-Id: CVE-2026-0861
Vulnerable-Commit: 9bf8e29ca136094f73f69f725f15c51facc97206
Reported-by: Igor Morgenstern, Aisle Research
Fixes: BZ #33796
Reviewed-by: Wilco Dijkstra <Wilco.Dijkstra@arm.com>
Signed-off-by: Siddhesh Poyarekar <siddhesh@gotplt.org>
(cherry picked from commit c9188d333717d3ceb7e3020011651f424f749f93)
---
malloc/malloc.c | 7 +++++--
malloc/tst-malloc-too-large.c | 10 ++--------
2 files changed, 7 insertions(+), 10 deletions(-)
diff --git a/malloc/malloc.c b/malloc/malloc.c
index bcb6e5b83c..e39354595e 100644
--- a/malloc/malloc.c
+++ b/malloc/malloc.c
@@ -5049,7 +5049,7 @@ _int_memalign (mstate av, size_t alignment, size_t bytes)
INTERNAL_SIZE_T size;
nb = checked_request2size (bytes);
- if (nb == 0)
+ if (nb == 0 || alignment > PTRDIFF_MAX)
{
__set_errno (ENOMEM);
return NULL;
@@ -5065,7 +5065,10 @@ _int_memalign (mstate av, size_t alignment, size_t bytes)
we don't find anything in those bins, the common malloc code will
scan starting at 2x. */
- /* Call malloc with worst case padding to hit alignment. */
+ /* Call malloc with worst case padding to hit alignment. ALIGNMENT is a
+ power of 2, so it tops out at (PTRDIFF_MAX >> 1) + 1, leaving plenty of
+ space to add MINSIZE and whatever checked_request2size adds to BYTES to
+ get NB. Consequently, total below also does not overflow. */
m = (char *) (_int_malloc (av, nb + alignment + MINSIZE));
if (m == 0)
diff --git a/malloc/tst-malloc-too-large.c b/malloc/tst-malloc-too-large.c
index 2b91377e54..15b25cf01d 100644
--- a/malloc/tst-malloc-too-large.c
+++ b/malloc/tst-malloc-too-large.c
@@ -152,7 +152,6 @@ test_large_allocations (size_t size)
}
-static long pagesize;
/* This function tests the following aligned memory allocation functions
using several valid alignments and precedes each allocation test with a
@@ -171,8 +170,8 @@ test_large_aligned_allocations (size_t size)
/* All aligned memory allocation functions expect an alignment that is a
power of 2. Given this, we test each of them with every valid
- alignment from 1 thru PAGESIZE. */
- for (align = 1; align <= pagesize; align *= 2)
+ alignment for the type of ALIGN, i.e. until it wraps to 0. */
+ for (align = 1; align > 0; align <<= 1)
{
test_setup ();
#if __GNUC_PREREQ (7, 0)
@@ -265,11 +264,6 @@ do_test (void)
DIAG_IGNORE_NEEDS_COMMENT (7, "-Walloc-size-larger-than=");
#endif
- /* Aligned memory allocation functions need to be tested up to alignment
- size equivalent to page size, which should be a power of 2. */
- pagesize = sysconf (_SC_PAGESIZE);
- TEST_VERIFY_EXIT (powerof2 (pagesize));
-
/* Loop 1: Ensure that all allocations with SIZE close to SIZE_MAX, i.e.
in the range (SIZE_MAX - 2^14, SIZE_MAX], fail.
--
2.52.0

View File

@@ -0,0 +1,50 @@
From d861635092a5ad3499baf18b2ff955b778734a0e Mon Sep 17 00:00:00 2001
From: Sunil K Pandey <sunil.k.pandey@intel.com>
Date: Tue, 9 Dec 2025 08:57:44 -0800
Subject: [PATCH] nptl: Optimize trylock for high cache contention workloads
(BZ #33704)
Check lock availability before acquisition to reduce cache line
bouncing. Significantly improves trylock throughput on multi-core
systems under heavy contention.
Tested on x86_64.
Fixes BZ #33704.
Co-authored-by: Alex M Wells <alex.m.wells@intel.com>
Reviewed-by: Wilco Dijkstra <Wilco.Dijkstra@arm.com>
(cherry picked from commit 63716823dbad9482e09972907ae98e9cb00f9b86)
---
nptl/pthread_mutex_trylock.c | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/nptl/pthread_mutex_trylock.c b/nptl/pthread_mutex_trylock.c
index 720c103f3f..6cf47403dd 100644
--- a/nptl/pthread_mutex_trylock.c
+++ b/nptl/pthread_mutex_trylock.c
@@ -48,7 +48,8 @@ ___pthread_mutex_trylock (pthread_mutex_t *mutex)
return 0;
}
- if (lll_trylock (mutex->__data.__lock) == 0)
+ if (atomic_load_relaxed (&(mutex->__data.__lock)) == 0
+ && lll_trylock (mutex->__data.__lock) == 0)
{
/* Record the ownership. */
mutex->__data.__owner = id;
@@ -71,7 +72,10 @@ ___pthread_mutex_trylock (pthread_mutex_t *mutex)
/*FALL THROUGH*/
case PTHREAD_MUTEX_ADAPTIVE_NP:
case PTHREAD_MUTEX_ERRORCHECK_NP:
- if (lll_trylock (mutex->__data.__lock) != 0)
+ /* Mutex type is already loaded, lock check overhead should
+ be minimal. */
+ if (atomic_load_relaxed (&(mutex->__data.__lock)) != 0
+ || lll_trylock (mutex->__data.__lock) != 0)
break;
/* Record the ownership. */
--
2.52.0

View File

@@ -0,0 +1,77 @@
From 329c775788b2c9ff3da774ccf59fba7b6b8ff08e Mon Sep 17 00:00:00 2001
From: Carlos O'Donell <carlos@redhat.com>
Date: Thu, 15 Jan 2026 15:09:38 -0500
Subject: [PATCH] resolv: Fix NSS DNS backend for getnetbyaddr (CVE-2026-0915)
The default network value of zero for net was never tested for and
results in a DNS query constructed from uninitialized stack bytes.
The solution is to provide a default query for the case where net
is zero.
Adding a test case for this was straight forward given the existence of
tst-resolv-network and if the test is added without the fix you observe
this failure:
FAIL: resolv/tst-resolv-network
original exit status 1
error: tst-resolv-network.c:174: invalid QNAME: \146\218\129\128
error: 1 test failures
With a random QNAME resulting from the use of uninitialized stack bytes.
After the fix the test passes.
Additionally verified using wireshark before and after to ensure
on-the-wire bytes for the DNS query were as expected.
No regressions on x86_64.
Reviewed-by: Florian Weimer <fweimer@redhat.com>
(cherry picked from commit e56ff82d5034ec66c6a78f517af6faa427f65b0b)
---
resolv/nss_dns/dns-network.c | 4 ++++
resolv/tst-resolv-network.c | 6 ++++++
2 files changed, 10 insertions(+)
diff --git a/resolv/nss_dns/dns-network.c b/resolv/nss_dns/dns-network.c
index b32fd0fcab..71d67aa6f8 100644
--- a/resolv/nss_dns/dns-network.c
+++ b/resolv/nss_dns/dns-network.c
@@ -207,6 +207,10 @@ _nss_dns_getnetbyaddr_r (uint32_t net, int type, struct netent *result,
sprintf (qbuf, "%u.%u.%u.%u.in-addr.arpa", net_bytes[3], net_bytes[2],
net_bytes[1], net_bytes[0]);
break;
+ default:
+ /* Default network (net is originally zero). */
+ strcpy (qbuf, "0.0.0.0.in-addr.arpa");
+ break;
}
net_buffer.buf = orig_net_buffer = (querybuf *) alloca (1024);
diff --git a/resolv/tst-resolv-network.c b/resolv/tst-resolv-network.c
index f40e6f926c..8d4f8badf3 100644
--- a/resolv/tst-resolv-network.c
+++ b/resolv/tst-resolv-network.c
@@ -46,6 +46,9 @@ handle_code (const struct resolv_response_context *ctx,
{
switch (code)
{
+ case 0:
+ send_ptr (b, qname, qclass, qtype, "0.in-addr.arpa");
+ break;
case 1:
send_ptr (b, qname, qclass, qtype, "1.in-addr.arpa");
break;
@@ -265,6 +268,9 @@ do_test (void)
"error: TRY_AGAIN\n");
/* Lookup by address, success cases. */
+ check_reverse (0,
+ "name: 0.in-addr.arpa\n"
+ "net: 0x00000000\n");
check_reverse (1,
"name: 1.in-addr.arpa\n"
"net: 0x00000001\n");
--
2.52.0

44
nss-missing-checks.patch Normal file
View File

@@ -0,0 +1,44 @@
From 4b1bd2ab9318f680a355913987a0ba514cbcd0c9 Mon Sep 17 00:00:00 2001
From: Florian Weimer <fweimer@redhat.com>
Date: Fri, 13 Feb 2026 09:02:07 +0100
Subject: [PATCH] nss: Missing checks in __nss_configure_lookup,
__nss_database_get (bug 28940)
This avoids a null pointer dereference in the
nss_database_check_reload_and_get function, and assertion failures.
Reviewed-by: Sam James <sam@gentoo.org>
---
nss/nss_database.c | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/nss/nss_database.c b/nss/nss_database.c
index efe77aeaff..cd7c9f00ec 100644
--- a/nss/nss_database.c
+++ b/nss/nss_database.c
@@ -251,9 +251,12 @@ __nss_configure_lookup (const char *dbname, const char *service_line)
/* Force any load/cache/read whatever to happen, so we can override
it. */
- __nss_database_get (db, &result);
+ if (!__nss_database_get (db, &result))
+ return -1;
local = nss_database_state_get ();
+ if (local == NULL)
+ return -1;
result = __nss_action_parse (service_line);
if (result == NULL)
@@ -478,6 +481,8 @@ bool
__nss_database_get (enum nss_database db, nss_action_list *actions)
{
struct nss_database_state *local = nss_database_state_get ();
+ if (local == NULL)
+ return false;
return nss_database_check_reload_and_get (local, actions, db);
}
libc_hidden_def (__nss_database_get)
--
2.53.0

658
s390-z17.patch Normal file
View File

@@ -0,0 +1,658 @@
From d56e24327cd59c97eccf3b666344f3297d9593a4 Mon Sep 17 00:00:00 2001
From: Stefan Liebler <stli@linux.ibm.com>
Date: Tue, 29 Apr 2025 13:28:58 +0200
Subject: [PATCH] S390: Add new s390 platform z17.
The glibc-hwcaps subdirectories are extended by "z17". Libraries are loaded if
the z17 facility bits are active:
- Miscellaneous-instruction-extensions facility 4
- Vector-enhancements-facility 3
- Vector-Packed-Decimal-Enhancement Facility 3
- CPU: Concurrent-Functions Facility
tst-glibc-hwcaps.c is extended in order to test z17 via new marker6.
In case of running on a z17 with a kernel not recognizing z17 yet,
AT_PLATFORM will be z900 but vector-bit in AT_HWCAP is set. This situation
is now recognized and this testcase does not fail.
A fatal glibc error is dumped if glibc was build with architecture
level set for z17, but run on an older machine (See dl-hwcap-check.h).
Note, you might get an SIGILL before this check if you don't use:
configure --with-rtld-early-cflags=-march=<older-machine>
ld.so --list-diagnostics now also dumps information about s390.cpu_features.
Independent from z17, the s390x kernel won't introduce new HWCAP-Bits if there
is no special handling needed in kernel itself. For z17, we don't have new
HWCAP flags, but have to check the facility bits retrieved by
stfle-instruction.
Instead of storing all the stfle-bits (currently four 64bit values) in the
cpu_features struct, we now only store those bits, which are needed within
glibc itself. Note that we have this list twice, one with original values and
the other one which can be filtered with GLIBC_TUNABLES=glibc.cpu.hwcaps.
Those new fields are stored in so far reserved space in cpu_features struct.
Thus processes started in between the update of glibc package and we e.g. have
a new ld.so and an old libc.so, won't crash. The glibc internal ifunc-resolvers
would not select the best optimized variant.
The users of stfle-bits are also updated:
- parsing of GLIBC_TUNABLES=glibc.cpu.hwcaps
- glibc internal ifunc-resolvers
- __libc_ifunc_impl_list
- sysconf
---
elf/Makefile | 9 +++
elf/tst-glibc-hwcaps-cache.script | 7 ++
sysdeps/s390/cpu-features.c | 77 +++++++++++++++----
sysdeps/s390/cpu-features.h | 55 +++++++++----
.../ifunc-resolve.h => dl-diagnostics-cpu.c} | 34 ++++----
sysdeps/s390/multiarch/ifunc-impl-list.c | 4 +-
sysdeps/s390/multiarch/ifunc-resolve.h | 2 +-
sysdeps/s390/s390-64/Makefile | 27 ++++++-
sysdeps/s390/s390-64/dl-hwcap-check.h | 21 ++++-
sysdeps/s390/s390-64/dl-hwcaps-subdirs.c | 12 ++-
sysdeps/s390/s390-64/tst-glibc-hwcaps.c | 52 +++++++++----
sysdeps/unix/sysv/linux/s390/sysconf.c | 2 +-
12 files changed, 230 insertions(+), 72 deletions(-)
copy sysdeps/s390/{multiarch/ifunc-resolve.h => dl-diagnostics-cpu.c} (51%)
diff --git a/elf/Makefile b/elf/Makefile
index 0303e08557..172fe149ca 100644
--- a/elf/Makefile
+++ b/elf/Makefile
@@ -732,6 +732,12 @@ modules-names += \
libmarkermod5-3 \
libmarkermod5-4 \
libmarkermod5-5 \
+ libmarkermod6-1 \
+ libmarkermod6-2 \
+ libmarkermod6-3 \
+ libmarkermod6-4 \
+ libmarkermod6-5 \
+ libmarkermod6-6 \
libtracemod1-1 \
libtracemod2-1 \
libtracemod3-1 \
@@ -2710,6 +2716,7 @@ LDFLAGS-libmarkermod2-1.so += -Wl,-soname,libmarkermod2.so
LDFLAGS-libmarkermod3-1.so += -Wl,-soname,libmarkermod3.so
LDFLAGS-libmarkermod4-1.so += -Wl,-soname,libmarkermod4.so
LDFLAGS-libmarkermod5-1.so += -Wl,-soname,libmarkermod5.so
+LDFLAGS-libmarkermod6-1.so += -Wl,-soname,libmarkermod6.so
$(objpfx)libmarkermod%.os : markermodMARKER-VALUE.c
$(compile-command.c) \
-DMARKER=marker$(firstword $(subst -, ,$*)) \
@@ -2724,6 +2731,8 @@ $(objpfx)libmarkermod4.so: $(objpfx)libmarkermod4-1.so
cp $< $@
$(objpfx)libmarkermod5.so: $(objpfx)libmarkermod5-1.so
cp $< $@
+$(objpfx)libmarkermod6.so: $(objpfx)libmarkermod6-1.so
+ cp $< $@
# tst-glibc-hwcaps-prepend checks that --glibc-hwcaps-prepend is
# preferred over auto-detected subdirectories.
diff --git a/elf/tst-glibc-hwcaps-cache.script b/elf/tst-glibc-hwcaps-cache.script
index d58fc8c5de..af89e9c6f8 100644
--- a/elf/tst-glibc-hwcaps-cache.script
+++ b/elf/tst-glibc-hwcaps-cache.script
@@ -5,6 +5,7 @@ cp $B/elf/libmarkermod2-1.so $L/libmarkermod2.so
cp $B/elf/libmarkermod3-1.so $L/libmarkermod3.so
cp $B/elf/libmarkermod4-1.so $L/libmarkermod4.so
cp $B/elf/libmarkermod5-1.so $L/libmarkermod5.so
+cp $B/elf/libmarkermod6-1.so $L/libmarkermod6.so
mkdirp 0770 $L/glibc-hwcaps/power9
cp $B/elf/libmarkermod2-2.so $L/glibc-hwcaps/power9/libmarkermod2.so
@@ -26,6 +27,12 @@ cp $B/elf/libmarkermod5-2.so $L/glibc-hwcaps/z13/libmarkermod5.so
cp $B/elf/libmarkermod5-3.so $L/glibc-hwcaps/z14/libmarkermod5.so
cp $B/elf/libmarkermod5-4.so $L/glibc-hwcaps/z15/libmarkermod5.so
cp $B/elf/libmarkermod5-5.so $L/glibc-hwcaps/z16/libmarkermod5.so
+mkdirp 0770 $L/glibc-hwcaps/z17
+cp $B/elf/libmarkermod6-2.so $L/glibc-hwcaps/z13/libmarkermod6.so
+cp $B/elf/libmarkermod6-3.so $L/glibc-hwcaps/z14/libmarkermod6.so
+cp $B/elf/libmarkermod6-4.so $L/glibc-hwcaps/z15/libmarkermod6.so
+cp $B/elf/libmarkermod6-5.so $L/glibc-hwcaps/z16/libmarkermod6.so
+cp $B/elf/libmarkermod6-6.so $L/glibc-hwcaps/z17/libmarkermod6.so
mkdirp 0770 $L/glibc-hwcaps/x86-64-v2
cp $B/elf/libmarkermod2-2.so $L/glibc-hwcaps/x86-64-v2/libmarkermod2.so
diff --git a/sysdeps/s390/cpu-features.c b/sysdeps/s390/cpu-features.c
index bc4ad601f1..f44270bd76 100644
--- a/sysdeps/s390/cpu-features.c
+++ b/sysdeps/s390/cpu-features.c
@@ -26,7 +26,7 @@
#define S390_COPY_CPU_FEATURES(SRC_PTR, DEST_PTR) \
(DEST_PTR)->hwcap = (SRC_PTR)->hwcap; \
- (DEST_PTR)->stfle_bits[0] = (SRC_PTR)->stfle_bits[0];
+ (DEST_PTR)->stfle_filtered = (SRC_PTR)->stfle_filtered;
static void
TUNABLE_CALLBACK (set_hwcaps) (tunable_val_t *valp)
@@ -76,7 +76,7 @@ TUNABLE_CALLBACK (set_hwcaps) (tunable_val_t *valp)
disable = true;
hwcap_mask = HWCAP_S390_VXRS | HWCAP_S390_VXRS_EXT
| HWCAP_S390_VXRS_EXT2;
- stfle_bits0_mask = S390_STFLE_MASK_ARCH13_MIE3;
+ stfle_bits0_mask = S390_STFLE_BIT61_ARCH13_MIE3;
}
else if (tunable_str_comma_strcmp_cte (&t, "z13")
|| tunable_str_comma_strcmp_cte (&t, "arch11"))
@@ -84,7 +84,7 @@ TUNABLE_CALLBACK (set_hwcaps) (tunable_val_t *valp)
reset_features = true;
disable = true;
hwcap_mask = HWCAP_S390_VXRS_EXT | HWCAP_S390_VXRS_EXT2;
- stfle_bits0_mask = S390_STFLE_MASK_ARCH13_MIE3;
+ stfle_bits0_mask = S390_STFLE_BIT61_ARCH13_MIE3;
}
else if (tunable_str_comma_strcmp_cte (&t, "z14")
|| tunable_str_comma_strcmp_cte (&t, "arch12"))
@@ -92,12 +92,14 @@ TUNABLE_CALLBACK (set_hwcaps) (tunable_val_t *valp)
reset_features = true;
disable = true;
hwcap_mask = HWCAP_S390_VXRS_EXT2;
- stfle_bits0_mask = S390_STFLE_MASK_ARCH13_MIE3;
+ stfle_bits0_mask = S390_STFLE_BIT61_ARCH13_MIE3;
}
else if (tunable_str_comma_strcmp_cte (&t, "z15")
|| tunable_str_comma_strcmp_cte (&t, "z16")
+ || tunable_str_comma_strcmp_cte (&t, "z17")
|| tunable_str_comma_strcmp_cte (&t, "arch13")
- || tunable_str_comma_strcmp_cte (&t, "arch14"))
+ || tunable_str_comma_strcmp_cte (&t, "arch14")
+ || tunable_str_comma_strcmp_cte (&t, "arch15"))
{
/* For z15 or newer we don't have to disable something, but we have
to reset to the original values. */
@@ -124,7 +126,7 @@ TUNABLE_CALLBACK (set_hwcaps) (tunable_val_t *valp)
hwcap_mask |= HWCAP_S390_VXRS | HWCAP_S390_VXRS_EXT;
}
else if (tunable_str_comma_strcmp_cte (&t, "STFLE_MIE3"))
- stfle_bits0_mask = S390_STFLE_MASK_ARCH13_MIE3;
+ stfle_bits0_mask = S390_STFLE_BIT61_ARCH13_MIE3;
/* Perform the actions determined above. */
if (reset_features)
@@ -143,22 +145,26 @@ TUNABLE_CALLBACK (set_hwcaps) (tunable_val_t *valp)
if (stfle_bits0_mask != 0ULL)
{
if (disable)
- cpu_features_curr.stfle_bits[0] &= ~stfle_bits0_mask;
+ cpu_features_curr.stfle_filtered &= ~stfle_bits0_mask;
else
- cpu_features_curr.stfle_bits[0] |= stfle_bits0_mask;
+ cpu_features_curr.stfle_filtered |= stfle_bits0_mask;
}
}
/* Copy back the features after checking that no unsupported features were
enabled by user. */
cpu_features->hwcap = cpu_features_curr.hwcap & cpu_features_orig.hwcap;
- cpu_features->stfle_bits[0] = cpu_features_curr.stfle_bits[0]
- & cpu_features_orig.stfle_bits[0];
+ cpu_features->stfle_filtered = cpu_features_curr.stfle_filtered
+ & cpu_features_orig.stfle_filtered;
}
static inline void
-init_cpu_features (struct cpu_features *cpu_features)
+init_cpu_features_no_tunables (struct cpu_features *cpu_features)
{
+ /* Only initialize once. */
+ if (cpu_features->hwcap != 0)
+ return;
+
/* Fill cpu_features as passed by kernel and machine. */
cpu_features->hwcap = GLRO(dl_hwcap);
@@ -167,20 +173,57 @@ init_cpu_features (struct cpu_features *cpu_features)
&& (cpu_features->hwcap & HWCAP_S390_ZARCH)
&& (cpu_features->hwcap & HWCAP_S390_HIGH_GPRS)))
{
- register unsigned long reg0 __asm__("0") = 0;
+ unsigned long long stfle_bits[4] = { 0 };
+ register unsigned long reg0 __asm__("0") = 3;
__asm__ __volatile__(".machine push" "\n\t"
".machine \"z9-109\"" "\n\t"
".machinemode \"zarch_nohighgprs\"\n\t"
"stfle %0" "\n\t"
".machine pop" "\n"
- : "=QS" (cpu_features->stfle_bits[0]),
+ : "=QS" (stfle_bits[0]),
"+d" (reg0)
: : "cc");
+
+ unsigned long long internal_stfle_bits = 0;
+
+ /* Facility bit 34: z10: General instructions extension. */
+ if ((stfle_bits[0] & (1ULL << (63 - 34))) != 0)
+ internal_stfle_bits |= S390_STFLE_BIT34_Z10;
+
+ /* Facility bit 45: z196: Distinct operands, popcount, ... */
+ if ((stfle_bits[0] & (1ULL << (63 - 45))) != 0)
+ internal_stfle_bits |= S390_STFLE_BIT45_Z196;
+
+ /* Facility bit 61: arch13/z15: Miscellaneous-Instruction-Extensions
+ Facility 3, e.g. mvcrl. */
+ if ((stfle_bits[0] & (1ULL << (63 - 61))) != 0)
+ internal_stfle_bits |= S390_STFLE_BIT61_ARCH13_MIE3;
+
+ /* Facility bit 84: arch15/z17: Miscellaneous-instruction-extensions 4 */
+ if ((stfle_bits[1] & (1ULL << (127 - 84))) != 0)
+ internal_stfle_bits |= S390_STFLE_BIT84_ARCH15_MIE4;
+
+ /* Facility bit 198: arch15/z17: Vector-enhancements-facility 3 */
+ if ((stfle_bits[3] & (1ULL << (255 - 198))) != 0)
+ internal_stfle_bits |= S390_STFLE_BIT198_ARCH15_VXRS_EXT3;
+
+ /* Facility bit 199: arch15/z17: Vector-Packed-Decimal-Enhancement 3 */
+ if ((stfle_bits[3] & (1ULL << (255 - 199))) != 0)
+ internal_stfle_bits |= S390_STFLE_BIT199_ARCH15_VXRS_PDE3;
+
+ /* Facility bit 201: arch15/z17: CPU: Concurrent-Functions Facility */
+ if ((stfle_bits[3] & (1ULL << (255 - 201))) != 0)
+ internal_stfle_bits |= S390_STFLE_BIT201_ARCH15_CON;
+
+ cpu_features->stfle_orig = internal_stfle_bits;
+ cpu_features->stfle_filtered = internal_stfle_bits;
}
- else
- {
- cpu_features->stfle_bits[0] = 0ULL;
- }
+}
+
+static inline void
+init_cpu_features (struct cpu_features *cpu_features)
+{
+ init_cpu_features_no_tunables (cpu_features);
TUNABLE_GET (glibc, cpu, hwcaps, tunable_val_t *, TUNABLE_CALLBACK (set_hwcaps));
}
diff --git a/sysdeps/s390/cpu-features.h b/sysdeps/s390/cpu-features.h
index 6efea28e35..fa92fbeb44 100644
--- a/sysdeps/s390/cpu-features.h
+++ b/sysdeps/s390/cpu-features.h
@@ -18,29 +18,58 @@
#ifndef __CPU_FEATURES_S390X_H
# define __CPU_FEATURES_S390X_H
-#define S390_STFLE_BITS_Z10 34 /* General instructions extension */
-#define S390_STFLE_BITS_Z196 45 /* Distinct operands, pop ... */
-#define S390_STFLE_BITS_ARCH13_MIE3 61 /* Miscellaneous-Instruction-Extensions
- Facility 3, e.g. mvcrl. */
+/* The following stfle bit definitions are intended to be used for the
+ glibc internal stfle_orig and stfle_filtered fields in cpu_features
+ struct. They can't be used on the double words retrieved by the
+ stfle-instruction. */
-#define S390_STFLE_MASK_ARCH13_MIE3 (1ULL << (63 - S390_STFLE_BITS_ARCH13_MIE3))
+/* Facility bit 34: z10: General instructions extension. */
+#define S390_STFLE_BIT34_Z10 (1ULL << 0)
+/* Facility bit 45: z196: Distinct operands, popcount, ... */
+#define S390_STFLE_BIT45_Z196 (1ULL << 1)
-#define S390_IS_ARCH13_MIE3(STFLE_BITS_ARRAY) \
- (((STFLE_BITS_ARRAY)[0] & S390_STFLE_MASK_ARCH13_MIE3) != 0)
+/* Facility bit 61: arch13/z15: Miscellaneous-Instruction-Extensions
+ Facility 3, e.g. mvcrl. */
+#define S390_STFLE_BIT61_ARCH13_MIE3 (1ULL << 2)
-#define S390_IS_Z196(STFLE_BITS_ARRAY) \
- (((STFLE_BITS_ARRAY)[0] & (1ULL << (63 - S390_STFLE_BITS_Z196))) != 0)
+/* Facility bit 84: arch15/z17: Miscellaneous-instruction-extensions
+ facility 4 */
+#define S390_STFLE_BIT84_ARCH15_MIE4 (1ULL << 3)
-#define S390_IS_Z10(STFLE_BITS_ARRAY) \
- (((STFLE_BITS_ARRAY)[0] & (1ULL << (63 - S390_STFLE_BITS_Z10))) != 0)
+/* Facility bit 198: arch15/z17: Vector-enhancements-facility 3 */
+#define S390_STFLE_BIT198_ARCH15_VXRS_EXT3 (1ULL << 4)
+
+/* Facility bit 199: arch15/z17: Vector-Packed-Decimal-Enhancement
+ Facility 3 */
+#define S390_STFLE_BIT199_ARCH15_VXRS_PDE3 (1ULL << 5)
+
+/* Facility bit 201: arch15/z17: CPU: Concurrent-Functions Facility */
+#define S390_STFLE_BIT201_ARCH15_CON (1ULL << 6)
+
+#define S390_IS_ARCH15(STFLE_BITS) \
+ ((((STFLE_BITS) & S390_STFLE_BIT84_ARCH15_MIE4) != 0) \
+ && (((STFLE_BITS) & S390_STFLE_BIT198_ARCH15_VXRS_EXT3) != 0) \
+ && (((STFLE_BITS) & S390_STFLE_BIT199_ARCH15_VXRS_PDE3) != 0) \
+ && (((STFLE_BITS) & S390_STFLE_BIT201_ARCH15_CON) != 0))
+
+#define S390_IS_ARCH13_MIE3(STFLE_BITS) \
+ (((STFLE_BITS) & S390_STFLE_BIT61_ARCH13_MIE3) != 0)
+
+#define S390_IS_Z196(STFLE_BITS) \
+ (((STFLE_BITS) & S390_STFLE_BIT45_Z196) != 0)
+
+#define S390_IS_Z10(STFLE_BITS) \
+ (((STFLE_BITS) & S390_STFLE_BIT34_Z10) != 0)
struct cpu_features
{
unsigned long int hwcap;
unsigned long int __reserved_hwcap2;
- unsigned long long stfle_bits[3];
- unsigned long long __reserved[11];
+ unsigned long long __reserved;
+ unsigned long long stfle_orig;
+ unsigned long long stfle_filtered;
+ unsigned long long __reserved2[11];
};
#endif /* __CPU_FEATURES_S390X_H */
diff --git a/sysdeps/s390/multiarch/ifunc-resolve.h b/sysdeps/s390/dl-diagnostics-cpu.c
similarity index 51%
copy from sysdeps/s390/multiarch/ifunc-resolve.h
copy to sysdeps/s390/dl-diagnostics-cpu.c
index 2a0c4a56a4..426af2df7a 100644
--- a/sysdeps/s390/multiarch/ifunc-resolve.h
+++ b/sysdeps/s390/dl-diagnostics-cpu.c
@@ -1,6 +1,5 @@
-/* IFUNC resolver function for CPU specific functions.
- 32/64 bit S/390 version.
- Copyright (C) 2015-2024 Free Software Foundation, Inc.
+/* Print CPU diagnostics data in ld.so. s390 version.
+ 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
@@ -17,19 +16,22 @@
License along with the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */
-#include <unistd.h>
-#include <dl-procinfo.h>
+#include <dl-diagnostics.h>
+#include <ldsodefs.h>
#include <cpu-features.h>
-#define s390_libc_ifunc_expr_stfle_init() \
- const unsigned long long *stfle_bits = features->stfle_bits;
+static void
+print_cpu_features_value (const char *label, uint64_t value)
+{
+ _dl_printf ("s390.cpu_features.");
+ _dl_diagnostics_print_labeled_value (label, value);
+}
-#define s390_libc_ifunc_expr_init() \
- const struct cpu_features *features = &GLRO(dl_s390_cpu_features); \
- /* The hwcap from kernel is passed as argument, but we \
- explicitly use the hwcaps from cpu-features struct. */ \
- hwcap = features->hwcap;
-
-#define s390_libc_ifunc_expr(TYPE_FUNC, FUNC, EXPR) \
- __ifunc (TYPE_FUNC, FUNC, EXPR, unsigned long int hwcap, \
- s390_libc_ifunc_expr_init);
+void
+_dl_diagnostics_cpu (void)
+{
+ const struct cpu_features *cpu_features = &GLRO(dl_s390_cpu_features);
+ print_cpu_features_value ("hwcap", cpu_features->hwcap);
+ print_cpu_features_value ("stfle_orig", cpu_features->stfle_orig);
+ print_cpu_features_value ("stfle_filtered", cpu_features->stfle_filtered);
+}
diff --git a/sysdeps/s390/multiarch/ifunc-impl-list.c b/sysdeps/s390/multiarch/ifunc-impl-list.c
index b05b86f6bd..48252785cd 100644
--- a/sysdeps/s390/multiarch/ifunc-impl-list.c
+++ b/sysdeps/s390/multiarch/ifunc-impl-list.c
@@ -81,8 +81,8 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
/* Get hardware information. */
const struct cpu_features *features = &GLRO(dl_s390_cpu_features);
unsigned long int dl_hwcap __attribute__ ((unused)) = features->hwcap;
- const unsigned long long * __attribute__((unused)) stfle_bits
- = features->stfle_bits;
+ const unsigned long long __attribute__((unused)) stfle_bits
+ = features->stfle_filtered;
#if HAVE_MEMSET_IFUNC
IFUNC_IMPL (i, name, memset,
diff --git a/sysdeps/s390/multiarch/ifunc-resolve.h b/sysdeps/s390/multiarch/ifunc-resolve.h
index 2a0c4a56a4..d63b624d0f 100644
--- a/sysdeps/s390/multiarch/ifunc-resolve.h
+++ b/sysdeps/s390/multiarch/ifunc-resolve.h
@@ -22,7 +22,7 @@
#include <cpu-features.h>
#define s390_libc_ifunc_expr_stfle_init() \
- const unsigned long long *stfle_bits = features->stfle_bits;
+ const unsigned long long stfle_bits = features->stfle_filtered;
#define s390_libc_ifunc_expr_init() \
const struct cpu_features *features = &GLRO(dl_s390_cpu_features); \
diff --git a/sysdeps/s390/s390-64/Makefile b/sysdeps/s390/s390-64/Makefile
index 66ed844e68..991025cd2a 100644
--- a/sysdeps/s390/s390-64/Makefile
+++ b/sysdeps/s390/s390-64/Makefile
@@ -11,7 +11,8 @@ $(objpfx)tst-glibc-hwcaps: \
$(objpfx)libmarkermod2-1.so \
$(objpfx)libmarkermod3-1.so \
$(objpfx)libmarkermod4-1.so \
- $(objpfx)libmarkermod5-1.so
+ $(objpfx)libmarkermod5-1.so \
+ $(objpfx)libmarkermod6-1.so
$(objpfx)tst-glibc-hwcaps.out: \
$(objpfx)libmarkermod2.so \
$(objpfx)glibc-hwcaps/z13/libmarkermod2.so \
@@ -26,7 +27,14 @@ $(objpfx)tst-glibc-hwcaps.out: \
$(objpfx)glibc-hwcaps/z13/libmarkermod5.so \
$(objpfx)glibc-hwcaps/z14/libmarkermod5.so \
$(objpfx)glibc-hwcaps/z15/libmarkermod5.so \
- $(objpfx)glibc-hwcaps/z16/libmarkermod5.so
+ $(objpfx)glibc-hwcaps/z16/libmarkermod5.so \
+ $(objpfx)libmarkermod6.so \
+ $(objpfx)glibc-hwcaps/z13/libmarkermod6.so \
+ $(objpfx)glibc-hwcaps/z14/libmarkermod6.so \
+ $(objpfx)glibc-hwcaps/z15/libmarkermod6.so \
+ $(objpfx)glibc-hwcaps/z16/libmarkermod6.so \
+ $(objpfx)glibc-hwcaps/z17/libmarkermod6.so
+
$(objpfx)glibc-hwcaps/z13/libmarkermod2.so: $(objpfx)libmarkermod2-2.so
$(make-target-directory)
@@ -58,6 +66,21 @@ $(objpfx)glibc-hwcaps/z15/libmarkermod5.so: $(objpfx)libmarkermod5-4.so
$(objpfx)glibc-hwcaps/z16/libmarkermod5.so: $(objpfx)libmarkermod5-5.so
$(make-target-directory)
cp $< $@
+$(objpfx)glibc-hwcaps/z13/libmarkermod6.so: $(objpfx)libmarkermod6-2.so
+ $(make-target-directory)
+ cp $< $@
+$(objpfx)glibc-hwcaps/z14/libmarkermod6.so: $(objpfx)libmarkermod6-3.so
+ $(make-target-directory)
+ cp $< $@
+$(objpfx)glibc-hwcaps/z15/libmarkermod6.so: $(objpfx)libmarkermod6-4.so
+ $(make-target-directory)
+ cp $< $@
+$(objpfx)glibc-hwcaps/z16/libmarkermod6.so: $(objpfx)libmarkermod6-5.so
+ $(make-target-directory)
+ cp $< $@
+$(objpfx)glibc-hwcaps/z17/libmarkermod6.so: $(objpfx)libmarkermod6-6.so
+ $(make-target-directory)
+ cp $< $@
ifeq (no,$(build-hardcoded-path-in-tests))
diff --git a/sysdeps/s390/s390-64/dl-hwcap-check.h b/sysdeps/s390/s390-64/dl-hwcap-check.h
index 6ad3242cc9..433a1ebbe8 100644
--- a/sysdeps/s390/s390-64/dl-hwcap-check.h
+++ b/sysdeps/s390/s390-64/dl-hwcap-check.h
@@ -25,8 +25,23 @@
static inline void
dl_hwcap_check (void)
{
-#if defined __ARCH__
-# if GCCMACRO__ARCH__ >= 14
+ /* Note: The s390x kernel won't introduce new HWCAP-Bits if there is
+ no special handling needed in kernel itself. Thus we have have
+ to check the facility-list retrieved with the stfle instruction.
+ We already have a common storage of this list in cpu-features.c.
+ This dl-hwcap-check.h file is included in
+ sysdeps/unix/sysv/linux/dl-sysdep.c, where also dl-machine.h and
+ cpu-features.c is included. Therefore we don't have a special
+ include here. */
+
+#if defined GCCMACRO__ARCH__
+# if GCCMACRO__ARCH__ >= 15
+ init_cpu_features_no_tunables (&GLRO(dl_s390_cpu_features));
+ if (!(S390_IS_ARCH15 (GLRO(dl_s390_cpu_features).stfle_orig)))
+ _dl_fatal_printf ("\
+Fatal glibc error: CPU lacks VXRS_EXT3/VXRS_PDE3/MIE4/Concurrent-functions \
+support (z17 or later required)\n");
+# elif GCCMACRO__ARCH__ >= 14
if (!(GLRO(dl_hwcap) & HWCAP_S390_VXRS_PDE2))
_dl_fatal_printf ("\
Fatal glibc error: CPU lacks VXRS_PDE2 support (z16 or later required)\n");
@@ -39,7 +54,7 @@ Fatal glibc error: CPU lacks VXRS_EXT2 support (z15 or later required)\n");
_dl_fatal_printf ("\
Fatal glibc error: CPU lacks VXE support (z14 or later required)\n");
# endif
-#endif /* __ARCH__ */
+#endif /* GCCMACRO__ARCH__ */
}
#endif /* _DL_HWCAP_CHECK_H */
diff --git a/sysdeps/s390/s390-64/dl-hwcaps-subdirs.c b/sysdeps/s390/s390-64/dl-hwcaps-subdirs.c
index 0a8cce1d3c..11c4bbe4f2 100644
--- a/sysdeps/s390/s390-64/dl-hwcaps-subdirs.c
+++ b/sysdeps/s390/s390-64/dl-hwcaps-subdirs.c
@@ -18,9 +18,10 @@
#include <dl-hwcaps.h>
#include <ldsodefs.h>
+#include <cpu-features.h>
-const char _dl_hwcaps_subdirs[] = "z16:z15:z14:z13";
-enum { subdirs_count = 4 }; /* Number of components in _dl_hwcaps_subdirs. */
+const char _dl_hwcaps_subdirs[] = "z17:z16:z15:z14:z13";
+enum { subdirs_count = 5 }; /* Number of components in _dl_hwcaps_subdirs. */
uint32_t
_dl_hwcaps_subdirs_active (void)
@@ -57,5 +58,12 @@ _dl_hwcaps_subdirs_active (void)
return _dl_hwcaps_subdirs_build_bitmask (subdirs_count, active);
++active;
+ /* z17.
+ Note: The kernel has not introduced new HWCAP bits as the new facilities do
+ not require kernel interaction. Thus we check the features via stfle. */
+ if (!(S390_IS_ARCH15 (GLRO(dl_s390_cpu_features).stfle_orig)))
+ return _dl_hwcaps_subdirs_build_bitmask (subdirs_count, active);
+ ++active;
+
return _dl_hwcaps_subdirs_build_bitmask (subdirs_count, active);
}
diff --git a/sysdeps/s390/s390-64/tst-glibc-hwcaps.c b/sysdeps/s390/s390-64/tst-glibc-hwcaps.c
index a7dec68d32..391816dfde 100644
--- a/sysdeps/s390/s390-64/tst-glibc-hwcaps.c
+++ b/sysdeps/s390/s390-64/tst-glibc-hwcaps.c
@@ -26,35 +26,53 @@ extern int marker2 (void);
extern int marker3 (void);
extern int marker4 (void);
extern int marker5 (void);
+extern int marker6 (void);
/* Return the arch level, 10 for the baseline libmarkermod*.so's. */
static int
compute_level (void)
{
const char *platform = (const char *) getauxval (AT_PLATFORM);
+ const unsigned long int hwcap = getauxval (AT_HWCAP);
+ const int latest_level = 15;
/* The arch* versions refer to the edition of the Principles of
Operation, and they are off by two when compared with the recent
product names. (The code below should not be considered an
accurate mapping to Principles of Operation editions for earlier
AT_PLATFORM strings). */
- if (strcmp (platform, "z900") == 0)
- return 10;
- if (strcmp (platform, "z990") == 0)
- return 10;
- if (strcmp (platform, "z9-109") == 0)
- return 10;
- if (strcmp (platform, "z10") == 0)
- return 10;
- if (strcmp (platform, "z196") == 0)
- return 10;
- if (strcmp (platform, "zEC12") == 0)
- return 10;
+ if ((strcmp (platform, "z900") == 0)
+ || (strcmp (platform, "z990") == 0)
+ || (strcmp (platform, "z9-109") == 0)
+ || (strcmp (platform, "z10") == 0)
+ || (strcmp (platform, "z196") == 0)
+ || (strcmp (platform, "zEC12") == 0))
+ {
+ if ((hwcap & HWCAP_S390_VX) == 0)
+ {
+ /* As vector-support was introduced with the newer z13
+ architecture, we are really on one of the tested older
+ architectures. */
+ return 10;
+ }
+ else
+ {
+ /* According to AT_PLATFORM we are on an older architecture
+ without vector-support, but according to HWCAPs vector
+ registers are supported. This means we are running on a
+ new architecture which is not yet known by the kernel.
+ Thus the default AT_PLATFORM string is used, which is the
+ oldest supported one. For this test, assume we are on
+ the latest known architecture. See
+ <kernel>/arch/s390/kernel/processor.c:setup_elf_platform().
+ */
+ return latest_level;
+ }
+ }
/* If we are running on z13 or newer and the kernel was booted with novx,
then AT_PLATFORM is z13 or newer, but _dl_hwcaps_subdirs_active will
return zero and the _dl_hwcaps_subdirs are not searched. */
- const unsigned long int hwcap = getauxval (AT_HWCAP);
if ((hwcap & HWCAP_S390_VX) == 0)
return 10;
@@ -66,9 +84,12 @@ compute_level (void)
return 13;
if (strcmp (platform, "z16") == 0)
return 14;
+ if (strcmp (platform, "z17") == 0)
+ return latest_level;
+
printf ("warning: unrecognized AT_PLATFORM value: %s\n", platform);
- /* Assume that the new platform supports z16. */
- return 14;
+ /* Assume that the new platform supports the latest known architecture. */
+ return latest_level;
}
static int
@@ -80,6 +101,7 @@ do_test (void)
TEST_COMPARE (marker3 (), MIN (level - 9, 3));
TEST_COMPARE (marker4 (), MIN (level - 9, 4));
TEST_COMPARE (marker5 (), MIN (level - 9, 5));
+ TEST_COMPARE (marker6 (), MIN (level - 9, 6));
return 0;
}
diff --git a/sysdeps/unix/sysv/linux/s390/sysconf.c b/sysdeps/unix/sysv/linux/s390/sysconf.c
index ca25822811..8b50a7f860 100644
--- a/sysdeps/unix/sysv/linux/s390/sysconf.c
+++ b/sysdeps/unix/sysv/linux/s390/sysconf.c
@@ -65,7 +65,7 @@ get_cache_info (int level, int attr, int type)
return 0L;
}
- if (!S390_IS_Z10 (features->stfle_bits))
+ if (!S390_IS_Z10 (features->stfle_orig))
{
/* We are at least on a z9 machine.
Return 256byte for LINESIZE for L1 d/i-cache,
--
2.52.0

176
wordexp-wrde-reuse.patch Normal file
View File

@@ -0,0 +1,176 @@
From 9fe8576664d43b87ca19401fb6a975e217e47623 Mon Sep 17 00:00:00 2001
From: Adhemerval Zanella <adhemerval.zanella@linaro.org>
Date: Thu, 15 Jan 2026 10:32:19 -0300
Subject: [PATCH] posix: Reset wordexp_t fields with WRDE_REUSE (CVE-2025-15281
/ BZ 33814)
The wordexp fails to properly initialize the input wordexp_t when
WRDE_REUSE is used. The wordexp_t struct is properly freed, but
reuses the old wc_wordc value and updates the we_wordv in the
wrong position. A later wordfree will then call free with an
invalid pointer.
Checked on x86_64-linux-gnu and i686-linux-gnu.
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
(cherry picked from commit 80cc58ea2de214f85b0a1d902a3b668ad2ecb302)
---
NEWS | 2 +
posix/Makefile | 11 +++++
posix/tst-wordexp-reuse.c | 89 +++++++++++++++++++++++++++++++++++++++
posix/wordexp.c | 2 +
4 files changed, 104 insertions(+)
create mode 100644 posix/tst-wordexp-reuse.c
diff --git a/posix/Makefile b/posix/Makefile
index 830278a423..0cd5572297 100644
--- a/posix/Makefile
+++ b/posix/Makefile
@@ -326,6 +326,7 @@ tests := \
tst-wait4 \
tst-waitid \
tst-wordexp-nocmd \
+ tst-wordexp-reuse \
tstgetopt \
# tests
@@ -454,6 +455,8 @@ generated += \
tst-rxspencer-no-utf8.mtrace \
tst-vfork3-mem.out \
tst-vfork3.mtrace \
+ tst-wordexp-reuse-mem.out \
+ tst-wordexp-reuse.mtrace \
# generated
endif
endif
@@ -489,6 +492,7 @@ tests-special += \
$(objpfx)tst-pcre-mem.out \
$(objpfx)tst-rxspencer-no-utf8-mem.out \
$(objpfx)tst-vfork3-mem.out \
+ $(objpfx)tst-wordexp-reuse.out \
# tests-special
endif
endif
@@ -772,3 +776,10 @@ $(objpfx)posix-conf-vars-def.h: $(..)scripts/gen-posix-conf-vars.awk \
$(make-target-directory)
$(AWK) -f $(filter-out Makefile, $^) > $@.tmp
mv -f $@.tmp $@
+
+tst-wordexp-reuse-ENV += MALLOC_TRACE=$(objpfx)tst-wordexp-reuse.mtrace \
+ LD_PRELOAD=$(common-objpfx)/malloc/libc_malloc_debug.so
+
+$(objpfx)tst-wordexp-reuse-mem.out: $(objpfx)tst-wordexp-reuse.out
+ $(common-objpfx)malloc/mtrace $(objpfx)tst-wordexp-reuse.mtrace > $@; \
+ $(evaluate-test)
diff --git a/posix/tst-wordexp-reuse.c b/posix/tst-wordexp-reuse.c
new file mode 100644
index 0000000000..3926b9f557
--- /dev/null
+++ b/posix/tst-wordexp-reuse.c
@@ -0,0 +1,89 @@
+/* Test for wordexp with WRDE_REUSE flag.
+ Copyright (C) 2026 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 <wordexp.h>
+#include <mcheck.h>
+
+#include <support/check.h>
+
+static int
+do_test (void)
+{
+ mtrace ();
+
+ {
+ wordexp_t p = { 0 };
+ TEST_COMPARE (wordexp ("one", &p, 0), 0);
+ TEST_COMPARE (p.we_wordc, 1);
+ TEST_COMPARE_STRING (p.we_wordv[0], "one");
+ TEST_COMPARE (wordexp ("two", &p, WRDE_REUSE), 0);
+ TEST_COMPARE (p.we_wordc, 1);
+ TEST_COMPARE_STRING (p.we_wordv[0], "two");
+ wordfree (&p);
+ }
+
+ {
+ wordexp_t p = { .we_offs = 2 };
+ TEST_COMPARE (wordexp ("one", &p, 0), 0);
+ TEST_COMPARE (p.we_wordc, 1);
+ TEST_COMPARE_STRING (p.we_wordv[0], "one");
+ TEST_COMPARE (wordexp ("two", &p, WRDE_REUSE | WRDE_DOOFFS), 0);
+ TEST_COMPARE (p.we_wordc, 1);
+ TEST_COMPARE_STRING (p.we_wordv[p.we_offs + 0], "two");
+ wordfree (&p);
+ }
+
+ {
+ wordexp_t p = { 0 };
+ TEST_COMPARE (wordexp ("one", &p, 0), 0);
+ TEST_COMPARE (p.we_wordc, 1);
+ TEST_COMPARE_STRING (p.we_wordv[0], "one");
+ TEST_COMPARE (wordexp ("two", &p, WRDE_REUSE | WRDE_APPEND), 0);
+ TEST_COMPARE (p.we_wordc, 1);
+ TEST_COMPARE_STRING (p.we_wordv[0], "two");
+ wordfree (&p);
+ }
+
+ {
+ wordexp_t p = { .we_offs = 2 };
+ TEST_COMPARE (wordexp ("one", &p, WRDE_DOOFFS), 0);
+ TEST_COMPARE (p.we_wordc, 1);
+ TEST_COMPARE_STRING (p.we_wordv[p.we_offs + 0], "one");
+ TEST_COMPARE (wordexp ("two", &p, WRDE_REUSE
+ | WRDE_DOOFFS), 0);
+ TEST_COMPARE (p.we_wordc, 1);
+ TEST_COMPARE_STRING (p.we_wordv[p.we_offs + 0], "two");
+ wordfree (&p);
+ }
+
+ {
+ wordexp_t p = { .we_offs = 2 };
+ TEST_COMPARE (wordexp ("one", &p, WRDE_DOOFFS), 0);
+ TEST_COMPARE (p.we_wordc, 1);
+ TEST_COMPARE_STRING (p.we_wordv[p.we_offs + 0], "one");
+ TEST_COMPARE (wordexp ("two", &p, WRDE_REUSE
+ | WRDE_DOOFFS | WRDE_APPEND), 0);
+ TEST_COMPARE (p.we_wordc, 1);
+ TEST_COMPARE_STRING (p.we_wordv[p.we_offs + 0], "two");
+ wordfree (&p);
+ }
+
+ return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/posix/wordexp.c b/posix/wordexp.c
index a7362ef31b..4cd2364519 100644
--- a/posix/wordexp.c
+++ b/posix/wordexp.c
@@ -2216,7 +2216,9 @@ wordexp (const char *words, wordexp_t *pwordexp, int flags)
{
/* Minimal implementation of WRDE_REUSE for now */
wordfree (pwordexp);
+ old_word.we_wordc = 0;
old_word.we_wordv = NULL;
+ pwordexp->we_wordc = 0;
}
if ((flags & WRDE_APPEND) == 0)
--
2.52.0