mirror of
https://github.com/NixOS/nixpkgs.git
synced 2026-07-06 17:13:24 -05:00
7915 lines
275 KiB
Diff
7915 lines
275 KiB
Diff
commit bdea6c37197a3c9bd976911cce5f580dea1c28dd
|
||
Author: Andreas K. Hüttel <dilfridge@gentoo.org>
|
||
Date: Mon Jul 28 20:35:38 2025 +0200
|
||
|
||
Replace advisories directory with pointer file
|
||
|
||
Signed-off-by: Andreas K. Hüttel <dilfridge@gentoo.org>
|
||
|
||
diff --git a/advisories/GLIBC-SA-2023-0001 b/advisories/GLIBC-SA-2023-0001
|
||
deleted file mode 100644
|
||
index 3d19c91b6a..0000000000
|
||
--- a/advisories/GLIBC-SA-2023-0001
|
||
+++ /dev/null
|
||
@@ -1,14 +0,0 @@
|
||
-printf: incorrect output for integers with thousands separator and width field
|
||
-
|
||
-When the printf family of functions is called with a format specifier
|
||
-that uses an <apostrophe> (enable grouping) and a minimum width
|
||
-specifier, the resulting output could be larger than reasonably expected
|
||
-by a caller that computed a tight bound on the buffer size. The
|
||
-resulting larger than expected output could result in a buffer overflow
|
||
-in the printf family of functions.
|
||
-
|
||
-CVE-Id: CVE-2023-25139
|
||
-Public-Date: 2023-02-02
|
||
-Vulnerable-Commit: e88b9f0e5cc50cab57a299dc7efe1a4eb385161d (2.37)
|
||
-Fix-Commit: c980549cc6a1c03c23cc2fe3e7b0fe626a0364b0 (2.38)
|
||
-Fix-Commit: 07b9521fc6369d000216b96562ff7c0ed32a16c4 (2.37-4)
|
||
diff --git a/advisories/GLIBC-SA-2023-0002 b/advisories/GLIBC-SA-2023-0002
|
||
deleted file mode 100644
|
||
index 5122669a64..0000000000
|
||
--- a/advisories/GLIBC-SA-2023-0002
|
||
+++ /dev/null
|
||
@@ -1,15 +0,0 @@
|
||
-getaddrinfo: Stack read overflow in no-aaaa mode
|
||
-
|
||
-If the system is configured in no-aaaa mode via /etc/resolv.conf,
|
||
-getaddrinfo is called for the AF_UNSPEC address family, and a DNS
|
||
-response is received over TCP that is larger than 2048 bytes,
|
||
-getaddrinfo may potentially disclose stack contents via the returned
|
||
-address data, or crash.
|
||
-
|
||
-CVE-Id: CVE-2023-4527
|
||
-Public-Date: 2023-09-12
|
||
-Vulnerable-Commit: f282cdbe7f436c75864e5640a409a10485e9abb2 (2.36)
|
||
-Fix-Commit: bd77dd7e73e3530203be1c52c8a29d08270cb25d (2.39)
|
||
-Fix-Commit: 4ea972b7edd7e36610e8cde18bf7a8149d7bac4f (2.36-113)
|
||
-Fix-Commit: b7529346025a130fee483d42178b5c118da971bb (2.37-38)
|
||
-Fix-Commit: b25508dd774b617f99419bdc3cf2ace4560cd2d6 (2.38-19)
|
||
diff --git a/advisories/GLIBC-SA-2023-0003 b/advisories/GLIBC-SA-2023-0003
|
||
deleted file mode 100644
|
||
index d3aef80348..0000000000
|
||
--- a/advisories/GLIBC-SA-2023-0003
|
||
+++ /dev/null
|
||
@@ -1,15 +0,0 @@
|
||
-getaddrinfo: Potential use-after-free
|
||
-
|
||
-When an NSS plugin only implements the _gethostbyname2_r and
|
||
-_getcanonname_r callbacks, getaddrinfo could use memory that was freed
|
||
-during buffer resizing, potentially causing a crash or read or write to
|
||
-arbitrary memory.
|
||
-
|
||
-CVE-Id: CVE-2023-4806
|
||
-Public-Date: 2023-09-12
|
||
-Fix-Commit: 973fe93a5675c42798b2161c6f29c01b0e243994 (2.39)
|
||
-Fix-Commit: e09ee267c03e3150c2c9ba28625ab130705a485e (2.34-420)
|
||
-Fix-Commit: e3ccb230a961b4797510e6a1f5f21fd9021853e7 (2.35-270)
|
||
-Fix-Commit: a9728f798ec7f05454c95637ee6581afaa9b487d (2.36-115)
|
||
-Fix-Commit: 6529a7466c935f36e9006b854d6f4e1d4876f942 (2.37-39)
|
||
-Fix-Commit: 00ae4f10b504bc4564e9f22f00907093f1ab9338 (2.38-20)
|
||
diff --git a/advisories/GLIBC-SA-2023-0004 b/advisories/GLIBC-SA-2023-0004
|
||
deleted file mode 100644
|
||
index 5286a7aa54..0000000000
|
||
--- a/advisories/GLIBC-SA-2023-0004
|
||
+++ /dev/null
|
||
@@ -1,16 +0,0 @@
|
||
-tunables: local privilege escalation through buffer overflow
|
||
-
|
||
-If a tunable of the form NAME=NAME=VAL is passed in the environment of a
|
||
-setuid program and NAME is valid, it may result in a buffer overflow,
|
||
-which could be exploited to achieve escalated privileges. This flaw was
|
||
-introduced in glibc 2.34.
|
||
-
|
||
-CVE-Id: CVE-2023-4911
|
||
-Public-Date: 2023-10-03
|
||
-Vulnerable-Commit: 2ed18c5b534d9e92fc006202a5af0df6b72e7aca (2.34)
|
||
-Fix-Commit: 1056e5b4c3f2d90ed2b4a55f96add28da2f4c8fa (2.39)
|
||
-Fix-Commit: dcc367f148bc92e7f3778a125f7a416b093964d9 (2.34-423)
|
||
-Fix-Commit: c84018a05aec80f5ee6f682db0da1130b0196aef (2.35-274)
|
||
-Fix-Commit: 22955ad85186ee05834e47e665056148ca07699c (2.36-118)
|
||
-Fix-Commit: b4e23c75aea756b4bddc4abcf27a1c6dca8b6bd3 (2.37-45)
|
||
-Fix-Commit: 750a45a783906a19591fb8ff6b7841470f1f5701 (2.38-27)
|
||
diff --git a/advisories/GLIBC-SA-2023-0005 b/advisories/GLIBC-SA-2023-0005
|
||
deleted file mode 100644
|
||
index cc4eb90b82..0000000000
|
||
--- a/advisories/GLIBC-SA-2023-0005
|
||
+++ /dev/null
|
||
@@ -1,18 +0,0 @@
|
||
-getaddrinfo: DoS due to memory leak
|
||
-
|
||
-The fix for CVE-2023-4806 introduced a memory leak when an application
|
||
-calls getaddrinfo for AF_INET6 with AI_CANONNAME, AI_ALL and AI_V4MAPPED
|
||
-flags set.
|
||
-
|
||
-CVE-Id: CVE-2023-5156
|
||
-Public-Date: 2023-09-25
|
||
-Vulnerable-Commit: e09ee267c03e3150c2c9ba28625ab130705a485e (2.34-420)
|
||
-Vulnerable-Commit: e3ccb230a961b4797510e6a1f5f21fd9021853e7 (2.35-270)
|
||
-Vulnerable-Commit: a9728f798ec7f05454c95637ee6581afaa9b487d (2.36-115)
|
||
-Vulnerable-Commit: 6529a7466c935f36e9006b854d6f4e1d4876f942 (2.37-39)
|
||
-Vulnerable-Commit: 00ae4f10b504bc4564e9f22f00907093f1ab9338 (2.38-20)
|
||
-Fix-Commit: 8006457ab7e1cd556b919f477348a96fe88f2e49 (2.34-421)
|
||
-Fix-Commit: 17092c0311f954e6f3c010f73ce3a78c24ac279a (2.35-272)
|
||
-Fix-Commit: 856bac55f98dc840e7c27cfa82262b933385de90 (2.36-116)
|
||
-Fix-Commit: 4473d1b87d04b25cdd0e0354814eeaa421328268 (2.37-42)
|
||
-Fix-Commit: 5ee59ca371b99984232d7584fe2b1a758b4421d3 (2.38-24)
|
||
diff --git a/advisories/GLIBC-SA-2024-0001 b/advisories/GLIBC-SA-2024-0001
|
||
deleted file mode 100644
|
||
index 28931c75ae..0000000000
|
||
--- a/advisories/GLIBC-SA-2024-0001
|
||
+++ /dev/null
|
||
@@ -1,15 +0,0 @@
|
||
-syslog: Heap buffer overflow in __vsyslog_internal
|
||
-
|
||
-__vsyslog_internal did not handle a case where printing a SYSLOG_HEADER
|
||
-containing a long program name failed to update the required buffer
|
||
-size, leading to the allocation and overflow of a too-small buffer on
|
||
-the heap.
|
||
-
|
||
-CVE-Id: CVE-2023-6246
|
||
-Public-Date: 2024-01-30
|
||
-Vulnerable-Commit: 52a5be0df411ef3ff45c10c7c308cb92993d15b1 (2.37)
|
||
-Fix-Commit: 6bd0e4efcc78f3c0115e5ea9739a1642807450da (2.39)
|
||
-Fix-Commit: 23514c72b780f3da097ecf33a793b7ba9c2070d2 (2.38-42)
|
||
-Fix-Commit: 97a4292aa4a2642e251472b878d0ec4c46a0e59a (2.37-57)
|
||
-Vulnerable-Commit: b0e7888d1fa2dbd2d9e1645ec8c796abf78880b9 (2.36-16)
|
||
-Fix-Commit: d1a83b6767f68b3cb5b4b4ea2617254acd040c82 (2.36-126)
|
||
diff --git a/advisories/GLIBC-SA-2024-0002 b/advisories/GLIBC-SA-2024-0002
|
||
deleted file mode 100644
|
||
index 940bfcf2fc..0000000000
|
||
--- a/advisories/GLIBC-SA-2024-0002
|
||
+++ /dev/null
|
||
@@ -1,15 +0,0 @@
|
||
-syslog: Heap buffer overflow in __vsyslog_internal
|
||
-
|
||
-__vsyslog_internal used the return value of snprintf/vsnprintf to
|
||
-calculate buffer sizes for memory allocation. If these functions (for
|
||
-any reason) failed and returned -1, the resulting buffer would be too
|
||
-small to hold output.
|
||
-
|
||
-CVE-Id: CVE-2023-6779
|
||
-Public-Date: 2024-01-30
|
||
-Vulnerable-Commit: 52a5be0df411ef3ff45c10c7c308cb92993d15b1 (2.37)
|
||
-Fix-Commit: 7e5a0c286da33159d47d0122007aac016f3e02cd (2.39)
|
||
-Fix-Commit: d0338312aace5bbfef85e03055e1212dd0e49578 (2.38-43)
|
||
-Fix-Commit: 67062eccd9a65d7fda9976a56aeaaf6c25a80214 (2.37-58)
|
||
-Vulnerable-Commit: b0e7888d1fa2dbd2d9e1645ec8c796abf78880b9 (2.36-16)
|
||
-Fix-Commit: 2bc9d7c002bdac38b5c2a3f11b78e309d7765b83 (2.36-127)
|
||
diff --git a/advisories/GLIBC-SA-2024-0003 b/advisories/GLIBC-SA-2024-0003
|
||
deleted file mode 100644
|
||
index b43a5150ab..0000000000
|
||
--- a/advisories/GLIBC-SA-2024-0003
|
||
+++ /dev/null
|
||
@@ -1,13 +0,0 @@
|
||
-syslog: Integer overflow in __vsyslog_internal
|
||
-
|
||
-__vsyslog_internal calculated a buffer size by adding two integers, but
|
||
-did not first check if the addition would overflow.
|
||
-
|
||
-CVE-Id: CVE-2023-6780
|
||
-Public-Date: 2024-01-30
|
||
-Vulnerable-Commit: 52a5be0df411ef3ff45c10c7c308cb92993d15b1 (2.37)
|
||
-Fix-Commit: ddf542da94caf97ff43cc2875c88749880b7259b (2.39)
|
||
-Fix-Commit: d37c2b20a4787463d192b32041c3406c2bd91de0 (2.38-44)
|
||
-Fix-Commit: 2b58cba076e912961ceaa5fa58588e4b10f791c0 (2.37-59)
|
||
-Vulnerable-Commit: b0e7888d1fa2dbd2d9e1645ec8c796abf78880b9 (2.36-16)
|
||
-Fix-Commit: b9b7d6a27aa0632f334352fa400771115b3c69b7 (2.36-128)
|
||
diff --git a/advisories/GLIBC-SA-2024-0004 b/advisories/GLIBC-SA-2024-0004
|
||
deleted file mode 100644
|
||
index 08df2b3118..0000000000
|
||
--- a/advisories/GLIBC-SA-2024-0004
|
||
+++ /dev/null
|
||
@@ -1,28 +0,0 @@
|
||
-ISO-2022-CN-EXT: fix out-of-bound writes when writing escape sequence
|
||
-
|
||
-The iconv() function in the GNU C Library versions 2.39 and older may
|
||
-overflow the output buffer passed to it by up to 4 bytes when converting
|
||
-strings to the ISO-2022-CN-EXT character set, which may be used to
|
||
-crash an application or overwrite a neighbouring variable.
|
||
-
|
||
-ISO-2022-CN-EXT uses escape sequences to indicate character set changes
|
||
-(as specified by RFC 1922). While the SOdesignation has the expected
|
||
-bounds checks, neither SS2designation nor SS3designation have its;
|
||
-allowing a write overflow of 1, 2, or 3 bytes with fixed values:
|
||
-'$+I', '$+J', '$+K', '$+L', '$+M', or '$*H'.
|
||
-
|
||
-CVE-Id: CVE-2024-2961
|
||
-Public-Date: 2024-04-17
|
||
-Vulnerable-Commit: 755104edc75c53f4a0e7440334e944ad3c6b32fc (2.1.93-169)
|
||
-Fix-Commit: f9dc609e06b1136bb0408be9605ce7973a767ada (2.40)
|
||
-Fix-Commit: 31da30f23cddd36db29d5b6a1c7619361b271fb4 (2.39-31)
|
||
-Fix-Commit: e1135387deded5d73924f6ca20c72a35dc8e1bda (2.38-66)
|
||
-Fix-Commit: 89ce64b269a897a7780e4c73a7412016381c6ecf (2.37-89)
|
||
-Fix-Commit: 4ed98540a7fd19f458287e783ae59c41e64df7b5 (2.36-164)
|
||
-Fix-Commit: 36280d1ce5e245aabefb877fe4d3c6cff95dabfa (2.35-315)
|
||
-Fix-Commit: a8b0561db4b9847ebfbfec20075697d5492a363c (2.34-459)
|
||
-Fix-Commit: ed4f16ff6bed3037266f1fa682ebd32a18fce29c (2.33-263)
|
||
-Fix-Commit: 682ad4c8623e611a971839990ceef00346289cc9 (2.32-140)
|
||
-Fix-Commit: 3703c32a8d304c1ee12126134ce69be965f38000 (2.31-154)
|
||
-
|
||
-Reported-By: Charles Fol
|
||
diff --git a/advisories/GLIBC-SA-2024-0005 b/advisories/GLIBC-SA-2024-0005
|
||
deleted file mode 100644
|
||
index a59596610a..0000000000
|
||
--- a/advisories/GLIBC-SA-2024-0005
|
||
+++ /dev/null
|
||
@@ -1,22 +0,0 @@
|
||
-nscd: Stack-based buffer overflow in netgroup cache
|
||
-
|
||
-If the Name Service Cache Daemon's (nscd) fixed size cache is exhausted
|
||
-by client requests then a subsequent client request for netgroup data
|
||
-may result in a stack-based buffer overflow. This flaw was introduced
|
||
-in glibc 2.15 when the cache was added to nscd.
|
||
-
|
||
-This vulnerability is only present in the nscd binary.
|
||
-
|
||
-CVE-Id: CVE-2024-33599
|
||
-Public-Date: 2024-04-23
|
||
-Vulnerable-Commit: 684ae515993269277448150a1ca70db3b94aa5bd (2.15)
|
||
-Fix-Commit: 69c58d5ef9f584ea198bd00f7964d364d0e6b921 (2.31-155)
|
||
-Fix-Commit: a77064893bfe8a701770e2f53a4d33805bc47a5a (2.32-141)
|
||
-Fix-Commit: 5c75001a96abcd50cbdb74df24c3f013188d076e (2.33-264)
|
||
-Fix-Commit: 52f73e5c4e29b14e79167272297977f360ae1e97 (2.34-460)
|
||
-Fix-Commit: 7a95873543ce225376faf13bb71c43dea6d24f86 (2.35-316)
|
||
-Fix-Commit: caa3151ca460bdd9330adeedd68c3112d97bffe4 (2.36-165)
|
||
-Fix-Commit: f75c298e747b2b8b41b1c2f551c011a52c41bfd1 (2.37-91)
|
||
-Fix-Commit: 5968aebb86164034b8f8421b4abab2f837a5bdaf (2.38-72)
|
||
-Fix-Commit: 1263d583d2e28afb8be53f8d6922f0842036f35d (2.39-35)
|
||
-Fix-Commit: 87801a8fd06db1d654eea3e4f7626ff476a9bdaa (2.40)
|
||
diff --git a/advisories/GLIBC-SA-2024-0006 b/advisories/GLIBC-SA-2024-0006
|
||
deleted file mode 100644
|
||
index d44148d3d9..0000000000
|
||
--- a/advisories/GLIBC-SA-2024-0006
|
||
+++ /dev/null
|
||
@@ -1,32 +0,0 @@
|
||
-nscd: Null pointer crash after notfound response
|
||
-
|
||
-If the Name Service Cache Daemon's (nscd) cache fails to add a not-found
|
||
-netgroup response to the cache, the client request can result in a null
|
||
-pointer dereference. This flaw was introduced in glibc 2.15 when the
|
||
-cache was added to nscd.
|
||
-
|
||
-This vulnerability is only present in the nscd binary.
|
||
-
|
||
-CVE-Id: CVE-2024-33600
|
||
-Public-Date: 2024-04-24
|
||
-Vulnerable-Commit: 684ae515993269277448150a1ca70db3b94aa5bd (2.15)
|
||
-Fix-Commit: b048a482f088e53144d26a61c390bed0210f49f2 (2.40)
|
||
-Fix-Commit: 7835b00dbce53c3c87bbbb1754a95fb5e58187aa (2.40)
|
||
-Fix-Commit: c99f886de54446cd4447db6b44be93dabbdc2f8b (2.39-37)
|
||
-Fix-Commit: 5a508e0b508c8ad53bd0d2fb48fd71b242626341 (2.39-36)
|
||
-Fix-Commit: 2ae9446c1b7a3064743b4a51c0bbae668ee43e4c (2.38-74)
|
||
-Fix-Commit: 541ea5172aa658c4bd5c6c6d6fd13903c3d5bb0a (2.38-73)
|
||
-Fix-Commit: a8070b31043c7585c36ba68a74298c4f7af075c3 (2.37-93)
|
||
-Fix-Commit: 5eea50c4402e39588de98aa1d4469a79774703d4 (2.37-92)
|
||
-Fix-Commit: f205b3af56740e3b014915b1bd3b162afe3407ef (2.36-167)
|
||
-Fix-Commit: c34f470a615b136170abd16142da5dd0c024f7d1 (2.36-166)
|
||
-Fix-Commit: bafadc589fbe21ae330e8c2af74db9da44a17660 (2.35-318)
|
||
-Fix-Commit: 4370bef52b0f3f3652c6aa13d7a9bb3ac079746d (2.35-317)
|
||
-Fix-Commit: 1f94122289a9bf7dba573f5d60327aaa2b85cf2e (2.34-462)
|
||
-Fix-Commit: 966d6ac9e40222b84bb21674cc4f83c8d72a5a26 (2.34-461)
|
||
-Fix-Commit: e3eef1b8fbdd3a7917af466ca9c4b7477251ca79 (2.33-266)
|
||
-Fix-Commit: f20a8d696b13c6261b52a6434899121f8b19d5a7 (2.33-265)
|
||
-Fix-Commit: be602180146de37582a3da3a0caa4b719645de9c (2.32-143)
|
||
-Fix-Commit: 394eae338199078b7961b051c191539870742d7b (2.32-142)
|
||
-Fix-Commit: 8d7949183760170c61e55def723c1d8050187874 (2.31-157)
|
||
-Fix-Commit: 304ce5fe466c4762b21b36c26926a4657b59b53e (2.31-156)
|
||
diff --git a/advisories/GLIBC-SA-2024-0007 b/advisories/GLIBC-SA-2024-0007
|
||
deleted file mode 100644
|
||
index b6928fa27a..0000000000
|
||
--- a/advisories/GLIBC-SA-2024-0007
|
||
+++ /dev/null
|
||
@@ -1,28 +0,0 @@
|
||
-nscd: netgroup cache may terminate daemon on memory allocation failure
|
||
-
|
||
-The Name Service Cache Daemon's (nscd) netgroup cache uses xmalloc or
|
||
-xrealloc and these functions may terminate the process due to a memory
|
||
-allocation failure resulting in a denial of service to the clients. The
|
||
-flaw was introduced in glibc 2.15 when the cache was added to nscd.
|
||
-
|
||
-This vulnerability is only present in the nscd binary.
|
||
-
|
||
-Subsequent refactoring of the netgroup cache only added more uses of
|
||
-xmalloc and xrealloc. Uses of xmalloc and xrealloc in other parts of
|
||
-nscd only occur during startup of the daemon and so are not affected by
|
||
-client requests that could trigger an out of memory followed by
|
||
-termination.
|
||
-
|
||
-CVE-Id: CVE-2024-33601
|
||
-Public-Date: 2024-04-24
|
||
-Vulnerable-Commit: 684ae515993269277448150a1ca70db3b94aa5bd (2.15)
|
||
-Fix-Commit: c04a21e050d64a1193a6daab872bca2528bda44b (2.40)
|
||
-Fix-Commit: a9a8d3eebb145779a18d90e3966009a1daa63cd8 (2.39-38)
|
||
-Fix-Commit: 71af8ca864345d39b746d5cee84b94b430fad5db (2.38-75)
|
||
-Fix-Commit: 6e106dc214d6a033a4e945d1c6cf58061f1c5f1f (2.37-94)
|
||
-Fix-Commit: b6742463694b1dfdd5120b91ee21cf05d15ec2e2 (2.36-168)
|
||
-Fix-Commit: 7a5864cac60e06000394128a5a2817b03542f5a3 (2.35-319)
|
||
-Fix-Commit: 86f1d5f4129c373ac6fb6df5bcf38273838843cb (2.34-463)
|
||
-Fix-Commit: 4d27d4b9a188786fc6a56745506cec2acfc51f83 (2.33-267)
|
||
-Fix-Commit: 3ed195a8ec89da281e3c4bf887a13d281b72d8f4 (2.32-144)
|
||
-Fix-Commit: bbf5a58ccb55679217f94de706164d15372fbbc0 (2.31-158)
|
||
diff --git a/advisories/GLIBC-SA-2024-0008 b/advisories/GLIBC-SA-2024-0008
|
||
deleted file mode 100644
|
||
index d93e2a6f0b..0000000000
|
||
--- a/advisories/GLIBC-SA-2024-0008
|
||
+++ /dev/null
|
||
@@ -1,26 +0,0 @@
|
||
-nscd: netgroup cache assumes NSS callback uses in-buffer strings
|
||
-
|
||
-The Name Service Cache Daemon's (nscd) netgroup cache can corrupt memory
|
||
-when the NSS callback does not store all strings in the provided buffer.
|
||
-The flaw was introduced in glibc 2.15 when the cache was added to nscd.
|
||
-
|
||
-This vulnerability is only present in the nscd binary.
|
||
-
|
||
-There is no guarantee from the NSS callback API that the returned
|
||
-strings are all within the buffer. However, the netgroup cache code
|
||
-assumes that the NSS callback uses in-buffer strings and if it doesn't
|
||
-the buffer resizing logic could lead to potential memory corruption.
|
||
-
|
||
-CVE-Id: CVE-2024-33602
|
||
-Public-Date: 2024-04-24
|
||
-Vulnerable-Commit: 684ae515993269277448150a1ca70db3b94aa5bd (2.15)
|
||
-Fix-Commit: c04a21e050d64a1193a6daab872bca2528bda44b (2.40)
|
||
-Fix-Commit: a9a8d3eebb145779a18d90e3966009a1daa63cd8 (2.39-38)
|
||
-Fix-Commit: 71af8ca864345d39b746d5cee84b94b430fad5db (2.38-75)
|
||
-Fix-Commit: 6e106dc214d6a033a4e945d1c6cf58061f1c5f1f (2.37-94)
|
||
-Fix-Commit: b6742463694b1dfdd5120b91ee21cf05d15ec2e2 (2.36-168)
|
||
-Fix-Commit: 7a5864cac60e06000394128a5a2817b03542f5a3 (2.35-319)
|
||
-Fix-Commit: 86f1d5f4129c373ac6fb6df5bcf38273838843cb (2.34-463)
|
||
-Fix-Commit: 4d27d4b9a188786fc6a56745506cec2acfc51f83 (2.33-267)
|
||
-Fix-Commit: 3ed195a8ec89da281e3c4bf887a13d281b72d8f4 (2.32-144)
|
||
-Fix-Commit: bbf5a58ccb55679217f94de706164d15372fbbc0 (2.31-158)
|
||
diff --git a/advisories/GLIBC-SA-2025-0001 b/advisories/GLIBC-SA-2025-0001
|
||
deleted file mode 100644
|
||
index b053d32e91..0000000000
|
||
--- a/advisories/GLIBC-SA-2025-0001
|
||
+++ /dev/null
|
||
@@ -1,40 +0,0 @@
|
||
-assert: Buffer overflow when printing assertion failure message
|
||
-
|
||
-When the assert() function fails, it does not allocate enough space for the
|
||
-assertion failure message string and size information, which may lead to a
|
||
-buffer overflow if the message string size aligns to page size.
|
||
-
|
||
-This bug can be triggered when an assertion in a program fails. The assertion
|
||
-failure message is allocated to allow developers to see this failure in core
|
||
-dumps and it typically includes, in addition to the invariant assertion
|
||
-string and function name, the name of the program. If the name of the failing
|
||
-program is user controlled, for example on a local system, this could allow an
|
||
-attacker to control the assertion failure to trigger this buffer overflow.
|
||
-
|
||
-The only viable vector for exploitation of this bug is local, if a setuid
|
||
-program exists that has an existing bug that results in an assertion failure.
|
||
-No such program has been discovered at the time of publishing this advisory,
|
||
-but the presence of custom setuid programs, although strongly discouraged as a
|
||
-security practice, cannot be discounted.
|
||
-
|
||
-CVE-Id: CVE-2025-0395
|
||
-Public-Date: 2025-01-22
|
||
-Vulnerable-Commit: f8a3b5bf8fa1d0c43d2458e03cc109a04fdef194 (2.13-175)
|
||
-Fix-Commit: 68ee0f704cb81e9ad0a78c644a83e1e9cd2ee578 (2.41)
|
||
-Fix-Commit: cdb9ba84191ce72e86346fb8b1d906e7cd930ea2 (2.42)
|
||
-Fix-Commit: 69fda28279b497bd405fdd442a6d8e4d3d5f681b (2.41-7)
|
||
-Fix-Commit: 7d4b6bcae91f29d7b4daf15bab06b66cf1d2217c (2.40-66)
|
||
-Fix-Commit: d6c156c326999f144cb5b73d29982108d549ad8a (2.40-71)
|
||
-Fix-Commit: 808a84a8b81468b517a4d721fdc62069cb8c211f (2.39-146)
|
||
-Fix-Commit: f6d48470aef9264d2d56f4c4533eb76db7f9c2e4 (2.39-150)
|
||
-Fix-Commit: c32fd59314c343db88c3ea4a203870481d33c3d2 (2.38-122)
|
||
-Fix-Commit: f984e2d7e8299726891a1a497a3c36cd5542a0bf (2.38-124)
|
||
-Fix-Commit: a3d7865b098a3a67c44f7812208d9ce4718873ba (2.37-143)
|
||
-Fix-Commit: b989519fe1683c204ac24ec92830e3fe3bfaccad (2.37-146)
|
||
-Fix-Commit: 7971add7ee4171fdd8dfd17e7c04c4ed77a18845 (2.36-216)
|
||
-Fix-Commit: 0487893d5c5bc6710d83d7c3152d888a0339559e (2.36-219)
|
||
-Fix-Commit: 8b5d4be762419c4f6176261c6fea40ac559b88dc (2.35-370)
|
||
-Fix-Commit: 8b3d09dc0d350191985f9d291cc30ce96f034b49 (2.35-373)
|
||
-Fix-Commit: df4e1f4a5096b385c9bcc94424cf2eaa227b3761 (2.34-500)
|
||
-Fix-Commit: 31eb872cb21449832ab47ad5db83281d240e1d03 (2.34-503)
|
||
-Reported-By: Qualys Security Advisory
|
||
diff --git a/advisories/GLIBC-SA-2025-0002 b/advisories/GLIBC-SA-2025-0002
|
||
deleted file mode 100644
|
||
index 161da13dd4..0000000000
|
||
--- a/advisories/GLIBC-SA-2025-0002
|
||
+++ /dev/null
|
||
@@ -1,23 +0,0 @@
|
||
-elf: static setuid binary dlopen may incorrectly search LD_LIBRARY_PATH
|
||
-
|
||
-A statically linked setuid binary that calls dlopen (including internal
|
||
-dlopen calls after setlocale or calls to NSS functions such as getaddrinfo)
|
||
-may incorrectly search LD_LIBRARY_PATH to determine which library to load,
|
||
-leading to the execution of library code that is attacker controlled.
|
||
-
|
||
-The only viable vector for exploitation of this bug is local, if a static
|
||
-setuid program exists, and that program calls dlopen, then it may search
|
||
-LD_LIBRARY_PATH to locate the SONAME to load. No such program has been
|
||
-discovered at the time of publishing this advisory, but the presence of
|
||
-custom setuid programs, although strongly discouraged as a security
|
||
-practice, cannot be discounted.
|
||
-
|
||
-CVE-Id: CVE-2025-4802
|
||
-Public-Date: 2025-05-16
|
||
-Vulnerable-Commit: 10e93d968716ab82931d593bada121c17c0a4b93 (2.27)
|
||
-Fix-Commit: 5451fa962cd0a90a0e2ec1d8910a559ace02bba0 (2.39)
|
||
-Fix-Commit: 3be3728df2f1912c80abd3288bc6e3a25ad679e4 (2.38-132)
|
||
-Fix-Commit: 7403ede2d7752e59e0c47d5d33d73c2bf850e7be (2.37-154)
|
||
-Fix-Commit: 2ef7850279b2931caf6d6d6743ebaa91839e1cf7 (2.36-227)
|
||
-Fix-Commit: 621c65ccf12ddd415ceeb2234423bd1acd0fabb3 (2.35-387)
|
||
-Fix-Commit: 35018c0fd20eac9ceaf60060fed2745b3177359d (2.34-517)
|
||
diff --git a/advisories/GLIBC-SA-2025-0003 b/advisories/GLIBC-SA-2025-0003
|
||
deleted file mode 100644
|
||
index 2adeb3ce00..0000000000
|
||
--- a/advisories/GLIBC-SA-2025-0003
|
||
+++ /dev/null
|
||
@@ -1,30 +0,0 @@
|
||
-power10: strcmp fails to save and restore nonvolatile vector registers
|
||
-
|
||
-The Power 10 implementation of strcmp in
|
||
-sysdeps/powerpc/powerpc64/le/power10/strcmp.S failed to save/restore
|
||
-nonvolatile vector registers in the 32-byte aligned loop path. This
|
||
-results in callers reading content from those registers in a different
|
||
-context, potentially altering program logic.
|
||
-
|
||
-There could be a program context where a user controlled string could
|
||
-leak through strcmp into program code, thus altering its logic. There
|
||
-is also a potential for sensitive strings passed into strcmp leaking
|
||
-through the clobbered registers into parts of the calling program that
|
||
-should otherwise not have had access to those strings.
|
||
-
|
||
-The impact of this flaw is limited to applications running on Power 10
|
||
-hardware that use the nonvolatile vector registers, i.e. v20 to v31
|
||
-assuming that they have been treated in accordance with the OpenPower
|
||
-psABI. It is possible to work around the issue for those specific
|
||
-applications by setting the glibc.cpu.hwcaps tunable to "-arch_3_1" like
|
||
-so:
|
||
-
|
||
- export GLIBC_TUNABLES=glibc.cpu.hwcaps=-arch_3_1
|
||
-
|
||
-CVE-Id: CVE-2025-5702
|
||
-Public-Date: 2025-06-04
|
||
-Vulnerable-Commit: 3367d8e180848030d1646f088759f02b8dfe0d6f (2.39)
|
||
-Fix-Commit: 15808c77b35319e67ee0dc8f984a9a1a434701bc (2.42)
|
||
-Fix-Commit: 0c76c951620f9e12df2a89b2c684878b55bb6795 (2.41-60)
|
||
-Fix-Commit: 7e12550b8e3a11764a4a9090ce6bd3fc23fc8a8e (2.40-139)
|
||
-Fix-Commit: 06a70769fd0b2e1f2a3085ad50ab620282bd77b3 (2.39-209)
|
||
diff --git a/advisories/GLIBC-SA-2025-0004 b/advisories/GLIBC-SA-2025-0004
|
||
deleted file mode 100644
|
||
index 9409ca27c4..0000000000
|
||
--- a/advisories/GLIBC-SA-2025-0004
|
||
+++ /dev/null
|
||
@@ -1,29 +0,0 @@
|
||
-power10: strncmp fails to save and restore nonvolatile vector registers
|
||
-
|
||
-The Power 10 implementation of strncmp in
|
||
-sysdeps/powerpc/powerpc64/le/power10/strncmp.S failed to save/restore
|
||
-nonvolatile vector registers in the 32-byte aligned loop path. This
|
||
-results in callers reading content from those registers in a different
|
||
-context, potentially altering program logic.
|
||
-
|
||
-There could be a program context where a user controlled string could
|
||
-leak through strncmp into program code, thus altering its logic. There
|
||
-is also a potential for sensitive strings passed into strncmp leaking
|
||
-through the clobbered registers into parts of the calling program that
|
||
-should otherwise not have had access to those strings.
|
||
-
|
||
-The impact of this flaw is limited to applications running on Power 10
|
||
-hardware that use the nonvolatile vector registers, i.e. v20 to v31
|
||
-assuming that they have been treated in accordance with the OpenPower
|
||
-psABI. It is possible to work around the issue for those specific
|
||
-applications by setting the glibc.cpu.hwcaps tunable to "-arch_3_1" like
|
||
-so:
|
||
-
|
||
- export GLIBC_TUNABLES=glibc.cpu.hwcaps=-arch_3_1
|
||
-
|
||
-CVE-Id: CVE-2025-5745
|
||
-Public-Date: 2025-06-05
|
||
-Vulnerable-Commit: 23f0d81608d0ca6379894ef81670cf30af7fd081 (2.40)
|
||
-Fix-Commit: 63c60101ce7c5eac42be90f698ba02099b41b965 (2.42)
|
||
-Fix-Commit: 84bdbf8a6f2fdafd3661489dbb7f79835a52da82 (2.41-57)
|
||
-Fix-Commit: 42a5a940c974d02540c8da26d6374c744d148cb9 (2.40-136)
|
||
diff --git a/advisories/GLIBC-SA-2025-0005 b/advisories/GLIBC-SA-2025-0005
|
||
deleted file mode 100644
|
||
index 8bcccc59a5..0000000000
|
||
--- a/advisories/GLIBC-SA-2025-0005
|
||
+++ /dev/null
|
||
@@ -1,14 +0,0 @@
|
||
-posix: Fix double-free after allocation failure in regcomp
|
||
-
|
||
-The regcomp function in the GNU C library version from 2.4 to 2.41 is
|
||
-subject to a double free if some previous allocation fails. It can be
|
||
-accomplished either by a malloc failure or by using an interposed
|
||
-malloc that injects random malloc failures. The double free can allow
|
||
-buffer manipulation depending of how the regex is constructed.
|
||
-This issue affects all architectures and ABIs supported by the GNU C
|
||
-library.
|
||
-
|
||
-CVE-Id: CVE-2025-8058
|
||
-Public-Date: 2025-07-22
|
||
-Vulnerable-Commit: 963d8d782fc98fb6dc3a66f0068795f9920c269d (2.3.3-1596)
|
||
-Fix-Commit: 7ea06e994093fa0bcca0d0ee2c1db271d8d7885d (2.42)
|
||
diff --git a/advisories/README b/advisories/README
|
||
deleted file mode 100644
|
||
index b8f8a829ca..0000000000
|
||
--- a/advisories/README
|
||
+++ /dev/null
|
||
@@ -1,77 +0,0 @@
|
||
-GNU C Library Security Advisory Format
|
||
-======================================
|
||
-
|
||
-Security advisories in this directory follow a simple git commit log
|
||
-format, with a heading and free-format description augmented with tags
|
||
-to allow parsing key information. References to code changes are
|
||
-specific to the glibc repository and follow a specific format:
|
||
-
|
||
- Tag-name: <commit-ref> (release-version)
|
||
-
|
||
-The <commit-ref> indicates a specific commit in the repository. The
|
||
-release-version indicates the publicly consumable release in which this
|
||
-commit is known to exist. The release-version is derived from the
|
||
-git-describe format, (i.e. stripped out from glibc-2.34.NNN-gxxxx) and
|
||
-is of the form 2.34-NNN. If the -NNN suffix is absent, it means that
|
||
-the change is in that release tarball, otherwise the change is on the
|
||
-release/2.YY/master branch and not in any released tarball.
|
||
-
|
||
-The following tags are currently being used:
|
||
-
|
||
-CVE-Id:
|
||
-This is the CVE-Id assigned under the CVE Program
|
||
-(https://www.cve.org/).
|
||
-
|
||
-Public-Date:
|
||
-The date this issue became publicly known.
|
||
-
|
||
-Vulnerable-Commit:
|
||
-The commit that introduced this vulnerability. There could be multiple
|
||
-entries, one for each release branch in the glibc repository; the
|
||
-release-version portion of this tag should tell you which branch this is
|
||
-on.
|
||
-
|
||
-Fix-Commit:
|
||
-The commit that fixed this vulnerability. There could be multiple
|
||
-entries for each release branch in the glibc repository, indicating that
|
||
-all of those commits contributed to fixing that issue in each of those
|
||
-branches.
|
||
-
|
||
-Reported-By:
|
||
-The entity that reported this issue. There could be multiple entries, one for
|
||
-each reporter.
|
||
-
|
||
-Adding an Advisory
|
||
-------------------
|
||
-
|
||
-An advisory for a CVE needs to be added on the master branch in two steps:
|
||
-
|
||
-1. Add the text of the advisory without any Fix-Commit tags along with
|
||
- the fix for the CVE. Add the Vulnerable-Commit tag, if applicable.
|
||
- The advisories directory does not exist in release branches, so keep
|
||
- the advisory text commit distinct from the code changes, to ease
|
||
- backports. Ask for the GLIBC-SA advisory number from the security
|
||
- team.
|
||
-
|
||
-2. Finish all backports on release branches and then back on the msater
|
||
- branch, add all commit refs to the advisory using the Fix-Commit
|
||
- tags. Don't bother adding the release-version subscript since the
|
||
- next step will overwrite it.
|
||
-
|
||
-3. Run the process-advisories.sh script in the scripts directory on the
|
||
- advisory:
|
||
-
|
||
- scripts/process-advisories.sh update GLIBC-SA-YYYY-NNNN
|
||
-
|
||
- (replace YYYY-NNNN with the actual advisory number).
|
||
-
|
||
-4. Verify the updated advisory and push the result.
|
||
-
|
||
-Getting a NEWS snippet from advisories
|
||
---------------------------------------
|
||
-
|
||
-Run:
|
||
-
|
||
- scripts/process-advisories.sh news
|
||
-
|
||
-and copy the content into the NEWS file.
|
||
|
||
commit 3ec4dd77f648da031bba4d3fa14825e057b5a40d
|
||
Author: Andreas K. Hüttel <dilfridge@gentoo.org>
|
||
Date: Mon Jul 28 23:39:48 2025 +0200
|
||
|
||
NEWS: add new section
|
||
|
||
Signed-off-by: Andreas K. Hüttel <dilfridge@gentoo.org>
|
||
|
||
diff --git a/NEWS b/NEWS
|
||
index f0b0e924a4..9cb8de11f9 100644
|
||
--- a/NEWS
|
||
+++ b/NEWS
|
||
@@ -5,6 +5,12 @@ See the end for copying conditions.
|
||
Please send GNU C library bug reports via <https://sourceware.org/bugzilla/>
|
||
using `glibc' in the "product" field.
|
||
|
||
+Version 2.42.1
|
||
+
|
||
+The following bugs were resolved with this release:
|
||
+
|
||
+ [insert bugs here]
|
||
+
|
||
Version 2.42
|
||
|
||
Major new features:
|
||
|
||
commit bc13db73937730401d592b33092db6df806d193e
|
||
Author: Sam James <sam@gentoo.org>
|
||
Date: Mon Jul 28 21:55:30 2025 +0100
|
||
|
||
inet-fortified: fix namespace violation (bug 33227)
|
||
|
||
We need to use __sz, not sz, as we do elsewhere.
|
||
|
||
Reviewed-by: Florian Weimer <fweimer@redhat.com>
|
||
(cherry picked from commit 87afbd7a1ad9c1dd116921817fa97198171045db)
|
||
|
||
diff --git a/inet/bits/inet-fortified.h b/inet/bits/inet-fortified.h
|
||
index 6738221a54..cc476ebcfd 100644
|
||
--- a/inet/bits/inet-fortified.h
|
||
+++ b/inet/bits/inet-fortified.h
|
||
@@ -45,15 +45,15 @@ __NTH (inet_pton (int __af,
|
||
__fortify_clang_warning_only_if_bos0_lt
|
||
(4, __dst, "inet_pton called with destination buffer size less than 4")
|
||
{
|
||
- size_t sz = 0;
|
||
+ size_t __sz = 0;
|
||
if (__af == AF_INET)
|
||
- sz = sizeof (struct in_addr);
|
||
+ __sz = sizeof (struct in_addr);
|
||
else if (__af == AF_INET6)
|
||
- sz = sizeof (struct in6_addr);
|
||
+ __sz = sizeof (struct in6_addr);
|
||
else
|
||
return __inet_pton_alias (__af, __src, __dst);
|
||
|
||
- return __glibc_fortify (inet_pton, sz, sizeof (char),
|
||
+ return __glibc_fortify (inet_pton, __sz, sizeof (char),
|
||
__glibc_objsize (__dst),
|
||
__af, __src, __dst);
|
||
};
|
||
|
||
commit fd18059c0fcf5568db3688da47403b663cf91c5e
|
||
Author: Davide Cavalca <davide@cavalca.name>
|
||
Date: Thu Jul 31 17:32:58 2025 +0200
|
||
|
||
stdlib: resolve a double lock init issue after fork [BZ #32994]
|
||
|
||
The __abort_fork_reset_child (introduced in
|
||
d40ac01cbbc66e6d9dbd8e3485605c63b2178251) call resets the lock after the
|
||
fork. This causes a DRD regression in valgrind
|
||
(https://bugs.kde.org/show_bug.cgi?id=503668), as it's effectively a
|
||
double initialization, despite it being actually ok in this case. As
|
||
suggested in https://sourceware.org/bugzilla/show_bug.cgi?id=32994#c2
|
||
we replace it here with a memcpy of another initialized lock instead,
|
||
which makes valgrind happy.
|
||
|
||
Reviewed-by: Florian Weimer <fweimer@redhat.com>
|
||
(cherry picked from commit d9a348d0927c7a1aec5caf3df3fcd36956b3eb23)
|
||
|
||
diff --git a/NEWS b/NEWS
|
||
index 9cb8de11f9..4610b8bbc6 100644
|
||
--- a/NEWS
|
||
+++ b/NEWS
|
||
@@ -9,7 +9,7 @@ Version 2.42.1
|
||
|
||
The following bugs were resolved with this release:
|
||
|
||
- [insert bugs here]
|
||
+ [32994] stdlib: resolve a double lock init issue after fork
|
||
|
||
Version 2.42
|
||
|
||
diff --git a/stdlib/abort.c b/stdlib/abort.c
|
||
index caa9e6dc04..904244a2fb 100644
|
||
--- a/stdlib/abort.c
|
||
+++ b/stdlib/abort.c
|
||
@@ -19,6 +19,7 @@
|
||
#include <internal-signals.h>
|
||
#include <libc-lock.h>
|
||
#include <pthreadP.h>
|
||
+#include <string.h>
|
||
#include <unistd.h>
|
||
|
||
/* Try to get a machine dependent instruction which will make the
|
||
@@ -42,7 +43,10 @@ __libc_rwlock_define_initialized (static, lock);
|
||
void
|
||
__abort_fork_reset_child (void)
|
||
{
|
||
- __libc_rwlock_init (lock);
|
||
+ /* Reinitialize lock without calling pthread_rwlock_init, to
|
||
+ avoid a valgrind DRD false positive. */
|
||
+ __libc_rwlock_define_initialized (, reset_lock);
|
||
+ memcpy (&lock, &reset_lock, sizeof (lock));
|
||
}
|
||
|
||
void
|
||
|
||
commit 2fadee530155bae6682ab2965d6ff3a2fc9eced6
|
||
Author: Florian Weimer <fweimer@redhat.com>
|
||
Date: Fri Aug 1 19:27:04 2025 +0200
|
||
|
||
elf: Extract rtld_setup_phdr function from dl_main
|
||
|
||
Remove historic binutils reference from comment and update
|
||
how this data is used by applications.
|
||
|
||
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
||
(cherry picked from commit 2cac9559e06044ba520e785c151fbbd25011865f)
|
||
|
||
diff --git a/elf/rtld.c b/elf/rtld.c
|
||
index 493f9696ea..6fb900fb31 100644
|
||
--- a/elf/rtld.c
|
||
+++ b/elf/rtld.c
|
||
@@ -1239,6 +1239,37 @@ rtld_setup_main_map (struct link_map *main_map)
|
||
return has_interp;
|
||
}
|
||
|
||
+/* Set up the program header information for the dynamic linker
|
||
+ itself. It can be accessed via _r_debug and dl_iterate_phdr
|
||
+ callbacks. */
|
||
+static void
|
||
+rtld_setup_phdr (void)
|
||
+{
|
||
+ /* Starting from binutils-2.23, the linker will define the magic
|
||
+ symbol __ehdr_start to point to our own ELF header if it is
|
||
+ visible in a segment that also includes the phdrs. */
|
||
+
|
||
+ const ElfW(Ehdr) *rtld_ehdr = &__ehdr_start;
|
||
+ assert (rtld_ehdr->e_ehsize == sizeof *rtld_ehdr);
|
||
+ assert (rtld_ehdr->e_phentsize == sizeof (ElfW(Phdr)));
|
||
+
|
||
+ const ElfW(Phdr) *rtld_phdr = (const void *) rtld_ehdr + rtld_ehdr->e_phoff;
|
||
+
|
||
+ _dl_rtld_map.l_phdr = rtld_phdr;
|
||
+ _dl_rtld_map.l_phnum = rtld_ehdr->e_phnum;
|
||
+
|
||
+
|
||
+ /* PT_GNU_RELRO is usually the last phdr. */
|
||
+ size_t cnt = rtld_ehdr->e_phnum;
|
||
+ while (cnt-- > 0)
|
||
+ if (rtld_phdr[cnt].p_type == PT_GNU_RELRO)
|
||
+ {
|
||
+ _dl_rtld_map.l_relro_addr = rtld_phdr[cnt].p_vaddr;
|
||
+ _dl_rtld_map.l_relro_size = rtld_phdr[cnt].p_memsz;
|
||
+ break;
|
||
+ }
|
||
+}
|
||
+
|
||
/* Adjusts the contents of the stack and related globals for the user
|
||
entry point. The ld.so processed skip_args arguments and bumped
|
||
_dl_argv and _dl_argc accordingly. Those arguments are removed from
|
||
@@ -1705,33 +1736,7 @@ dl_main (const ElfW(Phdr) *phdr,
|
||
++GL(dl_ns)[LM_ID_BASE]._ns_nloaded;
|
||
++GL(dl_load_adds);
|
||
|
||
- /* Starting from binutils-2.23, the linker will define the magic symbol
|
||
- __ehdr_start to point to our own ELF header if it is visible in a
|
||
- segment that also includes the phdrs. If that's not available, we use
|
||
- the old method that assumes the beginning of the file is part of the
|
||
- lowest-addressed PT_LOAD segment. */
|
||
-
|
||
- /* Set up the program header information for the dynamic linker
|
||
- itself. It is needed in the dl_iterate_phdr callbacks. */
|
||
- const ElfW(Ehdr) *rtld_ehdr = &__ehdr_start;
|
||
- assert (rtld_ehdr->e_ehsize == sizeof *rtld_ehdr);
|
||
- assert (rtld_ehdr->e_phentsize == sizeof (ElfW(Phdr)));
|
||
-
|
||
- const ElfW(Phdr) *rtld_phdr = (const void *) rtld_ehdr + rtld_ehdr->e_phoff;
|
||
-
|
||
- _dl_rtld_map.l_phdr = rtld_phdr;
|
||
- _dl_rtld_map.l_phnum = rtld_ehdr->e_phnum;
|
||
-
|
||
-
|
||
- /* PT_GNU_RELRO is usually the last phdr. */
|
||
- size_t cnt = rtld_ehdr->e_phnum;
|
||
- while (cnt-- > 0)
|
||
- if (rtld_phdr[cnt].p_type == PT_GNU_RELRO)
|
||
- {
|
||
- _dl_rtld_map.l_relro_addr = rtld_phdr[cnt].p_vaddr;
|
||
- _dl_rtld_map.l_relro_size = rtld_phdr[cnt].p_memsz;
|
||
- break;
|
||
- }
|
||
+ rtld_setup_phdr ();
|
||
|
||
/* Add the dynamic linker to the TLS list if it also uses TLS. */
|
||
if (_dl_rtld_map.l_tls_blocksize != 0)
|
||
|
||
commit 5e298d2d937b6da06500478be956abeb24357e05
|
||
Author: Florian Weimer <fweimer@redhat.com>
|
||
Date: Fri Aug 1 19:27:35 2025 +0200
|
||
|
||
elf: Handle ld.so with LOAD segment gaps in _dl_find_object (bug 31943)
|
||
|
||
Detect if ld.so not contiguous and handle that case in _dl_find_object.
|
||
Set l_find_object_processed even for initially loaded link maps,
|
||
otherwise dlopen of an initially loaded object adds it to
|
||
_dlfo_loaded_mappings (where maps are expected to be contiguous),
|
||
in addition to _dlfo_nodelete_mappings.
|
||
|
||
Test elf/tst-link-map-contiguous-ldso iterates over the loader
|
||
image, reading every word to make sure memory is actually mapped.
|
||
It only does that if the l_contiguous flag is set for the link map.
|
||
Otherwise, it finds gaps with mmap and checks that _dl_find_object
|
||
does not return the ld.so mapping for them.
|
||
|
||
The test elf/tst-link-map-contiguous-main does the same thing for
|
||
the libc.so shared object. This only works if the kernel loaded
|
||
the main program because the glibc dynamic loader may fill
|
||
the gaps with PROT_NONE mappings in some cases, making it contiguous,
|
||
but accesses to individual words may still fault.
|
||
|
||
Test elf/tst-link-map-contiguous-libc is again slightly different
|
||
because the dynamic loader always fills the gaps with PROT_NONE
|
||
mappings, so a different form of probing has to be used.
|
||
|
||
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
||
(cherry picked from commit 20681be149b9eb1b6c1f4246bf4bd801221c86cd)
|
||
|
||
diff --git a/NEWS b/NEWS
|
||
index 4610b8bbc6..cbe11ac95b 100644
|
||
--- a/NEWS
|
||
+++ b/NEWS
|
||
@@ -9,6 +9,7 @@ Version 2.42.1
|
||
|
||
The following bugs were resolved with this release:
|
||
|
||
+ [31943] _dl_find_object can fail if ld.so contains gaps between load segments
|
||
[32994] stdlib: resolve a double lock init issue after fork
|
||
|
||
Version 2.42
|
||
diff --git a/elf/Makefile b/elf/Makefile
|
||
index 48aa0b57e5..3a5596e2bb 100644
|
||
--- a/elf/Makefile
|
||
+++ b/elf/Makefile
|
||
@@ -543,6 +543,8 @@ tests-internal += \
|
||
tst-dl_find_object-threads \
|
||
tst-dlmopen2 \
|
||
tst-hash-collision3 \
|
||
+ tst-link-map-contiguous-ldso \
|
||
+ tst-link-map-contiguous-libc \
|
||
tst-ptrguard1 \
|
||
tst-stackguard1 \
|
||
tst-tls-surplus \
|
||
@@ -554,6 +556,10 @@ tests-internal += \
|
||
unload2 \
|
||
# tests-internal
|
||
|
||
+ifeq ($(build-hardcoded-path-in-tests),yes)
|
||
+tests-internal += tst-link-map-contiguous-main
|
||
+endif
|
||
+
|
||
tests-container += \
|
||
tst-dlopen-self-container \
|
||
tst-dlopen-tlsmodid-container \
|
||
diff --git a/elf/dl-find_object.c b/elf/dl-find_object.c
|
||
index 1e76373292..c9f4c1c8d1 100644
|
||
--- a/elf/dl-find_object.c
|
||
+++ b/elf/dl-find_object.c
|
||
@@ -465,6 +465,37 @@ _dl_find_object (void *pc1, struct dl_find_object *result)
|
||
}
|
||
rtld_hidden_def (_dl_find_object)
|
||
|
||
+/* Subroutine of _dlfo_process_initial to split out noncontigous link
|
||
+ maps. NODELETE is the number of used _dlfo_nodelete_mappings
|
||
+ elements. It is incremented as needed, and the new NODELETE value
|
||
+ is returned. */
|
||
+static size_t
|
||
+_dlfo_process_initial_noncontiguous_map (struct link_map *map,
|
||
+ size_t nodelete)
|
||
+{
|
||
+ struct dl_find_object_internal dlfo;
|
||
+ _dl_find_object_from_map (map, &dlfo);
|
||
+
|
||
+ /* PT_LOAD segments for a non-contiguous link map are added to the
|
||
+ non-closeable mappings. */
|
||
+ const ElfW(Phdr) *ph = map->l_phdr;
|
||
+ const ElfW(Phdr) *ph_end = map->l_phdr + map->l_phnum;
|
||
+ for (; ph < ph_end; ++ph)
|
||
+ if (ph->p_type == PT_LOAD)
|
||
+ {
|
||
+ if (_dlfo_nodelete_mappings != NULL)
|
||
+ {
|
||
+ /* Second pass only. */
|
||
+ _dlfo_nodelete_mappings[nodelete] = dlfo;
|
||
+ ElfW(Addr) start = ph->p_vaddr + map->l_addr;
|
||
+ _dlfo_nodelete_mappings[nodelete].map_start = start;
|
||
+ _dlfo_nodelete_mappings[nodelete].map_end = start + ph->p_memsz;
|
||
+ }
|
||
+ ++nodelete;
|
||
+ }
|
||
+ return nodelete;
|
||
+}
|
||
+
|
||
/* _dlfo_process_initial is called twice. First to compute the array
|
||
sizes from the initial loaded mappings. Second to fill in the
|
||
bases and infos arrays with the (still unsorted) data. Returns the
|
||
@@ -476,29 +507,8 @@ _dlfo_process_initial (void)
|
||
|
||
size_t nodelete = 0;
|
||
if (!main_map->l_contiguous)
|
||
- {
|
||
- struct dl_find_object_internal dlfo;
|
||
- _dl_find_object_from_map (main_map, &dlfo);
|
||
-
|
||
- /* PT_LOAD segments for a non-contiguous are added to the
|
||
- non-closeable mappings. */
|
||
- for (const ElfW(Phdr) *ph = main_map->l_phdr,
|
||
- *ph_end = main_map->l_phdr + main_map->l_phnum;
|
||
- ph < ph_end; ++ph)
|
||
- if (ph->p_type == PT_LOAD)
|
||
- {
|
||
- if (_dlfo_nodelete_mappings != NULL)
|
||
- {
|
||
- /* Second pass only. */
|
||
- _dlfo_nodelete_mappings[nodelete] = dlfo;
|
||
- _dlfo_nodelete_mappings[nodelete].map_start
|
||
- = ph->p_vaddr + main_map->l_addr;
|
||
- _dlfo_nodelete_mappings[nodelete].map_end
|
||
- = _dlfo_nodelete_mappings[nodelete].map_start + ph->p_memsz;
|
||
- }
|
||
- ++nodelete;
|
||
- }
|
||
- }
|
||
+ /* Contiguous case already handled in _dl_find_object_init. */
|
||
+ nodelete = _dlfo_process_initial_noncontiguous_map (main_map, nodelete);
|
||
|
||
size_t loaded = 0;
|
||
for (Lmid_t ns = 0; ns < GL(dl_nns); ++ns)
|
||
@@ -510,11 +520,18 @@ _dlfo_process_initial (void)
|
||
/* lt_library link maps are implicitly NODELETE. */
|
||
if (l->l_type == lt_library || l->l_nodelete_active)
|
||
{
|
||
- if (_dlfo_nodelete_mappings != NULL)
|
||
- /* Second pass only. */
|
||
- _dl_find_object_from_map
|
||
- (l, _dlfo_nodelete_mappings + nodelete);
|
||
- ++nodelete;
|
||
+ /* The kernel may have loaded ld.so with gaps. */
|
||
+ if (!l->l_contiguous && is_rtld_link_map (l))
|
||
+ nodelete
|
||
+ = _dlfo_process_initial_noncontiguous_map (l, nodelete);
|
||
+ else
|
||
+ {
|
||
+ if (_dlfo_nodelete_mappings != NULL)
|
||
+ /* Second pass only. */
|
||
+ _dl_find_object_from_map
|
||
+ (l, _dlfo_nodelete_mappings + nodelete);
|
||
+ ++nodelete;
|
||
+ }
|
||
}
|
||
else if (l->l_type == lt_loaded)
|
||
{
|
||
@@ -764,7 +781,6 @@ _dl_find_object_update_1 (struct link_map **loaded, size_t count)
|
||
/* Prefer newly loaded link map. */
|
||
assert (loaded_index1 > 0);
|
||
_dl_find_object_from_map (loaded[loaded_index1 - 1], dlfo);
|
||
- loaded[loaded_index1 - 1]->l_find_object_processed = 1;
|
||
--loaded_index1;
|
||
}
|
||
|
||
diff --git a/elf/dl-find_object.h b/elf/dl-find_object.h
|
||
index 9aa2439eaa..d9d75c4ad9 100644
|
||
--- a/elf/dl-find_object.h
|
||
+++ b/elf/dl-find_object.h
|
||
@@ -94,7 +94,7 @@ _dl_find_object_to_external (struct dl_find_object_internal *internal,
|
||
}
|
||
|
||
/* Extract the object location data from a link map and writes it to
|
||
- *RESULT using relaxed MO stores. */
|
||
+ *RESULT using relaxed MO stores. Set L->l_find_object_processed. */
|
||
static void __attribute__ ((unused))
|
||
_dl_find_object_from_map (struct link_map *l,
|
||
struct dl_find_object_internal *result)
|
||
@@ -141,8 +141,11 @@ _dl_find_object_from_map (struct link_map *l,
|
||
break;
|
||
}
|
||
if (read_seg == 3)
|
||
- return;
|
||
+ goto done;
|
||
}
|
||
+
|
||
+ done:
|
||
+ l->l_find_object_processed = 1;
|
||
}
|
||
|
||
/* Called by the dynamic linker to set up the data structures for the
|
||
diff --git a/elf/rtld.c b/elf/rtld.c
|
||
index 6fb900fb31..ef4d96c053 100644
|
||
--- a/elf/rtld.c
|
||
+++ b/elf/rtld.c
|
||
@@ -1241,7 +1241,7 @@ rtld_setup_main_map (struct link_map *main_map)
|
||
|
||
/* Set up the program header information for the dynamic linker
|
||
itself. It can be accessed via _r_debug and dl_iterate_phdr
|
||
- callbacks. */
|
||
+ callbacks, and it is used by _dl_find_object. */
|
||
static void
|
||
rtld_setup_phdr (void)
|
||
{
|
||
@@ -1259,6 +1259,29 @@ rtld_setup_phdr (void)
|
||
_dl_rtld_map.l_phnum = rtld_ehdr->e_phnum;
|
||
|
||
|
||
+ _dl_rtld_map.l_contiguous = 1;
|
||
+ /* The linker may not have produced a contiguous object. The kernel
|
||
+ will load the object with actual gaps (unlike the glibc loader
|
||
+ for shared objects, which always produces a contiguous mapping).
|
||
+ See similar logic in rtld_setup_main_map above. */
|
||
+ {
|
||
+ ElfW(Addr) expected_load_address = 0;
|
||
+ for (const ElfW(Phdr) *ph = rtld_phdr; ph < &rtld_phdr[rtld_ehdr->e_phnum];
|
||
+ ++ph)
|
||
+ if (ph->p_type == PT_LOAD)
|
||
+ {
|
||
+ ElfW(Addr) mapstart = ph->p_vaddr & ~(GLRO(dl_pagesize) - 1);
|
||
+ if (_dl_rtld_map.l_contiguous && expected_load_address != 0
|
||
+ && expected_load_address != mapstart)
|
||
+ _dl_rtld_map.l_contiguous = 0;
|
||
+ ElfW(Addr) allocend = ph->p_vaddr + ph->p_memsz;
|
||
+ /* The next expected address is the page following this load
|
||
+ segment. */
|
||
+ expected_load_address = ((allocend + GLRO(dl_pagesize) - 1)
|
||
+ & ~(GLRO(dl_pagesize) - 1));
|
||
+ }
|
||
+ }
|
||
+
|
||
/* PT_GNU_RELRO is usually the last phdr. */
|
||
size_t cnt = rtld_ehdr->e_phnum;
|
||
while (cnt-- > 0)
|
||
diff --git a/elf/tst-link-map-contiguous-ldso.c b/elf/tst-link-map-contiguous-ldso.c
|
||
new file mode 100644
|
||
index 0000000000..04de808bb2
|
||
--- /dev/null
|
||
+++ b/elf/tst-link-map-contiguous-ldso.c
|
||
@@ -0,0 +1,98 @@
|
||
+/* Check that _dl_find_object behavior matches up with gaps.
|
||
+ 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 <dlfcn.h>
|
||
+#include <gnu/lib-names.h>
|
||
+#include <link.h>
|
||
+#include <stdbool.h>
|
||
+#include <stdio.h>
|
||
+#include <support/check.h>
|
||
+#include <support/xdlfcn.h>
|
||
+#include <support/xunistd.h>
|
||
+#include <sys/mman.h>
|
||
+#include <unistd.h>
|
||
+
|
||
+static int
|
||
+do_test (void)
|
||
+{
|
||
+ struct link_map *l = xdlopen (LD_SO, RTLD_NOW);
|
||
+ if (!l->l_contiguous)
|
||
+ {
|
||
+ puts ("info: ld.so link map is not contiguous");
|
||
+
|
||
+ /* Try to find holes by probing with mmap. */
|
||
+ int pagesize = getpagesize ();
|
||
+ bool gap_found = false;
|
||
+ ElfW(Addr) addr = l->l_map_start;
|
||
+ TEST_COMPARE (addr % pagesize, 0);
|
||
+ while (addr < l->l_map_end)
|
||
+ {
|
||
+ void *expected = (void *) addr;
|
||
+ void *ptr = xmmap (expected, 1, PROT_READ | PROT_WRITE,
|
||
+ MAP_PRIVATE | MAP_ANONYMOUS, -1);
|
||
+ struct dl_find_object dlfo;
|
||
+ int dlfo_ret = _dl_find_object (expected, &dlfo);
|
||
+ if (ptr == expected)
|
||
+ {
|
||
+ if (dlfo_ret < 0)
|
||
+ {
|
||
+ TEST_COMPARE (dlfo_ret, -1);
|
||
+ printf ("info: hole without mapping data found at %p\n", ptr);
|
||
+ }
|
||
+ else
|
||
+ FAIL ("object \"%s\" found in gap at %p",
|
||
+ dlfo.dlfo_link_map->l_name, ptr);
|
||
+ gap_found = true;
|
||
+ }
|
||
+ else if (dlfo_ret == 0)
|
||
+ {
|
||
+ if ((void *) dlfo.dlfo_link_map != (void *) l)
|
||
+ {
|
||
+ printf ("info: object \"%s\" found at %p\n",
|
||
+ dlfo.dlfo_link_map->l_name, ptr);
|
||
+ gap_found = true;
|
||
+ }
|
||
+ }
|
||
+ else
|
||
+ TEST_COMPARE (dlfo_ret, -1);
|
||
+ xmunmap (ptr, 1);
|
||
+ addr += pagesize;
|
||
+ }
|
||
+ if (!gap_found)
|
||
+ FAIL ("no ld.so gap found");
|
||
+ }
|
||
+ else
|
||
+ {
|
||
+ puts ("info: ld.so link map is contiguous");
|
||
+
|
||
+ /* Assert that ld.so is truly contiguous in memory. */
|
||
+ volatile long int *p = (volatile long int *) l->l_map_start;
|
||
+ volatile long int *end = (volatile long int *) l->l_map_end;
|
||
+ while (p < end)
|
||
+ {
|
||
+ *p;
|
||
+ ++p;
|
||
+ }
|
||
+ }
|
||
+
|
||
+ xdlclose (l);
|
||
+
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+#include <support/test-driver.c>
|
||
diff --git a/elf/tst-link-map-contiguous-libc.c b/elf/tst-link-map-contiguous-libc.c
|
||
new file mode 100644
|
||
index 0000000000..eb5728c765
|
||
--- /dev/null
|
||
+++ b/elf/tst-link-map-contiguous-libc.c
|
||
@@ -0,0 +1,57 @@
|
||
+/* Check that the entire libc.so program image is readable if contiguous.
|
||
+ 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 <gnu/lib-names.h>
|
||
+#include <link.h>
|
||
+#include <support/check.h>
|
||
+#include <support/xdlfcn.h>
|
||
+#include <support/xunistd.h>
|
||
+#include <sys/mman.h>
|
||
+#include <unistd.h>
|
||
+
|
||
+static int
|
||
+do_test (void)
|
||
+{
|
||
+ struct link_map *l = xdlopen (LIBC_SO, RTLD_NOW);
|
||
+
|
||
+ /* The dynamic loader fills holes with PROT_NONE mappings. */
|
||
+ if (!l->l_contiguous)
|
||
+ FAIL_EXIT1 ("libc.so link map is not contiguous");
|
||
+
|
||
+ /* Direct probing does not work because not everything is readable
|
||
+ due to PROT_NONE mappings. */
|
||
+ int pagesize = getpagesize ();
|
||
+ ElfW(Addr) addr = l->l_map_start;
|
||
+ TEST_COMPARE (addr % pagesize, 0);
|
||
+ while (addr < l->l_map_end)
|
||
+ {
|
||
+ void *expected = (void *) addr;
|
||
+ void *ptr = xmmap (expected, 1, PROT_READ | PROT_WRITE,
|
||
+ MAP_PRIVATE | MAP_ANONYMOUS, -1);
|
||
+ if (ptr == expected)
|
||
+ FAIL ("hole in libc.so memory image after %lu bytes",
|
||
+ (unsigned long int) (addr - l->l_map_start));
|
||
+ xmunmap (ptr, 1);
|
||
+ addr += pagesize;
|
||
+ }
|
||
+
|
||
+ xdlclose (l);
|
||
+
|
||
+ return 0;
|
||
+}
|
||
+#include <support/test-driver.c>
|
||
diff --git a/elf/tst-link-map-contiguous-main.c b/elf/tst-link-map-contiguous-main.c
|
||
new file mode 100644
|
||
index 0000000000..2d1a054f0f
|
||
--- /dev/null
|
||
+++ b/elf/tst-link-map-contiguous-main.c
|
||
@@ -0,0 +1,45 @@
|
||
+/* Check that the entire main program image is readable if contiguous.
|
||
+ 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 <link.h>
|
||
+#include <support/check.h>
|
||
+#include <support/xdlfcn.h>
|
||
+
|
||
+static int
|
||
+do_test (void)
|
||
+{
|
||
+ struct link_map *l = xdlopen ("", RTLD_NOW);
|
||
+ if (!l->l_contiguous)
|
||
+ FAIL_UNSUPPORTED ("main link map is not contiguous");
|
||
+
|
||
+ /* This check only works if the kernel loaded the main program. The
|
||
+ dynamic loader replaces gaps with PROT_NONE mappings, resulting
|
||
+ in faults. */
|
||
+ volatile long int *p = (volatile long int *) l->l_map_start;
|
||
+ volatile long int *end = (volatile long int *) l->l_map_end;
|
||
+ while (p < end)
|
||
+ {
|
||
+ *p;
|
||
+ ++p;
|
||
+ }
|
||
+
|
||
+ xdlclose (l);
|
||
+
|
||
+ return 0;
|
||
+}
|
||
+#include <support/test-driver.c>
|
||
|
||
commit b38f3f60d5b157edcf4d8bd1fd3ed02d417889e0
|
||
Author: Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
||
Date: Fri Aug 1 15:00:25 2025 -0300
|
||
|
||
nptl: Fix SYSCALL_CANCEL for return values larger than INT_MAX (BZ 33245)
|
||
|
||
The SYSCALL_CANCEL calls __syscall_cancel, which in turn
|
||
calls __internal_syscall_cancel with an 'int' return instead of the
|
||
expected 'long int'. This causes issues with syscalls that return
|
||
values larger than INT_MAX, such as copy_file_range [1].
|
||
|
||
Checked on x86_64-linux-gnu.
|
||
|
||
[1] https://debbugs.gnu.org/cgi/bugreport.cgi?bug=79139
|
||
|
||
Reviewed-by: Andreas K. Huettel <dilfridge@gentoo.org>
|
||
(cherry picked from commit 7107bebf19286f42dcb0a97581137a5893c16206)
|
||
|
||
diff --git a/NEWS b/NEWS
|
||
index cbe11ac95b..1d04bdfef8 100644
|
||
--- a/NEWS
|
||
+++ b/NEWS
|
||
@@ -11,6 +11,7 @@ The following bugs were resolved with this release:
|
||
|
||
[31943] _dl_find_object can fail if ld.so contains gaps between load segments
|
||
[32994] stdlib: resolve a double lock init issue after fork
|
||
+ [33245] nptl: nptl: error in internal cancellation syscall handling
|
||
|
||
Version 2.42
|
||
|
||
diff --git a/nptl/cancellation.c b/nptl/cancellation.c
|
||
index 156e63dcf0..bed0383a23 100644
|
||
--- a/nptl/cancellation.c
|
||
+++ b/nptl/cancellation.c
|
||
@@ -72,8 +72,8 @@ __syscall_cancel (__syscall_arg_t a1, __syscall_arg_t a2,
|
||
__syscall_arg_t a5, __syscall_arg_t a6,
|
||
__SYSCALL_CANCEL7_ARG_DEF __syscall_arg_t nr)
|
||
{
|
||
- int r = __internal_syscall_cancel (a1, a2, a3, a4, a5, a6,
|
||
- __SYSCALL_CANCEL7_ARG nr);
|
||
+ long int r = __internal_syscall_cancel (a1, a2, a3, a4, a5, a6,
|
||
+ __SYSCALL_CANCEL7_ARG nr);
|
||
return __glibc_unlikely (INTERNAL_SYSCALL_ERROR_P (r))
|
||
? SYSCALL_ERROR_LABEL (INTERNAL_SYSCALL_ERRNO (r))
|
||
: r;
|
||
|
||
commit 9d5bf9c17db0f35268cd798660c8bbeea1f4071d
|
||
Author: H.J. Lu <hjl.tools@gmail.com>
|
||
Date: Sat Jul 19 07:43:26 2025 -0700
|
||
|
||
Delete temporary files in support_subprocess
|
||
|
||
Call support_delete_temp_files to delete temporary files before exit in
|
||
support_subprocess.
|
||
|
||
This partially fixes BZ #33182.
|
||
|
||
Signed-off-by: H.J. Lu <hjl.tools@gmail.com>
|
||
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
||
(cherry picked from commit d27b1a71cd424710813bd3d81afb32a36470d643)
|
||
|
||
diff --git a/support/support_subprocess.c b/support/support_subprocess.c
|
||
index be00dde3a7..8bf9a33ea2 100644
|
||
--- a/support/support_subprocess.c
|
||
+++ b/support/support_subprocess.c
|
||
@@ -25,6 +25,7 @@
|
||
#include <support/check.h>
|
||
#include <support/xunistd.h>
|
||
#include <support/subprocess.h>
|
||
+#include <support/temp_file-internal.h>
|
||
|
||
static struct support_subprocess
|
||
support_subprocess_init (void)
|
||
@@ -60,6 +61,8 @@ support_subprocess (void (*callback) (void *), void *closure)
|
||
xclose (result.stdout_pipe[1]);
|
||
xclose (result.stderr_pipe[1]);
|
||
callback (closure);
|
||
+ /* Make sure that temporary files are deleted. */
|
||
+ support_delete_temp_files ();
|
||
_exit (0);
|
||
}
|
||
xclose (result.stdout_pipe[1]);
|
||
|
||
commit 9ec7a532ffdb9a6e0a4b220d7a694d6120701035
|
||
Author: H.J. Lu <hjl.tools@gmail.com>
|
||
Date: Sat Jul 19 07:43:27 2025 -0700
|
||
|
||
tst-fopen-threaded.c: Delete temporary file
|
||
|
||
Update tst-fopen-threaded.c to call support_create_temp_directory to
|
||
create a temporary directory and open "file" in the temporary directory,
|
||
instead of using /tmp/openclosetest and leaving it behind.
|
||
|
||
This partially fixes BZ #33182.
|
||
|
||
Signed-off-by: H.J. Lu <hjl.tools@gmail.com>
|
||
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
||
(cherry picked from commit e7db5150603bb2224a2bfd9628cae04ddcbe49e3)
|
||
|
||
diff --git a/sysdeps/pthread/tst-fopen-threaded.c b/sysdeps/pthread/tst-fopen-threaded.c
|
||
index ade58ad19e..c17f1eaa13 100644
|
||
--- a/sysdeps/pthread/tst-fopen-threaded.c
|
||
+++ b/sysdeps/pthread/tst-fopen-threaded.c
|
||
@@ -34,11 +34,13 @@
|
||
#include <stdio.h>
|
||
#include <string.h>
|
||
#include <unistd.h>
|
||
+#include <stdlib.h>
|
||
|
||
#include <support/check.h>
|
||
#include <support/temp_file.h>
|
||
#include <support/xstdio.h>
|
||
#include <support/xthread.h>
|
||
+#include <support/support.h>
|
||
|
||
#define NUM_THREADS 100
|
||
#define ITERS 10
|
||
@@ -111,7 +113,8 @@ threadOpenCloseRoutine (void *argv)
|
||
/* Wait for all threads to be ready to call fopen and fclose. */
|
||
xpthread_barrier_wait (&barrier);
|
||
|
||
- FILE *fd = xfopen ("/tmp/openclosetest", "w+");
|
||
+ char *file = (char *) argv;
|
||
+ FILE *fd = xfopen (file, "w+");
|
||
xfclose (fd);
|
||
return NULL;
|
||
}
|
||
@@ -235,6 +238,10 @@ do_test (void)
|
||
xfclose (fd_file);
|
||
}
|
||
|
||
+ char *tempdir = support_create_temp_directory ("openclosetest-");
|
||
+ char *file = xasprintf ("%s/file", tempdir);
|
||
+ add_temp_file (file);
|
||
+
|
||
/* Test 3: Concurrent open/close. */
|
||
for (int reps = 1; reps <= ITERS; reps++)
|
||
{
|
||
@@ -243,7 +250,7 @@ do_test (void)
|
||
{
|
||
threads[i] =
|
||
xpthread_create (support_small_stack_thread_attribute (),
|
||
- threadOpenCloseRoutine, NULL);
|
||
+ threadOpenCloseRoutine, file);
|
||
}
|
||
for (int i = 0; i < NUM_THREADS; i++)
|
||
{
|
||
@@ -252,6 +259,9 @@ do_test (void)
|
||
xpthread_barrier_destroy (&barrier);
|
||
}
|
||
|
||
+ free (file);
|
||
+ free (tempdir);
|
||
+
|
||
return 0;
|
||
}
|
||
|
||
|
||
commit 41a77b78cff821007e3dd874619ebec7ce708c3d
|
||
Author: H.J. Lu <hjl.tools@gmail.com>
|
||
Date: Sat Jul 19 07:43:28 2025 -0700
|
||
|
||
tst-freopen4-main.c: Call support_capture_subprocess with chroot
|
||
|
||
Update tst-freopen4-main.c to call support_capture_subprocess with chroot,
|
||
which makes temporary files inaccessible, so that temporary files can be
|
||
deleted.
|
||
|
||
This partially fixes BZ #33182.
|
||
|
||
Signed-off-by: H.J. Lu <hjl.tools@gmail.com>
|
||
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
||
(cherry picked from commit 6463d4a7b28e5ee3891c34a8a1f0a59c24dfa9de)
|
||
|
||
diff --git a/stdio-common/tst-freopen4-main.c b/stdio-common/tst-freopen4-main.c
|
||
index 3336f5327d..436da4d203 100644
|
||
--- a/stdio-common/tst-freopen4-main.c
|
||
+++ b/stdio-common/tst-freopen4-main.c
|
||
@@ -28,25 +28,15 @@
|
||
#include <support/test-driver.h>
|
||
#include <support/xstdio.h>
|
||
#include <support/xunistd.h>
|
||
+#include <support/capture_subprocess.h>
|
||
|
||
-int
|
||
-do_test (void)
|
||
+static void
|
||
+do_test_chroot (void *data)
|
||
{
|
||
- mtrace ();
|
||
- char *temp_dir;
|
||
+ char *temp_dir = (char *) data;
|
||
FILE *fp;
|
||
int ret;
|
||
|
||
- /* These chroot tests verify that either reopening a renamed or
|
||
- deleted file works even in the absence of /proc, or that it fails
|
||
- (without memory leaks); thus, for example, such reopening does
|
||
- not crash in the absence of /proc. */
|
||
-
|
||
- support_become_root ();
|
||
- if (!support_can_chroot ())
|
||
- return EXIT_UNSUPPORTED;
|
||
-
|
||
- temp_dir = support_create_temp_directory ("tst-freopen4");
|
||
xchroot (temp_dir);
|
||
|
||
/* Test freopen with NULL, renamed file. This verifies that
|
||
@@ -96,6 +86,32 @@ do_test (void)
|
||
puts ("freopen of deleted file failed (OK)");
|
||
|
||
free (temp_dir);
|
||
+}
|
||
+
|
||
+int
|
||
+do_test (void)
|
||
+{
|
||
+ mtrace ();
|
||
+ char *temp_dir;
|
||
+
|
||
+ /* These chroot tests verify that either reopening a renamed or
|
||
+ deleted file works even in the absence of /proc, or that it fails
|
||
+ (without memory leaks); thus, for example, such reopening does
|
||
+ not crash in the absence of /proc. */
|
||
+
|
||
+ support_become_root ();
|
||
+ if (!support_can_chroot ())
|
||
+ return EXIT_UNSUPPORTED;
|
||
+
|
||
+ temp_dir = support_create_temp_directory ("tst-freopen4");
|
||
+
|
||
+ struct support_capture_subprocess result;
|
||
+ result = support_capture_subprocess (do_test_chroot, temp_dir);
|
||
+ support_capture_subprocess_check (&result, "freopen4", 0,
|
||
+ sc_allow_stdout);
|
||
+ fputs (result.out.buffer, stdout);
|
||
+ support_capture_subprocess_free (&result);
|
||
+
|
||
return 0;
|
||
}
|
||
|
||
|
||
commit c090b0cb1cde74aaeec01663dd55d6681dc92075
|
||
Author: H.J. Lu <hjl.tools@gmail.com>
|
||
Date: Sat Jul 19 07:43:29 2025 -0700
|
||
|
||
tst-env-setuid: Delete LD_DEBUG_OUTPUT output
|
||
|
||
Update tst-env-setuid.c to delete LD_DEBUG_OUTPUT output, instead of
|
||
leaving it behind.
|
||
|
||
This partially fixes BZ #33182.
|
||
|
||
Signed-off-by: H.J. Lu <hjl.tools@gmail.com>
|
||
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
||
(cherry picked from commit 5d23dfb289174d73b8907b86d2bef7a3ca889840)
|
||
|
||
diff --git a/elf/tst-env-setuid.c b/elf/tst-env-setuid.c
|
||
index 7209acd616..ff3eda7f91 100644
|
||
--- a/elf/tst-env-setuid.c
|
||
+++ b/elf/tst-env-setuid.c
|
||
@@ -40,6 +40,8 @@ static char SETGID_CHILD[] = "setgid-child";
|
||
# define PROFILE_LIB "tst-sonamemove-runmod2.so"
|
||
#endif
|
||
|
||
+#define LD_DEBUG_OUTPUT "/tmp/some-file"
|
||
+
|
||
struct envvar_t
|
||
{
|
||
const char *env;
|
||
@@ -61,7 +63,7 @@ static const struct envvar_t filtered_envvars[] =
|
||
{ "MALLOC_TRIM_THRESHOLD_", FILTERED_VALUE },
|
||
{ "RES_OPTIONS", FILTERED_VALUE },
|
||
{ "LD_DEBUG", "all" },
|
||
- { "LD_DEBUG_OUTPUT", "/tmp/some-file" },
|
||
+ { "LD_DEBUG_OUTPUT", LD_DEBUG_OUTPUT },
|
||
{ "LD_WARN", FILTERED_VALUE },
|
||
{ "LD_VERBOSE", FILTERED_VALUE },
|
||
{ "LD_BIND_NOW", "0" },
|
||
@@ -74,6 +76,14 @@ static const struct envvar_t unfiltered_envvars[] =
|
||
{ "LD_ASSUME_KERNEL", UNFILTERED_VALUE },
|
||
};
|
||
|
||
+static void
|
||
+unlink_ld_debug_output (pid_t pid)
|
||
+{
|
||
+ char *output = xasprintf ("%s.%d", LD_DEBUG_OUTPUT, pid);
|
||
+ unlink (output);
|
||
+ free (output);
|
||
+}
|
||
+
|
||
static int
|
||
test_child (void)
|
||
{
|
||
@@ -138,13 +148,21 @@ do_test (int argc, char **argv)
|
||
/* Setgid child process. */
|
||
if (argc == 2 && strcmp (argv[1], SETGID_CHILD) == 0)
|
||
{
|
||
+ pid_t ppid = getppid ();
|
||
+
|
||
if (getgid () == getegid ())
|
||
- /* This can happen if the file system is mounted nosuid. */
|
||
- FAIL_UNSUPPORTED ("SGID failed: GID and EGID match (%jd)\n",
|
||
- (intmax_t) getgid ());
|
||
+ {
|
||
+ /* This can happen if the file system is mounted nosuid. */
|
||
+ unlink_ld_debug_output (ppid);
|
||
+
|
||
+ FAIL_UNSUPPORTED ("SGID failed: GID and EGID match (%jd)\n",
|
||
+ (intmax_t) getgid ());
|
||
+ }
|
||
|
||
int ret = test_child ();
|
||
|
||
+ unlink_ld_debug_output (ppid);
|
||
+
|
||
if (ret != 0)
|
||
exit (1);
|
||
return 0;
|
||
|
||
commit e5754399b542640f3f69c5e2513c57a307656032
|
||
Author: H.J. Lu <hjl.tools@gmail.com>
|
||
Date: Tue Aug 5 09:16:14 2025 -0700
|
||
|
||
Revert "tst-freopen4-main.c: Call support_capture_subprocess with chroot"
|
||
|
||
Revert commit 6463d4a7b28e5ee3891c34a8a1f0a59c24dfa9de to fix
|
||
|
||
FAIL: stdio-common/tst-freopen4-mem
|
||
FAIL: stdio-common/tst-freopen64-4-mem
|
||
|
||
This fixes BZ #33254.
|
||
|
||
Reviewed-by: Sam James <sam@gentoo.org>
|
||
(cherry picked from commit adec0bf05bc23ec35573c7a5b96440089b69265e)
|
||
|
||
diff --git a/stdio-common/tst-freopen4-main.c b/stdio-common/tst-freopen4-main.c
|
||
index 436da4d203..3336f5327d 100644
|
||
--- a/stdio-common/tst-freopen4-main.c
|
||
+++ b/stdio-common/tst-freopen4-main.c
|
||
@@ -28,15 +28,25 @@
|
||
#include <support/test-driver.h>
|
||
#include <support/xstdio.h>
|
||
#include <support/xunistd.h>
|
||
-#include <support/capture_subprocess.h>
|
||
|
||
-static void
|
||
-do_test_chroot (void *data)
|
||
+int
|
||
+do_test (void)
|
||
{
|
||
- char *temp_dir = (char *) data;
|
||
+ mtrace ();
|
||
+ char *temp_dir;
|
||
FILE *fp;
|
||
int ret;
|
||
|
||
+ /* These chroot tests verify that either reopening a renamed or
|
||
+ deleted file works even in the absence of /proc, or that it fails
|
||
+ (without memory leaks); thus, for example, such reopening does
|
||
+ not crash in the absence of /proc. */
|
||
+
|
||
+ support_become_root ();
|
||
+ if (!support_can_chroot ())
|
||
+ return EXIT_UNSUPPORTED;
|
||
+
|
||
+ temp_dir = support_create_temp_directory ("tst-freopen4");
|
||
xchroot (temp_dir);
|
||
|
||
/* Test freopen with NULL, renamed file. This verifies that
|
||
@@ -86,32 +96,6 @@ do_test_chroot (void *data)
|
||
puts ("freopen of deleted file failed (OK)");
|
||
|
||
free (temp_dir);
|
||
-}
|
||
-
|
||
-int
|
||
-do_test (void)
|
||
-{
|
||
- mtrace ();
|
||
- char *temp_dir;
|
||
-
|
||
- /* These chroot tests verify that either reopening a renamed or
|
||
- deleted file works even in the absence of /proc, or that it fails
|
||
- (without memory leaks); thus, for example, such reopening does
|
||
- not crash in the absence of /proc. */
|
||
-
|
||
- support_become_root ();
|
||
- if (!support_can_chroot ())
|
||
- return EXIT_UNSUPPORTED;
|
||
-
|
||
- temp_dir = support_create_temp_directory ("tst-freopen4");
|
||
-
|
||
- struct support_capture_subprocess result;
|
||
- result = support_capture_subprocess (do_test_chroot, temp_dir);
|
||
- support_capture_subprocess_check (&result, "freopen4", 0,
|
||
- sc_allow_stdout);
|
||
- fputs (result.out.buffer, stdout);
|
||
- support_capture_subprocess_free (&result);
|
||
-
|
||
return 0;
|
||
}
|
||
|
||
|
||
commit c5476b7907d01207ede6bf57b26cef151b601f35
|
||
Author: Samuel Thibault <samuel.thibault@ens-lyon.org>
|
||
Date: Fri Jul 18 23:14:40 2025 +0200
|
||
|
||
hurd: support: Fix running SGID tests
|
||
|
||
Secure mode is enabled only if SGID actually provides a new privilege,
|
||
so we have to drop it before gaining it again.
|
||
|
||
Fixes commit 3a3fb2ed83f79100c116c824454095ecfb335ad7
|
||
("Fix error reporting (false negatives) in SGID tests")
|
||
|
||
(cherry picked from commit ad4589e2d834c80a042a8c354fb00cf33e06802c)
|
||
|
||
diff --git a/support/support_capture_subprocess.c b/support/support_capture_subprocess.c
|
||
index b4e4bf9502..c89e65b534 100644
|
||
--- a/support/support_capture_subprocess.c
|
||
+++ b/support/support_capture_subprocess.c
|
||
@@ -133,6 +133,27 @@ copy_and_spawn_sgid (const char *child_id, gid_t gid)
|
||
if (chmod (execname, 02750) != 0)
|
||
FAIL_UNSUPPORTED ("cannot make \"%s\" SGID: %m ", execname);
|
||
|
||
+ /* Now we can drop the privilege of that group. */
|
||
+ const int count = 64;
|
||
+ gid_t groups[count];
|
||
+ int ngroups = getgroups(count, groups);
|
||
+
|
||
+ if (ngroups < 0)
|
||
+ FAIL_UNSUPPORTED ("Could not get group list again for user %jd\n",
|
||
+ (intmax_t) getuid ());
|
||
+
|
||
+ int n = 0;
|
||
+ for (int i = 0; i < ngroups; i++)
|
||
+ {
|
||
+ if (groups[i] != gid)
|
||
+ {
|
||
+ if (n != i)
|
||
+ groups[n] = groups[i];
|
||
+ n++;
|
||
+ }
|
||
+ }
|
||
+ setgroups (n, groups);
|
||
+
|
||
/* We have the binary, now spawn the subprocess. Avoid using
|
||
support_subprogram because we only want the program exit status, not the
|
||
contents. */
|
||
|
||
commit 8a726b63047241c6dd4b55bf85eacd02244362a2
|
||
Author: Wilco Dijkstra <wilco.dijkstra@arm.com>
|
||
Date: Thu Jul 10 15:49:14 2025 +0000
|
||
|
||
malloc: Remove redundant NULL check
|
||
|
||
Remove a redundant NULL check from tcache_get_n.
|
||
|
||
Reviewed-by: Cupertino Miranda <cupertino.miranda@oracle.com>
|
||
(cherry picked from commit 089b4fb90fac8ed53039bc4c465c4d333c6b4048)
|
||
|
||
diff --git a/malloc/malloc.c b/malloc/malloc.c
|
||
index 5ca390cc22..cf5c02ff64 100644
|
||
--- a/malloc/malloc.c
|
||
+++ b/malloc/malloc.c
|
||
@@ -3208,11 +3208,10 @@ tcache_get_n (size_t tc_idx, tcache_entry **ep, bool mangled)
|
||
if (__glibc_unlikely (misaligned_mem (e)))
|
||
malloc_printerr ("malloc(): unaligned tcache chunk detected");
|
||
|
||
- void *ne = e == NULL ? NULL : REVEAL_PTR (e->next);
|
||
if (!mangled)
|
||
- *ep = ne;
|
||
+ *ep = REVEAL_PTR (e->next);
|
||
else
|
||
- *ep = PROTECT_PTR (ep, ne);
|
||
+ *ep = PROTECT_PTR (ep, REVEAL_PTR (e->next));
|
||
|
||
++(tcache->num_slots[tc_idx]);
|
||
e->key = 0;
|
||
@@ -3229,7 +3228,7 @@ tcache_put (mchunkptr chunk, size_t tc_idx)
|
||
static __always_inline void *
|
||
tcache_get (size_t tc_idx)
|
||
{
|
||
- return tcache_get_n (tc_idx, & tcache->entries[tc_idx], false);
|
||
+ return tcache_get_n (tc_idx, &tcache->entries[tc_idx], false);
|
||
}
|
||
|
||
static __always_inline tcache_entry **
|
||
|
||
commit c491dabd8a3de090d1ccb4589421a44e79c5b185
|
||
Author: Wilco Dijkstra <wilco.dijkstra@arm.com>
|
||
Date: Thu Jul 17 14:31:06 2025 +0000
|
||
|
||
malloc: Fix MAX_TCACHE_SMALL_SIZE
|
||
|
||
MAX_TCACHE_SMALL_SIZE should use chunk size since it is used after
|
||
checked_request2size. Increase limit of tcache_max_bytes by 1 since all
|
||
comparisons use '<'. As a result, the last tcache entry is now used as
|
||
expected.
|
||
|
||
Reviewed-by: DJ Delorie <dj@redhat.com>
|
||
(cherry picked from commit ad4caba4146583fc543cd434221dec7113c03e09)
|
||
|
||
diff --git a/malloc/malloc.c b/malloc/malloc.c
|
||
index cf5c02ff64..b89b654f17 100644
|
||
--- a/malloc/malloc.c
|
||
+++ b/malloc/malloc.c
|
||
@@ -294,9 +294,9 @@
|
||
# define TCACHE_SMALL_BINS 64
|
||
# define TCACHE_LARGE_BINS 12 /* Up to 4M chunks */
|
||
# define TCACHE_MAX_BINS (TCACHE_SMALL_BINS + TCACHE_LARGE_BINS)
|
||
-# define MAX_TCACHE_SMALL_SIZE tidx2usize (TCACHE_SMALL_BINS-1)
|
||
+# define MAX_TCACHE_SMALL_SIZE tidx2csize (TCACHE_SMALL_BINS-1)
|
||
|
||
-/* Only used to pre-fill the tunables. */
|
||
+# define tidx2csize(idx) (((size_t) idx) * MALLOC_ALIGNMENT + MINSIZE)
|
||
# define tidx2usize(idx) (((size_t) idx) * MALLOC_ALIGNMENT + MINSIZE - SIZE_SZ)
|
||
|
||
/* When "x" is from chunksize(). */
|
||
@@ -1932,7 +1932,7 @@ static struct malloc_par mp_ =
|
||
,
|
||
.tcache_count = TCACHE_FILL_COUNT,
|
||
.tcache_small_bins = TCACHE_SMALL_BINS,
|
||
- .tcache_max_bytes = MAX_TCACHE_SMALL_SIZE,
|
||
+ .tcache_max_bytes = MAX_TCACHE_SMALL_SIZE + 1,
|
||
.tcache_unsorted_limit = 0 /* No limit. */
|
||
#endif
|
||
};
|
||
@@ -5586,15 +5586,13 @@ do_set_arena_max (size_t value)
|
||
static __always_inline int
|
||
do_set_tcache_max (size_t value)
|
||
{
|
||
+ if (value > PTRDIFF_MAX)
|
||
+ return 0;
|
||
+
|
||
size_t nb = request2size (value);
|
||
size_t tc_idx = csize2tidx (nb);
|
||
|
||
- /* To check that value is not too big and request2size does not return an
|
||
- overflown value. */
|
||
- if (value > nb)
|
||
- return 0;
|
||
-
|
||
- if (nb > MAX_TCACHE_SMALL_SIZE)
|
||
+ if (tc_idx >= TCACHE_SMALL_BINS)
|
||
tc_idx = large_csize2tidx (nb);
|
||
|
||
LIBC_PROBE (memory_tunable_tcache_max_bytes, 2, value, mp_.tcache_max_bytes);
|
||
@@ -5603,7 +5601,7 @@ do_set_tcache_max (size_t value)
|
||
{
|
||
if (tc_idx < TCACHE_SMALL_BINS)
|
||
mp_.tcache_small_bins = tc_idx + 1;
|
||
- mp_.tcache_max_bytes = nb;
|
||
+ mp_.tcache_max_bytes = nb + 1;
|
||
return 1;
|
||
}
|
||
|
||
|
||
commit a96a82c4a5efd3139e75cd11fd2a5554164dd5a0
|
||
Author: Samuel Thibault <samuel.thibault@ens-lyon.org>
|
||
Date: Wed Jul 30 01:55:22 2025 +0200
|
||
|
||
malloc: Make sure tcache_key is odd enough
|
||
|
||
We want tcache_key not to be a commonly-occurring value in memory, so ensure
|
||
a minimum amount of one and zero bits.
|
||
|
||
And we need it non-zero, otherwise even if tcache_double_free_verify sets
|
||
e->key to 0 before calling __libc_free, it gets called again by __libc_free,
|
||
thus looping indefinitely.
|
||
|
||
Fixes: c968fe50628db74b52124d863cd828225a1d305c ("malloc: Use tailcalls in __libc_free")
|
||
(cherry picked from commit 2536c4f8584082a1ac4c5e0a2a6222e290d43983)
|
||
|
||
diff --git a/malloc/malloc.c b/malloc/malloc.c
|
||
index b89b654f17..e4e2f03600 100644
|
||
--- a/malloc/malloc.c
|
||
+++ b/malloc/malloc.c
|
||
@@ -230,6 +230,9 @@
|
||
/* For uintptr_t. */
|
||
#include <stdint.h>
|
||
|
||
+/* For stdc_count_ones. */
|
||
+#include <stdbit.h>
|
||
+
|
||
/* For va_arg, va_start, va_end. */
|
||
#include <stdarg.h>
|
||
|
||
@@ -3152,6 +3155,19 @@ tcache_key_initialize (void)
|
||
if (__getrandom_nocancel_nostatus_direct (&tcache_key, sizeof(tcache_key),
|
||
GRND_NONBLOCK)
|
||
!= sizeof (tcache_key))
|
||
+ tcache_key = 0;
|
||
+
|
||
+ /* We need tcache_key to be non-zero (otherwise tcache_double_free_verify's
|
||
+ clearing of e->key would go unnoticed and it would loop getting called
|
||
+ through __libc_free), and we want tcache_key not to be a
|
||
+ commonly-occurring value in memory, so ensure a minimum amount of one and
|
||
+ zero bits. */
|
||
+ int minimum_bits = __WORDSIZE / 4;
|
||
+ int maximum_bits = __WORDSIZE - minimum_bits;
|
||
+
|
||
+ while (labs (tcache_key) <= 0x1000000
|
||
+ || stdc_count_ones (tcache_key) < minimum_bits
|
||
+ || stdc_count_ones (tcache_key) > maximum_bits)
|
||
{
|
||
tcache_key = random_bits ();
|
||
#if __WORDSIZE == 64
|
||
|
||
commit d7274d718e6f3655eabe311d4eb70fabb5ffa7ef
|
||
Author: Samuel Thibault <samuel.thibault@ens-lyon.org>
|
||
Date: Sun Aug 10 23:43:37 2025 +0200
|
||
|
||
malloc: Fix checking for small negative values of tcache_key
|
||
|
||
tcache_key is unsigned so we should turn it explicitly to signed before
|
||
taking its absolute value.
|
||
|
||
(cherry picked from commit 8543577b04ded6d979ffcc5a818930e4d74d0645)
|
||
|
||
diff --git a/malloc/malloc.c b/malloc/malloc.c
|
||
index e4e2f03600..5f3e701fd1 100644
|
||
--- a/malloc/malloc.c
|
||
+++ b/malloc/malloc.c
|
||
@@ -3165,7 +3165,7 @@ tcache_key_initialize (void)
|
||
int minimum_bits = __WORDSIZE / 4;
|
||
int maximum_bits = __WORDSIZE - minimum_bits;
|
||
|
||
- while (labs (tcache_key) <= 0x1000000
|
||
+ while (labs ((intptr_t) tcache_key) <= 0x1000000
|
||
|| stdc_count_ones (tcache_key) < minimum_bits
|
||
|| stdc_count_ones (tcache_key) > maximum_bits)
|
||
{
|
||
|
||
commit 8dbaecbe92ac7ab73b7d0aae84626af59131e41b
|
||
Author: Jens Remus <jremus@linux.ibm.com>
|
||
Date: Fri Jul 25 15:40:03 2025 +0200
|
||
|
||
Use TLS initial-exec model for __libc_tsd_CTYPE_* thread variables [BZ #33234]
|
||
|
||
Commit 10a66a8e421b ("Remove <libc-tsd.h>") removed the TLS initial-exec
|
||
(IE) model attribute from the __libc_tsd_CTYPE_* thread variable declarations
|
||
and definitions. Commit a894f04d8776 ("Optimize __libc_tsd_* thread
|
||
variable access") restored it on declarations.
|
||
|
||
Restore the TLS initial-exec model attribute on __libc_tsd_CTYPE_* thread
|
||
variable definitions.
|
||
|
||
This resolves test tst-locale1 failure on s390 32-bit, when using a
|
||
GNU linker without the fix from GNU binutils commit aefebe82dc89
|
||
("IBM zSystems: Fix offset relative to static TLS").
|
||
|
||
Reviewed-by: Florian Weimer <fweimer@redhat.com>
|
||
(cherry picked from commit e5363e6f460c2d58809bf10fc96d70fd1ef8b5b2)
|
||
|
||
diff --git a/NEWS b/NEWS
|
||
index 1d04bdfef8..69aa600c6d 100644
|
||
--- a/NEWS
|
||
+++ b/NEWS
|
||
@@ -11,6 +11,7 @@ The following bugs were resolved with this release:
|
||
|
||
[31943] _dl_find_object can fail if ld.so contains gaps between load segments
|
||
[32994] stdlib: resolve a double lock init issue after fork
|
||
+ [33234] Use TLS initial-exec model for __libc_tsd_CTYPE_* thread variables
|
||
[33245] nptl: nptl: error in internal cancellation syscall handling
|
||
|
||
Version 2.42
|
||
diff --git a/ctype/ctype-info.c b/ctype/ctype-info.c
|
||
index b7d3422726..fb5acf9419 100644
|
||
--- a/ctype/ctype-info.c
|
||
+++ b/ctype/ctype-info.c
|
||
@@ -24,11 +24,11 @@
|
||
__ctype_init before user code runs, but this does not happen for
|
||
threads in secondary namespaces. With the initializers, secondary
|
||
namespaces at least get locale data from the C locale. */
|
||
-__thread const uint16_t * __libc_tsd_CTYPE_B
|
||
+__thread const uint16_t * __libc_tsd_CTYPE_B attribute_tls_model_ie
|
||
= (const uint16_t *) _nl_C_LC_CTYPE_class + 128;
|
||
-__thread const int32_t * __libc_tsd_CTYPE_TOLOWER
|
||
+__thread const int32_t * __libc_tsd_CTYPE_TOLOWER attribute_tls_model_ie
|
||
= (const int32_t *) _nl_C_LC_CTYPE_tolower + 128;
|
||
-__thread const int32_t * __libc_tsd_CTYPE_TOUPPER
|
||
+__thread const int32_t * __libc_tsd_CTYPE_TOUPPER attribute_tls_model_ie
|
||
= (const int32_t *) _nl_C_LC_CTYPE_toupper + 128;
|
||
|
||
|
||
|
||
commit d0f72b96f2e91e1aa93f7e826c71f74078ada7d0
|
||
Author: H.J. Lu <hjl.tools@gmail.com>
|
||
Date: Mon Jul 28 12:16:11 2025 -0700
|
||
|
||
i386: Add GLIBC_ABI_GNU_TLS version [BZ #33221]
|
||
|
||
On i386, programs and shared libraries with __thread usage may fail
|
||
silently at run-time against glibc without the TLS run-time fix for:
|
||
|
||
https://sourceware.org/bugzilla/show_bug.cgi?id=32996
|
||
|
||
Add GLIBC_ABI_GNU_TLS version to indicate that glibc has the working
|
||
GNU TLS run-time. Linker can add the GLIBC_ABI_GNU_TLS version to
|
||
binaries which depend on the working TLS run-time so that such programs
|
||
and shared libraries will fail to load and run at run-time against
|
||
libc.so without the GLIBC_ABI_GNU_TLS version, instead of fail silently
|
||
at random.
|
||
|
||
This fixes BZ #33221.
|
||
|
||
Signed-off-by: H.J. Lu <hjl.tools@gmail.com>
|
||
Reviewed-by: Sam James <sam@gentoo.org>
|
||
(cherry picked from commit ed1b7a5a489ab555a27fad9c101ebe2e1c1ba881)
|
||
|
||
diff --git a/sysdeps/i386/Makefile b/sysdeps/i386/Makefile
|
||
index ee6470d78e..c0c017b899 100644
|
||
--- a/sysdeps/i386/Makefile
|
||
+++ b/sysdeps/i386/Makefile
|
||
@@ -60,6 +60,15 @@ $(objpfx)tst-ld-sse-use.out: ../sysdeps/i386/tst-ld-sse-use.sh $(objpfx)ld.so
|
||
@echo "Checking ld.so for SSE register use. This will take a few seconds..."
|
||
$(BASH) $< $(objpfx) '$(NM)' '$(OBJDUMP)' '$(READELF)' > $@; \
|
||
$(evaluate-test)
|
||
+
|
||
+tests-special += $(objpfx)check-gnu-tls.out
|
||
+
|
||
+$(objpfx)check-gnu-tls.out: $(common-objpfx)libc.so
|
||
+ LC_ALL=C $(READELF) -V -W $< \
|
||
+ | sed -ne '/.gnu.version_d/, /.gnu.version_r/ p' \
|
||
+ | grep GLIBC_ABI_GNU_TLS > $@; \
|
||
+ $(evaluate-test)
|
||
+generated += check-gnu-tls.out
|
||
else
|
||
CFLAGS-.os += $(if $(filter rtld-%.os,$(@F)), $(rtld-CFLAGS))
|
||
endif
|
||
diff --git a/sysdeps/i386/Versions b/sysdeps/i386/Versions
|
||
index 36e23b466a..9c84c8ef04 100644
|
||
--- a/sysdeps/i386/Versions
|
||
+++ b/sysdeps/i386/Versions
|
||
@@ -28,6 +28,11 @@ libc {
|
||
GLIBC_2.13 {
|
||
__fentry__;
|
||
}
|
||
+ GLIBC_ABI_GNU_TLS {
|
||
+ # This symbol is used only for empty version map and will be removed
|
||
+ # by scripts/versions.awk.
|
||
+ __placeholder_only_for_empty_version_map;
|
||
+ }
|
||
}
|
||
libm {
|
||
GLIBC_2.1 {
|
||
|
||
commit 3970785bebcc3f1de4460072f3a041d178f64846
|
||
Author: H.J. Lu <hjl.tools@gmail.com>
|
||
Date: Mon Jul 28 12:18:22 2025 -0700
|
||
|
||
x86-64: Add GLIBC_ABI_GNU2_TLS version [BZ #33129]
|
||
|
||
Programs and shared libraries compiled with -mtls-dialect=gnu2 may fail
|
||
silently at run-time against glibc without the GNU2 TLS run-time fix
|
||
for:
|
||
|
||
https://sourceware.org/bugzilla/show_bug.cgi?id=31372
|
||
|
||
Add GLIBC_ABI_GNU2_TLS version to indicate that glibc has the working
|
||
GNU2 TLS run-time. Linker can add the GLIBC_ABI_GNU2_TLS version to
|
||
binaries which depend on the working GNU2 TLS run-time:
|
||
|
||
https://sourceware.org/bugzilla/show_bug.cgi?id=33130
|
||
|
||
so that such programs and shared libraries will fail to load and run at
|
||
run-time against libc.so without the GLIBC_ABI_GNU2_TLS version, instead
|
||
of fail silently at random.
|
||
|
||
This fixes BZ #33129.
|
||
|
||
Signed-off-by: H.J. Lu <hjl.tools@gmail.com>
|
||
Reviewed-by: Sam James <sam@gentoo.org>
|
||
(cherry picked from commit 9df8fa397d515dc86ff5565f6c45625e672d539e)
|
||
|
||
diff --git a/sysdeps/x86_64/Makefile b/sysdeps/x86_64/Makefile
|
||
index c3e1065c81..3ab8c1ed0f 100644
|
||
--- a/sysdeps/x86_64/Makefile
|
||
+++ b/sysdeps/x86_64/Makefile
|
||
@@ -212,6 +212,15 @@ LDFLAGS-tst-plt-rewrite2 = -Wl,-z,now
|
||
LDFLAGS-tst-plt-rewritemod2.so = -Wl,-z,now,-z,undefs
|
||
tst-plt-rewrite2-ENV = GLIBC_TUNABLES=glibc.cpu.plt_rewrite=2
|
||
$(objpfx)tst-plt-rewrite2: $(objpfx)tst-plt-rewritemod2.so
|
||
+
|
||
+tests-special += $(objpfx)check-gnu2-tls.out
|
||
+
|
||
+$(objpfx)check-gnu2-tls.out: $(common-objpfx)libc.so
|
||
+ LC_ALL=C $(READELF) -V -W $< \
|
||
+ | sed -ne '/.gnu.version_d/, /.gnu.version_r/ p' \
|
||
+ | grep GLIBC_ABI_GNU2_TLS > $@; \
|
||
+ $(evaluate-test)
|
||
+generated += check-gnu2-tls.out
|
||
endif
|
||
|
||
test-internal-extras += tst-gnu2-tls2mod1
|
||
diff --git a/sysdeps/x86_64/Versions b/sysdeps/x86_64/Versions
|
||
index e94758b236..a63c11bcb2 100644
|
||
--- a/sysdeps/x86_64/Versions
|
||
+++ b/sysdeps/x86_64/Versions
|
||
@@ -5,6 +5,11 @@ libc {
|
||
GLIBC_2.13 {
|
||
__fentry__;
|
||
}
|
||
+ GLIBC_ABI_GNU2_TLS {
|
||
+ # This symbol is used only for empty version map and will be removed
|
||
+ # by scripts/versions.awk.
|
||
+ __placeholder_only_for_empty_version_map;
|
||
+ }
|
||
}
|
||
libm {
|
||
GLIBC_2.1 {
|
||
|
||
commit 7a8f3c6ee4b565a02da4ba0dad9aaeaeed4639ce
|
||
Author: H.J. Lu <hjl.tools@gmail.com>
|
||
Date: Thu Aug 14 07:03:20 2025 -0700
|
||
|
||
x86-64: Add GLIBC_ABI_DT_X86_64_PLT [BZ #33212]
|
||
|
||
When the linker -z mark-plt option is used to add DT_X86_64_PLT,
|
||
DT_X86_64_PLTSZ and DT_X86_64_PLTENT, the r_addend field of the
|
||
R_X86_64_JUMP_SLOT relocation stores the offset of the indirect
|
||
branch instruction. However, glibc versions without the commit:
|
||
|
||
commit f8587a61892cbafd98ce599131bf4f103466f084
|
||
Author: H.J. Lu <hjl.tools@gmail.com>
|
||
Date: Fri May 20 19:21:48 2022 -0700
|
||
|
||
x86-64: Ignore r_addend for R_X86_64_GLOB_DAT/R_X86_64_JUMP_SLOT
|
||
|
||
According to x86-64 psABI, r_addend should be ignored for R_X86_64_GLOB_DAT
|
||
and R_X86_64_JUMP_SLOT. Since linkers always set their r_addends to 0, we
|
||
can ignore their r_addends.
|
||
|
||
Reviewed-by: Fangrui Song <maskray@google.com>
|
||
|
||
won't ignore the r_addend value in the R_X86_64_JUMP_SLOT relocation.
|
||
Such programs and shared libraries will fail at run-time randomly.
|
||
|
||
Add GLIBC_ABI_DT_X86_64_PLT version to indicate that glibc is compatible
|
||
with DT_X86_64_PLT.
|
||
|
||
The linker can add the glibc GLIBC_ABI_DT_X86_64_PLT version dependency
|
||
whenever -z mark-plt is passed to the linker. The resulting programs and
|
||
shared libraries will fail to load at run-time against libc.so without the
|
||
GLIBC_ABI_DT_X86_64_PLT version, instead of fail randomly.
|
||
|
||
This fixes BZ #33212.
|
||
|
||
Signed-off-by: H.J. Lu <hjl.tools@gmail.com>
|
||
Reviewed-by: Sam James <sam@gentoo.org>
|
||
(cherry picked from commit 399384e0c8193e31aea014220ccfa24300ae5938)
|
||
|
||
diff --git a/sysdeps/x86_64/Makefile b/sysdeps/x86_64/Makefile
|
||
index 3ab8c1ed0f..01100597a8 100644
|
||
--- a/sysdeps/x86_64/Makefile
|
||
+++ b/sysdeps/x86_64/Makefile
|
||
@@ -213,6 +213,15 @@ LDFLAGS-tst-plt-rewritemod2.so = -Wl,-z,now,-z,undefs
|
||
tst-plt-rewrite2-ENV = GLIBC_TUNABLES=glibc.cpu.plt_rewrite=2
|
||
$(objpfx)tst-plt-rewrite2: $(objpfx)tst-plt-rewritemod2.so
|
||
|
||
+tests-special += $(objpfx)check-dt-x86-64-plt.out
|
||
+
|
||
+$(objpfx)check-dt-x86-64-plt.out: $(common-objpfx)libc.so
|
||
+ LC_ALL=C $(READELF) -V -W $< \
|
||
+ | sed -ne '/.gnu.version_d/, /.gnu.version_r/ p' \
|
||
+ | grep GLIBC_ABI_DT_X86_64_PLT > $@; \
|
||
+ $(evaluate-test)
|
||
+generated += check-dt-x86-64-plt.out
|
||
+
|
||
tests-special += $(objpfx)check-gnu2-tls.out
|
||
|
||
$(objpfx)check-gnu2-tls.out: $(common-objpfx)libc.so
|
||
diff --git a/sysdeps/x86_64/Versions b/sysdeps/x86_64/Versions
|
||
index a63c11bcb2..0a759029e5 100644
|
||
--- a/sysdeps/x86_64/Versions
|
||
+++ b/sysdeps/x86_64/Versions
|
||
@@ -10,6 +10,11 @@ libc {
|
||
# by scripts/versions.awk.
|
||
__placeholder_only_for_empty_version_map;
|
||
}
|
||
+ GLIBC_ABI_DT_X86_64_PLT {
|
||
+ # This symbol is used only for empty version map and will be removed
|
||
+ # by scripts/versions.awk.
|
||
+ __placeholder_only_for_empty_version_map;
|
||
+ }
|
||
}
|
||
libm {
|
||
GLIBC_2.1 {
|
||
|
||
commit e87844ec42b77363a499ea4da6c4a6ab85eba310
|
||
Author: H.J. Lu <hjl.tools@gmail.com>
|
||
Date: Mon Aug 18 09:06:48 2025 -0700
|
||
|
||
i386: Also add GLIBC_ABI_GNU2_TLS version [BZ #33129]
|
||
|
||
Since the GNU2 TLS run-time bug:
|
||
|
||
https://sourceware.org/bugzilla/show_bug.cgi?id=31372
|
||
|
||
affects both i386 and x86-64, also add GLIBC_ABI_GNU2_TLS version to i386
|
||
to indicate the working GNU2 TLS run-time. For x86-64, the additional
|
||
GNU2 TLS run-time bug fix is needed for
|
||
|
||
https://sourceware.org/bugzilla/show_bug.cgi?id=31501
|
||
|
||
Signed-off-by: H.J. Lu <hjl.tools@gmail.com>
|
||
Reviewed-by: Sam James <sam@gentoo.org>
|
||
(cherry picked from commit bd4628f3f18ac312408782eea450429c6f044860)
|
||
|
||
diff --git a/sysdeps/x86/Makefile b/sysdeps/x86/Makefile
|
||
index 4fbd48e1c8..9e1c8cce85 100644
|
||
--- a/sysdeps/x86/Makefile
|
||
+++ b/sysdeps/x86/Makefile
|
||
@@ -135,6 +135,15 @@ LDFLAGS-tst-tls23 += -rdynamic
|
||
tst-tls23-mod.so-no-z-defs = yes
|
||
|
||
$(objpfx)tst-tls23-mod.so: $(libsupport)
|
||
+
|
||
+tests-special += $(objpfx)check-gnu2-tls.out
|
||
+
|
||
+$(objpfx)check-gnu2-tls.out: $(common-objpfx)libc.so
|
||
+ LC_ALL=C $(READELF) -V -W $< \
|
||
+ | sed -ne '/.gnu.version_d/, /.gnu.version_r/ p' \
|
||
+ | grep GLIBC_ABI_GNU2_TLS > $@; \
|
||
+ $(evaluate-test)
|
||
+generated += check-gnu2-tls.out
|
||
endif
|
||
|
||
ifeq ($(subdir),gmon)
|
||
diff --git a/sysdeps/x86/Versions b/sysdeps/x86/Versions
|
||
index 4b10c4b5d7..e8dcfccbe4 100644
|
||
--- a/sysdeps/x86/Versions
|
||
+++ b/sysdeps/x86/Versions
|
||
@@ -7,4 +7,9 @@ libc {
|
||
GLIBC_2.33 {
|
||
__x86_get_cpuid_feature_leaf;
|
||
}
|
||
+ GLIBC_ABI_GNU2_TLS {
|
||
+ # This symbol is used only for empty version map and will be removed
|
||
+ # by scripts/versions.awk.
|
||
+ __placeholder_only_for_empty_version_map;
|
||
+ }
|
||
}
|
||
diff --git a/sysdeps/x86_64/Makefile b/sysdeps/x86_64/Makefile
|
||
index 01100597a8..fe9f1cdddb 100644
|
||
--- a/sysdeps/x86_64/Makefile
|
||
+++ b/sysdeps/x86_64/Makefile
|
||
@@ -221,15 +221,6 @@ $(objpfx)check-dt-x86-64-plt.out: $(common-objpfx)libc.so
|
||
| grep GLIBC_ABI_DT_X86_64_PLT > $@; \
|
||
$(evaluate-test)
|
||
generated += check-dt-x86-64-plt.out
|
||
-
|
||
-tests-special += $(objpfx)check-gnu2-tls.out
|
||
-
|
||
-$(objpfx)check-gnu2-tls.out: $(common-objpfx)libc.so
|
||
- LC_ALL=C $(READELF) -V -W $< \
|
||
- | sed -ne '/.gnu.version_d/, /.gnu.version_r/ p' \
|
||
- | grep GLIBC_ABI_GNU2_TLS > $@; \
|
||
- $(evaluate-test)
|
||
-generated += check-gnu2-tls.out
|
||
endif
|
||
|
||
test-internal-extras += tst-gnu2-tls2mod1
|
||
diff --git a/sysdeps/x86_64/Versions b/sysdeps/x86_64/Versions
|
||
index 0a759029e5..6a989ad3b3 100644
|
||
--- a/sysdeps/x86_64/Versions
|
||
+++ b/sysdeps/x86_64/Versions
|
||
@@ -5,11 +5,6 @@ libc {
|
||
GLIBC_2.13 {
|
||
__fentry__;
|
||
}
|
||
- GLIBC_ABI_GNU2_TLS {
|
||
- # This symbol is used only for empty version map and will be removed
|
||
- # by scripts/versions.awk.
|
||
- __placeholder_only_for_empty_version_map;
|
||
- }
|
||
GLIBC_ABI_DT_X86_64_PLT {
|
||
# This symbol is used only for empty version map and will be removed
|
||
# by scripts/versions.awk.
|
||
|
||
commit e34453cd6a8c592c325756ff3c7ac0afd3975cb4
|
||
Author: Pierre Blanchard <pierre.blanchard@arm.com>
|
||
Date: Wed Aug 20 17:41:50 2025 +0000
|
||
|
||
AArch64: Fix SVE powf routine [BZ #33299]
|
||
|
||
Fix a bug in predicate logic introduced in last change.
|
||
A slight performance improvement from relying on all true
|
||
predicates during conversion from single to double.
|
||
This fixes BZ #33299.
|
||
|
||
Reviewed-by: Wilco Dijkstra <Wilco.Dijkstra@arm.com>
|
||
(cherry picked from commit aac077645a645bba0d67f3250e82017c539d0f4b)
|
||
|
||
diff --git a/sysdeps/aarch64/fpu/powf_sve.c b/sysdeps/aarch64/fpu/powf_sve.c
|
||
index 7046990aa1..65e9bd29d9 100644
|
||
--- a/sysdeps/aarch64/fpu/powf_sve.c
|
||
+++ b/sysdeps/aarch64/fpu/powf_sve.c
|
||
@@ -223,15 +223,15 @@ sv_powf_core (const svbool_t pg, svuint32_t i, svuint32_t iz, svint32_t k,
|
||
const svbool_t ptrue = svptrue_b64 ();
|
||
|
||
/* Unpack and promote input vectors (pg, y, z, i, k and sign_bias) into two
|
||
- * in order to perform core computation in double precision. */
|
||
+ in order to perform core computation in double precision. */
|
||
const svbool_t pg_lo = svunpklo (pg);
|
||
const svbool_t pg_hi = svunpkhi (pg);
|
||
- svfloat64_t y_lo
|
||
- = svcvt_f64_x (pg, svreinterpret_f32 (svunpklo (svreinterpret_u32 (y))));
|
||
- svfloat64_t y_hi
|
||
- = svcvt_f64_x (pg, svreinterpret_f32 (svunpkhi (svreinterpret_u32 (y))));
|
||
- svfloat64_t z_lo = svcvt_f64_x (pg, svreinterpret_f32 (svunpklo (iz)));
|
||
- svfloat64_t z_hi = svcvt_f64_x (pg, svreinterpret_f32 (svunpkhi (iz)));
|
||
+ svfloat64_t y_lo = svcvt_f64_x (
|
||
+ ptrue, svreinterpret_f32 (svunpklo (svreinterpret_u32 (y))));
|
||
+ svfloat64_t y_hi = svcvt_f64_x (
|
||
+ ptrue, svreinterpret_f32 (svunpkhi (svreinterpret_u32 (y))));
|
||
+ svfloat64_t z_lo = svcvt_f64_x (ptrue, svreinterpret_f32 (svunpklo (iz)));
|
||
+ svfloat64_t z_hi = svcvt_f64_x (ptrue, svreinterpret_f32 (svunpkhi (iz)));
|
||
svuint64_t i_lo = svunpklo (i);
|
||
svuint64_t i_hi = svunpkhi (i);
|
||
svint64_t k_lo = svunpklo (k);
|
||
@@ -312,7 +312,7 @@ svfloat32_t SV_NAME_F2 (pow) (svfloat32_t x, svfloat32_t y, const svbool_t pg)
|
||
(23 - V_POWF_EXP2_TABLE_BITS));
|
||
|
||
/* Compute core in extended precision and return intermediate ylogx results
|
||
- * to handle cases of underflow and underflow in exp. */
|
||
+ to handle cases of underflow and overflow in exp. */
|
||
svfloat32_t ylogx;
|
||
svfloat32_t ret
|
||
= sv_powf_core (yint_or_xpos, i, iz, k, y, sign_bias, &ylogx, d);
|
||
|
||
commit 1166170d95863e5a6f8121a5ca9d97713f524f49
|
||
Author: Florian Weimer <fweimer@redhat.com>
|
||
Date: Fri Sep 5 19:02:57 2025 +0200
|
||
|
||
libio: Define AT_RENAME_* with the same tokens as Linux
|
||
|
||
Linux uses different expressions for the RENAME_* and AT_RENAME_*
|
||
constants. Mirror that in <stdio.h>, so that the macro redefinitions
|
||
do not result in preprocessor warnings.
|
||
|
||
Reviewed-by: Collin Funk <collin.funk1@gmail.com>
|
||
(cherry picked from commit b173557da978a04ac3bdfc0bd3b0e7ac583b44d5)
|
||
|
||
diff --git a/libio/stdio.h b/libio/stdio.h
|
||
index d042b36618..e0e70945fa 100644
|
||
--- a/libio/stdio.h
|
||
+++ b/libio/stdio.h
|
||
@@ -168,11 +168,11 @@ extern int renameat (int __oldfd, const char *__old, int __newfd,
|
||
#ifdef __USE_GNU
|
||
/* Flags for renameat2. */
|
||
# define RENAME_NOREPLACE (1 << 0)
|
||
-# define AT_RENAME_NOREPLACE RENAME_NOREPLACE
|
||
+# define AT_RENAME_NOREPLACE 0x0001
|
||
# define RENAME_EXCHANGE (1 << 1)
|
||
-# define AT_RENAME_EXCHANGE RENAME_EXCHANGE
|
||
+# define AT_RENAME_EXCHANGE 0x0002
|
||
# define RENAME_WHITEOUT (1 << 2)
|
||
-# define AT_RENAME_WHITEOUT RENAME_WHITEOUT
|
||
+# define AT_RENAME_WHITEOUT 0x0004
|
||
|
||
/* Rename file OLD relative to OLDFD to NEW relative to NEWFD, with
|
||
additional flags. */
|
||
diff --git a/stdio-common/tst-renameat2.c b/stdio-common/tst-renameat2.c
|
||
index 12aa0f8b0f..6213e1376d 100644
|
||
--- a/stdio-common/tst-renameat2.c
|
||
+++ b/stdio-common/tst-renameat2.c
|
||
@@ -28,6 +28,12 @@
|
||
#include <support/xunistd.h>
|
||
#include <unistd.h>
|
||
|
||
+/* These constants are defined with different token sequences,
|
||
+ matching the Linux definitions, to avoid preprocessor warnings. */
|
||
+_Static_assert (RENAME_NOREPLACE == AT_RENAME_NOREPLACE, "RENAME_NOREPLACE");
|
||
+_Static_assert (RENAME_EXCHANGE == AT_RENAME_EXCHANGE, "RENAME_EXCHANGE");
|
||
+_Static_assert (RENAME_WHITEOUT == AT_RENAME_WHITEOUT, "RENAME_WHITEOUT");
|
||
+
|
||
/* Directory with the temporary files. */
|
||
static char *directory;
|
||
static int directory_fd;
|
||
|
||
commit 46b4e37c9e0619d0cf065ba207c29996b326a06f
|
||
Author: Florian Weimer <fweimer@redhat.com>
|
||
Date: Fri Sep 12 21:33:34 2025 +0200
|
||
|
||
nss: Group merge does not react to ERANGE during merge (bug 33361)
|
||
|
||
The break statement in CHECK_MERGE is expected to exit the surrounding
|
||
while loop, not the do-while loop with in the macro. Remove the
|
||
do-while loop from the macro. It is not needed to turn the macro
|
||
expansion into a single statement due to the way CHECK_MERGE is used
|
||
(and the statement expression would cover this anyway).
|
||
|
||
Reviewed-by: Collin Funk <collin.funk1@gmail.com>
|
||
(cherry picked from commit 0fceed254559836b57ee05188deac649bc505d05)
|
||
|
||
diff --git a/NEWS b/NEWS
|
||
index 69aa600c6d..06c27a8e17 100644
|
||
--- a/NEWS
|
||
+++ b/NEWS
|
||
@@ -13,6 +13,7 @@ The following bugs were resolved with this release:
|
||
[32994] stdlib: resolve a double lock init issue after fork
|
||
[33234] Use TLS initial-exec model for __libc_tsd_CTYPE_* thread variables
|
||
[33245] nptl: nptl: error in internal cancellation syscall handling
|
||
+ [33361] nss: Group merge does not react to ERANGE during merge
|
||
|
||
Version 2.42
|
||
|
||
diff --git a/nss/getXXbyYY_r.c b/nss/getXXbyYY_r.c
|
||
index eae6c3480e..2b0735fb6a 100644
|
||
--- a/nss/getXXbyYY_r.c
|
||
+++ b/nss/getXXbyYY_r.c
|
||
@@ -157,19 +157,15 @@ __merge_einval (LOOKUP_TYPE *a,
|
||
|
||
#define CHECK_MERGE(err, status) \
|
||
({ \
|
||
- do \
|
||
+ if (err) \
|
||
{ \
|
||
- if (err) \
|
||
- { \
|
||
- __set_errno (err); \
|
||
- if (err == ERANGE) \
|
||
- status = NSS_STATUS_TRYAGAIN; \
|
||
- else \
|
||
- status = NSS_STATUS_UNAVAIL; \
|
||
- break; \
|
||
- } \
|
||
+ __set_errno (err); \
|
||
+ if (err == ERANGE) \
|
||
+ status = NSS_STATUS_TRYAGAIN; \
|
||
+ else \
|
||
+ status = NSS_STATUS_UNAVAIL; \
|
||
+ break; \
|
||
} \
|
||
- while (0); \
|
||
})
|
||
|
||
/* Type of the lookup function we need here. */
|
||
|
||
commit 18fd689cdced8348e42991964557cddea0ba2dc5
|
||
Author: Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
||
Date: Mon Sep 8 13:06:13 2025 -0300
|
||
|
||
nptl: Fix MADV_GUARD_INSTALL logic for thread without guard page (BZ 33356)
|
||
|
||
The main issue is that setup_stack_prot fails to account for cases where
|
||
the cached thread stack lacks a guard page, which can cause madvise to
|
||
fail. Update the logic to also handle whether MADV_GUARD_INSTALL is
|
||
supported when resizing the guard page.
|
||
|
||
Checked on x86_64-linux-gnu with 6.8.0 and 6.15 kernels.
|
||
|
||
Reviewed-by: Florian Weimer <fweimer@redhat.com>
|
||
(cherry picked from commit 855bfa2566bbefefa27c516b344df58a75824a5c)
|
||
|
||
diff --git a/NEWS b/NEWS
|
||
index 06c27a8e17..ed3c114c7a 100644
|
||
--- a/NEWS
|
||
+++ b/NEWS
|
||
@@ -13,6 +13,8 @@ The following bugs were resolved with this release:
|
||
[32994] stdlib: resolve a double lock init issue after fork
|
||
[33234] Use TLS initial-exec model for __libc_tsd_CTYPE_* thread variables
|
||
[33245] nptl: nptl: error in internal cancellation syscall handling
|
||
+ [33356] nptl: creating thread stack with guardsize 0 can erroneously
|
||
+ conclude MADV_GUARD_INSTALL is available
|
||
[33361] nss: Group merge does not react to ERANGE during merge
|
||
|
||
Version 2.42
|
||
diff --git a/nptl/allocatestack.c b/nptl/allocatestack.c
|
||
index 800ca89720..fb8a60a21d 100644
|
||
--- a/nptl/allocatestack.c
|
||
+++ b/nptl/allocatestack.c
|
||
@@ -240,7 +240,7 @@ setup_stack_prot (char *mem, size_t size, struct pthread *pd,
|
||
/* Update the guard area of the thread stack MEM of size SIZE with the new
|
||
GUARDISZE. It uses the method defined by PD stack_mode. */
|
||
static inline bool
|
||
-adjust_stack_prot (char *mem, size_t size, const struct pthread *pd,
|
||
+adjust_stack_prot (char *mem, size_t size, struct pthread *pd,
|
||
size_t guardsize, size_t pagesize_m1)
|
||
{
|
||
/* The required guard area is larger than the current one. For
|
||
@@ -258,11 +258,23 @@ adjust_stack_prot (char *mem, size_t size, const struct pthread *pd,
|
||
so use the new guard placement with the new size. */
|
||
if (guardsize > pd->guardsize)
|
||
{
|
||
+ /* There was no need to previously setup a guard page, so we need
|
||
+ to check whether the kernel supports guard advise. */
|
||
char *guard = guard_position (mem, size, guardsize, pd, pagesize_m1);
|
||
- if (pd->stack_mode == ALLOCATE_GUARD_MADV_GUARD)
|
||
- return __madvise (guard, guardsize, MADV_GUARD_INSTALL) == 0;
|
||
- else if (pd->stack_mode == ALLOCATE_GUARD_PROT_NONE)
|
||
- return __mprotect (guard, guardsize, PROT_NONE) == 0;
|
||
+ if (atomic_load_relaxed (&allocate_stack_mode)
|
||
+ == ALLOCATE_GUARD_MADV_GUARD)
|
||
+ {
|
||
+ if (__madvise (guard, guardsize, MADV_GUARD_INSTALL) == 0)
|
||
+ {
|
||
+ pd->stack_mode = ALLOCATE_GUARD_MADV_GUARD;
|
||
+ return true;
|
||
+ }
|
||
+ atomic_store_relaxed (&allocate_stack_mode,
|
||
+ ALLOCATE_GUARD_PROT_NONE);
|
||
+ }
|
||
+
|
||
+ pd->stack_mode = ALLOCATE_GUARD_PROT_NONE;
|
||
+ return __mprotect (guard, guardsize, PROT_NONE) == 0;
|
||
}
|
||
/* The current guard area is larger than the required one. For
|
||
_STACK_GROWS_DOWN is means change the guard as:
|
||
diff --git a/nptl/tst-guard1.c b/nptl/tst-guard1.c
|
||
index e3e06df0fc..1c73d3fc93 100644
|
||
--- a/nptl/tst-guard1.c
|
||
+++ b/nptl/tst-guard1.c
|
||
@@ -21,6 +21,7 @@
|
||
#include <setjmp.h>
|
||
#include <stackinfo.h>
|
||
#include <stdio.h>
|
||
+#include <support/capture_subprocess.h>
|
||
#include <support/check.h>
|
||
#include <support/test-driver.h>
|
||
#include <support/xsignal.h>
|
||
@@ -202,7 +203,7 @@ tf (void *closure)
|
||
|
||
/* Test 1: caller provided stack without guard. */
|
||
static void
|
||
-do_test1 (void)
|
||
+do_test1 (void *closure)
|
||
{
|
||
pthread_attr_t attr;
|
||
xpthread_attr_init (&attr);
|
||
@@ -227,7 +228,7 @@ do_test1 (void)
|
||
|
||
/* Test 2: same as 1., but with a guard area. */
|
||
static void
|
||
-do_test2 (void)
|
||
+do_test2 (void *closure)
|
||
{
|
||
pthread_attr_t attr;
|
||
xpthread_attr_init (&attr);
|
||
@@ -250,18 +251,9 @@ do_test2 (void)
|
||
xmunmap (stack, stacksize);
|
||
}
|
||
|
||
-/* Test 3: pthread_create with default values. */
|
||
+/* Test 3: pthread_create without a guard area. */
|
||
static void
|
||
-do_test3 (void)
|
||
-{
|
||
- pthread_t t = xpthread_create (NULL, tf, NULL);
|
||
- void *status = xpthread_join (t);
|
||
- TEST_VERIFY (status == 0);
|
||
-}
|
||
-
|
||
-/* Test 4: pthread_create without a guard area. */
|
||
-static void
|
||
-do_test4 (void)
|
||
+do_test3 (void *closure)
|
||
{
|
||
pthread_attr_t attr;
|
||
xpthread_attr_init (&attr);
|
||
@@ -277,9 +269,18 @@ do_test4 (void)
|
||
xpthread_attr_destroy (&attr);
|
||
}
|
||
|
||
+/* Test 4: pthread_create with default values. */
|
||
+static void
|
||
+do_test4 (void *closure)
|
||
+{
|
||
+ pthread_t t = xpthread_create (NULL, tf, NULL);
|
||
+ void *status = xpthread_join (t);
|
||
+ TEST_VERIFY (status == 0);
|
||
+}
|
||
+
|
||
/* Test 5: pthread_create with non default stack and guard size value. */
|
||
static void
|
||
-do_test5 (void)
|
||
+do_test5 (void *closure)
|
||
{
|
||
pthread_attr_t attr;
|
||
xpthread_attr_init (&attr);
|
||
@@ -299,7 +300,7 @@ do_test5 (void)
|
||
test 3, but with a larger guard area. The pthread_create will need to
|
||
increase the guard area. */
|
||
static void
|
||
-do_test6 (void)
|
||
+do_test6 (void *closure)
|
||
{
|
||
pthread_attr_t attr;
|
||
xpthread_attr_init (&attr);
|
||
@@ -320,7 +321,7 @@ do_test6 (void)
|
||
pthread_create should use the cached stack from previous tests, but it
|
||
would require to reduce the guard area. */
|
||
static void
|
||
-do_test7 (void)
|
||
+do_test7 (void *closure)
|
||
{
|
||
pthread_t t = xpthread_create (NULL, tf, NULL);
|
||
void *status = xpthread_join (t);
|
||
@@ -346,21 +347,40 @@ do_test (void)
|
||
|
||
static const struct {
|
||
const char *descr;
|
||
- void (*test)(void);
|
||
+ void (*test) (void *);
|
||
} tests[] = {
|
||
{ "user provided stack without guard", do_test1 },
|
||
{ "user provided stack with guard", do_test2 },
|
||
- { "default attribute", do_test3 },
|
||
- { "default attribute without guard", do_test4 },
|
||
+ /* N.B: do_test3 should be before do_test4 to check if a new thread
|
||
+ that uses the thread stack previously allocated without a guard
|
||
+ page correctly sets up the guard pages even on a kernel without
|
||
+ MADV_GUARD_INSTALL support (BZ 33356). */
|
||
+ { "default attribute without guard", do_test3 },
|
||
+ { "default attribute", do_test4 },
|
||
+ /* Also checks if the guard is correctly removed from the cache thread
|
||
+ stack. */
|
||
+ { "default attribute without guard", do_test3 },
|
||
{ "non default stack and guard sizes", do_test5 },
|
||
{ "reused stack with larger guard", do_test6 },
|
||
{ "reused stack with smaller guard", do_test7 },
|
||
};
|
||
|
||
+ /* Run each test with a clean state. */
|
||
+ for (int i = 0; i < array_length (tests); i++)
|
||
+ {
|
||
+ printf ("debug: fork: test%01d: %s\n", i, tests[i].descr);
|
||
+ struct support_capture_subprocess result =
|
||
+ support_capture_subprocess (tests[i].test, NULL);
|
||
+ support_capture_subprocess_check (&result, tests[i].descr, 0,
|
||
+ sc_allow_none);
|
||
+ support_capture_subprocess_free (&result);
|
||
+ }
|
||
+
|
||
+ /* And now run the same tests along with the thread stack cache. */
|
||
for (int i = 0; i < array_length (tests); i++)
|
||
{
|
||
printf ("debug: test%01d: %s\n", i, tests[i].descr);
|
||
- tests[i].test();
|
||
+ tests[i].test ( NULL);
|
||
}
|
||
|
||
return 0;
|
||
|
||
commit bf48b17a28066a54f172e0d63da9fc5dc60c6355
|
||
Author: Sunil K Pandey <sunil.k.pandey@intel.com>
|
||
Date: Mon Oct 6 18:13:04 2025 -0700
|
||
|
||
x86: Detect Intel Wildcat Lake Processor
|
||
|
||
Detect Intel Wildcat Lake Processor and tune it similar to Intel Panther
|
||
Lake. https://cdrdv2.intel.com/v1/dl/getContent/671368 Section 1.2.
|
||
|
||
Reviewed-by: H.J. Lu <hjl.tools@gmail.com>
|
||
(cherry picked from commit f8dd52901b72805a831d5a4cb7d971e4a3c9970b)
|
||
|
||
diff --git a/sysdeps/x86/cpu-features.c b/sysdeps/x86/cpu-features.c
|
||
index b7d1506135..4bdade883e 100644
|
||
--- a/sysdeps/x86/cpu-features.c
|
||
+++ b/sysdeps/x86/cpu-features.c
|
||
@@ -543,6 +543,7 @@ enum intel_microarch
|
||
INTEL_BIGCORE_PANTHERLAKE,
|
||
INTEL_BIGCORE_GRANITERAPIDS,
|
||
INTEL_BIGCORE_DIAMONDRAPIDS,
|
||
+ INTEL_BIGCORE_WILDCATLAKE,
|
||
|
||
/* Mixed (bigcore + atom SOC). */
|
||
INTEL_MIXED_LAKEFIELD,
|
||
@@ -702,6 +703,8 @@ intel_get_fam6_microarch (unsigned int model,
|
||
return INTEL_BIGCORE_ARROWLAKE;
|
||
case 0xCC:
|
||
return INTEL_BIGCORE_PANTHERLAKE;
|
||
+ case 0xD5:
|
||
+ return INTEL_BIGCORE_WILDCATLAKE;
|
||
case 0xAD:
|
||
case 0xAE:
|
||
return INTEL_BIGCORE_GRANITERAPIDS;
|
||
@@ -934,6 +937,7 @@ disable_tsx:
|
||
case INTEL_BIGCORE_LUNARLAKE:
|
||
case INTEL_BIGCORE_ARROWLAKE:
|
||
case INTEL_BIGCORE_PANTHERLAKE:
|
||
+ case INTEL_BIGCORE_WILDCATLAKE:
|
||
case INTEL_BIGCORE_SAPPHIRERAPIDS:
|
||
case INTEL_BIGCORE_EMERALDRAPIDS:
|
||
case INTEL_BIGCORE_GRANITERAPIDS:
|
||
|
||
commit ab8c1b5d62d7be2c3c23f535bea3d7fff19c53ae
|
||
Author: Sunil K Pandey <sunil.k.pandey@intel.com>
|
||
Date: Wed Sep 24 09:38:17 2025 -0700
|
||
|
||
x86: Detect Intel Nova Lake Processor
|
||
|
||
Detect Intel Nova Lake Processor and tune it similar to Intel Panther
|
||
Lake. https://cdrdv2.intel.com/v1/dl/getContent/671368 Section 1.2.
|
||
|
||
Reviewed-by: H.J. Lu <hjl.tools@gmail.com>
|
||
(cherry picked from commit a114e29ddd530962d2b44aa9d89f1f6075abe7fa)
|
||
|
||
diff --git a/sysdeps/x86/cpu-features.c b/sysdeps/x86/cpu-features.c
|
||
index 4bdade883e..b67ef541dd 100644
|
||
--- a/sysdeps/x86/cpu-features.c
|
||
+++ b/sysdeps/x86/cpu-features.c
|
||
@@ -544,6 +544,7 @@ enum intel_microarch
|
||
INTEL_BIGCORE_GRANITERAPIDS,
|
||
INTEL_BIGCORE_DIAMONDRAPIDS,
|
||
INTEL_BIGCORE_WILDCATLAKE,
|
||
+ INTEL_BIGCORE_NOVALAKE,
|
||
|
||
/* Mixed (bigcore + atom SOC). */
|
||
INTEL_MIXED_LAKEFIELD,
|
||
@@ -821,6 +822,17 @@ disable_tsx:
|
||
break;
|
||
}
|
||
}
|
||
+ else if (family == 18)
|
||
+ switch (model)
|
||
+ {
|
||
+ case 0x01:
|
||
+ case 0x03:
|
||
+ microarch = INTEL_BIGCORE_NOVALAKE;
|
||
+ break;
|
||
+
|
||
+ default:
|
||
+ break;
|
||
+ }
|
||
else if (family == 19)
|
||
switch (model)
|
||
{
|
||
@@ -938,6 +950,7 @@ disable_tsx:
|
||
case INTEL_BIGCORE_ARROWLAKE:
|
||
case INTEL_BIGCORE_PANTHERLAKE:
|
||
case INTEL_BIGCORE_WILDCATLAKE:
|
||
+ case INTEL_BIGCORE_NOVALAKE:
|
||
case INTEL_BIGCORE_SAPPHIRERAPIDS:
|
||
case INTEL_BIGCORE_EMERALDRAPIDS:
|
||
case INTEL_BIGCORE_GRANITERAPIDS:
|
||
|
||
commit 6de12fc9ad56bc19fa6fcbd8ee502f29b5170d47
|
||
Author: Yury Khrustalev <yury.khrustalev@arm.com>
|
||
Date: Thu Sep 25 15:51:30 2025 +0100
|
||
|
||
aarch64: define macro for calling __libc_arm_za_disable
|
||
|
||
A common sequence of instructions is used in several places
|
||
in assembly files, so define it in one place as an assembly
|
||
macro.
|
||
|
||
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
||
(cherry picked from commit b4b713bd8921aff04773557da94fabb5fb9dd705)
|
||
|
||
diff --git a/sysdeps/aarch64/__longjmp.S b/sysdeps/aarch64/__longjmp.S
|
||
index 70ac02c44b..53b42e1bdc 100644
|
||
--- a/sysdeps/aarch64/__longjmp.S
|
||
+++ b/sysdeps/aarch64/__longjmp.S
|
||
@@ -26,16 +26,8 @@
|
||
ENTRY (__longjmp)
|
||
|
||
#if IS_IN(libc)
|
||
- /* Disable ZA state of SME in libc.a and libc.so, but not in ld.so.
|
||
- The calling convention of __libc_arm_za_disable allows to do
|
||
- this thus allowing to avoid saving to and reading from stack.
|
||
- As a result we also don't need to sign the return address and
|
||
- check it after returning because it is not stored to stack. */
|
||
- mov x13, x30
|
||
- cfi_register (x30, x13)
|
||
- bl __libc_arm_za_disable
|
||
- mov x30, x13
|
||
- cfi_register (x13, x30)
|
||
+ /* Disable ZA state of SME in libc.a and libc.so, but not in ld.so. */
|
||
+ CALL_LIBC_ARM_ZA_DISABLE
|
||
#endif
|
||
|
||
cfi_def_cfa (x0, 0)
|
||
diff --git a/sysdeps/aarch64/setjmp.S b/sysdeps/aarch64/setjmp.S
|
||
index 53c5e7d8cc..92cedfad83 100644
|
||
--- a/sysdeps/aarch64/setjmp.S
|
||
+++ b/sysdeps/aarch64/setjmp.S
|
||
@@ -37,16 +37,8 @@ ENTRY_ALIGN (__sigsetjmp, 2)
|
||
1:
|
||
|
||
#if IS_IN(libc)
|
||
- /* Disable ZA state of SME in libc.a and libc.so, but not in ld.so.
|
||
- The calling convention of __libc_arm_za_disable allows to do
|
||
- this thus allowing to avoid saving to and reading from stack.
|
||
- As a result we also don't need to sign the return address and
|
||
- check it after returning because it is not stored to stack. */
|
||
- mov x13, x30
|
||
- cfi_register (x30, x13)
|
||
- bl __libc_arm_za_disable
|
||
- mov x30, x13
|
||
- cfi_register (x13, x30)
|
||
+ /* Disable ZA state of SME in libc.a and libc.so, but not in ld.so. */
|
||
+ CALL_LIBC_ARM_ZA_DISABLE
|
||
#endif
|
||
|
||
stp x19, x20, [x0, #JB_X19<<3]
|
||
diff --git a/sysdeps/unix/sysv/linux/aarch64/setcontext.S b/sysdeps/unix/sysv/linux/aarch64/setcontext.S
|
||
index d9716f012e..8e98594663 100644
|
||
--- a/sysdeps/unix/sysv/linux/aarch64/setcontext.S
|
||
+++ b/sysdeps/unix/sysv/linux/aarch64/setcontext.S
|
||
@@ -49,15 +49,7 @@ ENTRY (__setcontext)
|
||
b C_SYMBOL_NAME (__syscall_error)
|
||
1:
|
||
/* Clear ZA state of SME. */
|
||
- /* The calling convention of __libc_arm_za_disable allows to do
|
||
- this thus allowing to avoid saving to and reading from stack.
|
||
- As a result we also don't need to sign the return address and
|
||
- check it after returning because it is not stored to stack. */
|
||
- mov x13, x30
|
||
- cfi_register (x30, x13)
|
||
- bl __libc_arm_za_disable
|
||
- mov x30, x13
|
||
- cfi_register (x13, x30)
|
||
+ CALL_LIBC_ARM_ZA_DISABLE
|
||
/* Restore the general purpose registers. */
|
||
mov x0, x9
|
||
cfi_def_cfa (x0, 0)
|
||
diff --git a/sysdeps/unix/sysv/linux/aarch64/sysdep.h b/sysdeps/unix/sysv/linux/aarch64/sysdep.h
|
||
index f0e8d64eef..fa01386b25 100644
|
||
--- a/sysdeps/unix/sysv/linux/aarch64/sysdep.h
|
||
+++ b/sysdeps/unix/sysv/linux/aarch64/sysdep.h
|
||
@@ -150,6 +150,18 @@
|
||
mov x8, SYS_ify (syscall_name); \
|
||
svc 0
|
||
|
||
+/* Clear ZA state of SME (ASM version). */
|
||
+/* The __libc_arm_za_disable function has special calling convention
|
||
+ that allows to call it without stack manipulation and preserving
|
||
+ most of the registers. */
|
||
+ .macro CALL_LIBC_ARM_ZA_DISABLE
|
||
+ mov x13, x30
|
||
+ .cfi_register x30, x13
|
||
+ bl __libc_arm_za_disable
|
||
+ mov x30, x13
|
||
+ .cfi_register x13, x30
|
||
+ .endm
|
||
+
|
||
#else /* not __ASSEMBLER__ */
|
||
|
||
# define VDSO_NAME "LINUX_2.6.39"
|
||
|
||
commit 256030b9842a10b1f22851b1de0c119761417544
|
||
Author: Yury Khrustalev <yury.khrustalev@arm.com>
|
||
Date: Thu Sep 25 15:54:36 2025 +0100
|
||
|
||
aarch64: clear ZA state of SME before clone and clone3 syscalls
|
||
|
||
This change adds a call to the __arm_za_disable() function immediately
|
||
before the SVC instruction inside clone() and clone3() wrappers. It also
|
||
adds a macro for inline clone() used in fork() and adds the same call to
|
||
the vfork implementation. This sets the ZA state of SME to "off" on return
|
||
from these functions (for both the child and the parent).
|
||
|
||
The __arm_za_disable() function is described in [1] (8.1.3). Note that
|
||
the internal Glibc name for this function is __libc_arm_za_disable().
|
||
|
||
When this change was originally proposed [2,3], it generated a long
|
||
discussion where several questions and concerns were raised. Here we
|
||
will address these concerns and explain why this change is useful and,
|
||
in fact, necessary.
|
||
|
||
In a nutshell, a C library that conforms to the AAPCS64 spec [1] (pertinent
|
||
to this change, mainly, the chapters 6.2 and 6.6), should have a call to the
|
||
__arm_za_disable() function in clone() and clone3() wrappers. The following
|
||
explains in detail why this is the case.
|
||
|
||
When we consider using the __arm_za_disable() function inside the clone()
|
||
and clone3() libc wrappers, we talk about the C library subroutines clone()
|
||
and clone3() rather than the syscalls with similar names. In the current
|
||
version of Glibc, clone() is public and clone3() is private, but it being
|
||
private is not pertinent to this discussion.
|
||
|
||
We will begin with stating that this change is NOT a bug fix for something
|
||
in the kernel. The requirement to call __arm_za_disable() does NOT come from
|
||
the kernel. It also is NOT needed to satisfy a contract between the kernel
|
||
and userspace. This is why it is not for the kernel documentation to describe
|
||
this requirement. This requirement is instead needed to satisfy a pure userspace
|
||
scheme outlined in [1] and to make sure that software that uses Glibc (or any
|
||
other C library that has correct handling of SME states (see below)) conforms
|
||
to [1] without having to unnecessarily become SME-aware thus losing portability.
|
||
|
||
To recap (see [1] (6.2)), SME extension defines SME state which is part of
|
||
processor state. Part of this SME state is ZA state that is necessary to
|
||
manage ZA storage register in the context of the ZA lazy saving scheme [1]
|
||
(6.6). This scheme exists because it would be challenging to handle ZA
|
||
storage of SME in either callee-saved or caller-saved manner.
|
||
|
||
There are 3 kinds of ZA state that are defined in terms of the PSTATE.ZA
|
||
bit and the TPIDR2_EL0 register (see [1] (6.6.3)):
|
||
|
||
- "off": PSTATE.ZA == 0
|
||
- "active": PSTATE.ZA == 1 TPIDR2_EL0 == null
|
||
- "dormant": PSTATE.ZA == 1 TPIDR2_EL0 != null
|
||
|
||
As [1] (6.7.2) outlines, every subroutine has exactly one SME-interface
|
||
depending on the permitted ZA-states on entry and on normal return from
|
||
a call to this subroutine. Callers of a subroutine must know and respect
|
||
the ZA-interface of the subroutines they are using. Using a subroutine
|
||
in a way that is not permitted by its ZA-interface is undefined behaviour.
|
||
|
||
In particular, clone() and clone3() (the C library functions) have the
|
||
ZA-private interface. This means that the permitted ZA-states on entry
|
||
are "off" and "dormant" and that the permitted states on return are "off"
|
||
or "dormant" (but if and only if it was "dormant" on entry).
|
||
|
||
This means that both functions in question should correctly handle both
|
||
"off" and "dormant" ZA-states on entry. The conforming states on return
|
||
are "off" and "dormant" (if inbound state was already "dormant").
|
||
|
||
This change ensures that the ZA-state on return is always "off". Note,
|
||
that, in the context of clone() and clone3(), "on return" means a point
|
||
when execution resumes at certain address after transferring from clone()
|
||
or clone3(). For the caller (we may refer to it as "parent") this is the
|
||
return address in the link register where the RET instruction jumps. For
|
||
the "child", this is the target branch address.
|
||
|
||
So, the "off" state on return is permitted and conformant. Why can't we
|
||
retain the "dormant" state? In theory, we can, but we shouldn't, here is
|
||
why.
|
||
|
||
Every subroutine with a private-ZA interface, including clone() and clone3(),
|
||
must comply with the lazy saving scheme [1] (6.7.2). This puts additional
|
||
responsibility on a subroutine if ZA-state on return is "dormant" because
|
||
this state has special meaning. The "caller" (that is the place in code
|
||
where execution is transferred to, so this include both "parent" and "child")
|
||
may check the ZA-state and use it as per the spec of the "dormant" state that
|
||
is outlined in [1] (6.6.6 and 6.6.7).
|
||
|
||
Conforming to this would require more code inside of clone() and clone3()
|
||
which hardly is desirable.
|
||
|
||
For the return to "parent" this could be achieved in theory, but given that
|
||
neither clone() nor clone3() are supposed to be used in the middle of an
|
||
SME operation, if wouldn't be useful. For the "return" to "child" this
|
||
would be particularly difficult to achieve given the complexity of these
|
||
functions and their interfaces. Most importantly, it would be illegal
|
||
and somewhat meaningless to allow a "child" to start execution in the
|
||
"dormant" ZA-state because the very essence of the "dormant" state implies
|
||
that there is a place to return and that there is some outer context that
|
||
we are allowed to interact with.
|
||
|
||
To sum up, calling __arm_za_disable() to ensure the "off" ZA-state when the
|
||
execution resumes after a call to clone() or clone3() is correct and also
|
||
the most simple way to conform to [1].
|
||
|
||
Can there be situations when we can avoid calling __arm_za_disable()?
|
||
|
||
Calling __arm_za_disable() implies certain (sufficiently small) overhead,
|
||
so one might rightly ponder avoiding making a call to this function when
|
||
we can afford not to. The most trivial cases like this (e.g. when the
|
||
calling thread doesn't have access to SME or to the TPIDR2_EL0 register)
|
||
are already handled by this function (see [1] (8.1.3 and 8.1.2)). Reasoning
|
||
about other possible use cases would require making code inside clone() and
|
||
clone3() more complicated and it would defeat the point of trying to make
|
||
an optimisation of not calling __arm_za_disable().
|
||
|
||
Why can't the kernel do this instead?
|
||
|
||
The handling of SME state by the kernel is described in [4]. In short,
|
||
kernel must not impose a specific ZA-interface onto a userspace function.
|
||
Interaction with the kernel happens (among other thing) via system calls.
|
||
In Glibc many of the system calls (notably, including SYS_clone and
|
||
SYS_clone3) are used via wrappers, and the kernel has no control of them
|
||
and, moreover, it cannot dictate how these wrappers should behave because
|
||
it is simply outside of the kernel's remit.
|
||
|
||
However, in certain cases, the kernel may ensure that a "child" doesn't
|
||
start in an incorrect state. This is what is done by the recent change
|
||
included in 6.16 kernel [5]. This is not enough to ensure that code that
|
||
uses clone() and clone3() function conforms to [1] when it runs on a
|
||
system that provides SME, hence this change.
|
||
|
||
[1]: https://github.com/ARM-software/abi-aa/blob/main/aapcs64/aapcs64.rst
|
||
[2]: https://inbox.sourceware.org/libc-alpha/20250522114828.2291047-1-yury.khrustalev@arm.com
|
||
[3]: https://inbox.sourceware.org/libc-alpha/20250609121407.3316070-1-yury.khrustalev@arm.com
|
||
[4]: https://www.kernel.org/doc/html/v6.16/arch/arm64/sme.html
|
||
[5]: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=cde5c32db55740659fca6d56c09b88800d88fd29
|
||
|
||
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
||
(cherry picked from commit 27effb3d50424fb9634be77a2acd614b0386ff25)
|
||
|
||
diff --git a/sysdeps/unix/sysv/linux/aarch64/clone.S b/sysdeps/unix/sysv/linux/aarch64/clone.S
|
||
index 40015c6933..53f1efd728 100644
|
||
--- a/sysdeps/unix/sysv/linux/aarch64/clone.S
|
||
+++ b/sysdeps/unix/sysv/linux/aarch64/clone.S
|
||
@@ -45,6 +45,9 @@ ENTRY(__clone)
|
||
and x1, x1, -16
|
||
cbz x1, .Lsyscall_error
|
||
|
||
+ /* Clear ZA state of SME. */
|
||
+ CALL_LIBC_ARM_ZA_DISABLE
|
||
+
|
||
/* Do the system call. */
|
||
/* X0:flags, x1:newsp, x2:parenttidptr, x3:newtls, x4:childtid. */
|
||
mov x0, x2 /* flags */
|
||
diff --git a/sysdeps/unix/sysv/linux/aarch64/clone3.S b/sysdeps/unix/sysv/linux/aarch64/clone3.S
|
||
index c9ca845ef2..bc978b7e10 100644
|
||
--- a/sysdeps/unix/sysv/linux/aarch64/clone3.S
|
||
+++ b/sysdeps/unix/sysv/linux/aarch64/clone3.S
|
||
@@ -46,6 +46,9 @@ ENTRY(__clone3)
|
||
cbz x10, .Lsyscall_error /* No NULL cl_args pointer. */
|
||
cbz x2, .Lsyscall_error /* No NULL function pointer. */
|
||
|
||
+ /* Clear ZA state of SME. */
|
||
+ CALL_LIBC_ARM_ZA_DISABLE
|
||
+
|
||
/* Do the system call, the kernel expects:
|
||
x8: system call number
|
||
x0: cl_args
|
||
diff --git a/sysdeps/unix/sysv/linux/aarch64/sysdep.h b/sysdeps/unix/sysv/linux/aarch64/sysdep.h
|
||
index fa01386b25..30003c0145 100644
|
||
--- a/sysdeps/unix/sysv/linux/aarch64/sysdep.h
|
||
+++ b/sysdeps/unix/sysv/linux/aarch64/sysdep.h
|
||
@@ -242,6 +242,31 @@
|
||
#undef HAVE_INTERNAL_BRK_ADDR_SYMBOL
|
||
#define HAVE_INTERNAL_BRK_ADDR_SYMBOL 1
|
||
|
||
+/* Clear ZA state of SME (C version). */
|
||
+/* The __libc_arm_za_disable function has special calling convention
|
||
+ that allows to call it without stack manipulation and preserving
|
||
+ most of the registers. */
|
||
+#define CALL_LIBC_ARM_ZA_DISABLE() \
|
||
+({ \
|
||
+ unsigned long int __tmp; \
|
||
+ asm volatile ( \
|
||
+ " mov %0, x30\n" \
|
||
+ " .cfi_register x30, %0\n" \
|
||
+ " bl __libc_arm_za_disable\n" \
|
||
+ " mov x30, %0\n" \
|
||
+ " .cfi_register %0, x30\n" \
|
||
+ : "=r" (__tmp) \
|
||
+ : \
|
||
+ : "x14", "x15", "x16", "x17", "x18", "memory" ); \
|
||
+})
|
||
+
|
||
+/* Do clear ZA state of SME before making normal clone syscall. */
|
||
+#define INLINE_CLONE_SYSCALL(a0, a1, a2, a3, a4) \
|
||
+({ \
|
||
+ CALL_LIBC_ARM_ZA_DISABLE (); \
|
||
+ INLINE_SYSCALL_CALL (clone, a0, a1, a2, a3, a4); \
|
||
+})
|
||
+
|
||
#endif /* __ASSEMBLER__ */
|
||
|
||
#endif /* linux/aarch64/sysdep.h */
|
||
diff --git a/sysdeps/unix/sysv/linux/aarch64/vfork.S b/sysdeps/unix/sysv/linux/aarch64/vfork.S
|
||
index d5943a7485..2600bc9be3 100644
|
||
--- a/sysdeps/unix/sysv/linux/aarch64/vfork.S
|
||
+++ b/sysdeps/unix/sysv/linux/aarch64/vfork.S
|
||
@@ -27,6 +27,9 @@
|
||
|
||
ENTRY (__vfork)
|
||
|
||
+ /* Clear ZA state of SME. */
|
||
+ CALL_LIBC_ARM_ZA_DISABLE
|
||
+
|
||
mov x0, #0x4111 /* CLONE_VM | CLONE_VFORK | SIGCHLD */
|
||
mov x1, sp
|
||
DO_CALL (clone, 2)
|
||
|
||
commit 71874f167aa5bb1538ff7e394beaacee28ebe65f
|
||
Author: Yury Khrustalev <yury.khrustalev@arm.com>
|
||
Date: Fri Sep 26 10:03:45 2025 +0100
|
||
|
||
aarch64: tests for SME
|
||
|
||
This commit adds tests for the following use cases relevant to handing of
|
||
the SME state:
|
||
|
||
- fork() and vfork()
|
||
- clone() and clone3()
|
||
- signal handler
|
||
|
||
While most cases are trivial, the case of clone3() is more complicated since
|
||
the clone3() symbol is not public in Glibc.
|
||
|
||
To avoid having to check all possible ways clone3() may be called via other
|
||
public functions (e.g. vfork() or pthread_create()), we put together a test
|
||
that links directly with clone3.o. All the existing functions that have calls
|
||
to clone3() may not actually use it, in which case the outcome of such tests
|
||
would be unexpected. Having a direct call to the clone3() symbol in the test
|
||
allows to check precisely what we need to test: that the __arm_za_disable()
|
||
function is indeed called and has the desired effect.
|
||
|
||
Linking to clone3.o also requires linking to __arm_za_disable.o that in
|
||
turn requires the _dl_hwcap2 hidden symbol which to provide in the test
|
||
and initialise it before using.
|
||
|
||
Co-authored-by: Adhemerval Zanella Netto <adhemerval.zanella@linaro.org>
|
||
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
||
(cherry picked from commit ecb0fc2f0f839f36cd2a106283142c9df8ea8214)
|
||
|
||
diff --git a/sysdeps/aarch64/Makefile b/sysdeps/aarch64/Makefile
|
||
index bb97d31355..9479fb9679 100644
|
||
--- a/sysdeps/aarch64/Makefile
|
||
+++ b/sysdeps/aarch64/Makefile
|
||
@@ -79,8 +79,18 @@ sysdep_routines += \
|
||
|
||
tests += \
|
||
tst-sme-jmp \
|
||
+ tst-sme-signal \
|
||
tst-sme-za-state \
|
||
# tests
|
||
+tests-internal += \
|
||
+ tst-sme-clone \
|
||
+ tst-sme-clone3 \
|
||
+ tst-sme-fork \
|
||
+ tst-sme-vfork \
|
||
+ # tests-internal
|
||
+
|
||
+$(objpfx)tst-sme-clone3: $(objpfx)clone3.o $(objpfx)__arm_za_disable.o
|
||
+
|
||
endif
|
||
|
||
ifeq ($(subdir),malloc)
|
||
diff --git a/sysdeps/aarch64/tst-sme-clone.c b/sysdeps/aarch64/tst-sme-clone.c
|
||
new file mode 100644
|
||
index 0000000000..7106ec7926
|
||
--- /dev/null
|
||
+++ b/sysdeps/aarch64/tst-sme-clone.c
|
||
@@ -0,0 +1,53 @@
|
||
+/* Test that ZA state of SME is cleared in both parent and child
|
||
+ when clone() syscall is used.
|
||
+ 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 "tst-sme-skeleton.c"
|
||
+
|
||
+#include <support/xsched.h>
|
||
+
|
||
+static int
|
||
+fun (void * const arg)
|
||
+{
|
||
+ printf ("in child: %s\n", (const char *)arg);
|
||
+ /* Check that ZA state of SME was disabled in child. */
|
||
+ check_sme_za_state ("after clone in child", /* Clear. */ true);
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+static char __attribute__((aligned(16)))
|
||
+stack[1024 * 1024];
|
||
+
|
||
+static void
|
||
+run (struct blk *ptr)
|
||
+{
|
||
+ char *syscall_name = (char *)"clone";
|
||
+ printf ("in parent: before %s\n", syscall_name);
|
||
+
|
||
+ /* Enabled ZA state so that effect of disabling be observable. */
|
||
+ enable_sme_za_state (ptr);
|
||
+ check_sme_za_state ("before clone", /* Clear. */ false);
|
||
+
|
||
+ pid_t pid = xclone (fun, syscall_name, stack, sizeof (stack),
|
||
+ CLONE_NEWUSER | CLONE_NEWNS | SIGCHLD);
|
||
+
|
||
+ /* Check that ZA state of SME was disabled in parent. */
|
||
+ check_sme_za_state ("after clone in parent", /* Clear. */ true);
|
||
+
|
||
+ TEST_VERIFY (xwaitpid (pid, NULL, 0) == pid);
|
||
+}
|
||
diff --git a/sysdeps/aarch64/tst-sme-clone3.c b/sysdeps/aarch64/tst-sme-clone3.c
|
||
new file mode 100644
|
||
index 0000000000..402b040cfd
|
||
--- /dev/null
|
||
+++ b/sysdeps/aarch64/tst-sme-clone3.c
|
||
@@ -0,0 +1,84 @@
|
||
+/* Test that ZA state of SME is cleared in both parent and child
|
||
+ when clone3() syscall is used.
|
||
+ 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 "tst-sme-skeleton.c"
|
||
+
|
||
+#include <clone3.h>
|
||
+
|
||
+#include <errno.h>
|
||
+#include <sys/wait.h>
|
||
+#include <support/xsched.h>
|
||
+
|
||
+/* Since clone3 is not a public symbol, we link this test explicitly
|
||
+ with clone3.o and have to provide this declaration. */
|
||
+int __clone3 (struct clone_args *cl_args, size_t size,
|
||
+ int (*func)(void *arg), void *arg);
|
||
+
|
||
+static int
|
||
+fun (void * const arg)
|
||
+{
|
||
+ printf ("in child: %s\n", (const char *)arg);
|
||
+ /* Check that ZA state of SME was disabled in child. */
|
||
+ check_sme_za_state ("after clone3 in child", /* Clear. */ true);
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+static char __attribute__((aligned(16)))
|
||
+stack[1024 * 1024];
|
||
+
|
||
+/* Required by __arm_za_disable.o and provided by the startup code
|
||
+ as a hidden symbol. */
|
||
+uint64_t _dl_hwcap2;
|
||
+
|
||
+static void
|
||
+run (struct blk *ptr)
|
||
+{
|
||
+ _dl_hwcap2 = getauxval (AT_HWCAP2);
|
||
+
|
||
+ char *syscall_name = (char *)"clone3";
|
||
+ struct clone_args args = {
|
||
+ .flags = CLONE_VM | CLONE_VFORK,
|
||
+ .exit_signal = SIGCHLD,
|
||
+ .stack = (uintptr_t) stack,
|
||
+ .stack_size = sizeof (stack),
|
||
+ };
|
||
+ printf ("in parent: before %s\n", syscall_name);
|
||
+
|
||
+ /* Enabled ZA state so that effect of disabling be observable. */
|
||
+ enable_sme_za_state (ptr);
|
||
+ check_sme_za_state ("before clone3", /* Clear. */ false);
|
||
+
|
||
+ pid_t pid = __clone3 (&args, sizeof (args), fun, syscall_name);
|
||
+
|
||
+ /* Check that ZA state of SME was disabled in parent. */
|
||
+ check_sme_za_state ("after clone3 in parent", /* Clear. */ true);
|
||
+
|
||
+ printf ("%s child pid: %d\n", syscall_name, pid);
|
||
+
|
||
+ xwaitpid (pid, NULL, 0);
|
||
+ printf ("in parent: after %s\n", syscall_name);
|
||
+}
|
||
+
|
||
+/* Workaround to simplify linking with clone3.o. */
|
||
+void __syscall_error(int code)
|
||
+{
|
||
+ int err = -code;
|
||
+ fprintf (stderr, "syscall error %d (%s)\n", err, strerror (err));
|
||
+ exit (err);
|
||
+}
|
||
diff --git a/sysdeps/aarch64/tst-sme-fork.c b/sysdeps/aarch64/tst-sme-fork.c
|
||
new file mode 100644
|
||
index 0000000000..b003b08884
|
||
--- /dev/null
|
||
+++ b/sysdeps/aarch64/tst-sme-fork.c
|
||
@@ -0,0 +1,43 @@
|
||
+/* Test that ZA state of SME is cleared in both parent and child
|
||
+ when fork() function is used.
|
||
+ 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 "tst-sme-skeleton.c"
|
||
+
|
||
+static void
|
||
+run (struct blk *blk)
|
||
+{
|
||
+ /* Enabled ZA state so that effect of disabling be observable. */
|
||
+ enable_sme_za_state (blk);
|
||
+ check_sme_za_state ("before fork", /* Clear. */ false);
|
||
+ fflush (stdout);
|
||
+
|
||
+ pid_t pid = xfork ();
|
||
+
|
||
+ if (pid == 0)
|
||
+ {
|
||
+ /* Check that ZA state of SME was disabled in child. */
|
||
+ check_sme_za_state ("after fork in child", /* Clear. */ true);
|
||
+ exit (0);
|
||
+ }
|
||
+
|
||
+ /* Check that ZA state of SME was disabled in parent. */
|
||
+ check_sme_za_state ("after fork in parent", /* Clear. */ true);
|
||
+
|
||
+ TEST_VERIFY (xwaitpid (pid, NULL, 0) == pid);
|
||
+}
|
||
diff --git a/sysdeps/aarch64/tst-sme-helper.h b/sysdeps/aarch64/tst-sme-helper.h
|
||
index f049416c2b..ab9c503e45 100644
|
||
--- a/sysdeps/aarch64/tst-sme-helper.h
|
||
+++ b/sysdeps/aarch64/tst-sme-helper.h
|
||
@@ -16,9 +16,6 @@
|
||
License along with the GNU C Library; if not, see
|
||
<https://www.gnu.org/licenses/>. */
|
||
|
||
-/* Streaming SVE vector register size. */
|
||
-static unsigned long svl;
|
||
-
|
||
struct blk {
|
||
void *za_save_buffer;
|
||
uint16_t num_za_save_slices;
|
||
@@ -68,10 +65,10 @@ start_za (void)
|
||
|
||
/* Load data into ZA byte by byte from p. */
|
||
static void __attribute__ ((noinline))
|
||
-load_za (const void *p)
|
||
+load_za (const void *buf, unsigned long svl)
|
||
{
|
||
register unsigned long x15 asm ("x15") = 0;
|
||
- register unsigned long x16 asm ("x16") = (unsigned long)p;
|
||
+ register unsigned long x16 asm ("x16") = (unsigned long)buf;
|
||
register unsigned long x17 asm ("x17") = svl;
|
||
|
||
asm volatile (
|
||
diff --git a/sysdeps/aarch64/tst-sme-jmp.c b/sysdeps/aarch64/tst-sme-jmp.c
|
||
index 103897ad36..b2d21c6e1a 100644
|
||
--- a/sysdeps/aarch64/tst-sme-jmp.c
|
||
+++ b/sysdeps/aarch64/tst-sme-jmp.c
|
||
@@ -29,6 +29,9 @@
|
||
|
||
#include "tst-sme-helper.h"
|
||
|
||
+/* Streaming SVE vector register size. */
|
||
+static unsigned long svl;
|
||
+
|
||
static uint8_t *za_orig;
|
||
static uint8_t *za_dump;
|
||
static uint8_t *za_save;
|
||
@@ -82,7 +85,7 @@ longjmp_test (void)
|
||
FAIL_EXIT1 ("svcr != 0: %lu", svcr);
|
||
set_tpidr2 (&blk);
|
||
start_za ();
|
||
- load_za (za_orig);
|
||
+ load_za (za_orig, svl);
|
||
|
||
print_data ("za save space", za_save);
|
||
p = get_tpidr2 ();
|
||
@@ -131,7 +134,7 @@ setcontext_test (void)
|
||
FAIL_EXIT1 ("svcr != 0: %lu", svcr);
|
||
set_tpidr2 (&blk);
|
||
start_za ();
|
||
- load_za (za_orig);
|
||
+ load_za (za_orig, svl);
|
||
|
||
print_data ("za save space", za_save);
|
||
p = get_tpidr2 ();
|
||
diff --git a/sysdeps/aarch64/tst-sme-signal.c b/sysdeps/aarch64/tst-sme-signal.c
|
||
new file mode 100644
|
||
index 0000000000..b4b07bcc44
|
||
--- /dev/null
|
||
+++ b/sysdeps/aarch64/tst-sme-signal.c
|
||
@@ -0,0 +1,115 @@
|
||
+/* Test handling of SME state in a signal handler.
|
||
+ 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 "tst-sme-skeleton.c"
|
||
+
|
||
+#include <support/xsignal.h>
|
||
+
|
||
+static struct _aarch64_ctx *
|
||
+extension (void *p)
|
||
+{
|
||
+ return p;
|
||
+}
|
||
+
|
||
+#ifndef TPIDR2_MAGIC
|
||
+#define TPIDR2_MAGIC 0x54504902
|
||
+#endif
|
||
+
|
||
+#ifndef ZA_MAGIC
|
||
+#define ZA_MAGIC 0x54366345
|
||
+#endif
|
||
+
|
||
+#ifndef ZT_MAGIC
|
||
+#define ZT_MAGIC 0x5a544e01
|
||
+#endif
|
||
+
|
||
+#ifndef EXTRA_MAGIC
|
||
+#define EXTRA_MAGIC 0x45585401
|
||
+#endif
|
||
+
|
||
+/* We use a pipe to make sure that the final check of the SME state
|
||
+ happens after signal handler finished. */
|
||
+static int pipefd[2];
|
||
+
|
||
+#define WRITE(msg) xwrite (1, msg, sizeof (msg));
|
||
+
|
||
+static void
|
||
+handler (int signo, siginfo_t *si, void *ctx)
|
||
+{
|
||
+ TEST_VERIFY (signo == SIGUSR1);
|
||
+ WRITE ("in the handler\n");
|
||
+ check_sme_za_state ("during signal", true /* State is clear. */);
|
||
+ ucontext_t *uc = ctx;
|
||
+ void *p = uc->uc_mcontext.__reserved;
|
||
+ unsigned int found = 0;
|
||
+ uint32_t m;
|
||
+ while ((m = extension (p)->magic))
|
||
+ {
|
||
+ if (m == TPIDR2_MAGIC)
|
||
+ {
|
||
+ WRITE ("found TPIDR2_MAGIC\n");
|
||
+ found += 1;
|
||
+ }
|
||
+ if (m == ZA_MAGIC)
|
||
+ {
|
||
+ WRITE ("found ZA_MAGIC\n");
|
||
+ found += 1;
|
||
+ }
|
||
+ if (m == ZT_MAGIC)
|
||
+ {
|
||
+ WRITE ("found ZT_MAGIC\n");
|
||
+ found += 1;
|
||
+ }
|
||
+ if (m == EXTRA_MAGIC)
|
||
+ {
|
||
+ WRITE ("found EXTRA_MAGIC\n");
|
||
+ struct { struct _aarch64_ctx h; uint64_t data; } *e = p;
|
||
+ p = (char *)e->data;
|
||
+ continue;
|
||
+ }
|
||
+ p = (char *)p + extension (p)->size;
|
||
+ }
|
||
+ TEST_COMPARE (found, 3);
|
||
+
|
||
+ /* Signal that the wait is over (see below). */
|
||
+ char message = '\0';
|
||
+ xwrite (pipefd[1], &message, 1);
|
||
+}
|
||
+
|
||
+static void
|
||
+run (struct blk *blk)
|
||
+{
|
||
+ xpipe (pipefd);
|
||
+
|
||
+ struct sigaction sigact;
|
||
+ sigemptyset (&sigact.sa_mask);
|
||
+ sigact.sa_flags = 0;
|
||
+ sigact.sa_flags |= SA_SIGINFO;
|
||
+ sigact.sa_sigaction = handler;
|
||
+ xsigaction (SIGUSR1, &sigact, NULL);
|
||
+
|
||
+ enable_sme_za_state (blk);
|
||
+ check_sme_za_state ("before signal", false /* State is not clear. */);
|
||
+ xraise (SIGUSR1);
|
||
+
|
||
+ /* Wait for signal handler to complete. */
|
||
+ char response;
|
||
+ xread (pipefd[0], &response, 1);
|
||
+
|
||
+ check_sme_za_state ("after signal", false /* State is not clear. */);
|
||
+}
|
||
diff --git a/sysdeps/aarch64/tst-sme-skeleton.c b/sysdeps/aarch64/tst-sme-skeleton.c
|
||
new file mode 100644
|
||
index 0000000000..ba84dda1cb
|
||
--- /dev/null
|
||
+++ b/sysdeps/aarch64/tst-sme-skeleton.c
|
||
@@ -0,0 +1,101 @@
|
||
+/* Template for SME tests.
|
||
+ 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 <stdio.h>
|
||
+#include <stddef.h>
|
||
+#include <stdint.h>
|
||
+#include <string.h>
|
||
+#include <sys/auxv.h>
|
||
+
|
||
+#include <support/check.h>
|
||
+#include <support/support.h>
|
||
+#include <support/xstdlib.h>
|
||
+#include <support/xunistd.h>
|
||
+#include <support/test-driver.h>
|
||
+
|
||
+#include "tst-sme-helper.h"
|
||
+
|
||
+/* Streaming SVE vector register size. */
|
||
+static unsigned long svl;
|
||
+
|
||
+static uint8_t *state;
|
||
+
|
||
+static void
|
||
+enable_sme_za_state (struct blk *blk)
|
||
+{
|
||
+ start_za ();
|
||
+ set_tpidr2 (blk);
|
||
+ load_za (blk, svl);
|
||
+}
|
||
+
|
||
+/* Check if SME state is disabled (when CLEAR is true) or
|
||
+ enabled (when CLEAR is false). */
|
||
+static void
|
||
+check_sme_za_state (const char msg[], bool clear)
|
||
+{
|
||
+ unsigned long svcr = get_svcr ();
|
||
+ void *tpidr2 = get_tpidr2 ();
|
||
+ printf ("[%s]\n", msg);
|
||
+ printf ("svcr = %016lx\n", svcr);
|
||
+ printf ("tpidr2 = %016lx\n", (unsigned long)tpidr2);
|
||
+ if (clear)
|
||
+ {
|
||
+ TEST_VERIFY (svcr == 0);
|
||
+ TEST_VERIFY (tpidr2 == NULL);
|
||
+ }
|
||
+ else
|
||
+ {
|
||
+ TEST_VERIFY (svcr != 0);
|
||
+ TEST_VERIFY (tpidr2 != NULL);
|
||
+ }
|
||
+}
|
||
+
|
||
+/* Should be defined in actual test that includes this
|
||
+ skeleton file. */
|
||
+static void
|
||
+run (struct blk *ptr);
|
||
+
|
||
+static int
|
||
+do_test (void)
|
||
+{
|
||
+ unsigned long hwcap2 = getauxval (AT_HWCAP2);
|
||
+ if ((hwcap2 & HWCAP2_SME) == 0)
|
||
+ return EXIT_UNSUPPORTED;
|
||
+
|
||
+ /* Get current streaming SVE vector length in bytes. */
|
||
+ svl = get_svl ();
|
||
+ printf ("svl: %lu\n", svl);
|
||
+
|
||
+ TEST_VERIFY_EXIT (!(svl < 16 || svl % 16 != 0 || svl >= (1 << 16)));
|
||
+
|
||
+ /* Initialise buffer for ZA state of SME. */
|
||
+ state = xmalloc (svl * svl);
|
||
+ memset (state, 1, svl * svl);
|
||
+ struct blk blk = {
|
||
+ .za_save_buffer = state,
|
||
+ .num_za_save_slices = svl,
|
||
+ .__reserved = {0},
|
||
+ };
|
||
+
|
||
+ run (&blk);
|
||
+
|
||
+ free (state);
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+#include <support/test-driver.c>
|
||
diff --git a/sysdeps/aarch64/tst-sme-vfork.c b/sysdeps/aarch64/tst-sme-vfork.c
|
||
new file mode 100644
|
||
index 0000000000..3feea065e5
|
||
--- /dev/null
|
||
+++ b/sysdeps/aarch64/tst-sme-vfork.c
|
||
@@ -0,0 +1,43 @@
|
||
+/* Test that ZA state of SME is cleared in both parent and child
|
||
+ when vfork() function is used.
|
||
+ 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 "tst-sme-skeleton.c"
|
||
+
|
||
+static void
|
||
+run (struct blk *blk)
|
||
+{
|
||
+ /* Enabled ZA state so that effect of disabling be observable. */
|
||
+ enable_sme_za_state (blk);
|
||
+ check_sme_za_state ("before vfork", /* Clear. */ false);
|
||
+ fflush (stdout);
|
||
+
|
||
+ pid_t pid = vfork ();
|
||
+
|
||
+ if (pid == 0)
|
||
+ {
|
||
+ /* Check that ZA state of SME was disabled in child. */
|
||
+ check_sme_za_state ("after vfork in child", /* Clear. */ true);
|
||
+ _exit (0);
|
||
+ }
|
||
+
|
||
+ /* Check that ZA state of SME was disabled in parent. */
|
||
+ check_sme_za_state ("after vfork in parent", /* Clear. */ true);
|
||
+
|
||
+ TEST_VERIFY (xwaitpid (pid, NULL, 0) == pid);
|
||
+}
|
||
diff --git a/sysdeps/aarch64/tst-sme-za-state.c b/sysdeps/aarch64/tst-sme-za-state.c
|
||
index 63f6eebeb4..00118ef506 100644
|
||
--- a/sysdeps/aarch64/tst-sme-za-state.c
|
||
+++ b/sysdeps/aarch64/tst-sme-za-state.c
|
||
@@ -16,47 +16,9 @@
|
||
License along with the GNU C Library; if not, see
|
||
<https://www.gnu.org/licenses/>. */
|
||
|
||
-#include <stdio.h>
|
||
-#include <setjmp.h>
|
||
-#include <stdlib.h>
|
||
-#include <string.h>
|
||
-#include <sys/auxv.h>
|
||
-
|
||
-#include <support/check.h>
|
||
-#include <support/support.h>
|
||
-#include <support/test-driver.h>
|
||
-
|
||
-#include "tst-sme-helper.h"
|
||
-
|
||
-static uint8_t *state;
|
||
-
|
||
-static void
|
||
-enable_sme_za_state (struct blk *ptr)
|
||
-{
|
||
- set_tpidr2 (ptr);
|
||
- start_za ();
|
||
- load_za (state);
|
||
-}
|
||
+#include "tst-sme-skeleton.c"
|
||
|
||
-static void
|
||
-check_sme_za_state (const char msg[], bool clear)
|
||
-{
|
||
- unsigned long svcr = get_svcr ();
|
||
- void *tpidr2 = get_tpidr2 ();
|
||
- printf ("[%s]\n", msg);
|
||
- printf ("svcr = %016lx\n", svcr);
|
||
- printf ("tpidr2 = %016lx\n", (unsigned long)tpidr2);
|
||
- if (clear)
|
||
- {
|
||
- TEST_VERIFY (svcr == 0);
|
||
- TEST_VERIFY (tpidr2 == NULL);
|
||
- }
|
||
- else
|
||
- {
|
||
- TEST_VERIFY (svcr != 0);
|
||
- TEST_VERIFY (tpidr2 != NULL);
|
||
- }
|
||
-}
|
||
+#include <setjmp.h>
|
||
|
||
static void
|
||
run (struct blk *ptr)
|
||
@@ -88,32 +50,3 @@ run (struct blk *ptr)
|
||
TEST_COMPARE (ret, 42);
|
||
check_sme_za_state ("after longjmp", /* Clear. */ true);
|
||
}
|
||
-
|
||
-static int
|
||
-do_test (void)
|
||
-{
|
||
- unsigned long hwcap2 = getauxval (AT_HWCAP2);
|
||
- if ((hwcap2 & HWCAP2_SME) == 0)
|
||
- return EXIT_UNSUPPORTED;
|
||
-
|
||
- /* Get current streaming SVE vector register size. */
|
||
- svl = get_svl ();
|
||
- printf ("svl: %lu\n", svl);
|
||
- TEST_VERIFY_EXIT (!(svl < 16 || svl % 16 != 0 || svl >= (1 << 16)));
|
||
-
|
||
- /* Initialise buffer for ZA state of SME. */
|
||
- state = xmalloc (svl * svl);
|
||
- memset (state, 1, svl * svl);
|
||
- struct blk blk = {
|
||
- .za_save_buffer = state,
|
||
- .num_za_save_slices = svl,
|
||
- .__reserved = {0},
|
||
- };
|
||
-
|
||
- run (&blk);
|
||
-
|
||
- free (state);
|
||
- return 0;
|
||
-}
|
||
-
|
||
-#include <support/test-driver.c>
|
||
|
||
commit bf499c2a4964bddc25a006ec1402f8996d78c6ff
|
||
Author: Jiamei Xie <xiejiamei@hygon.cn>
|
||
Date: Tue Oct 14 20:14:11 2025 +0800
|
||
|
||
x86: fix wmemset ifunc stray '!' (bug 33542)
|
||
|
||
The ifunc selector for wmemset had a stray '!' in the
|
||
X86_ISA_CPU_FEATURES_ARCH_P(...) check:
|
||
|
||
if (X86_ISA_CPU_FEATURE_USABLE_P (cpu_features, AVX2)
|
||
&& X86_ISA_CPU_FEATURES_ARCH_P (cpu_features,
|
||
AVX_Fast_Unaligned_Load, !))
|
||
|
||
This effectively negated the predicate and caused the AVX2/AVX512
|
||
paths to be skipped, making the dispatcher fall back to the SSE2
|
||
implementation even on CPUs where AVX2/AVX512 are available. The
|
||
regression leads to noticeable throughput loss for wmemset.
|
||
|
||
Remove the stray '!' so the AVX_Fast_Unaligned_Load capability is
|
||
tested as intended and the correct AVX2/EVEX variants are selected.
|
||
|
||
Impact:
|
||
- On AVX2/AVX512-capable x86_64, wmemset no longer incorrectly
|
||
falls back to SSE2; perf now shows __wmemset_evex/avx2 variants.
|
||
|
||
Testing:
|
||
- benchtests/bench-wmemset shows improved bandwidth across sizes.
|
||
- perf confirm the selected symbol is no longer SSE2.
|
||
|
||
Signed-off-by: xiejiamei <xiejiamei@hygon.com>
|
||
Signed-off-by: Li jing <lijing@hygon.cn>
|
||
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
||
(cherry picked from commit 4d86b6cdd8132e0410347e07262239750f86dfb4)
|
||
|
||
diff --git a/sysdeps/x86_64/multiarch/ifunc-wmemset.h b/sysdeps/x86_64/multiarch/ifunc-wmemset.h
|
||
index f95cca6ae5..50af138230 100644
|
||
--- a/sysdeps/x86_64/multiarch/ifunc-wmemset.h
|
||
+++ b/sysdeps/x86_64/multiarch/ifunc-wmemset.h
|
||
@@ -35,7 +35,7 @@ IFUNC_SELECTOR (void)
|
||
|
||
if (X86_ISA_CPU_FEATURE_USABLE_P (cpu_features, AVX2)
|
||
&& X86_ISA_CPU_FEATURES_ARCH_P (cpu_features,
|
||
- AVX_Fast_Unaligned_Load, !))
|
||
+ AVX_Fast_Unaligned_Load,))
|
||
{
|
||
if (X86_ISA_CPU_FEATURE_USABLE_P (cpu_features, AVX512VL))
|
||
{
|
||
|
||
commit de1fe81f471496366580ad728b8986a3424b2fd7
|
||
Author: Yury Khrustalev <yury.khrustalev@arm.com>
|
||
Date: Tue Oct 28 11:01:50 2025 +0000
|
||
|
||
aarch64: fix cfi directives around __libc_arm_za_disable
|
||
|
||
Incorrect CFI directive corrupted call stack information
|
||
and prevented debuggers from correctly displaying call
|
||
stack information.
|
||
|
||
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
||
(cherry picked from commit 2f77aec043f61e8533487850b11941a640ae2dea)
|
||
|
||
diff --git a/sysdeps/unix/sysv/linux/aarch64/sysdep.h b/sysdeps/unix/sysv/linux/aarch64/sysdep.h
|
||
index 30003c0145..8a7690d4a8 100644
|
||
--- a/sysdeps/unix/sysv/linux/aarch64/sysdep.h
|
||
+++ b/sysdeps/unix/sysv/linux/aarch64/sysdep.h
|
||
@@ -155,11 +155,12 @@
|
||
that allows to call it without stack manipulation and preserving
|
||
most of the registers. */
|
||
.macro CALL_LIBC_ARM_ZA_DISABLE
|
||
+ cfi_remember_state
|
||
mov x13, x30
|
||
- .cfi_register x30, x13
|
||
+ cfi_register(x30, x13)
|
||
bl __libc_arm_za_disable
|
||
mov x30, x13
|
||
- .cfi_register x13, x30
|
||
+ cfi_restore_state
|
||
.endm
|
||
|
||
#else /* not __ASSEMBLER__ */
|
||
@@ -250,11 +251,12 @@
|
||
({ \
|
||
unsigned long int __tmp; \
|
||
asm volatile ( \
|
||
+ " .cfi_remember_state\n" \
|
||
" mov %0, x30\n" \
|
||
- " .cfi_register x30, %0\n" \
|
||
+ " .cfi_register x30, %0\n" \
|
||
" bl __libc_arm_za_disable\n" \
|
||
" mov x30, %0\n" \
|
||
- " .cfi_register %0, x30\n" \
|
||
+ " .cfi_restore_state\n" \
|
||
: "=r" (__tmp) \
|
||
: \
|
||
: "x14", "x15", "x16", "x17", "x18", "memory" ); \
|
||
|
||
commit 17c3eab387c3ceb6972e57888a89b1480793f81a
|
||
Author: Yury Khrustalev <yury.khrustalev@arm.com>
|
||
Date: Tue Nov 11 11:40:25 2025 +0000
|
||
|
||
aarch64: fix includes in SME tests
|
||
|
||
Use the correct include for the SIGCHLD macro: signal.h
|
||
|
||
Reviewed-by: Wilco Dijkstra <Wilco.Dijkstra@arm.com>
|
||
(cherry picked from commit a9c426bcca59a9e228c4fbe75e75154217ec4ada)
|
||
|
||
diff --git a/sysdeps/aarch64/tst-sme-clone.c b/sysdeps/aarch64/tst-sme-clone.c
|
||
index 7106ec7926..b6ad54fa37 100644
|
||
--- a/sysdeps/aarch64/tst-sme-clone.c
|
||
+++ b/sysdeps/aarch64/tst-sme-clone.c
|
||
@@ -19,6 +19,7 @@
|
||
|
||
#include "tst-sme-skeleton.c"
|
||
|
||
+#include <signal.h>
|
||
#include <support/xsched.h>
|
||
|
||
static int
|
||
diff --git a/sysdeps/aarch64/tst-sme-clone3.c b/sysdeps/aarch64/tst-sme-clone3.c
|
||
index 402b040cfd..f420d5984d 100644
|
||
--- a/sysdeps/aarch64/tst-sme-clone3.c
|
||
+++ b/sysdeps/aarch64/tst-sme-clone3.c
|
||
@@ -22,7 +22,7 @@
|
||
#include <clone3.h>
|
||
|
||
#include <errno.h>
|
||
-#include <sys/wait.h>
|
||
+#include <signal.h>
|
||
#include <support/xsched.h>
|
||
|
||
/* Since clone3 is not a public symbol, we link this test explicitly
|
||
|
||
commit 97297120ce04f0edd16ed0357a11ef8731c5bd1e
|
||
Author: Joe Ramsay <Joe.Ramsay@arm.com>
|
||
Date: Thu Nov 6 15:36:03 2025 +0000
|
||
|
||
AArch64: Optimise SVE scalar callbacks
|
||
|
||
Instead of using SVE instructions to marshall special results into the
|
||
correct lane, just write the entire vector (and the predicate) to
|
||
memory, then use cheaper scalar operations.
|
||
|
||
Geomean speedup of 16% in special intervals on Neoverse with GCC 14.
|
||
|
||
Reviewed-by: Wilco Dijkstra <Wilco.Dijkstra@arm.com>
|
||
(cherry picked from commit 5b82fb18827e962af9f080fdf3c1a69802783f67)
|
||
|
||
diff --git a/sysdeps/aarch64/fpu/sv_math.h b/sysdeps/aarch64/fpu/sv_math.h
|
||
index 3d576df4cc..65d7f0ff20 100644
|
||
--- a/sysdeps/aarch64/fpu/sv_math.h
|
||
+++ b/sysdeps/aarch64/fpu/sv_math.h
|
||
@@ -24,11 +24,29 @@
|
||
|
||
#include "vecmath_config.h"
|
||
|
||
+#if !defined(__ARM_FEATURE_SVE_BITS) || __ARM_FEATURE_SVE_BITS == 0
|
||
+/* If not specified by -msve-vector-bits, assume maximum vector length. */
|
||
+# define SVE_VECTOR_BYTES 256
|
||
+#else
|
||
+# define SVE_VECTOR_BYTES (__ARM_FEATURE_SVE_BITS / 8)
|
||
+#endif
|
||
+#define SVE_NUM_FLTS (SVE_VECTOR_BYTES / sizeof (float))
|
||
+#define SVE_NUM_DBLS (SVE_VECTOR_BYTES / sizeof (double))
|
||
+/* Predicate is stored as one bit per byte of VL so requires VL / 64 bytes. */
|
||
+#define SVE_NUM_PG_BYTES (SVE_VECTOR_BYTES / sizeof (uint64_t))
|
||
+
|
||
#define SV_NAME_F1(fun) _ZGVsMxv_##fun##f
|
||
#define SV_NAME_D1(fun) _ZGVsMxv_##fun
|
||
#define SV_NAME_F2(fun) _ZGVsMxvv_##fun##f
|
||
#define SV_NAME_D2(fun) _ZGVsMxvv_##fun
|
||
|
||
+static inline void
|
||
+svstr_p (uint8_t *dst, svbool_t p)
|
||
+{
|
||
+ /* Predicate STR does not currently have an intrinsic. */
|
||
+ __asm__("str %0, [%x1]\n" : : "Upa"(p), "r"(dst) : "memory");
|
||
+}
|
||
+
|
||
/* Double precision. */
|
||
static inline svint64_t
|
||
sv_s64 (int64_t x)
|
||
@@ -51,33 +69,35 @@ sv_f64 (double x)
|
||
static inline svfloat64_t
|
||
sv_call_f64 (double (*f) (double), svfloat64_t x, svfloat64_t y, svbool_t cmp)
|
||
{
|
||
- svbool_t p = svpfirst (cmp, svpfalse ());
|
||
- while (svptest_any (cmp, p))
|
||
+ double tmp[SVE_NUM_DBLS];
|
||
+ uint8_t pg_bits[SVE_NUM_PG_BYTES];
|
||
+ svstr_p (pg_bits, cmp);
|
||
+ svst1 (svptrue_b64 (), tmp, svsel (cmp, x, y));
|
||
+
|
||
+ for (int i = 0; i < svcntd (); i++)
|
||
{
|
||
- double elem = svclastb_n_f64 (p, 0, x);
|
||
- elem = (*f) (elem);
|
||
- svfloat64_t y2 = svdup_n_f64 (elem);
|
||
- y = svsel_f64 (p, y2, y);
|
||
- p = svpnext_b64 (cmp, p);
|
||
+ if (pg_bits[i] & 1)
|
||
+ tmp[i] = f (tmp[i]);
|
||
}
|
||
- return y;
|
||
+ return svld1 (svptrue_b64 (), tmp);
|
||
}
|
||
|
||
static inline svfloat64_t
|
||
sv_call2_f64 (double (*f) (double, double), svfloat64_t x1, svfloat64_t x2,
|
||
svfloat64_t y, svbool_t cmp)
|
||
{
|
||
- svbool_t p = svpfirst (cmp, svpfalse ());
|
||
- while (svptest_any (cmp, p))
|
||
+ double tmp1[SVE_NUM_DBLS], tmp2[SVE_NUM_DBLS];
|
||
+ uint8_t pg_bits[SVE_NUM_PG_BYTES];
|
||
+ svstr_p (pg_bits, cmp);
|
||
+ svst1 (svptrue_b64 (), tmp1, svsel (cmp, x1, y));
|
||
+ svst1 (cmp, tmp2, x2);
|
||
+
|
||
+ for (int i = 0; i < svcntd (); i++)
|
||
{
|
||
- double elem1 = svclastb_n_f64 (p, 0, x1);
|
||
- double elem2 = svclastb_n_f64 (p, 0, x2);
|
||
- double ret = (*f) (elem1, elem2);
|
||
- svfloat64_t y2 = svdup_n_f64 (ret);
|
||
- y = svsel_f64 (p, y2, y);
|
||
- p = svpnext_b64 (cmp, p);
|
||
+ if (pg_bits[i] & 1)
|
||
+ tmp1[i] = f (tmp1[i], tmp2[i]);
|
||
}
|
||
- return y;
|
||
+ return svld1 (svptrue_b64 (), tmp1);
|
||
}
|
||
|
||
static inline svuint64_t
|
||
@@ -109,33 +129,40 @@ sv_f32 (float x)
|
||
static inline svfloat32_t
|
||
sv_call_f32 (float (*f) (float), svfloat32_t x, svfloat32_t y, svbool_t cmp)
|
||
{
|
||
- svbool_t p = svpfirst (cmp, svpfalse ());
|
||
- while (svptest_any (cmp, p))
|
||
+ float tmp[SVE_NUM_FLTS];
|
||
+ uint8_t pg_bits[SVE_NUM_PG_BYTES];
|
||
+ svstr_p (pg_bits, cmp);
|
||
+ svst1 (svptrue_b32 (), tmp, svsel (cmp, x, y));
|
||
+
|
||
+ for (int i = 0; i < svcntd (); i++)
|
||
{
|
||
- float elem = svclastb_n_f32 (p, 0, x);
|
||
- elem = f (elem);
|
||
- svfloat32_t y2 = svdup_n_f32 (elem);
|
||
- y = svsel_f32 (p, y2, y);
|
||
- p = svpnext_b32 (cmp, p);
|
||
+ uint8_t p = pg_bits[i];
|
||
+ if (p & 1)
|
||
+ tmp[i * 2] = f (tmp[i * 2]);
|
||
+ if (p & (1 << 4))
|
||
+ tmp[i * 2 + 1] = f (tmp[i * 2 + 1]);
|
||
}
|
||
- return y;
|
||
+ return svld1 (svptrue_b32 (), tmp);
|
||
}
|
||
|
||
static inline svfloat32_t
|
||
sv_call2_f32 (float (*f) (float, float), svfloat32_t x1, svfloat32_t x2,
|
||
svfloat32_t y, svbool_t cmp)
|
||
{
|
||
- svbool_t p = svpfirst (cmp, svpfalse ());
|
||
- while (svptest_any (cmp, p))
|
||
+ float tmp1[SVE_NUM_FLTS], tmp2[SVE_NUM_FLTS];
|
||
+ uint8_t pg_bits[SVE_NUM_PG_BYTES];
|
||
+ svstr_p (pg_bits, cmp);
|
||
+ svst1 (svptrue_b32 (), tmp1, svsel (cmp, x1, y));
|
||
+ svst1 (cmp, tmp2, x2);
|
||
+
|
||
+ for (int i = 0; i < svcntd (); i++)
|
||
{
|
||
- float elem1 = svclastb_n_f32 (p, 0, x1);
|
||
- float elem2 = svclastb_n_f32 (p, 0, x2);
|
||
- float ret = f (elem1, elem2);
|
||
- svfloat32_t y2 = svdup_n_f32 (ret);
|
||
- y = svsel_f32 (p, y2, y);
|
||
- p = svpnext_b32 (cmp, p);
|
||
+ uint8_t p = pg_bits[i];
|
||
+ if (p & 1)
|
||
+ tmp1[i * 2] = f (tmp1[i * 2], tmp2[i * 2]);
|
||
+ if (p & (1 << 4))
|
||
+ tmp1[i * 2 + 1] = f (tmp1[i * 2 + 1], tmp2[i * 2 + 1]);
|
||
}
|
||
- return y;
|
||
+ return svld1 (svptrue_b32 (), tmp1);
|
||
}
|
||
-
|
||
#endif
|
||
|
||
commit ec041b1f53bf1fd29d94ee147fac69da66437dc6
|
||
Author: Joe Ramsay <Joe.Ramsay@arm.com>
|
||
Date: Thu Nov 6 18:26:54 2025 +0000
|
||
|
||
AArch64: Fix instability in AdvSIMD tan
|
||
|
||
Previously presence of special-cases in one lane could affect the
|
||
results in other lanes due to unconditional scalar fallback. The old
|
||
WANT_SIMD_EXCEPT option (which has never been enabled in libmvec) has
|
||
been removed from AOR, making it easier to spot and fix this. 4%
|
||
improvement in throughput with GCC 14 on Neoverse V1. This bug is
|
||
present as far back as 2.39 (where tan was first introduced).
|
||
|
||
Reviewed-by: Wilco Dijkstra <Wilco.Dijkstra@arm.com>
|
||
(cherry picked from commit 6c22823da57aa5218f717f569c04c9573c0448c5)
|
||
|
||
diff --git a/sysdeps/aarch64/fpu/tan_advsimd.c b/sysdeps/aarch64/fpu/tan_advsimd.c
|
||
index 825c9754b3..d391a003d8 100644
|
||
--- a/sysdeps/aarch64/fpu/tan_advsimd.c
|
||
+++ b/sysdeps/aarch64/fpu/tan_advsimd.c
|
||
@@ -25,9 +25,7 @@ static const struct data
|
||
float64x2_t poly[9];
|
||
double half_pi[2];
|
||
float64x2_t two_over_pi, shift;
|
||
-#if !WANT_SIMD_EXCEPT
|
||
float64x2_t range_val;
|
||
-#endif
|
||
} data = {
|
||
/* Coefficients generated using FPMinimax. */
|
||
.poly = { V2 (0x1.5555555555556p-2), V2 (0x1.1111111110a63p-3),
|
||
@@ -38,20 +36,17 @@ static const struct data
|
||
.half_pi = { 0x1.921fb54442d18p0, 0x1.1a62633145c07p-54 },
|
||
.two_over_pi = V2 (0x1.45f306dc9c883p-1),
|
||
.shift = V2 (0x1.8p52),
|
||
-#if !WANT_SIMD_EXCEPT
|
||
.range_val = V2 (0x1p23),
|
||
-#endif
|
||
};
|
||
|
||
#define RangeVal 0x4160000000000000 /* asuint64(0x1p23). */
|
||
#define TinyBound 0x3e50000000000000 /* asuint64(2^-26). */
|
||
-#define Thresh 0x310000000000000 /* RangeVal - TinyBound. */
|
||
|
||
/* Special cases (fall back to scalar calls). */
|
||
static float64x2_t VPCS_ATTR NOINLINE
|
||
-special_case (float64x2_t x)
|
||
+special_case (float64x2_t x, float64x2_t n, float64x2_t d, uint64x2_t special)
|
||
{
|
||
- return v_call_f64 (tan, x, x, v_u64 (-1));
|
||
+ return v_call_f64 (tan, x, vdivq_f64 (n, d), special);
|
||
}
|
||
|
||
/* Vector approximation for double-precision tan.
|
||
@@ -65,14 +60,6 @@ float64x2_t VPCS_ATTR V_NAME_D1 (tan) (float64x2_t x)
|
||
very large inputs. Fall back to scalar routine for all lanes if any are
|
||
too large, or Inf/NaN. If fenv exceptions are expected, also fall back for
|
||
tiny input to avoid underflow. */
|
||
-#if WANT_SIMD_EXCEPT
|
||
- uint64x2_t iax = vreinterpretq_u64_f64 (vabsq_f64 (x));
|
||
- /* iax - tiny_bound > range_val - tiny_bound. */
|
||
- uint64x2_t special
|
||
- = vcgtq_u64 (vsubq_u64 (iax, v_u64 (TinyBound)), v_u64 (Thresh));
|
||
- if (__glibc_unlikely (v_any_u64 (special)))
|
||
- return special_case (x);
|
||
-#endif
|
||
|
||
/* q = nearest integer to 2 * x / pi. */
|
||
float64x2_t q
|
||
@@ -81,9 +68,8 @@ float64x2_t VPCS_ATTR V_NAME_D1 (tan) (float64x2_t x)
|
||
|
||
/* Use q to reduce x to r in [-pi/4, pi/4], by:
|
||
r = x - q * pi/2, in extended precision. */
|
||
- float64x2_t r = x;
|
||
float64x2_t half_pi = vld1q_f64 (dat->half_pi);
|
||
- r = vfmsq_laneq_f64 (r, q, half_pi, 0);
|
||
+ float64x2_t r = vfmsq_laneq_f64 (x, q, half_pi, 0);
|
||
r = vfmsq_laneq_f64 (r, q, half_pi, 1);
|
||
/* Further reduce r to [-pi/8, pi/8], to be reconstructed using double angle
|
||
formula. */
|
||
@@ -114,12 +100,13 @@ float64x2_t VPCS_ATTR V_NAME_D1 (tan) (float64x2_t x)
|
||
|
||
uint64x2_t no_recip = vtstq_u64 (vreinterpretq_u64_s64 (qi), v_u64 (1));
|
||
|
||
-#if !WANT_SIMD_EXCEPT
|
||
uint64x2_t special = vcageq_f64 (x, dat->range_val);
|
||
+ float64x2_t swap = vbslq_f64 (no_recip, n, vnegq_f64 (d));
|
||
+ d = vbslq_f64 (no_recip, d, n);
|
||
+ n = swap;
|
||
+
|
||
if (__glibc_unlikely (v_any_u64 (special)))
|
||
- return special_case (x);
|
||
-#endif
|
||
+ return special_case (x, n, d, special);
|
||
|
||
- return vdivq_f64 (vbslq_f64 (no_recip, n, vnegq_f64 (d)),
|
||
- vbslq_f64 (no_recip, d, n));
|
||
+ return vdivq_f64 (n, d);
|
||
}
|
||
|
||
commit 0c9430ed976b961343dd29b752091f3c4771cf30
|
||
Author: Joe Ramsay <Joe.Ramsay@arm.com>
|
||
Date: Thu Nov 6 18:29:33 2025 +0000
|
||
|
||
AArch64: Fix instability in AdvSIMD sinh
|
||
|
||
Previously presence of special-cases in one lane could affect the
|
||
results in other lanes due to unconditional scalar fallback. The old
|
||
WANT_SIMD_EXCEPT option (which has never been enabled in libmvec) has
|
||
been removed from AOR, making it easier to spot and fix
|
||
this. No measured change in performance. This patch applies cleanly as
|
||
far back as 2.41, however there are conflicts with 2.40 where sinh was
|
||
first introduced.
|
||
|
||
Reviewed-by: Wilco Dijkstra <Wilco.Dijkstra@arm.com>
|
||
(cherry picked from commit e45af510bc816e860c8e2e1d4a652b4fe15c4b34)
|
||
|
||
diff --git a/sysdeps/aarch64/fpu/sinh_advsimd.c b/sysdeps/aarch64/fpu/sinh_advsimd.c
|
||
index 0d6a4856f8..b6b60262c6 100644
|
||
--- a/sysdeps/aarch64/fpu/sinh_advsimd.c
|
||
+++ b/sysdeps/aarch64/fpu/sinh_advsimd.c
|
||
@@ -24,36 +24,26 @@ static const struct data
|
||
{
|
||
struct v_expm1_data d;
|
||
uint64x2_t halff;
|
||
-#if WANT_SIMD_EXCEPT
|
||
- uint64x2_t tiny_bound, thresh;
|
||
-#else
|
||
float64x2_t large_bound;
|
||
-#endif
|
||
} data = {
|
||
.d = V_EXPM1_DATA,
|
||
.halff = V2 (0x3fe0000000000000),
|
||
-#if WANT_SIMD_EXCEPT
|
||
- /* 2^-26, below which sinh(x) rounds to x. */
|
||
- .tiny_bound = V2 (0x3e50000000000000),
|
||
- /* asuint(large_bound) - asuint(tiny_bound). */
|
||
- .thresh = V2 (0x0230000000000000),
|
||
-#else
|
||
/* 2^9. expm1 helper overflows for large input. */
|
||
.large_bound = V2 (0x1p+9),
|
||
-#endif
|
||
};
|
||
|
||
static float64x2_t NOINLINE VPCS_ATTR
|
||
-special_case (float64x2_t x)
|
||
+special_case (float64x2_t x, float64x2_t t, float64x2_t halfsign,
|
||
+ uint64x2_t special)
|
||
{
|
||
- return v_call_f64 (sinh, x, x, v_u64 (-1));
|
||
+ return v_call_f64 (sinh, x, vmulq_f64 (t, halfsign), special);
|
||
}
|
||
|
||
/* Approximation for vector double-precision sinh(x) using expm1.
|
||
sinh(x) = (exp(x) - exp(-x)) / 2.
|
||
The greatest observed error is 2.52 ULP:
|
||
- _ZGVnN2v_sinh(-0x1.a098a2177a2b9p-2) got -0x1.ac2f05bb66fccp-2
|
||
- want -0x1.ac2f05bb66fc9p-2. */
|
||
+ _ZGVnN2v_sinh(0x1.9f6ff2ab6fb19p-2) got 0x1.aaed83a3153ccp-2
|
||
+ want 0x1.aaed83a3153c9p-2. */
|
||
float64x2_t VPCS_ATTR V_NAME_D1 (sinh) (float64x2_t x)
|
||
{
|
||
const struct data *d = ptr_barrier (&data);
|
||
@@ -63,21 +53,16 @@ float64x2_t VPCS_ATTR V_NAME_D1 (sinh) (float64x2_t x)
|
||
float64x2_t halfsign = vreinterpretq_f64_u64 (
|
||
vbslq_u64 (v_u64 (0x8000000000000000), ix, d->halff));
|
||
|
||
-#if WANT_SIMD_EXCEPT
|
||
- uint64x2_t special = vcgeq_u64 (
|
||
- vsubq_u64 (vreinterpretq_u64_f64 (ax), d->tiny_bound), d->thresh);
|
||
-#else
|
||
uint64x2_t special = vcageq_f64 (x, d->large_bound);
|
||
-#endif
|
||
-
|
||
- /* Fall back to scalar variant for all lanes if any of them are special. */
|
||
- if (__glibc_unlikely (v_any_u64 (special)))
|
||
- return special_case (x);
|
||
|
||
/* Up to the point that expm1 overflows, we can use it to calculate sinh
|
||
using a slight rearrangement of the definition of sinh. This allows us to
|
||
retain acceptable accuracy for very small inputs. */
|
||
float64x2_t t = expm1_inline (ax, &d->d);
|
||
t = vaddq_f64 (t, vdivq_f64 (t, vaddq_f64 (t, v_f64 (1.0))));
|
||
+
|
||
+ if (__glibc_unlikely (v_any_u64 (special)))
|
||
+ return special_case (x, t, halfsign, special);
|
||
+
|
||
return vmulq_f64 (t, halfsign);
|
||
}
|
||
|
||
commit 710d7a2e8374cf09280a0db170a6c813b70b59e5
|
||
Author: Pierre Blanchard <pierre.blanchard@arm.com>
|
||
Date: Tue Nov 18 15:03:10 2025 +0000
|
||
|
||
AArch64: fix SVE tanpi(f) [BZ #33642]
|
||
|
||
Fixed svld1rq using incorrect predicates (BZ #33642).
|
||
Next to no performance variations (tested on V1).
|
||
|
||
Reviewed-by: Wilco Dijkstra <Wilco.Dijkstra@arm.com>
|
||
(cherry picked from commit e889160273a4c2b68870c9adf341955867d76a7d)
|
||
|
||
diff --git a/sysdeps/aarch64/fpu/tanpi_sve.c b/sysdeps/aarch64/fpu/tanpi_sve.c
|
||
index 57c643ae29..bfe6828e1f 100644
|
||
--- a/sysdeps/aarch64/fpu/tanpi_sve.c
|
||
+++ b/sysdeps/aarch64/fpu/tanpi_sve.c
|
||
@@ -1,6 +1,6 @@
|
||
/* Double-precision (SVE) tanpi function
|
||
|
||
- Copyright (C) 2024 Free Software Foundation, Inc.
|
||
+ Copyright (C) 2024-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
|
||
@@ -58,10 +58,10 @@ svfloat64_t SV_NAME_D1 (tanpi) (svfloat64_t x, const svbool_t pg)
|
||
svfloat64_t r2 = svmul_x (pg, r, r);
|
||
svfloat64_t r4 = svmul_x (pg, r2, r2);
|
||
|
||
- svfloat64_t c_1_3 = svld1rq (pg, &d->c1);
|
||
- svfloat64_t c_5_7 = svld1rq (pg, &d->c5);
|
||
- svfloat64_t c_9_11 = svld1rq (pg, &d->c9);
|
||
- svfloat64_t c_13_14 = svld1rq (pg, &d->c13);
|
||
+ svfloat64_t c_1_3 = svld1rq (svptrue_b64 (), &d->c1);
|
||
+ svfloat64_t c_5_7 = svld1rq (svptrue_b64 (), &d->c5);
|
||
+ svfloat64_t c_9_11 = svld1rq (svptrue_b64 (), &d->c9);
|
||
+ svfloat64_t c_13_14 = svld1rq (svptrue_b64 (), &d->c13);
|
||
svfloat64_t p01 = svmla_lane (sv_f64 (d->c0), r2, c_1_3, 0);
|
||
svfloat64_t p23 = svmla_lane (sv_f64 (d->c2), r2, c_1_3, 1);
|
||
svfloat64_t p45 = svmla_lane (sv_f64 (d->c4), r2, c_5_7, 0);
|
||
diff --git a/sysdeps/aarch64/fpu/tanpif_sve.c b/sysdeps/aarch64/fpu/tanpif_sve.c
|
||
index 0285f56f34..6894379564 100644
|
||
--- a/sysdeps/aarch64/fpu/tanpif_sve.c
|
||
+++ b/sysdeps/aarch64/fpu/tanpif_sve.c
|
||
@@ -1,6 +1,6 @@
|
||
/* Single-precision (SVE) tanpi function
|
||
|
||
- Copyright (C) 2024 Free Software Foundation, Inc.
|
||
+ Copyright (C) 2024-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
|
||
@@ -37,7 +37,7 @@ const static struct v_tanpif_data
|
||
svfloat32_t SV_NAME_F1 (tanpi) (svfloat32_t x, const svbool_t pg)
|
||
{
|
||
const struct v_tanpif_data *d = ptr_barrier (&tanpif_data);
|
||
- svfloat32_t odd_coeffs = svld1rq (pg, &d->c1);
|
||
+ svfloat32_t odd_coeffs = svld1rq (svptrue_b32 (), &d->c1);
|
||
svfloat32_t n = svrintn_x (pg, x);
|
||
|
||
/* inf produces nan that propagates. */
|
||
|
||
commit 828b8d23f3fa05234d35032a61a746918accf91d
|
||
Author: Pierre Blanchard <pierre.blanchard@arm.com>
|
||
Date: Tue Nov 18 15:09:05 2025 +0000
|
||
|
||
AArch64: Fix and improve SVE pow(f) special cases
|
||
|
||
powf:
|
||
|
||
Update scalar special case function to best use new interface.
|
||
|
||
pow:
|
||
|
||
Make specialcase NOINLINE to prevent str/ldr leaking in fast path.
|
||
Remove depency in sv_call2, as new callback impl is not a
|
||
performance gain.
|
||
Replace with vectorised specialcase since structure of scalar
|
||
routine is fairly simple.
|
||
|
||
Throughput gain of about 5-10% on V1 for large values and 25% for subnormal `x`.
|
||
|
||
Reviewed-by: Wilco Dijkstra <Wilco.Dijkstra@arm.com>
|
||
(cherry picked from commit bb6519de1e6fe73d79bc71588ec4e5668907f080)
|
||
|
||
diff --git a/sysdeps/aarch64/fpu/pow_sve.c b/sysdeps/aarch64/fpu/pow_sve.c
|
||
index b8c1b39dca..becf1a8410 100644
|
||
--- a/sysdeps/aarch64/fpu/pow_sve.c
|
||
+++ b/sysdeps/aarch64/fpu/pow_sve.c
|
||
@@ -31,8 +31,8 @@
|
||
The SVE algorithm drops the tail in the exp computation at the price of
|
||
a lower accuracy, slightly above 1ULP.
|
||
The SVE algorithm also drops the special treatement of small (< 2^-65) and
|
||
- large (> 2^63) finite values of |y|, as they only affect non-round to nearest
|
||
- modes.
|
||
+ large (> 2^63) finite values of |y|, as they only affect non-round to
|
||
+ nearest modes.
|
||
|
||
Maximum measured error is 1.04 ULPs:
|
||
SV_NAME_D2 (pow) (0x1.3d2d45bc848acp+63, -0x1.a48a38b40cd43p-12)
|
||
@@ -156,42 +156,22 @@ sv_zeroinfnan (svbool_t pg, svuint64_t i)
|
||
a double. (int32_t)KI is the k used in the argument reduction and exponent
|
||
adjustment of scale, positive k here means the result may overflow and
|
||
negative k means the result may underflow. */
|
||
-static inline double
|
||
-specialcase (double tmp, uint64_t sbits, uint64_t ki)
|
||
-{
|
||
- double scale;
|
||
- if ((ki & 0x80000000) == 0)
|
||
- {
|
||
- /* k > 0, the exponent of scale might have overflowed by <= 460. */
|
||
- sbits -= 1009ull << 52;
|
||
- scale = asdouble (sbits);
|
||
- return 0x1p1009 * (scale + scale * tmp);
|
||
- }
|
||
- /* k < 0, need special care in the subnormal range. */
|
||
- sbits += 1022ull << 52;
|
||
- /* Note: sbits is signed scale. */
|
||
- scale = asdouble (sbits);
|
||
- double y = scale + scale * tmp;
|
||
- return 0x1p-1022 * y;
|
||
-}
|
||
-
|
||
-/* Scalar fallback for special cases of SVE pow's exp. */
|
||
static inline svfloat64_t
|
||
-sv_call_specialcase (svfloat64_t x1, svuint64_t u1, svuint64_t u2,
|
||
- svfloat64_t y, svbool_t cmp)
|
||
+specialcase (svfloat64_t tmp, svuint64_t sbits, svuint64_t ki, svbool_t cmp)
|
||
{
|
||
- svbool_t p = svpfirst (cmp, svpfalse ());
|
||
- while (svptest_any (cmp, p))
|
||
- {
|
||
- double sx1 = svclastb (p, 0, x1);
|
||
- uint64_t su1 = svclastb (p, 0, u1);
|
||
- uint64_t su2 = svclastb (p, 0, u2);
|
||
- double elem = specialcase (sx1, su1, su2);
|
||
- svfloat64_t y2 = sv_f64 (elem);
|
||
- y = svsel (p, y2, y);
|
||
- p = svpnext_b64 (cmp, p);
|
||
- }
|
||
- return y;
|
||
+ svbool_t p_pos = svcmpge_n_f64 (cmp, svreinterpret_f64_u64 (ki), 0.0);
|
||
+
|
||
+ /* Scale up or down depending on sign of k. */
|
||
+ svint64_t offset
|
||
+ = svsel_s64 (p_pos, sv_s64 (1009ull << 52), sv_s64 (-1022ull << 52));
|
||
+ svfloat64_t factor
|
||
+ = svsel_f64 (p_pos, sv_f64 (0x1p1009), sv_f64 (0x1p-1022));
|
||
+
|
||
+ svuint64_t offset_sbits
|
||
+ = svsub_u64_x (cmp, sbits, svreinterpret_u64_s64 (offset));
|
||
+ svfloat64_t scale = svreinterpret_f64_u64 (offset_sbits);
|
||
+ svfloat64_t res = svmad_f64_x (cmp, scale, tmp, scale);
|
||
+ return svmul_f64_x (cmp, res, factor);
|
||
}
|
||
|
||
/* Compute y+TAIL = log(x) where the rounded result is y and TAIL has about
|
||
@@ -214,8 +194,8 @@ sv_log_inline (svbool_t pg, svuint64_t ix, svfloat64_t *tail,
|
||
|
||
/* log(x) = k*Ln2 + log(c) + log1p(z/c-1). */
|
||
/* SVE lookup requires 3 separate lookup tables, as opposed to scalar version
|
||
- that uses array of structures. We also do the lookup earlier in the code to
|
||
- make sure it finishes as early as possible. */
|
||
+ that uses array of structures. We also do the lookup earlier in the code
|
||
+ to make sure it finishes as early as possible. */
|
||
svfloat64_t invc = svld1_gather_index (pg, __v_pow_log_data.invc, i);
|
||
svfloat64_t logc = svld1_gather_index (pg, __v_pow_log_data.logc, i);
|
||
svfloat64_t logctail = svld1_gather_index (pg, __v_pow_log_data.logctail, i);
|
||
@@ -325,14 +305,14 @@ sv_exp_inline (svbool_t pg, svfloat64_t x, svfloat64_t xtail,
|
||
svbool_t oflow = svcmpge (pg, abstop, HugeExp);
|
||
oflow = svand_z (pg, uoflow, svbic_z (pg, oflow, uflow));
|
||
|
||
- /* For large |x| values (512 < |x| < 1024) scale * (1 + TMP) can overflow
|
||
- or underflow. */
|
||
+ /* Handle underflow and overlow in scale.
|
||
+ For large |x| values (512 < |x| < 1024), scale * (1 + TMP) can
|
||
+ overflow or underflow. */
|
||
svbool_t special = svbic_z (pg, uoflow, svorr_z (pg, uflow, oflow));
|
||
+ if (__glibc_unlikely (svptest_any (pg, special)))
|
||
+ z = svsel (special, specialcase (tmp, sbits, ki, special), z);
|
||
|
||
- /* Update result with special and large cases. */
|
||
- z = sv_call_specialcase (tmp, sbits, ki, z, special);
|
||
-
|
||
- /* Handle underflow and overflow. */
|
||
+ /* Handle underflow and overflow in exp. */
|
||
svbool_t x_is_neg = svcmplt (pg, x, 0);
|
||
svuint64_t sign_mask
|
||
= svlsl_x (pg, sign_bias, 52 - V_POW_EXP_TABLE_BITS);
|
||
@@ -353,7 +333,7 @@ sv_exp_inline (svbool_t pg, svfloat64_t x, svfloat64_t xtail,
|
||
}
|
||
|
||
static inline double
|
||
-pow_sc (double x, double y)
|
||
+pow_specialcase (double x, double y)
|
||
{
|
||
uint64_t ix = asuint64 (x);
|
||
uint64_t iy = asuint64 (y);
|
||
@@ -382,6 +362,14 @@ pow_sc (double x, double y)
|
||
return x;
|
||
}
|
||
|
||
+/* Scalar fallback for special case routines with custom signature. */
|
||
+static svfloat64_t NOINLINE
|
||
+sv_pow_specialcase (svfloat64_t x1, svfloat64_t x2, svfloat64_t y,
|
||
+ svbool_t cmp)
|
||
+{
|
||
+ return sv_call2_f64 (pow_specialcase, x1, x2, y, cmp);
|
||
+}
|
||
+
|
||
svfloat64_t SV_NAME_D2 (pow) (svfloat64_t x, svfloat64_t y, const svbool_t pg)
|
||
{
|
||
const struct data *d = ptr_barrier (&data);
|
||
@@ -444,7 +432,7 @@ svfloat64_t SV_NAME_D2 (pow) (svfloat64_t x, svfloat64_t y, const svbool_t pg)
|
||
|
||
/* Cases of zero/inf/nan x or y. */
|
||
if (__glibc_unlikely (svptest_any (svptrue_b64 (), special)))
|
||
- vz = sv_call2_f64 (pow_sc, x, y, vz, special);
|
||
+ vz = sv_pow_specialcase (x, y, vz, special);
|
||
|
||
return vz;
|
||
}
|
||
diff --git a/sysdeps/aarch64/fpu/powf_sve.c b/sysdeps/aarch64/fpu/powf_sve.c
|
||
index 65e9bd29d9..76f54b3522 100644
|
||
--- a/sysdeps/aarch64/fpu/powf_sve.c
|
||
+++ b/sysdeps/aarch64/fpu/powf_sve.c
|
||
@@ -116,11 +116,10 @@ zeroinfnan (uint32_t ix)
|
||
preamble of scalar powf except that we do not update ix and sign_bias. This
|
||
is done in the preamble of the SVE powf. */
|
||
static inline float
|
||
-powf_specialcase (float x, float y, float z)
|
||
+powf_specialcase (float x, float y)
|
||
{
|
||
uint32_t ix = asuint (x);
|
||
uint32_t iy = asuint (y);
|
||
- /* Either (x < 0x1p-126 or inf or nan) or (y is 0 or inf or nan). */
|
||
if (__glibc_unlikely (zeroinfnan (iy)))
|
||
{
|
||
if (2 * iy == 0)
|
||
@@ -142,32 +141,15 @@ powf_specialcase (float x, float y, float z)
|
||
x2 = -x2;
|
||
return iy & 0x80000000 ? 1 / x2 : x2;
|
||
}
|
||
- /* We need a return here in case x<0 and y is integer, but all other tests
|
||
- need to be run. */
|
||
- return z;
|
||
+ /* Return x for convenience, but make sure result is never used. */
|
||
+ return x;
|
||
}
|
||
|
||
/* Scalar fallback for special case routines with custom signature. */
|
||
static svfloat32_t NOINLINE
|
||
-sv_call_powf_sc (svfloat32_t x1, svfloat32_t x2, svfloat32_t y)
|
||
+sv_call_powf_sc (svfloat32_t x1, svfloat32_t x2, svfloat32_t y, svbool_t cmp)
|
||
{
|
||
- /* Special cases of x or y: zero, inf and nan. */
|
||
- svbool_t xspecial = sv_zeroinfnan (svptrue_b32 (), svreinterpret_u32 (x1));
|
||
- svbool_t yspecial = sv_zeroinfnan (svptrue_b32 (), svreinterpret_u32 (x2));
|
||
- svbool_t cmp = svorr_z (svptrue_b32 (), xspecial, yspecial);
|
||
-
|
||
- svbool_t p = svpfirst (cmp, svpfalse ());
|
||
- while (svptest_any (cmp, p))
|
||
- {
|
||
- float sx1 = svclastb (p, 0, x1);
|
||
- float sx2 = svclastb (p, 0, x2);
|
||
- float elem = svclastb (p, 0, y);
|
||
- elem = powf_specialcase (sx1, sx2, elem);
|
||
- svfloat32_t y2 = sv_f32 (elem);
|
||
- y = svsel (p, y2, y);
|
||
- p = svpnext_b32 (cmp, p);
|
||
- }
|
||
- return y;
|
||
+ return sv_call2_f32 (powf_specialcase, x1, x2, y, cmp);
|
||
}
|
||
|
||
/* Compute core for half of the lanes in double precision. */
|
||
@@ -330,7 +312,7 @@ svfloat32_t SV_NAME_F2 (pow) (svfloat32_t x, svfloat32_t y, const svbool_t pg)
|
||
ret = svsel (yint_or_xpos, ret, sv_f32 (__builtin_nanf ("")));
|
||
|
||
if (__glibc_unlikely (svptest_any (cmp, cmp)))
|
||
- return sv_call_powf_sc (x, y, ret);
|
||
+ return sv_call_powf_sc (x, y, ret, cmp);
|
||
|
||
return ret;
|
||
}
|
||
|
||
commit 6b2957cfe8ad1e02c03a28abfc5a251c05e4005e
|
||
Author: Sachin Monga <smonga@linux.ibm.com>
|
||
Date: Fri Nov 21 00:30:04 2025 -0500
|
||
|
||
ppc64le: Restore optimized strcmp for power10
|
||
|
||
This patch addresses the actual cause of CVE-2025-5702
|
||
|
||
The vector non-volatile registers are not used anymore for
|
||
32 byte load and comparison operation
|
||
|
||
Additionally, the assembler workaround used earlier for the
|
||
instruction lxvp is replaced with actual instruction.
|
||
|
||
Signed-off-by: Sachin Monga <smonga@linux.ibm.com>
|
||
Co-authored-by: Paul Murphy <paumurph@redhat.com>
|
||
(cherry picked from commit 9a40b1cda519cc4f532acb6d020390829df3d81b)
|
||
|
||
diff --git a/sysdeps/powerpc/powerpc64/le/power10/strcmp.S b/sysdeps/powerpc/powerpc64/le/power10/strcmp.S
|
||
new file mode 100644
|
||
index 0000000000..0d4a53317c
|
||
--- /dev/null
|
||
+++ b/sysdeps/powerpc/powerpc64/le/power10/strcmp.S
|
||
@@ -0,0 +1,185 @@
|
||
+/* Optimized strcmp implementation for PowerPC64/POWER10.
|
||
+ 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 <sysdep.h>
|
||
+
|
||
+#ifndef STRCMP
|
||
+# define STRCMP strcmp
|
||
+#endif
|
||
+
|
||
+/* Implements the function
|
||
+ int [r3] strcmp (const char *s1 [r3], const char *s2 [r4]). */
|
||
+
|
||
+
|
||
+#define COMPARE_16(vreg1,vreg2,offset) \
|
||
+ lxv vreg1+32,offset(r3); \
|
||
+ lxv vreg2+32,offset(r4); \
|
||
+ vcmpnezb. v7,vreg1,vreg2; \
|
||
+ bne cr6,L(different); \
|
||
+
|
||
+#define COMPARE_32(vreg1,vreg2,offset,label1,label2) \
|
||
+ lxvp vreg1+32,offset(r3); \
|
||
+ lxvp vreg2+32,offset(r4); \
|
||
+ vcmpnezb. v7,vreg1+1,vreg2+1; \
|
||
+ bne cr6,L(label1); \
|
||
+ vcmpnezb. v7,vreg1,vreg2; \
|
||
+ bne cr6,L(label2); \
|
||
+
|
||
+#define TAIL(vreg1,vreg2) \
|
||
+ vctzlsbb r6,v7; \
|
||
+ vextubrx r5,r6,vreg1; \
|
||
+ vextubrx r4,r6,vreg2; \
|
||
+ subf r3,r4,r5; \
|
||
+ blr; \
|
||
+
|
||
+#define CHECK_N_BYTES(reg1,reg2,len_reg) \
|
||
+ sldi r0,len_reg,56; \
|
||
+ lxvl 32+v4,reg1,r0; \
|
||
+ lxvl 32+v5,reg2,r0; \
|
||
+ add reg1,reg1,len_reg; \
|
||
+ add reg2,reg2,len_reg; \
|
||
+ vcmpnezb. v7,v4,v5; \
|
||
+ vctzlsbb r6,v7; \
|
||
+ cmpld cr7,r6,len_reg; \
|
||
+ blt cr7,L(different); \
|
||
+
|
||
+
|
||
+ .machine power10
|
||
+ENTRY_TOCLESS (STRCMP, 4)
|
||
+ li r11,16
|
||
+ /* eq bit of cr1 used as swap status flag to indicate if
|
||
+ source pointers were swapped. */
|
||
+ crclr 4*cr1+eq
|
||
+ andi. r7,r3,15
|
||
+ sub r7,r11,r7 /* r7(nalign1) = 16 - (str1 & 15). */
|
||
+ andi. r9,r4,15
|
||
+ sub r5,r11,r9 /* r5(nalign2) = 16 - (str2 & 15). */
|
||
+ cmpld cr7,r7,r5
|
||
+ beq cr7,L(same_aligned)
|
||
+ blt cr7,L(nalign1_min)
|
||
+ /* Swap r3 and r4, and r7 and r5 such that r3 and r7 hold the
|
||
+ pointer which is closer to the next 16B boundary so that only
|
||
+ one CHECK_N_BYTES is needed before entering the loop below. */
|
||
+ mr r8,r4
|
||
+ mr r4,r3
|
||
+ mr r3,r8
|
||
+ mr r12,r7
|
||
+ mr r7,r5
|
||
+ mr r5,r12
|
||
+ crset 4*cr1+eq /* Set bit on swapping source pointers. */
|
||
+
|
||
+ .p2align 5
|
||
+L(nalign1_min):
|
||
+ CHECK_N_BYTES(r3,r4,r7)
|
||
+
|
||
+ .p2align 5
|
||
+L(s1_aligned):
|
||
+ /* r9 and r5 is number of bytes to be read after and before
|
||
+ page boundary correspondingly. */
|
||
+ sub r5,r5,r7
|
||
+ subfic r9,r5,16
|
||
+ /* Now let r7 hold the count of quadwords which can be
|
||
+ checked without crossing a page boundary. quadword offset is
|
||
+ (str2>>4)&0xFF. */
|
||
+ rlwinm r7,r4,28,0xFF
|
||
+ /* Below check is required only for first iteration. For second
|
||
+ iteration and beyond, the new loop counter is always 255. */
|
||
+ cmpldi r7,255
|
||
+ beq L(L3)
|
||
+ /* Get the initial loop count by 255-((str2>>4)&0xFF). */
|
||
+ subfic r11,r7,255
|
||
+
|
||
+ .p2align 5
|
||
+L(L1):
|
||
+ mtctr r11
|
||
+
|
||
+ .p2align 5
|
||
+L(L2):
|
||
+ COMPARE_16(v4,v5,0) /* Load 16B blocks using lxv. */
|
||
+ addi r3,r3,16
|
||
+ addi r4,r4,16
|
||
+ bdnz L(L2)
|
||
+ /* Cross the page boundary of s2, carefully. */
|
||
+
|
||
+ .p2align 5
|
||
+L(L3):
|
||
+ CHECK_N_BYTES(r3,r4,r5)
|
||
+ CHECK_N_BYTES(r3,r4,r9)
|
||
+ li r11,255 /* Load the new loop counter. */
|
||
+ b L(L1)
|
||
+
|
||
+ .p2align 5
|
||
+L(same_aligned):
|
||
+ CHECK_N_BYTES(r3,r4,r7)
|
||
+ /* Align s1 to 32B and adjust s2 address.
|
||
+ Use lxvp only if both s1 and s2 are 32B aligned. */
|
||
+ COMPARE_16(v4,v5,0)
|
||
+ COMPARE_16(v4,v5,16)
|
||
+ COMPARE_16(v4,v5,32)
|
||
+ COMPARE_16(v4,v5,48)
|
||
+ addi r3,r3,64
|
||
+ addi r4,r4,64
|
||
+ COMPARE_16(v4,v5,0)
|
||
+ COMPARE_16(v4,v5,16)
|
||
+
|
||
+ clrldi r6,r3,59
|
||
+ subfic r5,r6,32
|
||
+ add r3,r3,r5
|
||
+ add r4,r4,r5
|
||
+ andi. r5,r4,0x1F
|
||
+ beq cr0,L(32B_aligned_loop)
|
||
+
|
||
+ .p2align 5
|
||
+L(16B_aligned_loop):
|
||
+ COMPARE_16(v4,v5,0)
|
||
+ COMPARE_16(v4,v5,16)
|
||
+ COMPARE_16(v4,v5,32)
|
||
+ COMPARE_16(v4,v5,48)
|
||
+ addi r3,r3,64
|
||
+ addi r4,r4,64
|
||
+ b L(16B_aligned_loop)
|
||
+
|
||
+ /* Calculate and return the difference. */
|
||
+L(different):
|
||
+ vctzlsbb r6,v7
|
||
+ vextubrx r5,r6,v4
|
||
+ vextubrx r4,r6,v5
|
||
+ bt 4*cr1+eq,L(swapped)
|
||
+ subf r3,r4,r5
|
||
+ blr
|
||
+
|
||
+ /* If src pointers were swapped, then swap the
|
||
+ indices and calculate the return value. */
|
||
+L(swapped):
|
||
+ subf r3,r5,r4
|
||
+ blr
|
||
+
|
||
+ .p2align 5
|
||
+L(32B_aligned_loop):
|
||
+ COMPARE_32(v14,v16,0,tail1,tail2)
|
||
+ COMPARE_32(v14,v16,32,tail1,tail2)
|
||
+ COMPARE_32(v14,v16,64,tail1,tail2)
|
||
+ COMPARE_32(v14,v16,96,tail1,tail2)
|
||
+ addi r3,r3,128
|
||
+ addi r4,r4,128
|
||
+ b L(32B_aligned_loop)
|
||
+
|
||
+L(tail1): TAIL(v15,v17)
|
||
+L(tail2): TAIL(v14,v16)
|
||
+
|
||
+END (STRCMP)
|
||
+libc_hidden_builtin_def (strcmp)
|
||
diff --git a/sysdeps/powerpc/powerpc64/multiarch/Makefile b/sysdeps/powerpc/powerpc64/multiarch/Makefile
|
||
index e321ce54e0..818f287925 100644
|
||
--- a/sysdeps/powerpc/powerpc64/multiarch/Makefile
|
||
+++ b/sysdeps/powerpc/powerpc64/multiarch/Makefile
|
||
@@ -32,7 +32,7 @@ sysdep_routines += memcpy-power8-cached memcpy-power7 memcpy-a2 memcpy-power6 \
|
||
ifneq (,$(filter %le,$(config-machine)))
|
||
sysdep_routines += memcmp-power10 memcpy-power10 memmove-power10 memset-power10 \
|
||
rawmemchr-power9 rawmemchr-power10 \
|
||
- strcmp-power9 strncmp-power9 \
|
||
+ strcmp-power9 strcmp-power10 strncmp-power9 \
|
||
strcpy-power9 strcat-power10 stpcpy-power9 \
|
||
strlen-power9 strncpy-power9 stpncpy-power9 strlen-power10
|
||
endif
|
||
diff --git a/sysdeps/powerpc/powerpc64/multiarch/ifunc-impl-list.c b/sysdeps/powerpc/powerpc64/multiarch/ifunc-impl-list.c
|
||
index 016d05fd16..dde3bec709 100644
|
||
--- a/sysdeps/powerpc/powerpc64/multiarch/ifunc-impl-list.c
|
||
+++ b/sysdeps/powerpc/powerpc64/multiarch/ifunc-impl-list.c
|
||
@@ -366,6 +366,10 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
|
||
/* Support sysdeps/powerpc/powerpc64/multiarch/strcmp.c. */
|
||
IFUNC_IMPL (i, name, strcmp,
|
||
#ifdef __LITTLE_ENDIAN__
|
||
+ IFUNC_IMPL_ADD (array, i, strcmp,
|
||
+ (hwcap2 & PPC_FEATURE2_ARCH_3_1)
|
||
+ && (hwcap & PPC_FEATURE_HAS_VSX),
|
||
+ __strcmp_power10)
|
||
IFUNC_IMPL_ADD (array, i, strcmp,
|
||
hwcap2 & PPC_FEATURE2_ARCH_3_00
|
||
&& hwcap & PPC_FEATURE_HAS_ALTIVEC,
|
||
diff --git a/sysdeps/powerpc/powerpc64/multiarch/strcmp-power10.S b/sysdeps/powerpc/powerpc64/multiarch/strcmp-power10.S
|
||
new file mode 100644
|
||
index 0000000000..a4ee7fb53c
|
||
--- /dev/null
|
||
+++ b/sysdeps/powerpc/powerpc64/multiarch/strcmp-power10.S
|
||
@@ -0,0 +1,26 @@
|
||
+/* Optimized strcmp implementation for POWER10/PPC64.
|
||
+ 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/>. */
|
||
+
|
||
+#if defined __LITTLE_ENDIAN__ && IS_IN (libc)
|
||
+#define STRCMP __strcmp_power10
|
||
+
|
||
+#undef libc_hidden_builtin_def
|
||
+#define libc_hidden_builtin_def(name)
|
||
+
|
||
+#include <sysdeps/powerpc/powerpc64/le/power10/strcmp.S>
|
||
+#endif /* __LITTLE_ENDIAN__ && IS_IN (libc) */
|
||
diff --git a/sysdeps/powerpc/powerpc64/multiarch/strcmp.c b/sysdeps/powerpc/powerpc64/multiarch/strcmp.c
|
||
index 7c77c084a7..3c636e3bbc 100644
|
||
--- a/sysdeps/powerpc/powerpc64/multiarch/strcmp.c
|
||
+++ b/sysdeps/powerpc/powerpc64/multiarch/strcmp.c
|
||
@@ -29,12 +29,16 @@ extern __typeof (strcmp) __strcmp_power7 attribute_hidden;
|
||
extern __typeof (strcmp) __strcmp_power8 attribute_hidden;
|
||
# ifdef __LITTLE_ENDIAN__
|
||
extern __typeof (strcmp) __strcmp_power9 attribute_hidden;
|
||
+extern __typeof (strcmp) __strcmp_power10 attribute_hidden;
|
||
# endif
|
||
|
||
# undef strcmp
|
||
|
||
libc_ifunc_redirected (__redirect_strcmp, strcmp,
|
||
# ifdef __LITTLE_ENDIAN__
|
||
+ (hwcap2 & PPC_FEATURE2_ARCH_3_1
|
||
+ && hwcap & PPC_FEATURE_HAS_VSX)
|
||
+ ? __strcmp_power10 :
|
||
(hwcap2 & PPC_FEATURE2_ARCH_3_00
|
||
&& hwcap & PPC_FEATURE_HAS_ALTIVEC)
|
||
? __strcmp_power9 :
|
||
|
||
commit 2dbf973fe03f9b8fd5a4740ee0af0d47afdd7bbd
|
||
Author: Sachin Monga <smonga@linux.ibm.com>
|
||
Date: Fri Nov 21 00:30:52 2025 -0500
|
||
|
||
ppc64le: Restore optimized strncmp for power10
|
||
|
||
This patch addresses the actual cause of CVE-2025-5745
|
||
|
||
The vector non-volatile registers are not used anymore for
|
||
32 byte load and comparison operation
|
||
|
||
Additionally, the assembler workaround used earlier for the
|
||
instruction lxvp is replaced with actual instruction.
|
||
|
||
Signed-off-by: Sachin Monga <smonga@linux.ibm.com>
|
||
Co-authored-by: Paul Murphy <paumurph@redhat.com>
|
||
(cherry picked from commit 2ea943f7d487d6a4166658b32af7c5365889fc34)
|
||
|
||
diff --git a/sysdeps/powerpc/powerpc64/le/power10/strncmp.S b/sysdeps/powerpc/powerpc64/le/power10/strncmp.S
|
||
new file mode 100644
|
||
index 0000000000..6e09fcb7f2
|
||
--- /dev/null
|
||
+++ b/sysdeps/powerpc/powerpc64/le/power10/strncmp.S
|
||
@@ -0,0 +1,252 @@
|
||
+/* Optimized strncmp implementation for PowerPC64/POWER10.
|
||
+ 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 <sysdep.h>
|
||
+
|
||
+/* Implements the function
|
||
+
|
||
+ int [r3] strncmp (const char *s1 [r3], const char *s2 [r4], size_t [r5] n)
|
||
+
|
||
+ The implementation uses unaligned doubleword access to avoid specialized
|
||
+ code paths depending of data alignment for first 32 bytes and uses
|
||
+ vectorised loops after that. */
|
||
+
|
||
+#ifndef STRNCMP
|
||
+# define STRNCMP strncmp
|
||
+#endif
|
||
+
|
||
+#define COMPARE_16(vreg1,vreg2,offset) \
|
||
+ lxv vreg1+32,offset(r3); \
|
||
+ lxv vreg2+32,offset(r4); \
|
||
+ vcmpnezb. v7,vreg1,vreg2; \
|
||
+ bne cr6,L(different); \
|
||
+ cmpldi cr7,r5,16; \
|
||
+ ble cr7,L(ret0); \
|
||
+ addi r5,r5,-16;
|
||
+
|
||
+#define COMPARE_32(vreg1,vreg2,offset,label1,label2) \
|
||
+ lxvp vreg1+32,offset(r3); \
|
||
+ lxvp vreg2+32,offset(r4); \
|
||
+ vcmpnezb. v7,vreg1+1,vreg2+1; \
|
||
+ bne cr6,L(label1); \
|
||
+ vcmpnezb. v7,vreg1,vreg2; \
|
||
+ bne cr6,L(label2); \
|
||
+ cmpldi cr7,r5,32; \
|
||
+ ble cr7,L(ret0); \
|
||
+ addi r5,r5,-32;
|
||
+
|
||
+#define TAIL_FIRST_16B(vreg1,vreg2) \
|
||
+ vctzlsbb r6,v7; \
|
||
+ cmpld cr7,r5,r6; \
|
||
+ ble cr7,L(ret0); \
|
||
+ vextubrx r5,r6,vreg1; \
|
||
+ vextubrx r4,r6,vreg2; \
|
||
+ subf r3,r4,r5; \
|
||
+ blr;
|
||
+
|
||
+#define TAIL_SECOND_16B(vreg1,vreg2) \
|
||
+ vctzlsbb r6,v7; \
|
||
+ addi r0,r6,16; \
|
||
+ cmpld cr7,r5,r0; \
|
||
+ ble cr7,L(ret0); \
|
||
+ vextubrx r5,r6,vreg1; \
|
||
+ vextubrx r4,r6,vreg2; \
|
||
+ subf r3,r4,r5; \
|
||
+ blr;
|
||
+
|
||
+#define CHECK_N_BYTES(reg1,reg2,len_reg) \
|
||
+ sldi r6,len_reg,56; \
|
||
+ lxvl 32+v4,reg1,r6; \
|
||
+ lxvl 32+v5,reg2,r6; \
|
||
+ add reg1,reg1,len_reg; \
|
||
+ add reg2,reg2,len_reg; \
|
||
+ vcmpnezb v7,v4,v5; \
|
||
+ vctzlsbb r6,v7; \
|
||
+ cmpld cr7,r6,len_reg; \
|
||
+ blt cr7,L(different); \
|
||
+ cmpld cr7,r5,len_reg; \
|
||
+ ble cr7,L(ret0); \
|
||
+ sub r5,r5,len_reg; \
|
||
+
|
||
+ .machine power10
|
||
+ENTRY_TOCLESS (STRNCMP, 4)
|
||
+ /* Check if size is 0. */
|
||
+ cmpdi cr0,r5,0
|
||
+ beq cr0,L(ret0)
|
||
+ andi. r7,r3,4095
|
||
+ andi. r8,r4,4095
|
||
+ cmpldi cr0,r7,4096-16
|
||
+ cmpldi cr1,r8,4096-16
|
||
+ bgt cr0,L(crosses)
|
||
+ bgt cr1,L(crosses)
|
||
+ COMPARE_16(v4,v5,0)
|
||
+ addi r3,r3,16
|
||
+ addi r4,r4,16
|
||
+
|
||
+L(crosses):
|
||
+ andi. r7,r3,15
|
||
+ subfic r7,r7,16 /* r7(nalign1) = 16 - (str1 & 15). */
|
||
+ andi. r9,r4,15
|
||
+ subfic r8,r9,16 /* r8(nalign2) = 16 - (str2 & 15). */
|
||
+ cmpld cr7,r7,r8
|
||
+ beq cr7,L(same_aligned)
|
||
+ blt cr7,L(nalign1_min)
|
||
+
|
||
+ /* nalign2 is minimum and s2 pointer is aligned. */
|
||
+ CHECK_N_BYTES(r3,r4,r8)
|
||
+ /* Are we on the 64B hunk which crosses a page? */
|
||
+ andi. r10,r3,63 /* Determine offset into 64B hunk. */
|
||
+ andi. r8,r3,15 /* The offset into the 16B hunk. */
|
||
+ neg r7,r3
|
||
+ andi. r9,r7,15 /* Number of bytes after a 16B cross. */
|
||
+ rlwinm. r7,r7,26,0x3F /* ((r4-4096))>>6&63. */
|
||
+ beq L(compare_64_pagecross)
|
||
+ mtctr r7
|
||
+ b L(compare_64B_unaligned)
|
||
+
|
||
+ /* nalign1 is minimum and s1 pointer is aligned. */
|
||
+L(nalign1_min):
|
||
+ CHECK_N_BYTES(r3,r4,r7)
|
||
+ /* Are we on the 64B hunk which crosses a page? */
|
||
+ andi. r10,r4,63 /* Determine offset into 64B hunk. */
|
||
+ andi. r8,r4,15 /* The offset into the 16B hunk. */
|
||
+ neg r7,r4
|
||
+ andi. r9,r7,15 /* Number of bytes after a 16B cross. */
|
||
+ rlwinm. r7,r7,26,0x3F /* ((r4-4096))>>6&63. */
|
||
+ beq L(compare_64_pagecross)
|
||
+ mtctr r7
|
||
+
|
||
+ .p2align 5
|
||
+L(compare_64B_unaligned):
|
||
+ COMPARE_16(v4,v5,0)
|
||
+ COMPARE_16(v4,v5,16)
|
||
+ COMPARE_16(v4,v5,32)
|
||
+ COMPARE_16(v4,v5,48)
|
||
+ addi r3,r3,64
|
||
+ addi r4,r4,64
|
||
+ bdnz L(compare_64B_unaligned)
|
||
+
|
||
+ /* Cross the page boundary of s2, carefully. Only for first
|
||
+ iteration we have to get the count of 64B blocks to be checked.
|
||
+ From second iteration and beyond, loop counter is always 63. */
|
||
+L(compare_64_pagecross):
|
||
+ li r11, 63
|
||
+ mtctr r11
|
||
+ cmpldi r10,16
|
||
+ ble L(cross_4)
|
||
+ cmpldi r10,32
|
||
+ ble L(cross_3)
|
||
+ cmpldi r10,48
|
||
+ ble L(cross_2)
|
||
+L(cross_1):
|
||
+ CHECK_N_BYTES(r3,r4,r9)
|
||
+ CHECK_N_BYTES(r3,r4,r8)
|
||
+ COMPARE_16(v4,v5,0)
|
||
+ COMPARE_16(v4,v5,16)
|
||
+ COMPARE_16(v4,v5,32)
|
||
+ addi r3,r3,48
|
||
+ addi r4,r4,48
|
||
+ b L(compare_64B_unaligned)
|
||
+L(cross_2):
|
||
+ COMPARE_16(v4,v5,0)
|
||
+ addi r3,r3,16
|
||
+ addi r4,r4,16
|
||
+ CHECK_N_BYTES(r3,r4,r9)
|
||
+ CHECK_N_BYTES(r3,r4,r8)
|
||
+ COMPARE_16(v4,v5,0)
|
||
+ COMPARE_16(v4,v5,16)
|
||
+ addi r3,r3,32
|
||
+ addi r4,r4,32
|
||
+ b L(compare_64B_unaligned)
|
||
+L(cross_3):
|
||
+ COMPARE_16(v4,v5,0)
|
||
+ COMPARE_16(v4,v5,16)
|
||
+ addi r3,r3,32
|
||
+ addi r4,r4,32
|
||
+ CHECK_N_BYTES(r3,r4,r9)
|
||
+ CHECK_N_BYTES(r3,r4,r8)
|
||
+ COMPARE_16(v4,v5,0)
|
||
+ addi r3,r3,16
|
||
+ addi r4,r4,16
|
||
+ b L(compare_64B_unaligned)
|
||
+L(cross_4):
|
||
+ COMPARE_16(v4,v5,0)
|
||
+ COMPARE_16(v4,v5,16)
|
||
+ COMPARE_16(v4,v5,32)
|
||
+ addi r3,r3,48
|
||
+ addi r4,r4,48
|
||
+ CHECK_N_BYTES(r3,r4,r9)
|
||
+ CHECK_N_BYTES(r3,r4,r8)
|
||
+ b L(compare_64B_unaligned)
|
||
+
|
||
+L(same_aligned):
|
||
+ CHECK_N_BYTES(r3,r4,r7)
|
||
+ /* Align s1 to 32B and adjust s2 address.
|
||
+ Use lxvp only if both s1 and s2 are 32B aligned. */
|
||
+ COMPARE_16(v4,v5,0)
|
||
+ COMPARE_16(v4,v5,16)
|
||
+ COMPARE_16(v4,v5,32)
|
||
+ COMPARE_16(v4,v5,48)
|
||
+ addi r3,r3,64
|
||
+ addi r4,r4,64
|
||
+ COMPARE_16(v4,v5,0)
|
||
+ COMPARE_16(v4,v5,16)
|
||
+ addi r5,r5,32
|
||
+
|
||
+ clrldi r6,r3,59
|
||
+ subfic r7,r6,32
|
||
+ add r3,r3,r7
|
||
+ add r4,r4,r7
|
||
+ subf r5,r7,r5
|
||
+ andi. r7,r4,0x1F
|
||
+ beq cr0,L(32B_aligned_loop)
|
||
+
|
||
+ .p2align 5
|
||
+L(16B_aligned_loop):
|
||
+ COMPARE_16(v4,v5,0)
|
||
+ COMPARE_16(v4,v5,16)
|
||
+ COMPARE_16(v4,v5,32)
|
||
+ COMPARE_16(v4,v5,48)
|
||
+ addi r3,r3,64
|
||
+ addi r4,r4,64
|
||
+ b L(16B_aligned_loop)
|
||
+
|
||
+ /* Calculate and return the difference. */
|
||
+L(different):
|
||
+ TAIL_FIRST_16B(v4,v5)
|
||
+
|
||
+ .p2align 5
|
||
+L(32B_aligned_loop):
|
||
+ COMPARE_32(v14,v16,0,tail1,tail2)
|
||
+ COMPARE_32(v14,v16,32,tail1,tail2)
|
||
+ COMPARE_32(v14,v16,64,tail1,tail2)
|
||
+ COMPARE_32(v14,v16,96,tail1,tail2)
|
||
+ addi r3,r3,128
|
||
+ addi r4,r4,128
|
||
+ b L(32B_aligned_loop)
|
||
+
|
||
+L(tail1): TAIL_FIRST_16B(v15,v17)
|
||
+L(tail2): TAIL_SECOND_16B(v14,v16)
|
||
+
|
||
+ .p2align 5
|
||
+L(ret0):
|
||
+ li r3,0
|
||
+ blr
|
||
+
|
||
+END(STRNCMP)
|
||
+libc_hidden_builtin_def(strncmp)
|
||
diff --git a/sysdeps/powerpc/powerpc64/multiarch/Makefile b/sysdeps/powerpc/powerpc64/multiarch/Makefile
|
||
index 818f287925..c9178223a8 100644
|
||
--- a/sysdeps/powerpc/powerpc64/multiarch/Makefile
|
||
+++ b/sysdeps/powerpc/powerpc64/multiarch/Makefile
|
||
@@ -32,7 +32,7 @@ sysdep_routines += memcpy-power8-cached memcpy-power7 memcpy-a2 memcpy-power6 \
|
||
ifneq (,$(filter %le,$(config-machine)))
|
||
sysdep_routines += memcmp-power10 memcpy-power10 memmove-power10 memset-power10 \
|
||
rawmemchr-power9 rawmemchr-power10 \
|
||
- strcmp-power9 strcmp-power10 strncmp-power9 \
|
||
+ strcmp-power9 strcmp-power10 strncmp-power9 strncmp-power10 \
|
||
strcpy-power9 strcat-power10 stpcpy-power9 \
|
||
strlen-power9 strncpy-power9 stpncpy-power9 strlen-power10
|
||
endif
|
||
diff --git a/sysdeps/powerpc/powerpc64/multiarch/ifunc-impl-list.c b/sysdeps/powerpc/powerpc64/multiarch/ifunc-impl-list.c
|
||
index dde3bec709..f2b9cccde3 100644
|
||
--- a/sysdeps/powerpc/powerpc64/multiarch/ifunc-impl-list.c
|
||
+++ b/sysdeps/powerpc/powerpc64/multiarch/ifunc-impl-list.c
|
||
@@ -164,6 +164,9 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
|
||
/* Support sysdeps/powerpc/powerpc64/multiarch/strncmp.c. */
|
||
IFUNC_IMPL (i, name, strncmp,
|
||
#ifdef __LITTLE_ENDIAN__
|
||
+ IFUNC_IMPL_ADD (array, i, strncmp, hwcap2 & PPC_FEATURE2_ARCH_3_1
|
||
+ && hwcap & PPC_FEATURE_HAS_VSX,
|
||
+ __strncmp_power10)
|
||
IFUNC_IMPL_ADD (array, i, strncmp, hwcap2 & PPC_FEATURE2_ARCH_3_00
|
||
&& hwcap & PPC_FEATURE_HAS_ALTIVEC,
|
||
__strncmp_power9)
|
||
diff --git a/sysdeps/powerpc/powerpc64/multiarch/strncmp-power10.S b/sysdeps/powerpc/powerpc64/multiarch/strncmp-power10.S
|
||
new file mode 100644
|
||
index 0000000000..bb25bc75b8
|
||
--- /dev/null
|
||
+++ b/sysdeps/powerpc/powerpc64/multiarch/strncmp-power10.S
|
||
@@ -0,0 +1,25 @@
|
||
+/* 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/>. */
|
||
+
|
||
+#if defined __LITTLE_ENDIAN__ && IS_IN (libc)
|
||
+#define STRNCMP __strncmp_power10
|
||
+
|
||
+#undef libc_hidden_builtin_def
|
||
+#define libc_hidden_builtin_def(name)
|
||
+
|
||
+#include <sysdeps/powerpc/powerpc64/le/power10/strncmp.S>
|
||
+#endif
|
||
diff --git a/sysdeps/powerpc/powerpc64/multiarch/strncmp.c b/sysdeps/powerpc/powerpc64/multiarch/strncmp.c
|
||
index 4cfe27fa45..0a664a620d 100644
|
||
--- a/sysdeps/powerpc/powerpc64/multiarch/strncmp.c
|
||
+++ b/sysdeps/powerpc/powerpc64/multiarch/strncmp.c
|
||
@@ -29,6 +29,7 @@ extern __typeof (strncmp) __strncmp_ppc attribute_hidden;
|
||
extern __typeof (strncmp) __strncmp_power8 attribute_hidden;
|
||
# ifdef __LITTLE_ENDIAN__
|
||
extern __typeof (strncmp) __strncmp_power9 attribute_hidden;
|
||
+extern __typeof (strncmp) __strncmp_power10 attribute_hidden;
|
||
# endif
|
||
# undef strncmp
|
||
|
||
@@ -36,6 +37,9 @@ extern __typeof (strncmp) __strncmp_power9 attribute_hidden;
|
||
ifunc symbol properly. */
|
||
libc_ifunc_redirected (__redirect_strncmp, strncmp,
|
||
# ifdef __LITTLE_ENDIAN__
|
||
+ (hwcap2 & PPC_FEATURE2_ARCH_3_1
|
||
+ && hwcap & PPC_FEATURE_HAS_VSX)
|
||
+ ? __strncmp_power10 :
|
||
(hwcap2 & PPC_FEATURE2_ARCH_3_00
|
||
&& hwcap & PPC_FEATURE_HAS_ALTIVEC)
|
||
? __strncmp_power9 :
|
||
|
||
commit 8aaf4b732d7650c2db3beb4dc8bb70eab5b022c3
|
||
Author: Sachin Monga <smonga@linux.ibm.com>
|
||
Date: Thu Nov 27 03:28:17 2025 -0500
|
||
|
||
ppc64le: Power 10 rawmemchr clobbers v20 (bug #33091)
|
||
|
||
Replace non-volatile(v20) by volatile(v17)
|
||
since v20 is not restored
|
||
|
||
Reviewed-by: Peter Bergner <bergner@tenstorrent.com>
|
||
(cherry picked from commit b59799f14f97f697c3a36b4380bd4ce2fbe65f11)
|
||
|
||
diff --git a/sysdeps/powerpc/powerpc64/le/power10/strlen.S b/sysdeps/powerpc/powerpc64/le/power10/strlen.S
|
||
index ec644d5bff..29a5a7d960 100644
|
||
--- a/sysdeps/powerpc/powerpc64/le/power10/strlen.S
|
||
+++ b/sysdeps/powerpc/powerpc64/le/power10/strlen.S
|
||
@@ -31,7 +31,7 @@
|
||
# define FUNCNAME RAWMEMCHR
|
||
# endif
|
||
# define MCOUNT_NARGS 2
|
||
-# define VREG_ZERO v20
|
||
+# define VREG_ZERO v17
|
||
# define OFF_START_LOOP 256
|
||
# define RAWMEMCHR_SUBTRACT_VECTORS \
|
||
vsububm v4,v4,v18; \
|
||
|
||
commit b11411fe2ee7a8f3c3a2c1ee99c1729adb9a0efe
|
||
Author: Yury Khrustalev <yury.khrustalev@arm.com>
|
||
Date: Thu Nov 6 12:57:58 2025 +0000
|
||
|
||
posix: Fix invalid flags test for p{write,read}v2
|
||
|
||
Two tests fail from time to time when a new flag is added for the
|
||
p{write,read}v2 functions in a new Linux kernel:
|
||
|
||
- misc/tst-preadvwritev2
|
||
- misc/tst-preadvwritev64v2
|
||
|
||
This disrupts when testing Glibc on a system with a newer kernel
|
||
and it seems we can try improve testing for invalid flags setting
|
||
all the bits that are not supposed to be supported (rather than
|
||
setting only the next unsupported bit).
|
||
|
||
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
||
(cherry picked from commit 58a31b4316f1f687184eb147ffa1c676bc6a190e)
|
||
|
||
diff --git a/misc/tst-preadvwritev2-common.c b/misc/tst-preadvwritev2-common.c
|
||
index ff1007d6d2..5182fcdce0 100644
|
||
--- a/misc/tst-preadvwritev2-common.c
|
||
+++ b/misc/tst-preadvwritev2-common.c
|
||
@@ -109,9 +109,8 @@ do_test_with_invalid_iov (void)
|
||
static void
|
||
do_test_with_invalid_flags (void)
|
||
{
|
||
- /* Set the next bit from the mask of all supported flags. */
|
||
- int invalid_flag = RWF_SUPPORTED != 0 ? __builtin_clz (RWF_SUPPORTED) : 2;
|
||
- invalid_flag = 0x1 << ((sizeof (int) * CHAR_BIT) - invalid_flag);
|
||
+ /* Set all the bits that are not used by the supported flags. */
|
||
+ int invalid_flag = ~RWF_SUPPORTED;
|
||
|
||
char buf[32];
|
||
const struct iovec vec = { .iov_base = buf, .iov_len = sizeof (buf) };
|
||
|
||
commit efdf4c0c879590109778244046f84a80a4bf8fee
|
||
Author: DJ Delorie <dj@redhat.com>
|
||
Date: Wed Oct 15 21:37:56 2025 -0400
|
||
|
||
sprof: check pread size and offset for overflow
|
||
|
||
Add a bit of descriptive paranoia to the values we read from
|
||
the ELF headers and use to access data.
|
||
|
||
Reviewed-by: Collin Funk <collin.funk1@gmail.com>
|
||
(cherry picked from commit 324084649b2da2f6840e3a1b84159a4e9a9e9a74)
|
||
|
||
diff --git a/elf/sprof.c b/elf/sprof.c
|
||
index c82c7c9db6..e9d2a66a4f 100644
|
||
--- a/elf/sprof.c
|
||
+++ b/elf/sprof.c
|
||
@@ -38,6 +38,7 @@
|
||
#include <sys/mman.h>
|
||
#include <sys/param.h>
|
||
#include <sys/stat.h>
|
||
+#include <intprops.h>
|
||
|
||
/* Get libc version number. */
|
||
#include "../version.h"
|
||
@@ -410,6 +411,7 @@ load_shobj (const char *name)
|
||
int fd;
|
||
ElfW(Shdr) *shdr;
|
||
size_t pagesize = getpagesize ();
|
||
+ struct stat st;
|
||
|
||
/* Since we use dlopen() we must be prepared to work around the sometimes
|
||
strange lookup rules for the shared objects. If we have a file foo.so
|
||
@@ -550,14 +552,39 @@ load_shobj (const char *name)
|
||
error (EXIT_FAILURE, errno, _("Reopening shared object `%s' failed"),
|
||
map->l_name);
|
||
|
||
+ if (fstat (fd, &st) < 0)
|
||
+ error (EXIT_FAILURE, errno, _("stat(%s) failure"), map->l_name);
|
||
+
|
||
+ /* We're depending on data that's being read from the file, so be a
|
||
+ bit paranoid here and make sure the requests are reasonable -
|
||
+ i.e. both size and offset are nonnegative and smaller than the
|
||
+ file size, as well as the offset of the end of the data. PREAD
|
||
+ would have failed anyway, but this is more robust and explains
|
||
+ what happened better. Note that SZ must be unsigned and OFF may
|
||
+ be signed or unsigned. */
|
||
+#define PCHECK(sz1,off1) { \
|
||
+ size_t sz = sz1, end_off; \
|
||
+ off_t off = off1; \
|
||
+ if (sz > st.st_size \
|
||
+ || off < 0 || off > st.st_size \
|
||
+ || INT_ADD_WRAPV (sz, off, &end_off) \
|
||
+ || end_off > st.st_size) \
|
||
+ error (EXIT_FAILURE, ERANGE, \
|
||
+ _("read outside of file extents %zu + %zd > %zu"), \
|
||
+ sz, off, st.st_size); \
|
||
+ }
|
||
+
|
||
/* Map the section header. */
|
||
size_t size = ehdr->e_shnum * sizeof (ElfW(Shdr));
|
||
shdr = (ElfW(Shdr) *) alloca (size);
|
||
+ PCHECK (size, ehdr->e_shoff);
|
||
if (pread (fd, shdr, size, ehdr->e_shoff) != size)
|
||
error (EXIT_FAILURE, errno, _("reading of section headers failed"));
|
||
|
||
/* Get the section header string table. */
|
||
char *shstrtab = (char *) alloca (shdr[ehdr->e_shstrndx].sh_size);
|
||
+ PCHECK (shdr[ehdr->e_shstrndx].sh_size,
|
||
+ shdr[ehdr->e_shstrndx].sh_offset);
|
||
if (pread (fd, shstrtab, shdr[ehdr->e_shstrndx].sh_size,
|
||
shdr[ehdr->e_shstrndx].sh_offset)
|
||
!= shdr[ehdr->e_shstrndx].sh_size)
|
||
@@ -585,6 +612,7 @@ load_shobj (const char *name)
|
||
size_t size = debuglink_entry->sh_size;
|
||
char *debuginfo_fname = (char *) alloca (size + 1);
|
||
debuginfo_fname[size] = '\0';
|
||
+ PCHECK (size, debuglink_entry->sh_offset);
|
||
if (pread (fd, debuginfo_fname, size, debuglink_entry->sh_offset)
|
||
!= size)
|
||
{
|
||
@@ -638,21 +666,32 @@ load_shobj (const char *name)
|
||
if (fd2 != -1)
|
||
{
|
||
ElfW(Ehdr) ehdr2;
|
||
+ struct stat st;
|
||
+
|
||
+ if (fstat (fd2, &st) < 0)
|
||
+ error (EXIT_FAILURE, errno, _("stat(%s) failure"), workbuf);
|
||
|
||
/* Read the ELF header. */
|
||
+ PCHECK (sizeof (ehdr2), 0);
|
||
if (pread (fd2, &ehdr2, sizeof (ehdr2), 0) != sizeof (ehdr2))
|
||
error (EXIT_FAILURE, errno,
|
||
_("reading of ELF header failed"));
|
||
|
||
/* Map the section header. */
|
||
- size_t size = ehdr2.e_shnum * sizeof (ElfW(Shdr));
|
||
+ size_t size;
|
||
+ if (INT_MULTIPLY_WRAPV (ehdr2.e_shnum, sizeof (ElfW(Shdr)), &size))
|
||
+ error (EXIT_FAILURE, errno, _("too many section headers"));
|
||
+
|
||
ElfW(Shdr) *shdr2 = (ElfW(Shdr) *) alloca (size);
|
||
+ PCHECK (size, ehdr2.e_shoff);
|
||
if (pread (fd2, shdr2, size, ehdr2.e_shoff) != size)
|
||
error (EXIT_FAILURE, errno,
|
||
_("reading of section headers failed"));
|
||
|
||
/* Get the section header string table. */
|
||
shstrtab = (char *) alloca (shdr2[ehdr2.e_shstrndx].sh_size);
|
||
+ PCHECK (shdr2[ehdr2.e_shstrndx].sh_size,
|
||
+ shdr2[ehdr2.e_shstrndx].sh_offset);
|
||
if (pread (fd2, shstrtab, shdr2[ehdr2.e_shstrndx].sh_size,
|
||
shdr2[ehdr2.e_shstrndx].sh_offset)
|
||
!= shdr2[ehdr2.e_shstrndx].sh_size)
|
||
|
||
commit 2a0873aa81446149c6065237e1dc2511201bef88
|
||
Author: Collin Funk <collin.funk1@gmail.com>
|
||
Date: Wed Oct 22 01:51:09 2025 -0700
|
||
|
||
sprof: fix -Wformat warnings on 32-bit hosts
|
||
|
||
Reviewed-by: H.J. Lu <hjl.tools@gmail.com>
|
||
(cherry picked from commit 9681f645ba20fc3c18eb12ffebf94e3df1f888e3)
|
||
|
||
diff --git a/elf/sprof.c b/elf/sprof.c
|
||
index e9d2a66a4f..513e0470b2 100644
|
||
--- a/elf/sprof.c
|
||
+++ b/elf/sprof.c
|
||
@@ -570,8 +570,8 @@ load_shobj (const char *name)
|
||
|| INT_ADD_WRAPV (sz, off, &end_off) \
|
||
|| end_off > st.st_size) \
|
||
error (EXIT_FAILURE, ERANGE, \
|
||
- _("read outside of file extents %zu + %zd > %zu"), \
|
||
- sz, off, st.st_size); \
|
||
+ _("read outside of file extents %zu + %jd > %jd"), \
|
||
+ sz, (intmax_t) off, (intmax_t) st.st_size); \
|
||
}
|
||
|
||
/* Map the section header. */
|
||
|
||
commit 8dfb84ad4efbc39c7a7d9efdff6f6ac9017e0a53
|
||
Author: Florian Weimer <fweimer@redhat.com>
|
||
Date: Thu Nov 6 14:33:22 2025 +0100
|
||
|
||
support: Fix FILE * leak in check_for_unshare_hints in test-container
|
||
|
||
The file opened via fopen is never closed.
|
||
|
||
(cherry picked from commit 20a2a756089eacd7e7f4c02e381e82b5d0e40a2c)
|
||
|
||
diff --git a/support/test-container.c b/support/test-container.c
|
||
index 1c40ab377f..d78139622f 100644
|
||
--- a/support/test-container.c
|
||
+++ b/support/test-container.c
|
||
@@ -705,6 +705,7 @@ check_for_unshare_hints (int require_pidns)
|
||
|
||
val = -1; /* Sentinel. */
|
||
int cnt = fscanf (f, "%d", &val);
|
||
+ fclose (f);
|
||
if (cnt == 1 && val != files[i].bad_value)
|
||
continue;
|
||
|
||
|
||
commit a1d3294a5bed821aece03994ab4e72c8b822a962
|
||
Author: Florian Weimer <fweimer@redhat.com>
|
||
Date: Thu Nov 6 14:49:21 2025 +0100
|
||
|
||
support: Exit on consistency check failure in resolv_response_add_name
|
||
|
||
Using TEST_VERIFY (crname_target != crname) instructs some analysis
|
||
tools that crname_target == crname might hold. Under this assumption,
|
||
they report a use-after-free for crname_target->offset below, caused
|
||
by the previous free (crname).
|
||
|
||
Reviewed-by: Collin Funk <collin.funk1@gmail.com>
|
||
(cherry picked from commit b64335ff111c071fde61aec1c1a8460afb3d16d4)
|
||
|
||
diff --git a/support/resolv_test.c b/support/resolv_test.c
|
||
index ab37d3d58c..29e59da958 100644
|
||
--- a/support/resolv_test.c
|
||
+++ b/support/resolv_test.c
|
||
@@ -326,7 +326,7 @@ resolv_response_add_name (struct resolv_response_builder *b,
|
||
crname_target = *ptr;
|
||
else
|
||
crname_target = NULL;
|
||
- TEST_VERIFY (crname_target != crname);
|
||
+ TEST_VERIFY_EXIT (crname_target != crname);
|
||
/* Not added to the tree. */
|
||
free (crname);
|
||
}
|
||
|
||
commit f122d0b4d145814869bf10c56db1d971bcba55c5
|
||
Author: Sunil K Pandey <sunil.k.pandey@intel.com>
|
||
Date: Tue Dec 9 08:57:44 2025 -0800
|
||
|
||
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)
|
||
|
||
diff --git a/nptl/pthread_mutex_trylock.c b/nptl/pthread_mutex_trylock.c
|
||
index dbb8fcc754..392619021b 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. */
|
||
|
||
commit b0ec8fb689df862171f0f78994a3bdeb51313545
|
||
Author: Siddhesh Poyarekar <siddhesh@gotplt.org>
|
||
Date: Thu Jan 15 06:06:40 2026 -0500
|
||
|
||
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)
|
||
|
||
diff --git a/malloc/malloc.c b/malloc/malloc.c
|
||
index 5f3e701fd1..1d5aa304d3 100644
|
||
--- a/malloc/malloc.c
|
||
+++ b/malloc/malloc.c
|
||
@@ -5167,7 +5167,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;
|
||
@@ -5183,7 +5183,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 == NULL)
|
||
diff --git a/malloc/tst-malloc-too-large.c b/malloc/tst-malloc-too-large.c
|
||
index a548a37b46..a1bda673a3 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.
|
||
|
||
|
||
commit 453e6b8dbab935257eb0802b0c97bca6b67ba30e
|
||
Author: Carlos O'Donell <carlos@redhat.com>
|
||
Date: Thu Jan 15 15:09:38 2026 -0500
|
||
|
||
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)
|
||
|
||
diff --git a/resolv/nss_dns/dns-network.c b/resolv/nss_dns/dns-network.c
|
||
index 519f8422ca..e14e959d7c 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 d9f69649d0..181be80835 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");
|
||
|
||
commit cbf39c26b25801e9bc88499b4fd361ac172d4125
|
||
Author: Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
||
Date: Thu Jan 15 10:32:19 2026 -0300
|
||
|
||
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)
|
||
|
||
diff --git a/NEWS b/NEWS
|
||
index ed3c114c7a..7e7e1930dd 100644
|
||
--- a/NEWS
|
||
+++ b/NEWS
|
||
@@ -16,6 +16,8 @@ The following bugs were resolved with this release:
|
||
[33356] nptl: creating thread stack with guardsize 0 can erroneously
|
||
conclude MADV_GUARD_INSTALL is available
|
||
[33361] nss: Group merge does not react to ERANGE during merge
|
||
+ [33814] glob: wordexp with WRDE_REUSE and WRDE_APPEND may return
|
||
+ uninitialized memory
|
||
|
||
Version 2.42
|
||
|
||
diff --git a/posix/Makefile b/posix/Makefile
|
||
index a36e5decd3..1ea86efcc1 100644
|
||
--- a/posix/Makefile
|
||
+++ b/posix/Makefile
|
||
@@ -327,6 +327,7 @@ tests := \
|
||
tst-wait4 \
|
||
tst-waitid \
|
||
tst-wordexp-nocmd \
|
||
+ tst-wordexp-reuse \
|
||
tstgetopt \
|
||
# tests
|
||
|
||
@@ -457,6 +458,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
|
||
@@ -492,6 +495,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
|
||
@@ -775,3 +779,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 a69b732801..9df4bb7424 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)
|
||
|
||
commit 912d89a766847649a3857985a3b5e6065c51bfd4
|
||
Author: Florian Weimer <fweimer@redhat.com>
|
||
Date: Thu Jan 8 12:35:08 2026 +0100
|
||
|
||
Switch currency symbol for the bg_BG locale to euro
|
||
|
||
Bulgaria joined the eurozone on 2026-01-01.
|
||
|
||
Suggested-by: Йордан Гигов <jgigov@abv.bg>
|
||
Reviewed-by: Collin Funk <collin.funk1@gmail.com>
|
||
(cherry picked from commit 78fdb2d6b1c34ea8e779fd48f9436dfbd50b6387)
|
||
|
||
diff --git a/localedata/locales/bg_BG b/localedata/locales/bg_BG
|
||
index 159a6c3334..eda2a8d01b 100644
|
||
--- a/localedata/locales/bg_BG
|
||
+++ b/localedata/locales/bg_BG
|
||
@@ -248,8 +248,8 @@ reorder-end
|
||
END LC_COLLATE
|
||
|
||
LC_MONETARY
|
||
-int_curr_symbol "BGN "
|
||
-currency_symbol "лв."
|
||
+int_curr_symbol "EUR "
|
||
+currency_symbol "€"
|
||
mon_decimal_point ","
|
||
mon_thousands_sep " "
|
||
mon_grouping 3
|
||
|
||
commit 39897805917ab1c44dbf4452b9c4c2bbafc7117b
|
||
Author: Florian Weimer <fweimer@redhat.com>
|
||
Date: Fri Feb 13 09:02:07 2026 +0100
|
||
|
||
nss: Introduce dedicated struct nss_database_for_fork type
|
||
|
||
The initialized field in struct nss_database_data is rather confusing
|
||
because it is not used by the regular NSS code, only by the fork
|
||
state synchronization code. Introduce a separate type and place
|
||
the initialized field there.
|
||
|
||
Reviewed-by: Sam James <sam@gentoo.org>
|
||
(cherry picked from commit 7bb859f4198d0be19c31a9937eae4f6c2c9a079e)
|
||
|
||
diff --git a/nss/nss_database.c b/nss/nss_database.c
|
||
index a7ac32beb9..a6b7d5c956 100644
|
||
--- a/nss/nss_database.c
|
||
+++ b/nss/nss_database.c
|
||
@@ -56,7 +56,6 @@ global_state_allocate (void *closure)
|
||
{
|
||
result->data.nsswitch_conf.size = -1; /* Force reload. */
|
||
memset (result->data.services, 0, sizeof (result->data.services));
|
||
- result->data.initialized = true;
|
||
result->data.reload_disabled = false;
|
||
__libc_lock_init (result->lock);
|
||
result->root_ino = 0;
|
||
@@ -451,8 +450,8 @@ nss_database_check_reload_and_get (struct nss_database_state *local,
|
||
/* Avoid overwriting the global configuration until we have loaded
|
||
everything successfully. Otherwise, if the file change
|
||
information changes back to what is in the global configuration,
|
||
- the lookups would use the partially-written configuration. */
|
||
- struct nss_database_data staging = { .initialized = true, };
|
||
+ the lookups would use the partially-written configuration. */
|
||
+ struct nss_database_data staging = { };
|
||
|
||
bool ok = nss_database_reload (&staging, &initial);
|
||
|
||
@@ -503,7 +502,7 @@ __nss_database_freeres (void)
|
||
}
|
||
|
||
void
|
||
-__nss_database_fork_prepare_parent (struct nss_database_data *data)
|
||
+__nss_database_fork_prepare_parent (struct nss_database_for_fork *data)
|
||
{
|
||
/* Do not use allocate_once to trigger loading unnecessarily. */
|
||
struct nss_database_state *local = atomic_load_acquire (&global_database_state);
|
||
@@ -515,20 +514,21 @@ __nss_database_fork_prepare_parent (struct nss_database_data *data)
|
||
because it avoids acquiring the lock during the actual
|
||
fork. */
|
||
__libc_lock_lock (local->lock);
|
||
- *data = local->data;
|
||
+ data->data = local->data;
|
||
__libc_lock_unlock (local->lock);
|
||
+ data->initialized = true;
|
||
}
|
||
}
|
||
|
||
void
|
||
-__nss_database_fork_subprocess (struct nss_database_data *data)
|
||
+__nss_database_fork_subprocess (struct nss_database_for_fork *data)
|
||
{
|
||
struct nss_database_state *local = atomic_load_acquire (&global_database_state);
|
||
if (data->initialized)
|
||
{
|
||
/* Restore the state at the point of the fork. */
|
||
assert (local != NULL);
|
||
- local->data = *data;
|
||
+ local->data = data->data;
|
||
__libc_lock_init (local->lock);
|
||
}
|
||
else if (local != NULL)
|
||
diff --git a/nss/nss_database.h b/nss/nss_database.h
|
||
index 0eaea49685..c170da03f6 100644
|
||
--- a/nss/nss_database.h
|
||
+++ b/nss/nss_database.h
|
||
@@ -70,15 +70,21 @@ struct nss_database_data
|
||
struct file_change_detection nsswitch_conf;
|
||
nss_action_list services[NSS_DATABASE_COUNT];
|
||
int reload_disabled; /* Actually bool; int for atomic access. */
|
||
- bool initialized;
|
||
+};
|
||
+
|
||
+/* Use to store a consistent state snapshot across fork. */
|
||
+struct nss_database_for_fork
|
||
+{
|
||
+ bool initialized; /* Set to true if the data field below is initialized. */
|
||
+ struct nss_database_data data;
|
||
};
|
||
|
||
/* Called by fork in the parent process, before forking. */
|
||
-void __nss_database_fork_prepare_parent (struct nss_database_data *data)
|
||
+void __nss_database_fork_prepare_parent (struct nss_database_for_fork *)
|
||
attribute_hidden;
|
||
|
||
/* Called by fork in the new subprocess, after forking. */
|
||
-void __nss_database_fork_subprocess (struct nss_database_data *data)
|
||
+void __nss_database_fork_subprocess (struct nss_database_for_fork *)
|
||
attribute_hidden;
|
||
|
||
#endif /* _NSS_DATABASE_H */
|
||
diff --git a/posix/fork.c b/posix/fork.c
|
||
index 011e92fc1d..7f2370f2eb 100644
|
||
--- a/posix/fork.c
|
||
+++ b/posix/fork.c
|
||
@@ -50,7 +50,7 @@ __libc_fork (void)
|
||
|
||
lastrun = __run_prefork_handlers (multiple_threads);
|
||
|
||
- struct nss_database_data nss_database_data;
|
||
+ struct nss_database_for_fork nss_database_data;
|
||
|
||
/* If we are not running multiple threads, we do not have to
|
||
preserve lock state. If fork runs from a signal handler, only
|
||
|
||
commit 937ef7aaf3ce41038b3e12675a6298b86b389af2
|
||
Author: Florian Weimer <fweimer@redhat.com>
|
||
Date: Fri Feb 13 09:02:07 2026 +0100
|
||
|
||
Linux: In getlogin_r, use utmp fallback only for specific errors
|
||
|
||
Most importantly, if getwpuid_r fails, it does not make sense to retry
|
||
via utmp because the user ID obtained from there is less reliable than
|
||
the one from /proc/self/loginuid.
|
||
|
||
Reviewed-by: Sam James <sam@gentoo.org>
|
||
(cherry picked from commit 28660f4b45afa8921c2faebaec2846f95f670ba0)
|
||
|
||
diff --git a/sysdeps/unix/sysv/linux/getlogin_r.c b/sysdeps/unix/sysv/linux/getlogin_r.c
|
||
index f03ecd4da9..0e66944570 100644
|
||
--- a/sysdeps/unix/sysv/linux/getlogin_r.c
|
||
+++ b/sysdeps/unix/sysv/linux/getlogin_r.c
|
||
@@ -37,7 +37,12 @@ __getlogin_r_loginuid (char *name, size_t namesize)
|
||
{
|
||
int fd = __open_nocancel ("/proc/self/loginuid", O_RDONLY);
|
||
if (fd == -1)
|
||
- return -1;
|
||
+ {
|
||
+ if (errno == ENOENT)
|
||
+ /* Trigger utmp fallback. */
|
||
+ return -1;
|
||
+ return errno;
|
||
+ }
|
||
|
||
/* We are reading a 32-bit number. 12 bytes are enough for the text
|
||
representation. If not, something is wrong. */
|
||
@@ -45,6 +50,8 @@ __getlogin_r_loginuid (char *name, size_t namesize)
|
||
ssize_t n = TEMP_FAILURE_RETRY (__read_nocancel (fd, uidbuf,
|
||
sizeof (uidbuf)));
|
||
__close_nocancel_nostatus (fd);
|
||
+ if (n < 0)
|
||
+ return errno;
|
||
|
||
uid_t uid;
|
||
char *endp;
|
||
@@ -53,12 +60,13 @@ __getlogin_r_loginuid (char *name, size_t namesize)
|
||
|| (uidbuf[n] = '\0',
|
||
uid = strtoul (uidbuf, &endp, 10),
|
||
endp == uidbuf || *endp != '\0'))
|
||
- return -1;
|
||
+ return EINVAL;
|
||
|
||
/* If there is no login uid, linux sets /proc/self/loginid to the sentinel
|
||
value of, (uid_t) -1, so check if that value is set and return early to
|
||
avoid making unneeded nss lookups. */
|
||
if (uid == (uid_t) -1)
|
||
+ /* Trigger utmp fallback. */
|
||
return -1;
|
||
|
||
struct passwd pwd;
|
||
@@ -78,9 +86,14 @@ __getlogin_r_loginuid (char *name, size_t namesize)
|
||
}
|
||
}
|
||
|
||
- if (res != 0 || tpwd == NULL)
|
||
+ if (res != 0)
|
||
+ {
|
||
+ result = res;
|
||
+ goto out;
|
||
+ }
|
||
+ if (tpwd == NULL)
|
||
{
|
||
- result = -1;
|
||
+ result = ENOENT;
|
||
goto out;
|
||
}
|
||
|
||
|
||
commit ebd45473f5421e0fced5ba2cde0f1aaa36e79b61
|
||
Author: Florian Weimer <fweimer@redhat.com>
|
||
Date: Fri Feb 13 09:02:07 2026 +0100
|
||
|
||
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>
|
||
(cherry picked from commit 5b713b49443eb6a4e54e50e2f0147105f86dab02)
|
||
|
||
diff --git a/nss/Makefile b/nss/Makefile
|
||
index 1991b7482a..f690c29b94 100644
|
||
--- a/nss/Makefile
|
||
+++ b/nss/Makefile
|
||
@@ -326,6 +326,7 @@ tests := \
|
||
tst-gshadow \
|
||
tst-nss-getpwent \
|
||
tst-nss-hash \
|
||
+ tst-nss-malloc-failure-getlogin_r \
|
||
tst-nss-test1 \
|
||
tst-nss-test2 \
|
||
tst-nss-test4 \
|
||
diff --git a/nss/nss_database.c b/nss/nss_database.c
|
||
index a6b7d5c956..7aa460c7df 100644
|
||
--- a/nss/nss_database.c
|
||
+++ b/nss/nss_database.c
|
||
@@ -250,9 +250,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)
|
||
@@ -477,6 +480,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)
|
||
diff --git a/nss/tst-nss-malloc-failure-getlogin_r.c b/nss/tst-nss-malloc-failure-getlogin_r.c
|
||
new file mode 100644
|
||
index 0000000000..0e2985ad57
|
||
--- /dev/null
|
||
+++ b/nss/tst-nss-malloc-failure-getlogin_r.c
|
||
@@ -0,0 +1,345 @@
|
||
+/* Test NSS/getlogin_r with injected allocation failures (bug 28940).
|
||
+ 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 <errno.h>
|
||
+#include <getopt.h>
|
||
+#include <malloc.h>
|
||
+#include <netdb.h>
|
||
+#include <nss.h>
|
||
+#include <stdbool.h>
|
||
+#include <stdlib.h>
|
||
+#include <string.h>
|
||
+#include <support/check.h>
|
||
+#include <support/namespace.h>
|
||
+#include <support/support.h>
|
||
+#include <support/xstdio.h>
|
||
+#include <unistd.h>
|
||
+
|
||
+/* This test calls getpwuid_r via getlogin_r (on Linux).
|
||
+
|
||
+ This test uses the NSS system configuration to exercise that code
|
||
+ path. It means that it can fail (crash) if malloc failure is not
|
||
+ handled by NSS modules for the passwd database. */
|
||
+
|
||
+/* Data structure allocated via MAP_SHARED, so that writes from the
|
||
+ subprocess are visible. */
|
||
+struct shared_data
|
||
+{
|
||
+ /* Number of tracked allocations performed so far. */
|
||
+ volatile unsigned int allocation_count;
|
||
+
|
||
+ /* If this number is reached, one allocation fails. */
|
||
+ volatile unsigned int failing_allocation;
|
||
+
|
||
+ /* The number of allocations performed during initialization
|
||
+ (before the actual getlogin_r call). */
|
||
+ volatile unsigned int init_allocation_count;
|
||
+
|
||
+ /* Error code of an expected getlogin_r failure. */
|
||
+ volatile int expected_failure;
|
||
+
|
||
+ /* The subprocess stores the expected name here. */
|
||
+ char name[100];
|
||
+};
|
||
+
|
||
+/* Allocation count in shared mapping. */
|
||
+static struct shared_data *shared;
|
||
+
|
||
+/* Returns true if a failure should be injected for this allocation. */
|
||
+static bool
|
||
+fail_this_allocation (void)
|
||
+{
|
||
+ if (shared != NULL)
|
||
+ {
|
||
+ unsigned int count = shared->allocation_count;
|
||
+ shared->allocation_count = count + 1;
|
||
+ return count == shared->failing_allocation;
|
||
+ }
|
||
+ else
|
||
+ return false;
|
||
+}
|
||
+
|
||
+/* Failure-injecting wrappers for allocation functions used by glibc. */
|
||
+
|
||
+void *
|
||
+malloc (size_t size)
|
||
+{
|
||
+ if (fail_this_allocation ())
|
||
+ {
|
||
+ errno = ENOMEM;
|
||
+ return NULL;
|
||
+ }
|
||
+ extern __typeof (malloc) __libc_malloc;
|
||
+ return __libc_malloc (size);
|
||
+}
|
||
+
|
||
+void *
|
||
+calloc (size_t a, size_t b)
|
||
+{
|
||
+ if (fail_this_allocation ())
|
||
+ {
|
||
+ errno = ENOMEM;
|
||
+ return NULL;
|
||
+ }
|
||
+ extern __typeof (calloc) __libc_calloc;
|
||
+ return __libc_calloc (a, b);
|
||
+}
|
||
+
|
||
+void *
|
||
+realloc (void *ptr, size_t size)
|
||
+{
|
||
+ if (fail_this_allocation ())
|
||
+ {
|
||
+ errno = ENOMEM;
|
||
+ return NULL;
|
||
+ }
|
||
+ extern __typeof (realloc) __libc_realloc;
|
||
+ return __libc_realloc (ptr, size);
|
||
+}
|
||
+
|
||
+/* No-op subprocess to verify that support_isolate_in_subprocess does
|
||
+ not perform any heap allocations. */
|
||
+static void
|
||
+no_op (void *ignored)
|
||
+{
|
||
+}
|
||
+
|
||
+/* Perform a getlogin_r call in a subprocess, to obtain the number of
|
||
+ allocations used and the expected result of a successful call. */
|
||
+static void
|
||
+initialize (void *configure_lookup)
|
||
+{
|
||
+ shared->init_allocation_count = 0;
|
||
+ if (configure_lookup != NULL)
|
||
+ {
|
||
+ TEST_COMPARE (__nss_configure_lookup ("passwd", configure_lookup), 0);
|
||
+ shared->init_allocation_count = shared->allocation_count;
|
||
+ }
|
||
+
|
||
+ shared->name[0] = '\0';
|
||
+ int ret = getlogin_r (shared->name, sizeof (shared->name));
|
||
+ if (ret != 0)
|
||
+ {
|
||
+ printf ("info: getlogin_r failed: %s (%d)\n",
|
||
+ strerrorname_np (ret), ret);
|
||
+ shared->expected_failure = ret;
|
||
+ }
|
||
+ else
|
||
+ {
|
||
+ shared->expected_failure = 0;
|
||
+ if (shared->name[0] == '\0')
|
||
+ FAIL ("error: getlogin_r succeeded without result\n");
|
||
+ else
|
||
+ printf ("info: getlogin_r: \"%s\"\n", shared->name);
|
||
+ }
|
||
+}
|
||
+
|
||
+/* Perform getlogin_r in a subprocess with fault injection. */
|
||
+static void
|
||
+test_in_subprocess (void *configure_lookup)
|
||
+{
|
||
+ if (configure_lookup != NULL
|
||
+ && __nss_configure_lookup ("passwd", configure_lookup) < 0)
|
||
+ {
|
||
+ printf ("info: __nss_configure_lookup failed: %s (%d)\n",
|
||
+ strerrorname_np (errno), errno);
|
||
+ TEST_COMPARE (errno, ENOMEM);
|
||
+ TEST_VERIFY (shared->allocation_count <= shared->init_allocation_count);
|
||
+ return;
|
||
+ }
|
||
+
|
||
+ unsigned int inject_at = shared->failing_allocation;
|
||
+ char name[sizeof (shared->name)] = "name not set";
|
||
+ int ret = getlogin_r (name, sizeof (name));
|
||
+ shared->failing_allocation = ~0U;
|
||
+
|
||
+ if (ret == 0)
|
||
+ {
|
||
+ TEST_COMPARE (shared->expected_failure, 0);
|
||
+ TEST_COMPARE_STRING (name, shared->name);
|
||
+ }
|
||
+ else
|
||
+ {
|
||
+ printf ("info: allocation %u failure results in error %s (%d)\n",
|
||
+ inject_at, strerrorname_np (ret), ret);
|
||
+
|
||
+ if (ret != ENOMEM)
|
||
+ {
|
||
+ if (shared->expected_failure != 0)
|
||
+ TEST_COMPARE (ret, shared->expected_failure);
|
||
+ else if (configure_lookup == NULL)
|
||
+ /* The ENOENT failure can happen due to an issue related
|
||
+ to bug 22041: dlopen failure does not result in ENOMEM. */
|
||
+ TEST_COMPARE (ret, ENOENT);
|
||
+ else
|
||
+ FAIL ("unexpected getlogin_r error");
|
||
+ }
|
||
+ }
|
||
+
|
||
+ if (shared->expected_failure == 0)
|
||
+ {
|
||
+ /* The second call should succeed. */
|
||
+ puts ("info: about to perform second getlogin_r call");
|
||
+ ret = getlogin_r (name, sizeof (name));
|
||
+ if (configure_lookup == NULL)
|
||
+ {
|
||
+ /* This check can fail due to bug 22041 if the malloc error
|
||
+ injection causes a failure internally in dlopen. */
|
||
+ if (ret != 0)
|
||
+ {
|
||
+ printf ("warning: second getlogin_r call failed with %s (%d)\n",
|
||
+ strerrorname_np (ret), ret);
|
||
+ TEST_COMPARE (ret, ENOENT);
|
||
+ }
|
||
+ }
|
||
+ else
|
||
+ /* If __nss_configure_lookup has been called, the error caching
|
||
+ bug does not happen because nss_files is built-in, and the
|
||
+ second getlogin_r is expected to succeed. */
|
||
+ TEST_COMPARE (ret, 0);
|
||
+ if (ret == 0)
|
||
+ TEST_COMPARE_STRING (name, shared->name);
|
||
+ }
|
||
+}
|
||
+
|
||
+/* Set by the --failing-allocation command line option. Together with
|
||
+ --direct, this can be used to trigger an allocation failure in the
|
||
+ original process, which may help with debugging. */
|
||
+static int option_failing_allocation = -1;
|
||
+
|
||
+/* Set by --override, to be used with --failing-allocation. Turns on
|
||
+ the __nss_configure_lookup call for passwd/files, which is disabled
|
||
+ by default. */
|
||
+static int option_override = 0;
|
||
+
|
||
+static int
|
||
+do_test (void)
|
||
+{
|
||
+ char files[] = "files";
|
||
+
|
||
+ if (option_failing_allocation >= 0)
|
||
+ {
|
||
+ /* The test was invoked with --failing-allocation. Perform just
|
||
+ one test, using the original nsswitch.conf. This is a
|
||
+ condensed version of the probing/testing loop below. */
|
||
+ printf ("info: testing with failing allocation %d\n",
|
||
+ option_failing_allocation);
|
||
+ shared = support_shared_allocate (sizeof (*shared));
|
||
+ shared->failing_allocation = ~0U;
|
||
+ char *configure_lookup = option_override ? files : NULL;
|
||
+ support_isolate_in_subprocess (initialize, configure_lookup);
|
||
+ shared->allocation_count = 0;
|
||
+ shared->failing_allocation = option_failing_allocation;
|
||
+ test_in_subprocess (configure_lookup); /* No subprocess. */
|
||
+ support_shared_free (shared);
|
||
+ shared = NULL;
|
||
+ return 0;
|
||
+ }
|
||
+
|
||
+ bool any_success = false;
|
||
+
|
||
+ for (int do_configure_lookup = 0; do_configure_lookup < 2;
|
||
+ ++do_configure_lookup)
|
||
+ {
|
||
+ if (do_configure_lookup)
|
||
+ puts ("info: testing with nsswitch.conf override");
|
||
+ else
|
||
+ puts ("info: testing with original nsswitch.conf");
|
||
+
|
||
+ char *configure_lookup = do_configure_lookup ? files : NULL;
|
||
+
|
||
+ shared = support_shared_allocate (sizeof (*shared));
|
||
+
|
||
+ /* Disable fault injection. */
|
||
+ shared->failing_allocation = ~0U;
|
||
+
|
||
+ support_isolate_in_subprocess (no_op, NULL);
|
||
+ TEST_COMPARE (shared->allocation_count, 0);
|
||
+
|
||
+ support_isolate_in_subprocess (initialize, configure_lookup);
|
||
+
|
||
+ if (shared->name[0] != '\0')
|
||
+ any_success = true;
|
||
+
|
||
+ /* The number of allocations in the successful case. Once the
|
||
+ number of expected allocations is exceeded, injecting further
|
||
+ failures does not make a difference (assuming that the number
|
||
+ of malloc calls is deterministic). */
|
||
+ unsigned int maximum_allocation_count = shared->allocation_count;
|
||
+ printf ("info: initial getlogin_r performed %u allocations\n",
|
||
+ maximum_allocation_count);
|
||
+
|
||
+ for (unsigned int inject_at = 0; inject_at <= maximum_allocation_count;
|
||
+ ++inject_at)
|
||
+ {
|
||
+ printf ("info: running fault injection at allocation %u\n",
|
||
+ inject_at);
|
||
+ shared->allocation_count = 0;
|
||
+ shared->failing_allocation = inject_at;
|
||
+ support_isolate_in_subprocess (test_in_subprocess, configure_lookup);
|
||
+ }
|
||
+
|
||
+ support_shared_free (shared);
|
||
+ shared = NULL;
|
||
+ }
|
||
+
|
||
+ {
|
||
+ FILE *fp = fopen (_PATH_NSSWITCH_CONF, "r");
|
||
+ if (fp == NULL)
|
||
+ printf ("info: no %s file\n", _PATH_NSSWITCH_CONF);
|
||
+ else
|
||
+ {
|
||
+ printf ("info: %s contents follows\n", _PATH_NSSWITCH_CONF);
|
||
+ int last_ch = '\n';
|
||
+ while (true)
|
||
+ {
|
||
+ int ch = fgetc (fp);
|
||
+ if (ch == EOF)
|
||
+ break;
|
||
+ putchar (ch);
|
||
+ last_ch = ch;
|
||
+ }
|
||
+ if (last_ch != '\n')
|
||
+ putchar ('\n');
|
||
+ printf ("(end of %s contents)\n", _PATH_NSSWITCH_CONF);
|
||
+ xfclose (fp);
|
||
+ }
|
||
+ }
|
||
+
|
||
+ support_record_failure_barrier ();
|
||
+
|
||
+ if (!any_success)
|
||
+ FAIL_UNSUPPORTED ("no successful getlogin_r calls");
|
||
+
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+static void
|
||
+cmdline_process (int c)
|
||
+{
|
||
+ if (c == 'F')
|
||
+ option_failing_allocation = atoi (optarg);
|
||
+}
|
||
+
|
||
+#define CMDLINE_OPTIONS \
|
||
+ { "failing-allocation", required_argument, NULL, 'F' }, \
|
||
+ { "override", no_argument, &option_override, 1 },
|
||
+
|
||
+#define CMDLINE_PROCESS cmdline_process
|
||
+
|
||
+#include <support/test-driver.c>
|
||
|
||
commit 9cd9c9054409d192aab06bfea32624af9ffa8121
|
||
Author: Florian Weimer <fweimer@redhat.com>
|
||
Date: Fri Nov 28 11:46:09 2025 +0100
|
||
|
||
iconvdata: Fix invalid pointer arithmetic in ANSI_X3.110 module
|
||
|
||
The expression inptr + 1 can technically be invalid: if inptr == inend,
|
||
inptr may point one element past the end of an array.
|
||
|
||
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
||
(cherry picked from commit e98bd0c54d5e296ad1be91b6fe35260c6b87e733)
|
||
|
||
diff --git a/iconvdata/ansi_x3.110.c b/iconvdata/ansi_x3.110.c
|
||
index c5506b13b8..94e6e6b745 100644
|
||
--- a/iconvdata/ansi_x3.110.c
|
||
+++ b/iconvdata/ansi_x3.110.c
|
||
@@ -407,7 +407,7 @@ static const char from_ucs4[][2] =
|
||
is also available. */ \
|
||
uint32_t ch2; \
|
||
\
|
||
- if (inptr + 1 >= inend) \
|
||
+ if (inend - inptr <= 1) \
|
||
{ \
|
||
/* The second character is not available. */ \
|
||
result = __GCONV_INCOMPLETE_INPUT; \
|
||
|
||
commit 1a19d5a507eb82a2cf1cf8bd1c14ca1758fb8a82
|
||
Author: Florian Weimer <fweimer@redhat.com>
|
||
Date: Mon Jan 26 17:12:37 2026 +0100
|
||
|
||
posix: Run tst-wordexp-reuse-mem test
|
||
|
||
The test was not properly scheduled for execution with a Makefile
|
||
dependency.
|
||
|
||
Fixes commit 80cc58ea2de214f85b0a1d902a3b668ad2ecb302 ("posix: Reset
|
||
wordexp_t fields with WRDE_REUSE (CVE-2025-15281 / BZ 33814").
|
||
|
||
(cherry picked from commit bed2db02f3183e93f21d506786c5f884a1dec9e7)
|
||
|
||
diff --git a/posix/Makefile b/posix/Makefile
|
||
index 1ea86efcc1..0b29c9aa4e 100644
|
||
--- a/posix/Makefile
|
||
+++ b/posix/Makefile
|
||
@@ -495,7 +495,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 \
|
||
+ $(objpfx)tst-wordexp-reuse-mem.out \
|
||
# tests-special
|
||
endif
|
||
endif
|
||
|
||
commit 8e863fb1c92360520704a69dc948be6bb4a17cb3
|
||
Author: Carlos O'Donell <carlos@redhat.com>
|
||
Date: Fri Mar 20 16:43:33 2026 -0400
|
||
|
||
resolv: Count records correctly (CVE-2026-4437)
|
||
|
||
The answer section boundary was previously ignored, and the code in
|
||
getanswer_ptr would iterate past the last resource record, but not
|
||
beyond the end of the returned data. This could lead to subsequent data
|
||
being interpreted as answer records, thus violating the DNS
|
||
specification. Such resource records could be maliciously crafted and
|
||
hidden from other tooling, but processed by the glibc stub resolver and
|
||
acted upon by the application. While we trust the data returned by the
|
||
configured recursive resolvers, we should not trust its format and
|
||
should validate it as required. It is a security issue to incorrectly
|
||
process the DNS protocol.
|
||
|
||
A regression test is added for response section crossing.
|
||
|
||
No regressions on x86_64-linux-gnu.
|
||
|
||
Reviewed-by: Collin Funk <collin.funk1@gmail.com>
|
||
(cherry picked from commit 9f5f18aab40ec6b61fa49a007615e6077e9a979b)
|
||
|
||
diff --git a/resolv/Makefile b/resolv/Makefile
|
||
index 8fa3398d76..0ba5fba710 100644
|
||
--- a/resolv/Makefile
|
||
+++ b/resolv/Makefile
|
||
@@ -104,6 +104,7 @@ tests += \
|
||
tst-resolv-basic \
|
||
tst-resolv-binary \
|
||
tst-resolv-byaddr \
|
||
+ tst-resolv-dns-section \
|
||
tst-resolv-edns \
|
||
tst-resolv-invalid-cname \
|
||
tst-resolv-network \
|
||
@@ -115,6 +116,7 @@ tests += \
|
||
tst-resolv-semi-failure \
|
||
tst-resolv-short-response \
|
||
tst-resolv-trailing \
|
||
+ # tests
|
||
|
||
# This test calls __res_context_send directly, which is not exported
|
||
# from libresolv.
|
||
@@ -293,6 +295,8 @@ $(objpfx)tst-resolv-aliases: $(objpfx)libresolv.so $(shared-thread-library)
|
||
$(objpfx)tst-resolv-basic: $(objpfx)libresolv.so $(shared-thread-library)
|
||
$(objpfx)tst-resolv-binary: $(objpfx)libresolv.so $(shared-thread-library)
|
||
$(objpfx)tst-resolv-byaddr: $(objpfx)libresolv.so $(shared-thread-library)
|
||
+$(objpfx)tst-resolv-dns-section: $(objpfx)libresolv.so \
|
||
+ $(shared-thread-library)
|
||
$(objpfx)tst-resolv-edns: $(objpfx)libresolv.so $(shared-thread-library)
|
||
$(objpfx)tst-resolv-network: $(objpfx)libresolv.so $(shared-thread-library)
|
||
$(objpfx)tst-resolv-res_init: $(objpfx)libresolv.so
|
||
diff --git a/resolv/nss_dns/dns-host.c b/resolv/nss_dns/dns-host.c
|
||
index 14da73ee1d..27096edad2 100644
|
||
--- a/resolv/nss_dns/dns-host.c
|
||
+++ b/resolv/nss_dns/dns-host.c
|
||
@@ -820,7 +820,7 @@ getanswer_ptr (unsigned char *packet, size_t packetlen,
|
||
/* expected_name may be updated to point into this buffer. */
|
||
unsigned char name_buffer[NS_MAXCDNAME];
|
||
|
||
- while (ancount > 0)
|
||
+ for (; ancount > 0; --ancount)
|
||
{
|
||
struct ns_rr_wire rr;
|
||
if (!__ns_rr_cursor_next (&c, &rr))
|
||
diff --git a/resolv/tst-resolv-dns-section.c b/resolv/tst-resolv-dns-section.c
|
||
new file mode 100644
|
||
index 0000000000..1171baef51
|
||
--- /dev/null
|
||
+++ b/resolv/tst-resolv-dns-section.c
|
||
@@ -0,0 +1,162 @@
|
||
+/* Test handling of invalid section transitions (bug 34014).
|
||
+ Copyright (C) 2022-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 <array_length.h>
|
||
+#include <errno.h>
|
||
+#include <netdb.h>
|
||
+#include <resolv.h>
|
||
+#include <stdlib.h>
|
||
+#include <string.h>
|
||
+#include <support/check.h>
|
||
+#include <support/format_nss.h>
|
||
+#include <support/resolv_test.h>
|
||
+#include <support/support.h>
|
||
+
|
||
+/* Name of test, and the second section type. */
|
||
+struct item {
|
||
+ const char *test;
|
||
+ int ns_section;
|
||
+};
|
||
+
|
||
+static const struct item test_items[] =
|
||
+ {
|
||
+ { "Test crossing from ns_s_an to ns_s_ar.", ns_s_ar },
|
||
+ { "Test crossing from ns_s_an to ns_s_an.", ns_s_ns },
|
||
+
|
||
+ { NULL, 0 },
|
||
+ };
|
||
+
|
||
+/* The response is designed to contain the following:
|
||
+ - An Answer section with one T_PTR record that is skipped.
|
||
+ - A second section with a semantically invalid T_PTR record.
|
||
+ The original defect is that the response parsing would cross
|
||
+ section boundaries and handle the additional section T_PTR
|
||
+ as if it were an answer. A conforming implementation would
|
||
+ stop as soon as it reaches the end of the section. */
|
||
+static void
|
||
+response (const struct resolv_response_context *ctx,
|
||
+ struct resolv_response_builder *b,
|
||
+ const char *qname, uint16_t qclass, uint16_t qtype)
|
||
+{
|
||
+ TEST_COMPARE (qclass, C_IN);
|
||
+
|
||
+ /* We only test PTR. */
|
||
+ TEST_COMPARE (qtype, T_PTR);
|
||
+
|
||
+ unsigned int count;
|
||
+ char *tail = NULL;
|
||
+
|
||
+ if (strstr (qname, "in-addr.arpa") != NULL
|
||
+ && sscanf (qname, "%u.%ms", &count, &tail) == 2)
|
||
+ TEST_COMPARE_STRING (tail, "0.168.192.in-addr.arpa");
|
||
+ else if (sscanf (qname, "%x.%ms", &count, &tail) == 2)
|
||
+ {
|
||
+ TEST_COMPARE_STRING (tail, "\
|
||
+0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2.ip6.arpa");
|
||
+ }
|
||
+ else
|
||
+ FAIL_EXIT1 ("invalid QNAME: %s\n", qname);
|
||
+ free (tail);
|
||
+
|
||
+ /* We have a bounded number of possible tests. */
|
||
+ TEST_VERIFY (count >= 0);
|
||
+ TEST_VERIFY (count <= 15);
|
||
+
|
||
+ struct resolv_response_flags flags = {};
|
||
+ resolv_response_init (b, flags);
|
||
+ resolv_response_add_question (b, qname, qclass, qtype);
|
||
+ resolv_response_section (b, ns_s_an);
|
||
+
|
||
+ /* Actual answer record, but the wrong name (skipped). */
|
||
+ resolv_response_open_record (b, "1.0.0.10.in-addr.arpa", qclass, qtype, 60);
|
||
+
|
||
+ /* Record the answer. */
|
||
+ resolv_response_add_name (b, "test.ptr.example.net");
|
||
+ resolv_response_close_record (b);
|
||
+
|
||
+ /* Add a second section to test section boundary crossing. */
|
||
+ resolv_response_section (b, test_items[count].ns_section);
|
||
+ /* Semantically incorrect, but hide a T_PTR entry. */
|
||
+ resolv_response_open_record (b, qname, qclass, qtype, 60);
|
||
+ resolv_response_add_name (b, "wrong.ptr.example.net");
|
||
+ resolv_response_close_record (b);
|
||
+}
|
||
+
|
||
+
|
||
+/* Perform one check using a reverse lookup. */
|
||
+static void
|
||
+check_reverse (int af, int count)
|
||
+{
|
||
+ TEST_VERIFY (af == AF_INET || af == AF_INET6);
|
||
+ TEST_VERIFY (count < array_length (test_items));
|
||
+
|
||
+ char addr[sizeof (struct in6_addr)] = { 0 };
|
||
+ socklen_t addrlen;
|
||
+ if (af == AF_INET)
|
||
+ {
|
||
+ addr[0] = (char) 192;
|
||
+ addr[1] = (char) 168;
|
||
+ addr[2] = (char) 0;
|
||
+ addr[3] = (char) count;
|
||
+ addrlen = 4;
|
||
+ }
|
||
+ else
|
||
+ {
|
||
+ addr[0] = 0x20;
|
||
+ addr[1] = 0x01;
|
||
+ addr[2] = 0x0d;
|
||
+ addr[3] = 0xb8;
|
||
+ addr[4] = addr[5] = addr[6] = addr[7] = 0x0;
|
||
+ addr[8] = addr[9] = addr[10] = addr[11] = 0x0;
|
||
+ addr[12] = 0x0;
|
||
+ addr[13] = 0x0;
|
||
+ addr[14] = 0x0;
|
||
+ addr[15] = count;
|
||
+ addrlen = 16;
|
||
+ }
|
||
+
|
||
+ h_errno = 0;
|
||
+ struct hostent *answer = gethostbyaddr (addr, addrlen, af);
|
||
+ TEST_VERIFY (answer == NULL);
|
||
+ TEST_VERIFY (h_errno == NO_RECOVERY);
|
||
+ if (answer != NULL)
|
||
+ printf ("error: unexpected success: %s\n",
|
||
+ support_format_hostent (answer));
|
||
+}
|
||
+
|
||
+static int
|
||
+do_test (void)
|
||
+{
|
||
+ struct resolv_test *obj = resolv_test_start
|
||
+ ((struct resolv_redirect_config)
|
||
+ {
|
||
+ .response_callback = response
|
||
+ });
|
||
+
|
||
+ for (int i = 0; test_items[i].test != NULL; i++)
|
||
+ {
|
||
+ check_reverse (AF_INET, i);
|
||
+ check_reverse (AF_INET6, i);
|
||
+ }
|
||
+
|
||
+ resolv_test_end (obj);
|
||
+
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+#include <support/test-driver.c>
|
||
|
||
commit 426378547e6ddead92f28f5558a124eb0821d2f9
|
||
Author: Carlos O'Donell <carlos@redhat.com>
|
||
Date: Fri Mar 20 17:14:33 2026 -0400
|
||
|
||
resolv: Check hostname for validity (CVE-2026-4438)
|
||
|
||
The processed hostname in getanswer_ptr should be correctly checked to
|
||
avoid invalid characters from being allowed, including shell
|
||
metacharacters. It is a security issue to fail to check the returned
|
||
hostname for validity.
|
||
|
||
A regression test is added for invalid metacharacters and other cases
|
||
of invalid or valid characters.
|
||
|
||
No regressions on x86_64-linux-gnu.
|
||
|
||
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
||
(cherry picked from commit e10977481f4db4b2a3ce34fa4c3a1e26651ae312)
|
||
|
||
diff --git a/resolv/Makefile b/resolv/Makefile
|
||
index 0ba5fba710..088a22ea18 100644
|
||
--- a/resolv/Makefile
|
||
+++ b/resolv/Makefile
|
||
@@ -107,6 +107,7 @@ tests += \
|
||
tst-resolv-dns-section \
|
||
tst-resolv-edns \
|
||
tst-resolv-invalid-cname \
|
||
+ tst-resolv-invalid-ptr \
|
||
tst-resolv-network \
|
||
tst-resolv-noaaaa \
|
||
tst-resolv-noaaaa-vc \
|
||
@@ -306,6 +307,8 @@ $(objpfx)tst-resolv-res_init-thread: $(objpfx)libresolv.so \
|
||
$(shared-thread-library)
|
||
$(objpfx)tst-resolv-invalid-cname: $(objpfx)libresolv.so \
|
||
$(shared-thread-library)
|
||
+$(objpfx)tst-resolv-invalid-ptr: $(objpfx)libresolv.so \
|
||
+ $(shared-thread-library)
|
||
$(objpfx)tst-resolv-noaaaa: $(objpfx)libresolv.so $(shared-thread-library)
|
||
$(objpfx)tst-resolv-noaaaa-vc: $(objpfx)libresolv.so $(shared-thread-library)
|
||
$(objpfx)tst-resolv-nondecimal: $(objpfx)libresolv.so $(shared-thread-library)
|
||
diff --git a/resolv/nss_dns/dns-host.c b/resolv/nss_dns/dns-host.c
|
||
index 27096edad2..1bc2e1df95 100644
|
||
--- a/resolv/nss_dns/dns-host.c
|
||
+++ b/resolv/nss_dns/dns-host.c
|
||
@@ -866,7 +866,7 @@ getanswer_ptr (unsigned char *packet, size_t packetlen,
|
||
char hname[MAXHOSTNAMELEN + 1];
|
||
if (__ns_name_unpack (c.begin, c.end, rr.rdata,
|
||
name_buffer, sizeof (name_buffer)) < 0
|
||
- || !__res_binary_hnok (expected_name)
|
||
+ || !__res_binary_hnok (name_buffer)
|
||
|| __ns_name_ntop (name_buffer, hname, sizeof (hname)) < 0)
|
||
{
|
||
*h_errnop = NO_RECOVERY;
|
||
diff --git a/resolv/tst-resolv-invalid-ptr.c b/resolv/tst-resolv-invalid-ptr.c
|
||
new file mode 100644
|
||
index 0000000000..0c802ab967
|
||
--- /dev/null
|
||
+++ b/resolv/tst-resolv-invalid-ptr.c
|
||
@@ -0,0 +1,255 @@
|
||
+/* Test handling of invalid T_PTR results (bug 34015).
|
||
+ Copyright (C) 2022-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 <array_length.h>
|
||
+#include <errno.h>
|
||
+#include <netdb.h>
|
||
+#include <resolv.h>
|
||
+#include <stdlib.h>
|
||
+#include <string.h>
|
||
+#include <support/check.h>
|
||
+#include <support/format_nss.h>
|
||
+#include <support/resolv_test.h>
|
||
+#include <support/support.h>
|
||
+
|
||
+/* Name of test, the answer, the expected error return, and if we
|
||
+ expect the call to fail. */
|
||
+struct item {
|
||
+ const char *test;
|
||
+ const char *answer;
|
||
+ int expected;
|
||
+ bool fail;
|
||
+};
|
||
+
|
||
+static const struct item test_items[] =
|
||
+ {
|
||
+ /* Test for invalid characters. */
|
||
+ { "Invalid use of \"|\"",
|
||
+ "test.|.ptr.example", NO_RECOVERY, true },
|
||
+ { "Invalid use of \"&\"",
|
||
+ "test.&.ptr.example", NO_RECOVERY, true },
|
||
+ { "Invalid use of \";\"",
|
||
+ "test.;.ptr.example", NO_RECOVERY, true },
|
||
+ { "Invalid use of \"<\"",
|
||
+ "test.<.ptr.example", NO_RECOVERY, true },
|
||
+ { "Invalid use of \">\"",
|
||
+ "test.>.ptr.example", NO_RECOVERY, true },
|
||
+ { "Invalid use of \"(\"",
|
||
+ "test.(.ptr.example", NO_RECOVERY, true },
|
||
+ { "Invalid use of \")\"",
|
||
+ "test.).ptr.example", NO_RECOVERY, true },
|
||
+ { "Invalid use of \"$\"",
|
||
+ "test.$.ptr.example", NO_RECOVERY, true },
|
||
+ { "Invalid use of \"`\"",
|
||
+ "test.`.ptr.example", NO_RECOVERY, true },
|
||
+ { "Invalid use of \"\\\"",
|
||
+ "test.\\.ptr.example", NO_RECOVERY, true },
|
||
+ { "Invalid use of \"\'\"",
|
||
+ "test.'.ptr.example", NO_RECOVERY, true },
|
||
+ { "Invalid use of \"\"\"",
|
||
+ "test.\".ptr.example", NO_RECOVERY, true },
|
||
+ { "Invalid use of \" \"",
|
||
+ "test. .ptr.example", NO_RECOVERY, true },
|
||
+ { "Invalid use of \"\\t\"",
|
||
+ "test.\t.ptr.example", NO_RECOVERY, true },
|
||
+ { "Invalid use of \"\\n\"",
|
||
+ "test.\n.ptr.example", NO_RECOVERY, true },
|
||
+ { "Invalid use of \"\\r\"",
|
||
+ "test.\r.ptr.example", NO_RECOVERY, true },
|
||
+ { "Invalid use of \"*\"",
|
||
+ "test.*.ptr.example", NO_RECOVERY, true },
|
||
+ { "Invalid use of \"?\"",
|
||
+ "test.?.ptr.example", NO_RECOVERY, true },
|
||
+ { "Invalid use of \"[\"",
|
||
+ "test.[.ptr.example", NO_RECOVERY, true },
|
||
+ { "Invalid use of \"]\"",
|
||
+ "test.].ptr.example", NO_RECOVERY, true },
|
||
+ { "Invalid use of \",\"",
|
||
+ "test.,.ptr.example", NO_RECOVERY, true },
|
||
+ { "Invalid use of \"~\"",
|
||
+ "test.~.ptr.example", NO_RECOVERY, true },
|
||
+ { "Invalid use of \":\"",
|
||
+ "test.:.ptr.example", NO_RECOVERY, true },
|
||
+ { "Invalid use of \"!\"",
|
||
+ "test.!.ptr.example", NO_RECOVERY, true },
|
||
+ { "Invalid use of \"@\"",
|
||
+ "test.@.ptr.example", NO_RECOVERY, true },
|
||
+ { "Invalid use of \"#\"",
|
||
+ "test.#.ptr.example", NO_RECOVERY, true },
|
||
+ { "Invalid use of \"%\"",
|
||
+ "test.%%.ptr.example", NO_RECOVERY, true },
|
||
+ { "Invalid use of \"^\"",
|
||
+ "test.^.ptr.example", NO_RECOVERY, true },
|
||
+
|
||
+ /* Test for invalid UTF-8 characters (2-byte, 4-byte, 6-byte). */
|
||
+ { "Invalid use of UTF-8 (2-byte, U+00C0-U+00C2)",
|
||
+ "ÁÂÃ.test.ptr.example", NO_RECOVERY, true },
|
||
+ { "Invalid use of UTF-8 (4-byte, U+0750-U+0752)",
|
||
+ "ݐݑݒ.test.ptr.example", NO_RECOVERY, true },
|
||
+ { "Invalid use of UTF-8 (6-byte, U+0904-U+0906)",
|
||
+ "ऄअआ.test.ptr.example", NO_RECOVERY, true },
|
||
+
|
||
+ /* Test for "-" which may be valid depending on position. */
|
||
+ { "Invalid leading \"-\"",
|
||
+ "-test.ptr.example", NO_RECOVERY, true },
|
||
+ { "Valid trailing \"-\"",
|
||
+ "test-.ptr.example", 0, false },
|
||
+ { "Valid mid-label use of \"-\"",
|
||
+ "te-st.ptr.example", 0, false },
|
||
+
|
||
+ /* Test for "_" which is always valid in any position. */
|
||
+ { "Valid leading use of \"_\"",
|
||
+ "_test.ptr.example", 0, false },
|
||
+ { "Valid mid-label use of \"_\"",
|
||
+ "te_st.ptr.example", 0, false },
|
||
+ { "Valid trailing use of \"_\"",
|
||
+ "test_.ptr.example", 0, false },
|
||
+
|
||
+ /* Sanity test the broader set [A-Za-z0-9_-] of valid characters. */
|
||
+ { "Valid \"[A-Z]\"",
|
||
+ "test.ABCDEFGHIJKLMNOPQRSTUVWXYZ.ptr.example", 0, false },
|
||
+ { "Valid \"[a-z]\"",
|
||
+ "test.abcdefghijklmnopqrstuvwxyz.ptr.example", 0, false },
|
||
+ { "Valid \"[0-9]\"",
|
||
+ "test.0123456789.ptr.example", 0, false },
|
||
+ { "Valid mixed use of \"[A-Za-z0-9_-]\"",
|
||
+ "test.012abcABZ_-.ptr.example", 0, false },
|
||
+ };
|
||
+
|
||
+static void
|
||
+response (const struct resolv_response_context *ctx,
|
||
+ struct resolv_response_builder *b,
|
||
+ const char *qname, uint16_t qclass, uint16_t qtype)
|
||
+{
|
||
+ TEST_COMPARE (qclass, C_IN);
|
||
+
|
||
+ /* We only test PTR. */
|
||
+ TEST_COMPARE (qtype, T_PTR);
|
||
+
|
||
+ unsigned int count, count1;
|
||
+ char *tail = NULL;
|
||
+
|
||
+ /* The test implementation can handle up to 255 tests. */
|
||
+ if (strstr (qname, "in-addr.arpa") != NULL
|
||
+ && sscanf (qname, "%u.%ms", &count, &tail) == 2)
|
||
+ TEST_COMPARE_STRING (tail, "0.168.192.in-addr.arpa");
|
||
+ else if (sscanf (qname, "%x.%x.%ms", &count, &count1, &tail) == 3)
|
||
+ {
|
||
+ TEST_COMPARE_STRING (tail, "\
|
||
+0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2.ip6.arpa");
|
||
+ count |= count1 << 4;
|
||
+ }
|
||
+ else
|
||
+ FAIL_EXIT1 ("invalid QNAME: %s\n", qname);
|
||
+ free (tail);
|
||
+
|
||
+ /* Cross check. Count has a fixed bound (soft limit). */
|
||
+ TEST_VERIFY (count >= 0 && count <= 255);
|
||
+
|
||
+ /* We have a fixed number of tests (hard limit). */
|
||
+ TEST_VERIFY_EXIT (count < array_length (test_items));
|
||
+
|
||
+ struct resolv_response_flags flags = {};
|
||
+ resolv_response_init (b, flags);
|
||
+ resolv_response_add_question (b, qname, qclass, qtype);
|
||
+ resolv_response_section (b, ns_s_an);
|
||
+
|
||
+ /* Actual answer record. */
|
||
+ resolv_response_open_record (b, qname, qclass, qtype, 60);
|
||
+
|
||
+ /* Record the answer. */
|
||
+ resolv_response_add_name (b, test_items[count].answer);
|
||
+ resolv_response_close_record (b);
|
||
+}
|
||
+
|
||
+/* Perform one check using a reverse lookup. */
|
||
+static void
|
||
+check_reverse (int af, int count)
|
||
+{
|
||
+ TEST_VERIFY (af == AF_INET || af == AF_INET6);
|
||
+ TEST_VERIFY_EXIT (count < array_length (test_items));
|
||
+
|
||
+ /* Generate an address to query for each test. */
|
||
+ char addr[sizeof (struct in6_addr)] = { 0 };
|
||
+ socklen_t addrlen;
|
||
+ if (af == AF_INET)
|
||
+ {
|
||
+ addr[0] = (char) 192;
|
||
+ addr[1] = (char) 168;
|
||
+ addr[2] = (char) 0;
|
||
+ addr[3] = (char) count;
|
||
+ addrlen = 4;
|
||
+ }
|
||
+ else
|
||
+ {
|
||
+ addr[0] = 0x20;
|
||
+ addr[1] = 0x01;
|
||
+ addr[2] = 0x0d;
|
||
+ addr[3] = 0xb8;
|
||
+ addr[4] = addr[5] = addr[6] = addr[7] = 0x0;
|
||
+ addr[8] = addr[9] = addr[10] = addr[11] = 0x0;
|
||
+ addr[12] = 0x0;
|
||
+ addr[13] = 0x0;
|
||
+ addr[14] = 0x0;
|
||
+ addr[15] = (char) count;
|
||
+ addrlen = 16;
|
||
+ }
|
||
+
|
||
+ h_errno = 0;
|
||
+ struct hostent *answer = gethostbyaddr (addr, addrlen, af);
|
||
+
|
||
+ /* Verify h_errno is as expected. */
|
||
+ TEST_COMPARE (h_errno, test_items[count].expected);
|
||
+ if (h_errno != test_items[count].expected)
|
||
+ /* And print more information if it's not. */
|
||
+ printf ("INFO: %s\n", test_items[count].test);
|
||
+
|
||
+ if (test_items[count].fail)
|
||
+ {
|
||
+ /* We expected a failure so verify answer is NULL. */
|
||
+ TEST_VERIFY (answer == NULL);
|
||
+ /* If it's not NULL we should print out what we received. */
|
||
+ if (answer != NULL)
|
||
+ printf ("error: unexpected success: %s\n",
|
||
+ support_format_hostent (answer));
|
||
+ }
|
||
+ else
|
||
+ /* We don't expect a failure so answer must be valid. */
|
||
+ TEST_COMPARE_STRING (answer->h_name, test_items[count].answer);
|
||
+}
|
||
+
|
||
+static int
|
||
+do_test (void)
|
||
+{
|
||
+ struct resolv_test *obj = resolv_test_start
|
||
+ ((struct resolv_redirect_config)
|
||
+ {
|
||
+ .response_callback = response
|
||
+ });
|
||
+
|
||
+ for (int i = 0; i < array_length (test_items); i++)
|
||
+ {
|
||
+ check_reverse (AF_INET, i);
|
||
+ check_reverse (AF_INET6, i);
|
||
+ }
|
||
+ resolv_test_end (obj);
|
||
+
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+#include <support/test-driver.c>
|
||
|
||
commit 68099ccc941664481386c62cba40bbc5dac8b00e
|
||
Author: Xi Ruoyao <xry111@xry111.site>
|
||
Date: Tue Feb 3 16:20:12 2026 +0800
|
||
|
||
elf: parse /proc/self/maps as the last resort to find the gap for tst-link-map-contiguous-ldso
|
||
|
||
The initialization process of libc.so calls mmap() several times and the
|
||
kernel may lay the maps into the gap. If all pages in the gap are
|
||
occupied, the test would not be able to find the gap with mmap() and the
|
||
test would fail.
|
||
|
||
The failure reproduces most frequently on LoongArch because with the
|
||
commonly used page size (16 KiB) the gap only contains 4 pages and the
|
||
probability they are all occupied is not near to zero.
|
||
|
||
With the changes in the patch, a test run may output:
|
||
|
||
info: ld.so link map is not contiguous
|
||
info: object "/dev/zero" found at 0x7ffff1fe0000 - 0x7ffff1fe4000
|
||
info: anonymous mapping found at 0x7ffff1fe4000 - 0x7ffff1fec000
|
||
|
||
Also take the chance to fix a mistake in the "object found at" message
|
||
which has puzzled me during the initial debug session.
|
||
|
||
Signed-off-by: Xi Ruoyao <xry111@xry111.site>
|
||
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
||
(cherry picked from commit aed8390a6a22e5751fc12704c0c5f2a8271fc286)
|
||
|
||
diff --git a/elf/tst-link-map-contiguous-ldso.c b/elf/tst-link-map-contiguous-ldso.c
|
||
index 04de808bb2..f0e26682f2 100644
|
||
--- a/elf/tst-link-map-contiguous-ldso.c
|
||
+++ b/elf/tst-link-map-contiguous-ldso.c
|
||
@@ -18,15 +18,73 @@
|
||
|
||
#include <dlfcn.h>
|
||
#include <gnu/lib-names.h>
|
||
+#include <inttypes.h>
|
||
#include <link.h>
|
||
#include <stdbool.h>
|
||
#include <stdio.h>
|
||
#include <support/check.h>
|
||
+#include <support/support.h>
|
||
#include <support/xdlfcn.h>
|
||
#include <support/xunistd.h>
|
||
+#include <support/xstdio.h>
|
||
#include <sys/mman.h>
|
||
#include <unistd.h>
|
||
|
||
+/* Slow path in case we cannot find a gap with mmap (when the runtime has
|
||
+ mapped all the pages in the gap for some reason). */
|
||
+static bool
|
||
+find_gap_with_proc_self_map (const struct link_map *l)
|
||
+{
|
||
+ int pagesize = getpagesize ();
|
||
+
|
||
+ support_need_proc ("Reads /proc/self/maps to find gap in ld.so mapping");
|
||
+
|
||
+ /* Parse /proc/self/maps and find all the mappings in the ld.so range
|
||
+ but not from ld.so. */
|
||
+ FILE *f = xfopen ("/proc/self/maps", "r");
|
||
+ char *line = NULL, *path_ldso = NULL;
|
||
+ size_t len;
|
||
+ bool found = false;
|
||
+ while (xgetline (&line, &len, f))
|
||
+ {
|
||
+ uintptr_t from, to;
|
||
+ char *path = NULL;
|
||
+ int r = sscanf (line, "%" SCNxPTR "-%" SCNxPTR "%*s%*s%*s%*s%ms",
|
||
+ &from, &to, &path);
|
||
+
|
||
+ TEST_VERIFY (r == 2 || r == 3);
|
||
+ TEST_COMPARE (from % pagesize, 0);
|
||
+ TEST_COMPARE (to % pagesize, 0);
|
||
+
|
||
+ if (path_ldso == NULL && l->l_map_start == from)
|
||
+ {
|
||
+ TEST_COMPARE (r, 3);
|
||
+ path_ldso = path;
|
||
+ continue;
|
||
+ }
|
||
+
|
||
+ if (from > l->l_map_start && to < l->l_map_end
|
||
+ && (r == 2 || (path_ldso != NULL && strcmp (path, path_ldso))))
|
||
+ {
|
||
+ if (r == 2)
|
||
+ printf ("info: anonymous mapping found at 0x%" PRIxPTR " - 0x%"
|
||
+ PRIxPTR "\n", from, to);
|
||
+ else
|
||
+ printf ("info: object \"%s\" found at 0x%" PRIxPTR " - 0x%"
|
||
+ PRIxPTR "\n", path, from, to);
|
||
+
|
||
+ found = true;
|
||
+ }
|
||
+
|
||
+ free (path);
|
||
+ }
|
||
+
|
||
+ free (path_ldso);
|
||
+ free (line);
|
||
+ xfclose (f);
|
||
+ return found;
|
||
+}
|
||
+
|
||
static int
|
||
do_test (void)
|
||
{
|
||
@@ -64,16 +122,18 @@ do_test (void)
|
||
if ((void *) dlfo.dlfo_link_map != (void *) l)
|
||
{
|
||
printf ("info: object \"%s\" found at %p\n",
|
||
- dlfo.dlfo_link_map->l_name, ptr);
|
||
+ dlfo.dlfo_link_map->l_name, expected);
|
||
gap_found = true;
|
||
}
|
||
}
|
||
else
|
||
TEST_COMPARE (dlfo_ret, -1);
|
||
+
|
||
xmunmap (ptr, 1);
|
||
addr += pagesize;
|
||
}
|
||
- if (!gap_found)
|
||
+
|
||
+ if (!gap_found && !find_gap_with_proc_self_map (l))
|
||
FAIL ("no ld.so gap found");
|
||
}
|
||
else
|
||
|
||
commit a56a2943d2ce541102c630142c2eae0fbfc5886b
|
||
Author: Michael Jeanson <mjeanson@efficios.com>
|
||
Date: Fri Feb 20 11:01:00 2026 -0500
|
||
|
||
tests: fix tst-rseq with Linux 7.0
|
||
|
||
A sub-test of tst-rseq is to validate the return code and errno of the
|
||
rseq syscall when attempting to register the exact same rseq area as was
|
||
done in the dynamic loader.
|
||
|
||
This involves finding the rseq area address by adding the
|
||
'__rseq_offset' to the thread pointer and calculating the area size from
|
||
the AT_RSEQ_FEATURE_SIZE auxiliary vector. However the test currently
|
||
calculates the size of the rseq area allocation in the TLS block which
|
||
must be a multiple of AT_RSEQ_ALIGN.
|
||
|
||
Up until now that happened to be the same value since the feature size
|
||
and alignment exposed by the kernel were below the minimum ABI size of
|
||
32. Starting with Linux 7.0 the feature size has reached 33 while the
|
||
alignment is now 64.
|
||
|
||
This results in the test trying to re-register the rseq area with a
|
||
different size and thus not getting the expected errno value.
|
||
|
||
Signed-off-by: Michael Jeanson <mjeanson@efficios.com>
|
||
Reviewed-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
|
||
(cherry picked from commit 67f303b47dc584f204e3f2441b9832082415eebc)
|
||
|
||
diff --git a/sysdeps/unix/sysv/linux/tst-rseq.c b/sysdeps/unix/sysv/linux/tst-rseq.c
|
||
index 00181cfefb..e83ea2b939 100644
|
||
--- a/sysdeps/unix/sysv/linux/tst-rseq.c
|
||
+++ b/sysdeps/unix/sysv/linux/tst-rseq.c
|
||
@@ -48,8 +48,7 @@ do_rseq_main_test (void)
|
||
size_t rseq_align = MAX (getauxval (AT_RSEQ_ALIGN), RSEQ_MIN_ALIGN);
|
||
size_t rseq_feature_size = MAX (getauxval (AT_RSEQ_FEATURE_SIZE),
|
||
RSEQ_AREA_SIZE_INITIAL_USED);
|
||
- size_t rseq_alloc_size = roundup (MAX (rseq_feature_size,
|
||
- RSEQ_AREA_SIZE_INITIAL_USED), rseq_align);
|
||
+ size_t rseq_reg_size = MAX (rseq_feature_size, RSEQ_AREA_SIZE_INITIAL);
|
||
struct rseq *rseq_abi = __thread_pointer () + __rseq_offset;
|
||
|
||
TEST_VERIFY_EXIT (rseq_thread_registered ());
|
||
@@ -89,8 +88,8 @@ do_rseq_main_test (void)
|
||
/* Test a rseq registration with the same arguments as the internal
|
||
registration which should fail with errno == EBUSY. */
|
||
TEST_VERIFY (((unsigned long) rseq_abi % rseq_align) == 0);
|
||
- TEST_VERIFY (__rseq_size <= rseq_alloc_size);
|
||
- int ret = syscall (__NR_rseq, rseq_abi, rseq_alloc_size, 0, RSEQ_SIG);
|
||
+ TEST_VERIFY (__rseq_size <= rseq_reg_size);
|
||
+ int ret = syscall (__NR_rseq, rseq_abi, rseq_reg_size, 0, RSEQ_SIG);
|
||
TEST_VERIFY (ret != 0);
|
||
TEST_COMPARE (errno, EBUSY);
|
||
}
|
||
|
||
commit f13c1bb0f97fbc12a6ba1ab5669ce561ea32b80a
|
||
Author: Florian Weimer <fweimer@redhat.com>
|
||
Date: Thu Apr 16 19:13:43 2026 +0200
|
||
|
||
Use pending character state in IBM1390, IBM1399 character sets (CVE-2026-4046)
|
||
|
||
Follow the example in iso-2022-jp-3.c and use the __count state
|
||
variable to store the pending character. This avoids restarting
|
||
the conversion if the output buffer ends between two 4-byte UCS-4
|
||
code points, so that the assert reported in the bug can no longer
|
||
happen.
|
||
|
||
Even though the fix is applied to ibm1364.c, the change is only
|
||
effective for the two HAS_COMBINED codecs for IBM1390, IBM1399.
|
||
|
||
The test case was mostly auto-generated using
|
||
claude-4.6-opus-high-thinking, and composer-2-fast shows up in the
|
||
log as well. During review, gpt-5.4-xhigh flagged that the original
|
||
version of the test case was not exercising the new character
|
||
flush logic.
|
||
|
||
This fixes bug 33980.
|
||
|
||
Assisted-by: LLM
|
||
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
|
||
(cherry picked from commit d6f08d1cf027f4eb2ba289a6cc66853722d4badc)
|
||
|
||
diff --git a/iconvdata/Makefile b/iconvdata/Makefile
|
||
index 5a2abeea24..cc689f63e9 100644
|
||
--- a/iconvdata/Makefile
|
||
+++ b/iconvdata/Makefile
|
||
@@ -76,7 +76,7 @@ tests = bug-iconv1 bug-iconv2 tst-loading tst-e2big tst-iconv4 bug-iconv4 \
|
||
tst-iconv6 bug-iconv5 bug-iconv6 tst-iconv7 bug-iconv8 bug-iconv9 \
|
||
bug-iconv10 bug-iconv11 bug-iconv12 tst-iconv-big5-hkscs-to-2ucs4 \
|
||
bug-iconv13 bug-iconv14 bug-iconv15 \
|
||
- tst-iconv-iso-2022-cn-ext
|
||
+ tst-iconv-iso-2022-cn-ext tst-bug33980
|
||
ifeq ($(have-thread-library),yes)
|
||
tests += bug-iconv3
|
||
endif
|
||
@@ -333,6 +333,8 @@ $(objpfx)bug-iconv15.out: $(addprefix $(objpfx), $(gconv-modules)) \
|
||
$(addprefix $(objpfx),$(modules.so))
|
||
$(objpfx)tst-iconv-iso-2022-cn-ext.out: $(addprefix $(objpfx), $(gconv-modules)) \
|
||
$(addprefix $(objpfx),$(modules.so))
|
||
+$(objpfx)tst-bug33980.out: $(addprefix $(objpfx), $(gconv-modules)) \
|
||
+ $(addprefix $(objpfx),$(modules.so))
|
||
|
||
$(objpfx)iconv-test.out: run-iconv-test.sh \
|
||
$(addprefix $(objpfx), $(gconv-modules)) \
|
||
diff --git a/iconvdata/ibm1364.c b/iconvdata/ibm1364.c
|
||
index 45c62acee5..244c61ad7a 100644
|
||
--- a/iconvdata/ibm1364.c
|
||
+++ b/iconvdata/ibm1364.c
|
||
@@ -67,12 +67,29 @@
|
||
|
||
/* Since this is a stateful encoding we have to provide code which resets
|
||
the output state to the initial state. This has to be done during the
|
||
- flushing. */
|
||
+ flushing. For the to-internal direction (FROM_DIRECTION is true),
|
||
+ there may be a pending character that needs flushing. */
|
||
#define EMIT_SHIFT_TO_INIT \
|
||
if ((data->__statep->__count & ~7) != sb) \
|
||
{ \
|
||
if (FROM_DIRECTION) \
|
||
- data->__statep->__count &= 7; \
|
||
+ { \
|
||
+ uint32_t ch = data->__statep->__count >> 7; \
|
||
+ if (__glibc_unlikely (ch != 0)) \
|
||
+ { \
|
||
+ if (__glibc_unlikely (outend - outbuf < 4)) \
|
||
+ status = __GCONV_FULL_OUTPUT; \
|
||
+ else \
|
||
+ { \
|
||
+ put32 (outbuf, ch); \
|
||
+ outbuf += 4; \
|
||
+ /* Clear character and db bit. */ \
|
||
+ data->__statep->__count &= 7; \
|
||
+ } \
|
||
+ } \
|
||
+ else \
|
||
+ data->__statep->__count &= 7; \
|
||
+ } \
|
||
else \
|
||
{ \
|
||
/* We are not in the initial state. To switch back we have \
|
||
@@ -99,11 +116,13 @@
|
||
*curcsp = save_curcs
|
||
|
||
|
||
-/* Current codeset type. */
|
||
+/* Current codeset type. The bit is stored in the __count variable of
|
||
+ the conversion state. If the db bit is set, bit 7 and above store
|
||
+ a pending UCS-4 code point if non-zero. */
|
||
enum
|
||
{
|
||
- sb = 0,
|
||
- db = 64
|
||
+ sb = 0, /* Single byte mode. */
|
||
+ db = 64 /* Double byte mode. */
|
||
};
|
||
|
||
|
||
@@ -119,21 +138,29 @@ enum
|
||
} \
|
||
else \
|
||
{ \
|
||
- /* This is a combined character. Make sure we have room. */ \
|
||
- if (__glibc_unlikely (outptr + 8 > outend)) \
|
||
- { \
|
||
- result = __GCONV_FULL_OUTPUT; \
|
||
- break; \
|
||
- } \
|
||
- \
|
||
const struct divide *cmbp \
|
||
= &DB_TO_UCS4_COMB[ch - __TO_UCS4_COMBINED_MIN]; \
|
||
assert (cmbp->res1 != 0 && cmbp->res2 != 0); \
|
||
\
|
||
put32 (outptr, cmbp->res1); \
|
||
outptr += 4; \
|
||
- put32 (outptr, cmbp->res2); \
|
||
- outptr += 4; \
|
||
+ \
|
||
+ /* See whether we have room for the second character. */ \
|
||
+ if (outend - outptr >= 4) \
|
||
+ { \
|
||
+ put32 (outptr, cmbp->res2); \
|
||
+ outptr += 4; \
|
||
+ } \
|
||
+ else \
|
||
+ { \
|
||
+ /* Otherwise store only the first character now, and \
|
||
+ put the second one into the queue. */ \
|
||
+ curcs |= cmbp->res2 << 7; \
|
||
+ inptr += 2; \
|
||
+ /* Tell the caller why we terminate the loop. */ \
|
||
+ result = __GCONV_FULL_OUTPUT; \
|
||
+ break; \
|
||
+ } \
|
||
} \
|
||
}
|
||
#else
|
||
@@ -153,7 +180,20 @@ enum
|
||
#define LOOPFCT FROM_LOOP
|
||
#define BODY \
|
||
{ \
|
||
- uint32_t ch = *inptr; \
|
||
+ uint32_t ch; \
|
||
+ \
|
||
+ ch = curcs >> 7; \
|
||
+ if (__glibc_unlikely (ch != 0)) \
|
||
+ { \
|
||
+ put32 (outptr, ch); \
|
||
+ outptr += 4; \
|
||
+ /* Remove the pending character, but preserve state bits. */ \
|
||
+ curcs &= (1 << 7) - 1; \
|
||
+ continue; \
|
||
+ } \
|
||
+ \
|
||
+ /* Otherwise read the next input byte. */ \
|
||
+ ch = *inptr; \
|
||
\
|
||
if (__builtin_expect (ch, 0) == SO) \
|
||
{ \
|
||
diff --git a/iconvdata/tst-bug33980.c b/iconvdata/tst-bug33980.c
|
||
new file mode 100644
|
||
index 0000000000..c9693e0efe
|
||
--- /dev/null
|
||
+++ b/iconvdata/tst-bug33980.c
|
||
@@ -0,0 +1,153 @@
|
||
+/* Test for bug 33980: combining characters in IBM1390/IBM1399.
|
||
+ 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 <alloc_buffer.h>
|
||
+#include <errno.h>
|
||
+#include <iconv.h>
|
||
+#include <stdbool.h>
|
||
+#include <string.h>
|
||
+
|
||
+#include <support/check.h>
|
||
+#include <support/next_to_fault.h>
|
||
+#include <support/support.h>
|
||
+
|
||
+/* Run iconv in a loop with a small output buffer of OUTBUFSIZE bytes
|
||
+ starting at OUTBUF. OUTBUF should be right before an unmapped page
|
||
+ so that writing past the end will fault. Skip SHIFT bytes at the
|
||
+ start of the input and output, to exercise different buffer
|
||
+ alignment. TRUNCATE indicates skipped bytes at the end of
|
||
+ input (0 and 1 a valid). */
|
||
+static void
|
||
+test_one (const char *encoding, unsigned int shift, unsigned int truncate,
|
||
+ char *outbuf, size_t outbufsize)
|
||
+{
|
||
+ /* In IBM1390 and IBM1399, the DBCS code 0xECB5 expands to two
|
||
+ Unicode code points when translated. */
|
||
+ static char input[] =
|
||
+ {
|
||
+ /* 8 letters X. */
|
||
+ 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7,
|
||
+ /* SO, 0xECB5, SI: shift to DBCS, special character, shift back. */
|
||
+ 0x0e, 0xec, 0xb5, 0x0f
|
||
+ };
|
||
+
|
||
+ /* Expected output after UTF-8 conversion. */
|
||
+ static char expected[] =
|
||
+ {
|
||
+ 'X', 'X', 'X', 'X', 'X', 'X', 'X', 'X',
|
||
+ /* U+304B (HIRAGANA LETTER KA). */
|
||
+ 0xe3, 0x81, 0x8b,
|
||
+ /* U+309A (COMBINING KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK). */
|
||
+ 0xe3, 0x82, 0x9a
|
||
+ };
|
||
+
|
||
+ iconv_t cd = iconv_open ("UTF-8", encoding);
|
||
+ TEST_VERIFY_EXIT (cd != (iconv_t) -1);
|
||
+
|
||
+ char result_storage[64];
|
||
+ struct alloc_buffer result_buf
|
||
+ = alloc_buffer_create (result_storage, sizeof (result_storage));
|
||
+
|
||
+ char *inptr = &input[shift];
|
||
+ size_t inleft = sizeof (input) - shift - truncate;
|
||
+
|
||
+ while (inleft > 0)
|
||
+ {
|
||
+ char *outptr = outbuf;
|
||
+ size_t outleft = outbufsize;
|
||
+ size_t inleft_before = inleft;
|
||
+
|
||
+ size_t ret = iconv (cd, &inptr, &inleft, &outptr, &outleft);
|
||
+ size_t produced = outptr - outbuf;
|
||
+ alloc_buffer_copy_bytes (&result_buf, outbuf, produced);
|
||
+
|
||
+ if (ret == (size_t) -1 && errno == E2BIG)
|
||
+ {
|
||
+ if (produced == 0 && inleft == inleft_before)
|
||
+ {
|
||
+ /* Output buffer too small to make progress. This is
|
||
+ expected for very small output buffer sizes. */
|
||
+ TEST_VERIFY_EXIT (outbufsize < 3);
|
||
+ break;
|
||
+ }
|
||
+ continue;
|
||
+ }
|
||
+ if (ret == (size_t) -1)
|
||
+ FAIL_EXIT1 ("%s (outbufsize %zu): iconv: %m", encoding, outbufsize);
|
||
+ break;
|
||
+ }
|
||
+
|
||
+ /* Flush any pending state (e.g. a buffered combined character).
|
||
+ With outbufsize < 3, we could not store the first character, so
|
||
+ the second character did not become pending, and there is nothing
|
||
+ to flush. */
|
||
+ {
|
||
+ char *outptr = outbuf;
|
||
+ size_t outleft = outbufsize;
|
||
+
|
||
+ size_t ret = iconv (cd, NULL, NULL, &outptr, &outleft);
|
||
+ TEST_VERIFY_EXIT (ret == 0);
|
||
+ size_t produced = outptr - outbuf;
|
||
+ alloc_buffer_copy_bytes (&result_buf, outbuf, produced);
|
||
+
|
||
+ /* Second flush does not provide more data. */
|
||
+ outptr = outbuf;
|
||
+ outleft = outbufsize;
|
||
+ ret = iconv (cd, NULL, NULL, &outptr, &outleft);
|
||
+ TEST_VERIFY_EXIT (ret == 0);
|
||
+ TEST_VERIFY (outptr == outbuf);
|
||
+ }
|
||
+
|
||
+ TEST_VERIFY_EXIT (!alloc_buffer_has_failed (&result_buf));
|
||
+ size_t result_used
|
||
+ = sizeof (result_storage) - alloc_buffer_size (&result_buf);
|
||
+
|
||
+ if (outbufsize >= 3)
|
||
+ {
|
||
+ TEST_COMPARE (inleft, 0);
|
||
+ TEST_COMPARE (result_used, sizeof (expected) - shift);
|
||
+ TEST_COMPARE_BLOB (result_storage, result_used,
|
||
+ &expected[shift], sizeof (expected) - shift);
|
||
+ }
|
||
+ else
|
||
+ /* If the buffer is too small, only the leading X could be converted. */
|
||
+ TEST_COMPARE (result_used, 8 - shift);
|
||
+
|
||
+ TEST_VERIFY_EXIT (iconv_close (cd) == 0);
|
||
+}
|
||
+
|
||
+static int
|
||
+do_test (void)
|
||
+{
|
||
+ struct support_next_to_fault ntf
|
||
+ = support_next_to_fault_allocate (8);
|
||
+
|
||
+ for (int shift = 0; shift <= 8; ++shift)
|
||
+ for (int truncate = 0; truncate < 2; ++truncate)
|
||
+ for (size_t outbufsize = 1; outbufsize <= 8; outbufsize++)
|
||
+ {
|
||
+ char *outbuf = ntf.buffer + ntf.length - outbufsize;
|
||
+ test_one ("IBM1390", shift, truncate, outbuf, outbufsize);
|
||
+ test_one ("IBM1399", shift, truncate, outbuf, outbufsize);
|
||
+ }
|
||
+
|
||
+ support_next_to_fault_free (&ntf);
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+#include <support/test-driver.c>
|
||
|
||
commit 12feedaf67e11c4618dc50c6aab4dbfd1e6d9531
|
||
Author: DJ Delorie <dj@redhat.com>
|
||
Date: Mon Jan 26 22:24:42 2026 -0500
|
||
|
||
include: isolate __O_CLOEXEC flag for sys/mount.h and fcntl.h
|
||
|
||
Including sys/mount.h should not implicitly include fcntl.h
|
||
as that causes namespace pollution and conflicts with kernel
|
||
headers. It only needs O_CLOEXEC for OPEN_TREE_CLOEXEC
|
||
(although it shouldn't need that, but it's defined that way)
|
||
so we provide that define (via a private version) separately.
|
||
|
||
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
||
Tested-by: Florian Weimer <fweimer@redhat.com>
|
||
(cherry picked from commit 419245719ccbc7dad6a97f24465e7f09c090327a)
|
||
|
||
diff --git a/io/fcntl.c b/io/fcntl.c
|
||
index e88e28664c..b7dab1bb39 100644
|
||
--- a/io/fcntl.c
|
||
+++ b/io/fcntl.c
|
||
@@ -18,6 +18,10 @@
|
||
#include <errno.h>
|
||
#include <fcntl.h>
|
||
|
||
+#ifndef __O_CLOEXEC
|
||
+# error __O_CLOEXEC not defined by fcntl.h/cloexec.h
|
||
+#endif
|
||
+
|
||
/* Perform file control operations on FD. */
|
||
int
|
||
__fcntl (int fd, int cmd, ...)
|
||
diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile
|
||
index c47cbdf428..053041f256 100644
|
||
--- a/sysdeps/unix/sysv/linux/Makefile
|
||
+++ b/sysdeps/unix/sysv/linux/Makefile
|
||
@@ -129,6 +129,7 @@ CFLAGS-test-errno-linux.c += $(no-fortify-source)
|
||
|
||
sysdep_headers += \
|
||
bits/a.out.h \
|
||
+ bits/cloexec.h \
|
||
bits/epoll.h \
|
||
bits/eventfd.h \
|
||
bits/inotify.h \
|
||
diff --git a/sysdeps/unix/sysv/linux/alpha/bits/cloexec.h b/sysdeps/unix/sysv/linux/alpha/bits/cloexec.h
|
||
new file mode 100644
|
||
index 0000000000..f381f28a53
|
||
--- /dev/null
|
||
+++ b/sysdeps/unix/sysv/linux/alpha/bits/cloexec.h
|
||
@@ -0,0 +1 @@
|
||
+#define __O_CLOEXEC 010000000
|
||
diff --git a/sysdeps/unix/sysv/linux/bits/cloexec.h b/sysdeps/unix/sysv/linux/bits/cloexec.h
|
||
new file mode 100644
|
||
index 0000000000..3059fb6473
|
||
--- /dev/null
|
||
+++ b/sysdeps/unix/sysv/linux/bits/cloexec.h
|
||
@@ -0,0 +1 @@
|
||
+#define __O_CLOEXEC 02000000
|
||
diff --git a/sysdeps/unix/sysv/linux/bits/fcntl-linux.h b/sysdeps/unix/sysv/linux/bits/fcntl-linux.h
|
||
index f425a4bf22..98954feaca 100644
|
||
--- a/sysdeps/unix/sysv/linux/bits/fcntl-linux.h
|
||
+++ b/sysdeps/unix/sysv/linux/bits/fcntl-linux.h
|
||
@@ -81,9 +81,7 @@
|
||
#ifndef __O_NOFOLLOW
|
||
# define __O_NOFOLLOW 0400000
|
||
#endif
|
||
-#ifndef __O_CLOEXEC
|
||
-# define __O_CLOEXEC 02000000
|
||
-#endif
|
||
+#include <bits/cloexec.h>
|
||
#ifndef __O_DIRECT
|
||
# define __O_DIRECT 040000
|
||
#endif
|
||
diff --git a/sysdeps/unix/sysv/linux/hppa/bits/cloexec.h b/sysdeps/unix/sysv/linux/hppa/bits/cloexec.h
|
||
new file mode 100644
|
||
index 0000000000..f381f28a53
|
||
--- /dev/null
|
||
+++ b/sysdeps/unix/sysv/linux/hppa/bits/cloexec.h
|
||
@@ -0,0 +1 @@
|
||
+#define __O_CLOEXEC 010000000
|
||
diff --git a/sysdeps/unix/sysv/linux/sparc/bits/cloexec.h b/sysdeps/unix/sysv/linux/sparc/bits/cloexec.h
|
||
new file mode 100644
|
||
index 0000000000..6706eaa7d5
|
||
--- /dev/null
|
||
+++ b/sysdeps/unix/sysv/linux/sparc/bits/cloexec.h
|
||
@@ -0,0 +1 @@
|
||
+#define __O_CLOEXEC 0x400000
|
||
diff --git a/sysdeps/unix/sysv/linux/sys/mount.h b/sysdeps/unix/sysv/linux/sys/mount.h
|
||
index b549e75148..365da1c296 100644
|
||
--- a/sysdeps/unix/sysv/linux/sys/mount.h
|
||
+++ b/sysdeps/unix/sysv/linux/sys/mount.h
|
||
@@ -21,7 +21,6 @@
|
||
#ifndef _SYS_MOUNT_H
|
||
#define _SYS_MOUNT_H 1
|
||
|
||
-#include <fcntl.h>
|
||
#include <features.h>
|
||
#include <stdint.h>
|
||
#include <stddef.h>
|
||
@@ -266,6 +265,11 @@ enum fsconfig_command
|
||
|
||
/* open_tree flags. */
|
||
#define OPEN_TREE_CLONE 1 /* Clone the target tree and attach the clone */
|
||
+#ifndef O_CLOEXEC
|
||
+# include <bits/cloexec.h>
|
||
+# define O_CLOEXEC __O_CLOEXEC
|
||
+#endif
|
||
+#undef OPEN_TREE_CLOEXEC
|
||
#define OPEN_TREE_CLOEXEC O_CLOEXEC /* Close the file on execve() */
|
||
|
||
|
||
diff --git a/sysdeps/unix/sysv/linux/tst-mount.c b/sysdeps/unix/sysv/linux/tst-mount.c
|
||
index 40913c7082..78a2772b2f 100644
|
||
--- a/sysdeps/unix/sysv/linux/tst-mount.c
|
||
+++ b/sysdeps/unix/sysv/linux/tst-mount.c
|
||
@@ -20,6 +20,7 @@
|
||
#include <support/check.h>
|
||
#include <support/xunistd.h>
|
||
#include <support/namespace.h>
|
||
+#include <fcntl.h> /* For AT_ constants. */
|
||
#include <sys/mount.h>
|
||
|
||
_Static_assert (sizeof (struct mount_attr) == MOUNT_ATTR_SIZE_VER0,
|
||
|
||
commit 3ecfa68561d723564a1fb565366182eb4acb3e8f
|
||
Author: Florian Weimer <fweimer@redhat.com>
|
||
Date: Wed Mar 4 18:32:36 2026 +0100
|
||
|
||
Linux: Only define OPEN_TREE_* macros in <sys/mount.h> if undefined (bug 33921)
|
||
|
||
There is a conditional inclusion of <linux/mount.h> earlier in the file.
|
||
If that defines the macros, do not redefine them. This addresses build
|
||
problems as the token sequence used by the UAPI macro definitions
|
||
changes between Linux versions.
|
||
|
||
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
||
(cherry picked from commit d12b017cddfeb9fe9920ba054ae3dfcb8e9238b8)
|
||
|
||
diff --git a/sysdeps/unix/sysv/linux/sys/mount.h b/sysdeps/unix/sysv/linux/sys/mount.h
|
||
index 365da1c296..30ba56c1e8 100644
|
||
--- a/sysdeps/unix/sysv/linux/sys/mount.h
|
||
+++ b/sysdeps/unix/sysv/linux/sys/mount.h
|
||
@@ -264,14 +264,16 @@ enum fsconfig_command
|
||
#define FSOPEN_CLOEXEC 0x00000001
|
||
|
||
/* open_tree flags. */
|
||
-#define OPEN_TREE_CLONE 1 /* Clone the target tree and attach the clone */
|
||
+#ifndef OPEN_TREE_CLONE
|
||
+# define OPEN_TREE_CLONE 1 /* Clone the target tree and attach the clone */
|
||
+#endif
|
||
#ifndef O_CLOEXEC
|
||
# include <bits/cloexec.h>
|
||
# define O_CLOEXEC __O_CLOEXEC
|
||
#endif
|
||
-#undef OPEN_TREE_CLOEXEC
|
||
-#define OPEN_TREE_CLOEXEC O_CLOEXEC /* Close the file on execve() */
|
||
-
|
||
+#ifndef OPEN_TREE_CLOEXEC
|
||
+# define OPEN_TREE_CLOEXEC O_CLOEXEC /* Close the file on execve() */
|
||
+#endif
|
||
|
||
__BEGIN_DECLS
|
||
|
||
|
||
commit 3e87cf9be93acf19d685e8003fc649cdb052a891
|
||
Author: H.J. Lu <hjl.tools@gmail.com>
|
||
Date: Mon Apr 13 10:46:42 2026 +0800
|
||
|
||
abilist.awk: Handle weak unversioned defined symbols
|
||
|
||
After
|
||
|
||
commit f685e3953f9a38a41bbd0a597f9882870cee13d5
|
||
Author: H.J. Lu <hjl.tools@gmail.com>
|
||
Date: Wed Oct 29 09:49:57 2025 +0800
|
||
|
||
elf: Don't set its DT_VERSYM entry for unversioned symbol
|
||
|
||
ld no longer assigns version index 1 to unversioned defined symbol.
|
||
For libmachuser.so, "objdump --dynamic-syms" reports:
|
||
|
||
0000dd30 w DF .text 000000f8 processor_start
|
||
|
||
instead of
|
||
|
||
0000dd30 w DF .text 000000f8 (Base) processor_start
|
||
|
||
Also allow NF == 6 for weak unversioned dynamic symbols. This fixes BZ
|
||
33650.
|
||
|
||
Signed-off-by: H.J. Lu <hjl.tools@gmail.com>
|
||
Reviewed-by: Sam James <sam@gentoo.org>
|
||
(cherry picked from commit ee5d1db2a81468413fbf7c82779ffa782f429d1a)
|
||
|
||
diff --git a/scripts/abilist.awk b/scripts/abilist.awk
|
||
index 6cc7af6ac8..7ea1edf8c0 100644
|
||
--- a/scripts/abilist.awk
|
||
+++ b/scripts/abilist.awk
|
||
@@ -38,7 +38,7 @@ $4 == "*UND*" { next }
|
||
$2 == "l" { next }
|
||
|
||
# If the target uses ST_OTHER, it will be output before the symbol name.
|
||
-$2 == "g" || $2 == "w" && (NF == 7 || NF == 8) {
|
||
+$2 == "g" || $2 == "w" && (NF == 6 || NF == 7 || NF == 8) {
|
||
type = $3;
|
||
size = $5;
|
||
sub(/^0*/, "", size);
|
||
|
||
commit b4bca35ab9e76890504c4dbdd5eaf15a93514580
|
||
Author: Rocket Ma <marocketbd@gmail.com>
|
||
Date: Fri May 1 20:39:07 2026 -0700
|
||
|
||
libio: Fix ungetwc operating on byte stream [BZ #33998]
|
||
|
||
* libio/wgenops.c: When _IO_wdefault_pbackfail attempts to push back one
|
||
character, it accidently compare the wchar to push back with the last
|
||
char from byte stream, instead of wide stream. Under specific coding,
|
||
attacker may exploit this to leak information. This commit fix bug
|
||
33998, or CVE-2026-5928.
|
||
|
||
Signed-off-by: Rocket Ma <marocketbd@gmail.com>
|
||
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
|
||
(cherry picked from commit ef3bfb5f910011f3780cb06aa47e730035f53285)
|
||
|
||
diff --git a/libio/Makefile b/libio/Makefile
|
||
index f020f8ec4d..fa2b8ae791 100644
|
||
--- a/libio/Makefile
|
||
+++ b/libio/Makefile
|
||
@@ -83,6 +83,7 @@ tests = \
|
||
bug-ungetwc1 \
|
||
bug-ungetwc2 \
|
||
bug-wfflush \
|
||
+ bug-wgenops-bz33998 \
|
||
bug-wmemstream1 \
|
||
bug-wsetpos \
|
||
test-fmemopen \
|
||
diff --git a/libio/bug-wgenops-bz33998.c b/libio/bug-wgenops-bz33998.c
|
||
new file mode 100644
|
||
index 0000000000..cc4067da99
|
||
--- /dev/null
|
||
+++ b/libio/bug-wgenops-bz33998.c
|
||
@@ -0,0 +1,54 @@
|
||
+/* Regression test for ungetwc operating on byte stream (BZ #33998)
|
||
+ Copyright (C) 2026 The GNU Toolchain Authors.
|
||
+ 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 "support/temp_file.h"
|
||
+#include "support/xstdio.h"
|
||
+#include "support/xunistd.h"
|
||
+#include <stdlib.h>
|
||
+#include <unistd.h>
|
||
+#include <sys/mman.h>
|
||
+#include <stdio.h>
|
||
+#include <wchar.h>
|
||
+#include <support/check.h>
|
||
+
|
||
+static int
|
||
+do_test (void)
|
||
+{
|
||
+ char *filename;
|
||
+ int fd = create_temp_file ("tst-bz33998-", &filename);
|
||
+ TEST_VERIFY (fd != -1);
|
||
+ xwrite (fd, "A", sizeof ("A")); // write "A\0" by design
|
||
+ xclose (fd);
|
||
+
|
||
+ FILE *fp = xfopen (filename, "r+");
|
||
+ TEST_COMPARE (getwc (fp), L'A');
|
||
+ /* If the bug is fixed, then ungetwc should not touch byte stream.
|
||
+ If the bug is not fixed, ungetwc firstly match last read char, L'A',
|
||
+ failed, then the pbackfail branch, matching last read char in byte
|
||
+ stream, that is, '\0' (initialized when setup wide stream). */
|
||
+ char *old_read_ptr = fp->_IO_read_ptr;
|
||
+ TEST_COMPARE (ungetwc (L'\0', fp), L'\0');
|
||
+ TEST_VERIFY (fp->_IO_read_ptr == old_read_ptr);
|
||
+
|
||
+ xfclose (fp);
|
||
+ free (filename);
|
||
+
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+#include <support/test-driver.c>
|
||
diff --git a/libio/wgenops.c b/libio/wgenops.c
|
||
index 0a11d1b1de..9e0b2c00ea 100644
|
||
--- a/libio/wgenops.c
|
||
+++ b/libio/wgenops.c
|
||
@@ -108,8 +108,8 @@ _IO_wdefault_pbackfail (FILE *fp, wint_t c)
|
||
{
|
||
if (fp->_wide_data->_IO_read_ptr > fp->_wide_data->_IO_read_base
|
||
&& !_IO_in_backup (fp)
|
||
- && (wint_t) fp->_IO_read_ptr[-1] == c)
|
||
- --fp->_IO_read_ptr;
|
||
+ && (wint_t) fp->_wide_data->_IO_read_ptr[-1] == c)
|
||
+ --fp->_wide_data->_IO_read_ptr;
|
||
else
|
||
{
|
||
/* Need to handle a filebuf in write mode (switch to read mode). FIXME!*/
|
||
|
||
commit 4ebd33dd77eabe8d4c45232bed4b42a31d2f9edc
|
||
Author: Rocket Ma <marocketbd@gmail.com>
|
||
Date: Fri Apr 17 23:48:41 2026 -0700
|
||
|
||
stdio-common: Fix buffer overflow in scanf %mc [BZ #34008]
|
||
|
||
* stdio-common/vfscanf-internal.c: When enlarging allocated buffer with
|
||
format %mc or %mC, glibc allocates one byte less, leading to
|
||
user-controlled one byte overflow. This commit fixes BZ #34008, or
|
||
CVE-2026-5450.
|
||
|
||
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
|
||
Signed-off-by: Rocket Ma <marocketbd@gmail.com>
|
||
Reviewed-by: H.J. Lu <hjl.tools@gmail.com>
|
||
(cherry picked from commit 839898777226a3ed88c0859f25ffe712519b4ead)
|
||
|
||
diff --git a/stdio-common/Makefile b/stdio-common/Makefile
|
||
index 64b3575acb..e52c333808 100644
|
||
--- a/stdio-common/Makefile
|
||
+++ b/stdio-common/Makefile
|
||
@@ -347,6 +347,7 @@ tests := \
|
||
tst-vfprintf-user-type \
|
||
tst-vfprintf-width-i18n \
|
||
tst-vfprintf-width-prec-alloc \
|
||
+ tst-vfscanf-bz34008 \
|
||
tst-wc-printf \
|
||
tstdiomisc \
|
||
tstgetln \
|
||
@@ -562,6 +563,9 @@ tst-printf-bz18872-ENV = MALLOC_TRACE=$(objpfx)tst-printf-bz18872.mtrace \
|
||
tst-vfprintf-width-prec-ENV = \
|
||
MALLOC_TRACE=$(objpfx)tst-vfprintf-width-prec.mtrace \
|
||
LD_PRELOAD=$(common-objpfx)/malloc/libc_malloc_debug.so
|
||
+tst-vfscanf-bz34008-ENV = \
|
||
+ MALLOC_CHECK_=3 \
|
||
+ LD_PRELOAD=$(common-objpfx)/malloc/libc_malloc_debug.so
|
||
tst-printf-bz25691-ENV = \
|
||
MALLOC_TRACE=$(objpfx)tst-printf-bz25691.mtrace \
|
||
LD_PRELOAD=$(common-objpfx)/malloc/libc_malloc_debug.so
|
||
diff --git a/stdio-common/tst-vfscanf-bz34008.c b/stdio-common/tst-vfscanf-bz34008.c
|
||
new file mode 100644
|
||
index 0000000000..48371c8a3d
|
||
--- /dev/null
|
||
+++ b/stdio-common/tst-vfscanf-bz34008.c
|
||
@@ -0,0 +1,48 @@
|
||
+/* Regression test for vfscanf %Nmc out-of-bound write (BZ #34008)
|
||
+ Copyright (C) 2026 The GNU Toolchain Authors.
|
||
+ 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 "malloc/mcheck.h"
|
||
+#include <stddef.h>
|
||
+#include <stdio.h>
|
||
+#include <string.h>
|
||
+#include <wchar.h>
|
||
+#include <stdlib.h>
|
||
+#include <malloc.h>
|
||
+#include <support/check.h>
|
||
+
|
||
+#define WIDTH 0x410
|
||
+#define SCANFSTR "%1040mc"
|
||
+static int
|
||
+do_test (void)
|
||
+{
|
||
+ mcheck_pedantic (NULL);
|
||
+ char *input = malloc (WIDTH + 1);
|
||
+ TEST_VERIFY (input != NULL);
|
||
+ memset (input, 'A', WIDTH);
|
||
+ input[WIDTH] = '\0';
|
||
+
|
||
+ char *buf = NULL;
|
||
+ TEST_VERIFY (sscanf (input, SCANFSTR, &buf) != -1);
|
||
+ TEST_VERIFY (buf != NULL);
|
||
+
|
||
+ free (buf);
|
||
+ free (input);
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+#include <support/test-driver.c>
|
||
diff --git a/stdio-common/vfscanf-internal.c b/stdio-common/vfscanf-internal.c
|
||
index 86ae5019a6..17b5565d0f 100644
|
||
--- a/stdio-common/vfscanf-internal.c
|
||
+++ b/stdio-common/vfscanf-internal.c
|
||
@@ -853,8 +853,7 @@ __vfscanf_internal (FILE *s, const char *format, va_list argptr,
|
||
{
|
||
/* Enlarge the buffer. */
|
||
size_t newsize
|
||
- = strsize
|
||
- + (strsize >= width ? width - 1 : strsize);
|
||
+ = strsize + (strsize >= width ? width : strsize);
|
||
|
||
str = (char *) realloc (*strptr, newsize);
|
||
if (str == NULL)
|
||
@@ -925,7 +924,7 @@ __vfscanf_internal (FILE *s, const char *format, va_list argptr,
|
||
&& wstr == (wchar_t *) *strptr + strsize)
|
||
{
|
||
size_t newsize
|
||
- = strsize + (strsize > width ? width - 1 : strsize);
|
||
+ = strsize + (strsize >= width ? width : strsize);
|
||
/* Enlarge the buffer. */
|
||
wstr = (wchar_t *) realloc (*strptr,
|
||
newsize * sizeof (wchar_t));
|
||
@@ -980,7 +979,7 @@ __vfscanf_internal (FILE *s, const char *format, va_list argptr,
|
||
&& wstr == (wchar_t *) *strptr + strsize)
|
||
{
|
||
size_t newsize
|
||
- = strsize + (strsize > width ? width - 1 : strsize);
|
||
+ = strsize + (strsize >= width ? width : strsize);
|
||
/* Enlarge the buffer. */
|
||
wstr = (wchar_t *) realloc (*strptr,
|
||
newsize * sizeof (wchar_t));
|