mirror of
git://sourceware.org/git/glibc.git
synced 2026-09-08 23:58:31 +08:00
Compare commits
68
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f8f3d451ba | ||
|
|
d9a8ff5c01 | ||
|
|
1c1f5103a9 | ||
|
|
049168237f | ||
|
|
0770e8b07c | ||
|
|
20b3e87176 | ||
|
|
72351055c6 | ||
|
|
8dad0ee453 | ||
|
|
f024355965 | ||
|
|
c4dac931ab | ||
|
|
76115597fe | ||
|
|
c29ca5d216 | ||
|
|
3ad1bbd8f9 | ||
|
|
138c43f018 | ||
|
|
713998bf00 | ||
|
|
2a35bab35b | ||
|
|
4964178b4d | ||
|
|
0afa34adb0 | ||
|
|
7d26579873 | ||
|
|
8017bcfc4d | ||
|
|
a388c4002d | ||
|
|
bc95068f5f | ||
|
|
1c9988e525 | ||
|
|
dae425b554 | ||
|
|
8759917de5 | ||
|
|
3a418da6a3 | ||
|
|
e64ae5a591 | ||
|
|
c9225a3e73 | ||
|
|
c46f7b2fd6 | ||
|
|
1d7d1a16b0 | ||
|
|
349297a4eb | ||
|
|
fdf10644d6 | ||
|
|
a6fa9a9594 | ||
|
|
fe0ccc9564 | ||
|
|
22f3d24a6b | ||
|
|
a13ebdbc7e | ||
|
|
446f708e4c | ||
|
|
ced45fd472 | ||
|
|
89cbf46693 | ||
|
|
18b97b03b7 | ||
|
|
a47b5b2b3e | ||
|
|
4070d808be | ||
|
|
2890b35cd3 | ||
|
|
e9517114ac | ||
|
|
1634cc11a5 | ||
|
|
d1d8d27164 | ||
|
|
8362e8ce10 | ||
|
|
ce1013a197 | ||
|
|
60cabd0464 | ||
|
|
02ffd413cf | ||
|
|
2695314378 | ||
|
|
dd9945c0ba | ||
|
|
5c6fca0c62 | ||
|
|
2be6cf2e75 | ||
|
|
305ce0b588 | ||
|
|
2ee41ba6ec | ||
|
|
fa4a40c7d4 | ||
|
|
9898ea58b5 | ||
|
|
c3ceb93dc4 | ||
|
|
911bd469f8 | ||
|
|
48f5a05a7a | ||
|
|
d6cb7ce0e9 | ||
|
|
140c760d71 | ||
|
|
856c426a75 | ||
|
|
144ba30208 | ||
|
|
022abaeacb | ||
|
|
45b58d6bd1 | ||
|
|
f02515d8a6 |
@@ -0,0 +1,2 @@
|
||||
For the GNU C Library Security Advisories, see the git master branch:
|
||||
https://sourceware.org/git/?p=glibc.git;a=tree;f=advisories;hb=HEAD
|
||||
@@ -5,6 +5,20 @@ 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.43.1
|
||||
|
||||
The following bugs are resolved with this release:
|
||||
|
||||
[33623] [ldbl-128ibm] roundl, ceill, truncl, floorl bad sign of zero
|
||||
results
|
||||
[33848] build: Build fails at openat2.h, redefinition of 'struct
|
||||
open_how'
|
||||
[33904] build: error: '__vasprintf_chk' undeclared here
|
||||
[34507] nptl: Pretty-printer tests FAIL instead of UNSUPPORTED when
|
||||
cross-testing without python3 on target
|
||||
[34509] libc: [m68k] Regression: Perl locks up after upgrading glibc
|
||||
to 2.43
|
||||
|
||||
Version 2.43
|
||||
|
||||
Major new features:
|
||||
|
||||
@@ -431,8 +431,9 @@ py-env := PYTHONPATH=$(py-const-dir):$(..)scripts:$${PYTHONPATH}
|
||||
# The pretty printer files and test_common_printers.py must be present for all.
|
||||
$(tests-printers-out): $(objpfx)%.out: $(objpfx)% %.py %.c $(pretty-printers) \
|
||||
$(..)scripts/test_printers_common.py
|
||||
$(test-wrapper-env) $(py-env) \
|
||||
$(PYTHON) $*.py $*.c $(objpfx)$* $(pretty-printers) > $@; \
|
||||
$(test-wrapper-env) $(py-env) sh -c \
|
||||
'command -v $(firstword $(PYTHON)) > /dev/null 2>&1 || exit 77; \
|
||||
exec $(PYTHON) $*.py $*.c $(objpfx)$* $(pretty-printers)' > $@; \
|
||||
$(evaluate-test)
|
||||
endif
|
||||
|
||||
|
||||
@@ -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)
|
||||
@@ -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)
|
||||
@@ -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)
|
||||
@@ -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)
|
||||
@@ -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)
|
||||
@@ -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)
|
||||
@@ -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)
|
||||
@@ -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)
|
||||
@@ -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
|
||||
@@ -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)
|
||||
@@ -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)
|
||||
@@ -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)
|
||||
@@ -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)
|
||||
@@ -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
|
||||
@@ -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)
|
||||
@@ -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)
|
||||
@@ -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)
|
||||
@@ -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)
|
||||
@@ -1,41 +0,0 @@
|
||||
Integer overflow in memalign leads to heap corruption
|
||||
|
||||
Passing too large an alignment to the memalign suite of functions
|
||||
(memalign, posix_memalign, aligned_alloc) in the GNU C Library version
|
||||
2.30 to 2.42 may result in an integer overflow, which could consequently
|
||||
result in a heap corruption.
|
||||
|
||||
Note that the attacker must have control over both, the size as well as
|
||||
the alignment arguments of the memalign function to be able to exploit
|
||||
this. The size parameter must be close enough to PTRDIFF_MAX so as to
|
||||
overflow size_t along with the large alignment argument. This limits
|
||||
the malicious inputs for the alignment for memalign to the range [1<<62
|
||||
+ 1, 1<<63] and exactly 1<<63 for posix_memalign and aligned_alloc.
|
||||
|
||||
Typically the alignment argument passed to such functions is a known
|
||||
constrained quantity (e.g. page size, block size, struct sizes) and is
|
||||
not attacker controlled, because of which this may not be easily
|
||||
exploitable in practice. An application bug could potentially result in
|
||||
the input alignment being too large, e.g. due to a different buffer
|
||||
overflow or integer overflow in the application or its dependent
|
||||
libraries, but that is again an uncommon usage pattern given typical
|
||||
sources of alignments.
|
||||
|
||||
CVE-Id: CVE-2026-0861
|
||||
Public-Date: 2026-01-14
|
||||
Vulnerable-Commit: 9bf8e29ca136094f73f69f725f15c51facc97206 (2.30)
|
||||
Fix-Commit: c9188d333717d3ceb7e3020011651f424f749f93 (2.43)
|
||||
Fix-Commit: 7f19ef14fbce095d4c77395e258320cad2ea2b28 (2.30-153)
|
||||
Fix-Commit: f18446d7b4a423090ee5e328c36b3c2a0f26041c (2.31-166)
|
||||
Fix-Commit: 8aef9e7a7af9565c0324b4ecb38b30dfa3782fd8 (2.32-151)
|
||||
Fix-Commit: 011293b4fd748cdd6f95874ba2b6aba9a3df8bff (2.33-275)
|
||||
Fix-Commit: 2c77e52108a58956c9f674b36e1f59a4e3fdcf4d (2.34-525)
|
||||
Fix-Commit: 499d1ccafccfe64df1b88deea2fa84d8180e8e8f (2.35-399)
|
||||
Fix-Commit: fb6b8822175769b5794fb6ea04f2895483a29b61 (2.36-244)
|
||||
Fix-Commit: 7b913d41a07836def826f2164c52541a9835f324 (2.37-172)
|
||||
Fix-Commit: 744b63026a29f7eedbbc8e3a01a7f48a6eb0a085 (2.38-212)
|
||||
Fix-Commit: fb22fd3f5b415dd4cd6f7b5741c2f0412374e242 (2.39-286)
|
||||
Fix-Commit: bfc4dd9e526eacf3017dd8864ba0848e9d045dd4 (2.40-216)
|
||||
Fix-Commit: 1e2c1ea4307197ccece0cda574bcfebf9080894c (2.41-121)
|
||||
Fix-Commit: b0ec8fb689df862171f0f78994a3bdeb51313545 (2.42-49)
|
||||
Reported-by: Igor Morgenstern, Aisle Research
|
||||
@@ -1,36 +0,0 @@
|
||||
getnetbyaddr and getnetbyaddr_r leak stack contents to DNS resovler
|
||||
|
||||
Calling getnetbyaddr or getnetbyaddr_r with a configured nsswitch.conf
|
||||
that specifies the library's DNS backend for networks and queries for a
|
||||
zero-valued network in the GNU C Library version 2.0 to version 2.42
|
||||
can leak stack contents to the configured DNS resolver.
|
||||
|
||||
A defect in the _nss_dns_getnetbyaddr_r function which implements
|
||||
getnetbyaddr and getnetbyaddr_r in the dns-based network database can
|
||||
pass stack contents unmodified to the configured DNS resolver as part of
|
||||
the network DNS query when the network queried is the default network
|
||||
i.e. net == 0x0. This stack contents leaking in the query is considered
|
||||
a loss of confidentiality for the host making the query. Typically it
|
||||
is rare to call these APIs with a net value of zero, and if an attacker
|
||||
can control the net value it can only leak adjacent stack, and so loss
|
||||
of confidentiality is spatially limited. The leak might be used to
|
||||
accelerate an ASLR bypass by knowing pointer values, but also requires
|
||||
network adjacent access to snoop between the application and the
|
||||
DNS server; making the attack complexity higher.
|
||||
|
||||
CVE-Id: CVE-2026-0915
|
||||
Public-Date: 2026-01-15
|
||||
Vulnerable-Commit: 5f0e6fc702296840d2daa39f83f6cb1e40073d58 (1.92-1)
|
||||
Fix-Commit: e56ff82d5034ec66c6a78f517af6faa427f65b0b (2.43)
|
||||
Fix-Commit: 453e6b8dbab935257eb0802b0c97bca6b67ba30e (2.42-50)
|
||||
Fix-Commit: 15c9839a0b853f552b4ed9047841b6223f3c104d (2.41-122)
|
||||
Fix-Commit: 329c775788b2c9ff3da774ccf59fba7b6b8ff08e (2.40-217)
|
||||
Fix-Commit: 831f63b94ceb92fb14c0d1a7ddad35a0d1404c71 (2.39-287)
|
||||
Fix-Commit: 49125ffc8e1674dc2a100dfdc5b78796f22e16f2 (2.38-213)
|
||||
Fix-Commit: ddcaed5dfb05b2c1a6ea842fd6b643501365450a (2.37-173)
|
||||
Fix-Commit: a6bf47887f24b2b394acb301a3189fda04bd4d4d (2.36-245)
|
||||
Fix-Commit: 66f0cb057c9b4fb1249a5fec6ef4a63511a37899 (2.35-400)
|
||||
Fix-Commit: 96863dee262225cfb79f9fe45e06fd188319c7b8 (2.34-526)
|
||||
Fix-Commit: d210011f1536c8322157cbb4fe4229b35c834c08 (2.33-276)
|
||||
Fix-Commit: 1bc1832cfc74c2a601220969f36e789a5e9f0ebe (2.32-152)
|
||||
Reported-by: Igor Morgenstern, Aisle Research
|
||||
@@ -1,36 +0,0 @@
|
||||
wordexp with WRDE_REUSE and WRDE_APPEND may return uninitialized memory
|
||||
|
||||
Calling wordexp with WRDE_REUSE in conjunction with WRDE_APPEND in the
|
||||
GNU C Library version 2.0 to version 2.42 may cause the interface to
|
||||
return uninitialized memory in the we_wordv member, which on subsequent
|
||||
calls to wordfree may abort the process.
|
||||
|
||||
The implementation of WRDE_REUSE in conjunction with WRDE_APPEND fails
|
||||
to clear the we_wordc member of the structure, and as such, when new
|
||||
words are added internally, a leading we_wordc count number of entries
|
||||
are skipped since they are assumed initialized. These skipped entries
|
||||
are not initialized, but are the contents of a realloc-expanded array of
|
||||
pointers. If the caller inspects the we_wordv array, it will
|
||||
dereference invalid pointers and crash. If the caller calls wordfree,
|
||||
the malloc implementation may detect the invalid pointers and abort the
|
||||
process. Calls to wordexp using WRDE_REUSE and WRDE_APPEND have never
|
||||
worked correctly and thus the existence of applications that make use of
|
||||
this feature is unlikely.
|
||||
|
||||
CVE-Id: CVE-2025-15281
|
||||
Public-Date: 2026-01-20
|
||||
Vulnerable-Commit: 8f2ece695d8822e9ecc63ecd157e90bf17a6fe65 (1.93-260)
|
||||
Fix-Commit: 80cc58ea2de214f85b0a1d902a3b668ad2ecb302 (2.43)
|
||||
Fix-Commit: cbf39c26b25801e9bc88499b4fd361ac172d4125 (2.42-51)
|
||||
Fix-Commit: fb4db64a04ad6c96cd1fbb7e02eb59323b1f2ac2 (2.41-123)
|
||||
Fix-Commit: 9fe8576664d43b87ca19401fb6a975e217e47623 (2.40-218)
|
||||
Fix-Commit: ce65d944e38a20cb70af2a48a4b8aa5d8fabe1cc (2.39-288)
|
||||
Fix-Commit: d5409a1be010699794264162c551ba60f05ee6c3 (2.38-214)
|
||||
Fix-Commit: ff2b172803f6bbd897755d2ce83ec4323a1a15b3 (2.37-174)
|
||||
Fix-Commit: e97cfe2293ed097eb3d0b4c18274d22855e65130 (2.36-246)
|
||||
Fix-Commit: bb59339d02faebac534a87eea50c83c948f35b77 (2.35-401)
|
||||
Fix-Commit: 2b656ff94d72f93c84d8da2e7c76456c1994f02e (2.34-527)
|
||||
Fix-Commit: 1d8ed2067a8a5d162a07670d0d063429679f17a0 (2.33-277)
|
||||
Fix-Commit: 3a56c4ee4ea49b8f2391a2d8d6220013c4160a79 (2.32-153)
|
||||
Fix-Commit: 28eb5caf895ced5d895cb02757e109004a2d33e5 (2.31-167)
|
||||
Reported-by: Vitaly Simonovich
|
||||
@@ -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.
|
||||
@@ -97,12 +97,6 @@ ifeq (yesyes,$(build-shared)$(run-built-tests))
|
||||
tests-special += $(objpfx)list-tunables.out
|
||||
endif
|
||||
|
||||
# Make sure that the compiler does not insert any library calls in tunables
|
||||
# code paths.
|
||||
ifeq (yes,$(have-loop-to-function))
|
||||
CFLAGS-dl-tunables.c += -fno-tree-loop-distribute-patterns
|
||||
endif
|
||||
|
||||
all-dl-routines = $(dl-routines) $(sysdep-dl-routines)
|
||||
# But they are absent from the shared libc, because that code is in ld.so.
|
||||
elide-routines.os = \
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
|
||||
#include <dl-machine.h>
|
||||
#include <dl-debug.h>
|
||||
#include <dl-symbol-redir-ifunc.h>
|
||||
|
||||
#define RESOLVE_MAP(map, scope, sym, version, flags) map
|
||||
#include "dynamic-link.h"
|
||||
|
||||
+6
-13
@@ -33,20 +33,11 @@
|
||||
#include <array_length.h>
|
||||
#include <dl-minimal-malloc.h>
|
||||
#include <dl-symbol-redir-ifunc.h>
|
||||
#include <malloc-hugepages.h>
|
||||
|
||||
#define TUNABLES_INTERNAL 1
|
||||
#include "dl-tunables.h"
|
||||
|
||||
/* The function might be called before the process is self-relocated. */
|
||||
static size_t
|
||||
__attribute_optimization_barrier__
|
||||
_dl_strlen (const char *s)
|
||||
{
|
||||
const char *p = s;
|
||||
for (; *s != '\0'; s++);
|
||||
return s - p;
|
||||
}
|
||||
|
||||
static char **
|
||||
get_next_env (char **envp, char **name, char **val, char ***prev_envp)
|
||||
{
|
||||
@@ -306,6 +297,10 @@ __tunables_init (char **envp)
|
||||
char *envval = NULL;
|
||||
char **prev_envp = envp;
|
||||
|
||||
/* Default to glibc.malloc.hugetlb=1 if DEFAULT_THP_PAGESIZE is non-zero. */
|
||||
if (DEFAULT_THP_PAGESIZE > 0)
|
||||
TUNABLE_SET (glibc, malloc, hugetlb, 1);
|
||||
|
||||
/* Ignore tunables for AT_SECURE programs. */
|
||||
if (__libc_enable_secure)
|
||||
return;
|
||||
@@ -335,10 +330,8 @@ __tunables_init (char **envp)
|
||||
if (tunable_is_name (name, envname))
|
||||
{
|
||||
/* The environment variable is always null-terminated. */
|
||||
size_t envvallen = _dl_strlen (envval);
|
||||
|
||||
tunables_env_alias[i] =
|
||||
(struct tunable_toset_t) { cur, envval, envvallen };
|
||||
(struct tunable_toset_t) { cur, envval, strlen (envval) };
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ do_test (void)
|
||||
|
||||
{
|
||||
/* Install the default implementation of libmarkermod1.so. */
|
||||
char *conf_path = xasprintf ("%s/ld.so.conf", support_sysconfdir_prefix);
|
||||
char *conf_path = xasprintf ("%s/ld.so.conf.d/hwcaps.conf", support_sysconfdir_prefix);
|
||||
xmkdirp (support_sysconfdir_prefix, 0777);
|
||||
support_write_file_string (conf_path, "/glibc-test/lib\n");
|
||||
free (conf_path);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -26,16 +26,8 @@ run_program_env=$3
|
||||
LC_ALL=C
|
||||
export LC_ALL
|
||||
|
||||
# Unset tunables and their aliases.
|
||||
GLIBC_TUNABLES=
|
||||
MALLOC_ARENA_MAX=
|
||||
MALLOC_ARENA_TEST=
|
||||
MALLOC_CHECK_=
|
||||
MALLOC_MMAP_MAX_=
|
||||
MALLOC_MMAP_THRESHOLD_=
|
||||
MALLOC_PERTURB_=
|
||||
MALLOC_TOP_PAD_=
|
||||
MALLOC_TRIM_THRESHOLD_=
|
||||
# Unset tunables.
|
||||
export GLIBC_TUNABLES=glibc.malloc.hugetlb=0
|
||||
|
||||
${test_wrapper_env} \
|
||||
${run_program_env} \
|
||||
|
||||
@@ -39,8 +39,8 @@ struct protoent_data {};
|
||||
#include <nss/nss_files/files-parse.c>
|
||||
LINE_PARSER
|
||||
("#",
|
||||
STRING_FIELD (result->p_name, isspace, 1);
|
||||
INT_FIELD (result->p_proto, isspace, 1, 10,);
|
||||
STRING_FIELD (result->p_name, isspace, true);
|
||||
INT_FIELD (result->p_proto, isspace, true, 10,);
|
||||
)
|
||||
|
||||
enum nss_status
|
||||
|
||||
@@ -39,9 +39,9 @@ struct servent_data {};
|
||||
#define ISSC_OR_SPACE(c) ((c) == ';' || isspace (c))
|
||||
LINE_PARSER
|
||||
("#",
|
||||
STRING_FIELD (result->s_name, ISSC_OR_SPACE, 1);
|
||||
STRING_FIELD (result->s_proto, ISSC_OR_SPACE, 1);
|
||||
INT_FIELD (result->s_port, ISSC_OR_SPACE, 10, 0, htons);
|
||||
STRING_FIELD (result->s_name, ISSC_OR_SPACE, true);
|
||||
STRING_FIELD (result->s_proto, ISSC_OR_SPACE, true);
|
||||
INT_FIELD (result->s_port, ISSC_OR_SPACE, false, 10, htons);
|
||||
)
|
||||
|
||||
enum nss_status
|
||||
|
||||
+2
-1
@@ -139,7 +139,8 @@ $(objpfx)test-iconvconfig.out: $(objpfx)iconvconfig
|
||||
rm -f $$tmp) > $@; \
|
||||
$(evaluate-test)
|
||||
|
||||
$(objpfx)tst-iconv_prog.out: tst-iconv_prog.sh $(objpfx)iconv_prog
|
||||
$(objpfx)tst-iconv_prog.out: tst-iconv_prog.sh $(objpfx)iconv_prog \
|
||||
$(gen-locales)
|
||||
$(BASH) $< $(common-objdir) '$(test-wrapper-env)' \
|
||||
'$(run-program-env)' '$(rpath-link)' > $@; \
|
||||
$(evaluate-test)
|
||||
|
||||
+4
-2
@@ -144,8 +144,10 @@
|
||||
if (irreversible == NULL) \
|
||||
{ \
|
||||
/* This means we are in call from __gconv_transliterate. In this \
|
||||
case we are not doing any error recovery ourselves. */ \
|
||||
result = __gconv_mark_illegal_input (step_data); \
|
||||
case we are not doing any error recovery ourselves. Do not create \
|
||||
a persistent error state. If __gconv_transliterate exhausts all \
|
||||
alternatives, it will call __gconv_mark_illegal_input itself. */ \
|
||||
result = __GCONV_ILLEGAL_INPUT; \
|
||||
break; \
|
||||
} \
|
||||
\
|
||||
|
||||
+20
-10
@@ -29,10 +29,10 @@ LIBPATH=$codir:$codir/iconvdata
|
||||
|
||||
# How the start the iconv(1) program. $from is not defined/expanded yet.
|
||||
ICONV='
|
||||
$test_wrapper_env $run_program_env
|
||||
$codir/elf/ld.so --library-path $library_path:$LIBPATH --inhibit-rpath ${from}.so
|
||||
$codir/iconv/iconv_prog
|
||||
'
|
||||
ICONV="$test_wrapper_env $run_program_env $ICONV"
|
||||
|
||||
TIMEOUTFACTOR=${TIMEOUTFACTOR:-1}
|
||||
|
||||
@@ -220,6 +220,7 @@ testarray=(
|
||||
"\x00\x00;;INVALID;UTF-8;1"
|
||||
"\x00\x00;;UTF-8;INVALID;1"
|
||||
"\xc3\xa9;;UTF-8;ASCII//TRANSLIT;0"
|
||||
"X\xc2\xbdY;;UTF-8;ASCII//TRANSLIT;0"
|
||||
)
|
||||
|
||||
# Requires $twobyte input, $c flag, $from, and $to to be set; sets $ret
|
||||
@@ -280,12 +281,21 @@ check_errtest_result ()
|
||||
fi
|
||||
}
|
||||
|
||||
for testcommand in "${testarray[@]}"; do
|
||||
twobyte="$(echo "$testcommand" | cut -d";" -f 1)"
|
||||
c="$(echo "$testcommand" | cut -d";" -f 2)"
|
||||
from="$(echo "$testcommand" | cut -d";" -f 3)"
|
||||
to="$(echo "$testcommand" | cut -d";" -f 4)"
|
||||
eret="$(echo "$testcommand" | cut -d";" -f 5)"
|
||||
execute_test
|
||||
check_errtest_result
|
||||
done
|
||||
run_test_array ()
|
||||
{
|
||||
for testcommand in "${testarray[@]}"; do
|
||||
twobyte="$(echo "$testcommand" | cut -d";" -f 1)"
|
||||
c="$(echo "$testcommand" | cut -d";" -f 2)"
|
||||
from="$(echo "$testcommand" | cut -d";" -f 3)"
|
||||
to="$(echo "$testcommand" | cut -d";" -f 4)"
|
||||
eret="$(echo "$testcommand" | cut -d";" -f 5)"
|
||||
execute_test
|
||||
check_errtest_result
|
||||
done
|
||||
}
|
||||
|
||||
echo "info: testing C locale"
|
||||
run_test_array
|
||||
echo "info: testing en_US.UTF-8 locale"
|
||||
run_program_env="$run_program_env LC_ALL=en_US.UTF-8"
|
||||
run_test_array
|
||||
|
||||
+6
-1
@@ -76,7 +76,8 @@ 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 \
|
||||
tst-jisx0213-progress
|
||||
ifeq ($(have-thread-library),yes)
|
||||
tests += bug-iconv3
|
||||
endif
|
||||
@@ -333,6 +334,10 @@ $(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)tst-jisx0213-progress.out: \
|
||||
$(addprefix $(objpfx), $(gconv-modules)) $(addprefix $(objpfx),$(modules.so))
|
||||
|
||||
$(objpfx)iconv-test.out: run-iconv-test.sh \
|
||||
$(addprefix $(objpfx), $(gconv-modules)) \
|
||||
|
||||
@@ -224,6 +224,9 @@
|
||||
STANDARD_FROM_LOOP_ERR_HANDLER (1); \
|
||||
} \
|
||||
} \
|
||||
else \
|
||||
/* There was a pending character. Clear it. */ \
|
||||
*statep = 0; \
|
||||
\
|
||||
put32 (outptr, ch); \
|
||||
outptr += 4; \
|
||||
|
||||
+55
-15
@@ -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) \
|
||||
{ \
|
||||
|
||||
@@ -226,6 +226,9 @@
|
||||
STANDARD_FROM_LOOP_ERR_HANDLER (1); \
|
||||
} \
|
||||
} \
|
||||
else \
|
||||
/* There was a pending character. Clear it. */ \
|
||||
*statep = 0; \
|
||||
\
|
||||
put32 (outptr, ch); \
|
||||
outptr += 4; \
|
||||
|
||||
@@ -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>
|
||||
@@ -0,0 +1,124 @@
|
||||
/* Test JISX0213 combining character conversion progress (bug 34556, bug 34568).
|
||||
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/>. */
|
||||
|
||||
/* Certain JISX0213 byte sequences map to a combining sequence, for
|
||||
example U+304B (HIRAGANA LETTER KA) followed by U+309A (COMBINING
|
||||
SEMI-VOICED SOUND MARK). When converting to internal encoding
|
||||
(actually UTF-32) with a small output buffer, the first code point
|
||||
is emitted and the second is queued in the converter state. This
|
||||
test verifies that the queued code point is consumed exactly once
|
||||
on retry, so that the conversion makes progress and terminates. */
|
||||
|
||||
#include <errno.h>
|
||||
#include <iconv.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <support/check.h>
|
||||
#include <support/support.h>
|
||||
|
||||
static void
|
||||
test_one (const char *charset, const char *input, size_t outbufsize)
|
||||
{
|
||||
printf ("info: %s: testing output buffer size %zu\n", charset, outbufsize);
|
||||
|
||||
/* Expected UTF-32 output. */
|
||||
static const wchar_t expected[] = { 0x304b, 0x309a, 'A' };
|
||||
|
||||
/* Use WCHAR_T encoding to avoid the BOM. */
|
||||
iconv_t cd = iconv_open ("WCHAR_T", charset);
|
||||
TEST_VERIFY_EXIT (cd != (iconv_t) -1);
|
||||
|
||||
char result[64];
|
||||
size_t result_len = 0;
|
||||
|
||||
char *inptr = (char *) input;
|
||||
size_t inleft = strlen (input);
|
||||
|
||||
char outbuf[64];
|
||||
|
||||
int iterations = 0;
|
||||
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;
|
||||
|
||||
TEST_VERIFY_EXIT (result_len + produced <= sizeof (result));
|
||||
memcpy (result + result_len, outbuf, produced);
|
||||
result_len += produced;
|
||||
|
||||
if (ret == (size_t) -1 && errno == E2BIG)
|
||||
{
|
||||
if (produced == 0 && inleft == inleft_before)
|
||||
{
|
||||
/* Output buffer too small for a single code point. */
|
||||
TEST_VERIFY_EXIT (outbufsize < 4);
|
||||
break;
|
||||
}
|
||||
/* Bound iterations to detect non-progress bugs. */
|
||||
if (++iterations < 10)
|
||||
continue;
|
||||
else
|
||||
{
|
||||
FAIL ("%s: no progress", charset);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
if (ret == (size_t) -1)
|
||||
FAIL_EXIT1 ("outbufsize %zu: iconv: %m", outbufsize);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Flush pending converter state. */
|
||||
{
|
||||
char *outptr = outbuf;
|
||||
size_t outleft = outbufsize;
|
||||
size_t ret = iconv (cd, NULL, NULL, &outptr, &outleft);
|
||||
TEST_VERIFY (ret == 0);
|
||||
size_t produced = outptr - outbuf;
|
||||
memcpy (result + result_len, outbuf, produced);
|
||||
result_len += produced;
|
||||
}
|
||||
|
||||
if (outbufsize >= 4)
|
||||
{
|
||||
TEST_COMPARE (inleft, 0);
|
||||
TEST_COMPARE_BLOB (result, result_len,
|
||||
expected, sizeof (expected));
|
||||
}
|
||||
|
||||
out:
|
||||
TEST_VERIFY_EXIT (iconv_close (cd) == 0);
|
||||
}
|
||||
|
||||
static int
|
||||
do_test (void)
|
||||
{
|
||||
for (size_t outbufsize = 1; outbufsize <= 16; outbufsize++)
|
||||
{
|
||||
test_one ("EUC-JISX0213", "\244\367A", outbufsize);
|
||||
test_one ("SHIFT_JISX0213", "\202\365A", outbufsize);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#include <support/test-driver.c>
|
||||
@@ -3,6 +3,8 @@
|
||||
#ifndef _ISOMAC
|
||||
libc_hidden_proto (__fgets_unlocked_chk)
|
||||
libc_hidden_ldbl_proto (vfprintf)
|
||||
extern int __vasprintf_chk (char **, int, const char *, __gnuc_va_list) __THROW;
|
||||
libc_hidden_ldbl_proto (__vasprintf_chk)
|
||||
extern int __vfprintf_chk (FILE *, int, const char *, __gnuc_va_list);
|
||||
libc_hidden_ldbl_proto (__vfprintf_chk)
|
||||
#endif
|
||||
|
||||
@@ -70,6 +70,11 @@ libc_hidden_proto (__libc_res_nameinquery)
|
||||
extern __typeof (__res_queriesmatch) __libc_res_queriesmatch;
|
||||
libc_hidden_proto (__libc_res_queriesmatch)
|
||||
|
||||
extern const struct res_sym __p_class_syms[];
|
||||
libresolv_hidden_proto (__p_class_syms)
|
||||
extern const struct res_sym __p_type_syms[];
|
||||
libresolv_hidden_proto (__p_type_syms)
|
||||
|
||||
/* Variant of res_hnok which operates on binary (but uncompressed) names. */
|
||||
bool __res_binary_hnok (const unsigned char *dn) attribute_hidden;
|
||||
|
||||
|
||||
@@ -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, ...)
|
||||
|
||||
@@ -84,6 +84,7 @@ tests = \
|
||||
bug-ungetwc1 \
|
||||
bug-ungetwc2 \
|
||||
bug-wfflush \
|
||||
bug-wgenops-bz33998 \
|
||||
bug-wmemstream1 \
|
||||
bug-wsetpos \
|
||||
test-fmemopen \
|
||||
@@ -107,6 +108,7 @@ tests = \
|
||||
tst-fgetc-after-eof \
|
||||
tst-fgetwc \
|
||||
tst-fgetws \
|
||||
tst-fopen-ccs-empty \
|
||||
tst-fopenloc2 \
|
||||
tst-fputws \
|
||||
tst-freopen \
|
||||
|
||||
@@ -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>
|
||||
+7
-5
@@ -339,12 +339,14 @@ _IO_new_file_fopen (FILE *fp, const char *filename, const char *mode,
|
||||
*((char *) __mempcpy (ccs, cs + 5, endp - (cs + 5))) = '\0';
|
||||
strip (ccs, ccs);
|
||||
|
||||
if (__wcsmbs_named_conv (&fcts, ccs[2] == '\0'
|
||||
? upstr (ccs, cs + 5) : ccs) != 0)
|
||||
/* After stripping, ccs[2] == '\0' means the charset name is empty.
|
||||
This is not a valid charset and would cause problems downstream.
|
||||
Reject it with EINVAL (BZ #34574, CVE-2026-18374). */
|
||||
if (ccs[2] == '\0' || __wcsmbs_named_conv (&fcts, ccs) != 0)
|
||||
{
|
||||
/* Something went wrong, we cannot load the conversion modules.
|
||||
This means we cannot proceed since the user explicitly asked
|
||||
for these. */
|
||||
/* Either the charset name is empty after strip(), or conversion
|
||||
modules cannot be loaded. This means we cannot proceed since
|
||||
the user explicitly asked for character conversion. */
|
||||
(void) _IO_file_close_it (fp);
|
||||
free (ccs);
|
||||
__set_errno (EINVAL);
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
/* Test fopen with an empty ",ccs=" value in the mode string (bug 34574).
|
||||
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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <support/check.h>
|
||||
#include <support/support.h>
|
||||
#include <support/temp_file.h>
|
||||
#include <support/xunistd.h>
|
||||
|
||||
static void
|
||||
check_fopen_fails (const char *path, const char *mode)
|
||||
{
|
||||
errno = 0;
|
||||
FILE *fp = fopen (path, mode);
|
||||
TEST_VERIFY (fp == NULL);
|
||||
TEST_COMPARE (errno, EINVAL);
|
||||
if (fp != NULL)
|
||||
fclose (fp);
|
||||
}
|
||||
|
||||
static int
|
||||
do_test (void)
|
||||
{
|
||||
char *path;
|
||||
xclose (create_temp_file ("tst-fopen-ccs-empty", &path));
|
||||
|
||||
/* The value is blank and the mode string continues well past it. */
|
||||
enum { size = 1024 * 1024 };
|
||||
char *mode = xmalloc (size);
|
||||
memset (mode, 'X', size);
|
||||
mode[size - 1] = '\0';
|
||||
static const char prefix[] = "w,ccs= ,";
|
||||
memcpy (mode, prefix, sizeof (prefix) - 1);
|
||||
check_fopen_fails (path, mode);
|
||||
free (mode);
|
||||
|
||||
check_fopen_fails (path, "w,ccs=");
|
||||
check_fopen_fails (path, "w,ccs=,");
|
||||
|
||||
free (path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#include <support/test-driver.c>
|
||||
+2
-2
@@ -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!*/
|
||||
|
||||
+17
-19
@@ -1902,26 +1902,11 @@ free_perturb (char *p, size_t n)
|
||||
|
||||
/* ----------- Routines dealing with transparent huge pages ----------- */
|
||||
|
||||
static __always_inline void
|
||||
thp_init (void)
|
||||
{
|
||||
/* Initialize only once if DEFAULT_THP_PAGESIZE is defined. */
|
||||
if (DEFAULT_THP_PAGESIZE == 0 || mp_.thp_mode != malloc_thp_mode_not_supported)
|
||||
return;
|
||||
|
||||
/* Set thp_pagesize even if thp_mode is never. This reduces frequency
|
||||
of MORECORE () invocation. */
|
||||
mp_.thp_mode = __malloc_thp_mode ();
|
||||
mp_.thp_pagesize = DEFAULT_THP_PAGESIZE;
|
||||
}
|
||||
|
||||
static inline void
|
||||
madvise_thp (void *p, INTERNAL_SIZE_T size)
|
||||
{
|
||||
#ifdef MADV_HUGEPAGE
|
||||
|
||||
thp_init ();
|
||||
|
||||
/* Only use __madvise if the system is using 'madvise' mode and the size
|
||||
is at least a huge page, otherwise the call is wasteful. */
|
||||
if (mp_.thp_mode != malloc_thp_mode_madvise || size < mp_.thp_pagesize)
|
||||
@@ -2472,9 +2457,6 @@ sysmalloc (INTERNAL_SIZE_T nb, mstate av)
|
||||
previous calls. Otherwise, we correct to page-align below.
|
||||
*/
|
||||
|
||||
/* Ensure thp_pagesize is initialized. */
|
||||
thp_init ();
|
||||
|
||||
if (__glibc_unlikely (mp_.thp_pagesize != 0))
|
||||
{
|
||||
uintptr_t lastbrk = (uintptr_t) MORECORE (0);
|
||||
@@ -5132,10 +5114,26 @@ do_set_mxfast (size_t value)
|
||||
static __always_inline int
|
||||
do_set_hugetlb (size_t value)
|
||||
{
|
||||
/* Enable THP if DEFAULT_THP_PAGESIZE is non-zero. */
|
||||
if (DEFAULT_THP_PAGESIZE > 0)
|
||||
{
|
||||
mp_.thp_mode = malloc_thp_mode_madvise;
|
||||
mp_.thp_pagesize = DEFAULT_THP_PAGESIZE;
|
||||
}
|
||||
|
||||
if (value == 0)
|
||||
mp_.thp_mode = malloc_thp_mode_never;
|
||||
{
|
||||
/* Turn off THP support completely. */
|
||||
mp_.thp_mode = malloc_thp_mode_never;
|
||||
mp_.thp_pagesize = 0;
|
||||
}
|
||||
else if (value == 1)
|
||||
{
|
||||
/* Avoid querying the THP page size/mode since accessing /sys/kernel/mm
|
||||
is relatively slow and might not be accessible in containers. */
|
||||
if (DEFAULT_THP_PAGESIZE > 0)
|
||||
return 0;
|
||||
|
||||
mp_.thp_mode = __malloc_thp_mode ();
|
||||
if (mp_.thp_mode == malloc_thp_mode_madvise
|
||||
|| mp_.thp_mode == malloc_thp_mode_always)
|
||||
|
||||
+33
-21
@@ -620,42 +620,54 @@ This tunable controls Guarded Control Stack (GCS) for the process.
|
||||
|
||||
Accepted values are:
|
||||
|
||||
0 = disabled: do not enable GCS.
|
||||
|
||||
1 = enforced: check markings and fail if any binary is not marked.
|
||||
|
||||
2 = optional: check markings but keep GCS off if any binary is unmarked.
|
||||
|
||||
3 = override: enable GCS, markings are ignored.
|
||||
@itemize @bullet
|
||||
@item @code{0} = disabled: do not enable GCS.
|
||||
@item @code{1} = enforced: check markings and abort if any binary is not
|
||||
marked, otherwise enable GCS and lock all GCS features.
|
||||
@item @code{2} = optional: check markings but keep GCS off if any binary
|
||||
is unmarked, otherwise enable GCS but do not lock any GCS features.
|
||||
@item @code{3} = override: enable GCS and lock all GCS features, markings
|
||||
are ignored.
|
||||
@end itemize
|
||||
|
||||
If unmarked binary is loaded via @code{dlopen} when GCS is enabled and
|
||||
markings are not ignored (@code{aarch64_gcs == 1} or @code{2}), then
|
||||
the process will be aborted.
|
||||
markings are not ignored (i.e. @code{aarch64_gcs == 1} or @code{2}), then
|
||||
@code{dlopen} will return an error.
|
||||
|
||||
Default is @code{0}, so GCS is disabled by default.
|
||||
|
||||
This tunable is specific to AArch64. On systems that do not support
|
||||
This tunable is specific to AArch64. On systems that do not support
|
||||
Guarded Control Stack this tunable has no effect.
|
||||
|
||||
GCS features (or operations on shadow stack) such as @code{STATUS} (i.e.
|
||||
enabling and disabling GCS), @code{WRITE}, and @code{PUSH}, will be locked
|
||||
for the @code{enforced} and @code{override} tunable values.
|
||||
|
||||
Before enabling GCS for the process the value of this tunable is checked
|
||||
and depending on it the following outcomes are possible.
|
||||
|
||||
@code{aarch64_gcs == 0}: GCS will not be enabled and GCS markings will not be
|
||||
@itemize @bullet
|
||||
@item
|
||||
@code{aarch64_gcs == 0}: GCS will remain disabled and GCS markings will not be
|
||||
checked for any binaries.
|
||||
|
||||
@item
|
||||
@code{aarch64_gcs == 1}: GCS markings will be checked for all binaries loaded
|
||||
at startup and, only if all binaries are GCS-marked, GCS will be enabled. If
|
||||
any of the binaries are not GCS-marked, the process will abort. Subsequent call
|
||||
to @code{dlopen} for an unmarked binary will also result in abort.
|
||||
|
||||
at startup and, only if all binaries are GCS-marked, GCS will be enabled and
|
||||
all GCS features will be locked. If any of the binaries are not GCS-marked,
|
||||
the process will abort. Subsequent call to @code{dlopen} for an unmarked binary
|
||||
will result in @code{dlopen} returning an error.
|
||||
@item
|
||||
@code{aarch64_gcs == 2}: GCS markings will be checked for all binaries loaded
|
||||
at startup and, if any of such binaries are not GCS-marked, GCS will not be
|
||||
enabled and there will be no more checks for GCS marking. If all binaries
|
||||
loaded at startup are GCS-marked, then GCS will be enabled, in which case a
|
||||
call to @code{dlopen} for an unmarked binary will also result in abort.
|
||||
enabled and there will be no more checks for GCS marking. If all binaries
|
||||
loaded at startup are GCS-marked, then GCS will be enabled but GCS features
|
||||
will not be locked. In this case a call to @code{dlopen} for an unmarked binary
|
||||
will result in @code{dlopen} returning an error.
|
||||
@item
|
||||
@code{aarch64_gcs == 3}: GCS will be enabled and all GCS features will be
|
||||
locked. GCS markings will not be checked for any binaries.
|
||||
@end itemize
|
||||
|
||||
@code{aarch64_gcs == 3}: GCS will be enabled and GCS markings will not be
|
||||
checked for any binaries.
|
||||
@end deftp
|
||||
|
||||
@node Memory Related Tunables
|
||||
|
||||
@@ -6483,6 +6483,8 @@ fma 0x1.000002p-126 -0x1.000002p-26 0x1p103
|
||||
fma 0x1.000002p-126 0x1.000002p-26 -0x1p103
|
||||
fma 0x1.000002p-126 -0x1.000002p-26 -0x1p103
|
||||
|
||||
fma 0x1.000008p+0 0x1.000008p+0 0x1p+11
|
||||
|
||||
fma 0x1.7fp+13 0x1.0000000000001p+0 0x1.ffep-48
|
||||
fma 0x1.fffp+0 0x1.0000000000001p+0 -0x1.fffp+0
|
||||
fma 0x1.0000002p+0 0x1.ffffffcp-1 0x1p-300
|
||||
|
||||
@@ -13364,6 +13364,31 @@ fma 0x1.000002p-126 -0x1.000002p-26 -0x1p103
|
||||
= fma tonearest ibm128 0x4.000008p-128 -0x4.000008p-28 -0x8p+100 : -0x8p+100 : inexact
|
||||
= fma towardzero ibm128 0x4.000008p-128 -0x4.000008p-28 -0x8p+100 : -0x8p+100 : inexact
|
||||
= fma upward ibm128 0x4.000008p-128 -0x4.000008p-28 -0x8p+100 : -0x8p+100 : inexact
|
||||
fma 0x1.000008p+0 0x1.000008p+0 0x1p+11
|
||||
= fma downward binary32 0x1.000008p+0 0x1.000008p+0 0x8p+8 : 0x8.01p+8 : inexact
|
||||
= fma tonearest binary32 0x1.000008p+0 0x1.000008p+0 0x8p+8 : 0x8.01p+8 : inexact
|
||||
= fma towardzero binary32 0x1.000008p+0 0x1.000008p+0 0x8p+8 : 0x8.01p+8 : inexact
|
||||
= fma upward binary32 0x1.000008p+0 0x1.000008p+0 0x8p+8 : 0x8.01001p+8 : inexact
|
||||
= fma downward binary64 0x1.000008p+0 0x1.000008p+0 0x8p+8 : 0x8.0100001p+8 : inexact
|
||||
= fma tonearest binary64 0x1.000008p+0 0x1.000008p+0 0x8p+8 : 0x8.0100001p+8 : inexact
|
||||
= fma towardzero binary64 0x1.000008p+0 0x1.000008p+0 0x8p+8 : 0x8.0100001p+8 : inexact
|
||||
= fma upward binary64 0x1.000008p+0 0x1.000008p+0 0x8p+8 : 0x8.0100001000008p+8 : inexact
|
||||
= fma downward intel96 0x1.000008p+0 0x1.000008p+0 0x8p+8 : 0x8.0100001000004p+8 :
|
||||
= fma tonearest intel96 0x1.000008p+0 0x1.000008p+0 0x8p+8 : 0x8.0100001000004p+8 :
|
||||
= fma towardzero intel96 0x1.000008p+0 0x1.000008p+0 0x8p+8 : 0x8.0100001000004p+8 :
|
||||
= fma upward intel96 0x1.000008p+0 0x1.000008p+0 0x8p+8 : 0x8.0100001000004p+8 :
|
||||
= fma downward m68k96 0x1.000008p+0 0x1.000008p+0 0x8p+8 : 0x8.0100001000004p+8 :
|
||||
= fma tonearest m68k96 0x1.000008p+0 0x1.000008p+0 0x8p+8 : 0x8.0100001000004p+8 :
|
||||
= fma towardzero m68k96 0x1.000008p+0 0x1.000008p+0 0x8p+8 : 0x8.0100001000004p+8 :
|
||||
= fma upward m68k96 0x1.000008p+0 0x1.000008p+0 0x8p+8 : 0x8.0100001000004p+8 :
|
||||
= fma downward binary128 0x1.000008p+0 0x1.000008p+0 0x8p+8 : 0x8.0100001000004p+8 :
|
||||
= fma tonearest binary128 0x1.000008p+0 0x1.000008p+0 0x8p+8 : 0x8.0100001000004p+8 :
|
||||
= fma towardzero binary128 0x1.000008p+0 0x1.000008p+0 0x8p+8 : 0x8.0100001000004p+8 :
|
||||
= fma upward binary128 0x1.000008p+0 0x1.000008p+0 0x8p+8 : 0x8.0100001000004p+8 :
|
||||
= fma downward ibm128 0x1.000008p+0 0x1.000008p+0 0x8p+8 : 0x8.0100001000004p+8 :
|
||||
= fma tonearest ibm128 0x1.000008p+0 0x1.000008p+0 0x8p+8 : 0x8.0100001000004p+8 :
|
||||
= fma towardzero ibm128 0x1.000008p+0 0x1.000008p+0 0x8p+8 : 0x8.0100001000004p+8 :
|
||||
= fma upward ibm128 0x1.000008p+0 0x1.000008p+0 0x8p+8 : 0x8.0100001000004p+8 :
|
||||
fma 0x1.7fp+13 0x1.0000000000001p+0 0x1.ffep-48
|
||||
= fma downward binary64 0x2.fep+12 0x1.0000000000001p+0 0x1.ffep-48 : 0x2.fe00000000002p+12 : inexact
|
||||
= fma tonearest binary64 0x2.fep+12 0x1.0000000000001p+0 0x1.ffep-48 : 0x2.fe00000000002p+12 : inexact
|
||||
|
||||
@@ -79,6 +79,9 @@ static const struct test_f_f_data ceil_test_data[] =
|
||||
TEST_f_f (ceil, -max_value, -max_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
|
||||
|
||||
#if MANT_DIG >= 64
|
||||
/* The input value can only be represented in long double. */
|
||||
TEST_f_f (ceil, -0x0.ffffffffffffffffp0L, minus_zero, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
|
||||
|
||||
/* The result can only be represented in long double. */
|
||||
TEST_f_f (ceil, 4503599627370495.5L, 4503599627370496.0L, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
|
||||
TEST_f_f (ceil, 4503599627370496.25L, 4503599627370497.0L, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
|
||||
|
||||
@@ -79,6 +79,9 @@ static const struct test_f_f_data floor_test_data[] =
|
||||
TEST_f_f (floor, -max_value, -max_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
|
||||
|
||||
#if MANT_DIG >= 64
|
||||
/* The input value can only be represented in long double. */
|
||||
TEST_f_f (floor, 0x0.ffffffffffffffffp0L, plus_zero, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
|
||||
|
||||
/* The result can only be represented in long double. */
|
||||
TEST_f_f (floor, 4503599627370495.5L, 4503599627370495.0L, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
|
||||
TEST_f_f (floor, 4503599627370496.25L, 4503599627370496.0L, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
|
||||
|
||||
@@ -99,6 +99,10 @@ static const struct test_f_f_data round_test_data[] =
|
||||
#endif
|
||||
|
||||
#if MANT_DIG >= 64
|
||||
/* The input value can only be represented in long double. */
|
||||
TEST_f_f (round, 0x0.ffffffffffffffffp-1L, plus_zero, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
|
||||
TEST_f_f (round, -0x0.ffffffffffffffffp-1L, minus_zero, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
|
||||
|
||||
/* The result can only be represented in long double. */
|
||||
TEST_f_f (round, 4503599627370495.5L, 4503599627370496.0L, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
|
||||
TEST_f_f (round, 4503599627370496.25L, 4503599627370496.0L, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
|
||||
|
||||
@@ -91,6 +91,10 @@ static const struct test_f_f_data trunc_test_data[] =
|
||||
TEST_f_f (trunc, -4294967296.625L, -4294967296.0L, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
|
||||
|
||||
#if MANT_DIG >= 64
|
||||
/* The input value can only be represented in long double. */
|
||||
TEST_f_f (trunc, 0x0.ffffffffffffffffp0L, plus_zero, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
|
||||
TEST_f_f (trunc, -0x0.ffffffffffffffffp0L, minus_zero, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
|
||||
|
||||
/* The result can only be represented in long double. */
|
||||
TEST_f_f (trunc, 4503599627370495.5L, 4503599627370495.0L, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
|
||||
TEST_f_f (trunc, 4503599627370496.25L, 4503599627370496.0L, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
|
||||
|
||||
+11
-20
@@ -85,6 +85,7 @@
|
||||
#include <assert.h>
|
||||
#include <stdalign.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <search.h>
|
||||
@@ -406,12 +407,13 @@ __tdelete (const void *key, void **vrootp, __compar_fn_t compar)
|
||||
int cmp;
|
||||
node *rootp = (node *) vrootp;
|
||||
node root, unchained;
|
||||
/* Stack of nodes so we remember the parents without recursion. It's
|
||||
_very_ unlikely that there are paths longer than 40 nodes. The tree
|
||||
would need to have around 250.000 nodes. */
|
||||
int stacksize = 40;
|
||||
/* Stack of nodes so we remember the parents without recursion. The
|
||||
stack size is a conservative approximation of the maximum height
|
||||
of a red-black tree, based on size of the address space.
|
||||
Actual numbers are closer to 57 (32 bit) and 117 (63 bit). */
|
||||
enum { stacksize = 2 * UINTPTR_WIDTH };
|
||||
int sp = 0;
|
||||
node **nodestack = alloca (sizeof (node *) * stacksize);
|
||||
node *nodestack[stacksize];
|
||||
|
||||
if (rootp == NULL)
|
||||
return NULL;
|
||||
@@ -424,14 +426,7 @@ __tdelete (const void *key, void **vrootp, __compar_fn_t compar)
|
||||
root = DEREFNODEPTR(rootp);
|
||||
while ((cmp = (*compar) (key, root->key)) != 0)
|
||||
{
|
||||
if (sp == stacksize)
|
||||
{
|
||||
node **newstack;
|
||||
stacksize += 20;
|
||||
newstack = alloca (sizeof (node *) * stacksize);
|
||||
nodestack = memcpy (newstack, nodestack, sp * sizeof (node *));
|
||||
}
|
||||
|
||||
assert (sp < stacksize);
|
||||
nodestack[sp++] = rootp;
|
||||
p = DEREFNODEPTR(rootp);
|
||||
if (cmp < 0)
|
||||
@@ -470,13 +465,7 @@ __tdelete (const void *key, void **vrootp, __compar_fn_t compar)
|
||||
node upn;
|
||||
for (;;)
|
||||
{
|
||||
if (sp == stacksize)
|
||||
{
|
||||
node **newstack;
|
||||
stacksize += 20;
|
||||
newstack = alloca (sizeof (node *) * stacksize);
|
||||
nodestack = memcpy (newstack, nodestack, sp * sizeof (node *));
|
||||
}
|
||||
assert (sp < stacksize);
|
||||
nodestack[sp++] = parentp;
|
||||
parentp = up;
|
||||
upn = DEREFNODEPTR(up);
|
||||
@@ -541,6 +530,7 @@ __tdelete (const void *key, void **vrootp, __compar_fn_t compar)
|
||||
SETNODEPTR(pp,q);
|
||||
/* Make sure pp is right if the case below tries to use
|
||||
it. */
|
||||
assert (sp < stacksize);
|
||||
nodestack[sp++] = pp = LEFTPTR(q);
|
||||
q = RIGHT(p);
|
||||
}
|
||||
@@ -625,6 +615,7 @@ __tdelete (const void *key, void **vrootp, __compar_fn_t compar)
|
||||
SETLEFT(p,RIGHT(q));
|
||||
SETRIGHT(q,p);
|
||||
SETNODEPTR(pp,q);
|
||||
assert (sp < stacksize);
|
||||
nodestack[sp++] = pp = RIGHTPTR(q);
|
||||
q = LEFT(p);
|
||||
}
|
||||
|
||||
@@ -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 \
|
||||
|
||||
+13
-8
@@ -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;
|
||||
@@ -242,9 +241,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)
|
||||
@@ -439,8 +441,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);
|
||||
|
||||
@@ -466,6 +468,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)
|
||||
@@ -491,7 +495,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);
|
||||
@@ -503,20 +507,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)
|
||||
|
||||
+9
-3
@@ -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 */
|
||||
|
||||
@@ -36,16 +36,16 @@ LINE_PARSER
|
||||
unsigned int number;
|
||||
|
||||
if (cnt < 5)
|
||||
INT_FIELD (number, ISCOLON , 0, 16, (unsigned int))
|
||||
INT_FIELD (number, ISCOLON , false, 16, (unsigned int))
|
||||
else
|
||||
INT_FIELD (number, isspace, 1, 16, (unsigned int))
|
||||
INT_FIELD (number, isspace, true, 16, (unsigned int))
|
||||
|
||||
if (number > 0xff)
|
||||
return 0;
|
||||
result->e_addr.ether_addr_octet[cnt] = number;
|
||||
}
|
||||
};
|
||||
STRING_FIELD (result->e_name, isspace, 1);
|
||||
STRING_FIELD (result->e_name, isspace, true);
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -53,7 +53,7 @@ LINE_PARSER
|
||||
{
|
||||
char *addr;
|
||||
|
||||
STRING_FIELD (addr, isspace, 1);
|
||||
STRING_FIELD (addr, isspace, true);
|
||||
|
||||
/* Parse address. */
|
||||
if (__inet_pton (af == AF_UNSPEC ? AF_INET : af, addr, entdata->host_addr)
|
||||
@@ -96,7 +96,7 @@ LINE_PARSER
|
||||
entdata->h_addr_ptrs[1] = NULL;
|
||||
result->h_addr_list = entdata->h_addr_ptrs;
|
||||
|
||||
STRING_FIELD (result->h_name, isspace, 1);
|
||||
STRING_FIELD (result->h_name, isspace, true);
|
||||
})
|
||||
|
||||
#define EXTRA_ARGS_VALUE , AF_INET, 0
|
||||
|
||||
@@ -38,9 +38,9 @@ LINE_PARSER
|
||||
char *cp;
|
||||
int n = 1;
|
||||
|
||||
STRING_FIELD (result->n_name, isspace, 1);
|
||||
STRING_FIELD (result->n_name, isspace, true);
|
||||
|
||||
STRING_FIELD (addr, isspace, 1);
|
||||
STRING_FIELD (addr, isspace, true);
|
||||
/* 'inet_network' does not add zeroes at the end if the network number
|
||||
does not contain four byte values. We shift result ourselves if
|
||||
necessary. */
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <nss_files.h>
|
||||
|
||||
|
||||
@@ -29,8 +29,8 @@ struct protoent_data {};
|
||||
#include "files-parse.c"
|
||||
LINE_PARSER
|
||||
("#",
|
||||
STRING_FIELD (result->p_name, isspace, 1);
|
||||
INT_FIELD (result->p_proto, isspace, 1, 10,);
|
||||
STRING_FIELD (result->p_name, isspace, true);
|
||||
INT_FIELD (result->p_proto, isspace, true, 10,);
|
||||
)
|
||||
|
||||
#include GENERIC
|
||||
|
||||
@@ -29,8 +29,8 @@ struct rpcent_data {};
|
||||
#include "files-parse.c"
|
||||
LINE_PARSER
|
||||
("#",
|
||||
STRING_FIELD (result->r_name, isspace, 1);
|
||||
INT_FIELD (result->r_number, isspace, 1, 10,);
|
||||
STRING_FIELD (result->r_name, isspace, true);
|
||||
INT_FIELD (result->r_number, isspace, true, 10,);
|
||||
)
|
||||
|
||||
#include GENERIC
|
||||
|
||||
@@ -31,9 +31,9 @@ struct servent_data {};
|
||||
#define ISSLASH(c) ((c) == '/')
|
||||
LINE_PARSER
|
||||
("#",
|
||||
STRING_FIELD (result->s_name, isspace, 1);
|
||||
INT_FIELD (result->s_port, ISSLASH, 10, 0, htons);
|
||||
STRING_FIELD (result->s_proto, isspace, 1);
|
||||
STRING_FIELD (result->s_name, isspace, true);
|
||||
INT_FIELD (result->s_port, ISSLASH, false, 10, htons);
|
||||
STRING_FIELD (result->s_proto, isspace, true);
|
||||
)
|
||||
|
||||
#include GENERIC
|
||||
|
||||
@@ -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>
|
||||
@@ -1,5 +1,5 @@
|
||||
# Dutch translations for GNU libc.
|
||||
# Copyright (C) 2025 Free Software Foundation, Inc.
|
||||
# Copyright (C) 2026 Free Software Foundation, Inc.
|
||||
# This file is distributed under the same license as the glibc package.
|
||||
#
|
||||
# "You don't get rich by treating other people well."
|
||||
@@ -8,13 +8,13 @@
|
||||
# Erwin Poeze <erwin.poeze@gmail.com>, 2009.
|
||||
# Benno Schulenberg <benno@vertaalt.nl>, 2006, 2007, 2008, 2010, 2011, 2012.
|
||||
# Benno Schulenberg <benno@vertaalt.nl>, 2013, 2014, 2015, 2017, 2018, 2019.
|
||||
# Benno Schulenberg <benno@vertaalt.nl>, 2020, 2021, 2022, 2023, 2025.
|
||||
# Benno Schulenberg <benno@vertaalt.nl>, 2020, 2021, 2022, 2023, 2025, 2026.
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: libc-2.40.9000\n"
|
||||
"Project-Id-Version: libc-2.42.9000\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2026-01-19 16:22+0100\n"
|
||||
"PO-Revision-Date: 2025-01-06 15:44+0100\n"
|
||||
"PO-Revision-Date: 2026-01-25 13:21+0100\n"
|
||||
"Last-Translator: Benno Schulenberg <vertaling@coevern.nl>\n"
|
||||
"Language-Team: Dutch <vertaling@vrijschrift.org>\n"
|
||||
"Language: nl\n"
|
||||
@@ -112,6 +112,16 @@ msgstr "%s: Te veel argumenten\n"
|
||||
msgid "(PROGRAM ERROR) Option should have been recognized!?"
|
||||
msgstr "**Interne programmafout**: optie had herkend moeten worden!?"
|
||||
|
||||
#: assert/assert-perr.c:45
|
||||
#, c-format
|
||||
msgid "%s%s%s:%s: %s%sUnexpected error: %s.\n"
|
||||
msgstr "%s%s%s:%s: %s%sOnverwachte fout: %s.\n"
|
||||
|
||||
#: assert/assert.c:37
|
||||
#, c-format
|
||||
msgid "%s%s%s:%s: %s%sAssertion `%s' failed.\n"
|
||||
msgstr "%s%s%s:%s: %s%sControletest '%s' faalt.\n"
|
||||
|
||||
#: catgets/gencat.c:112
|
||||
msgid "Create C header file NAME containing symbol definitions"
|
||||
msgstr "headerbestand met symbooldefinities aanmaken"
|
||||
@@ -1301,6 +1311,16 @@ msgstr "kan interne descriptor niet aanmaken"
|
||||
msgid "Reopening shared object `%s' failed"
|
||||
msgstr "heropenen van gedeeld object '%s' is mislukt"
|
||||
|
||||
#: elf/sprof.c:556 elf/sprof.c:672
|
||||
#, c-format
|
||||
msgid "stat(%s) failure"
|
||||
msgstr "stat(%s) is mislukt"
|
||||
|
||||
#: elf/sprof.c:573
|
||||
#, c-format
|
||||
msgid "read outside of file extents %zu + %jd > %jd"
|
||||
msgstr "leespoging buiten de bestands-extents -- %zu + %jd > %jd"
|
||||
|
||||
#: elf/sprof.c:582 elf/sprof.c:689
|
||||
#, c-format
|
||||
msgid "reading of section headers failed"
|
||||
@@ -1326,6 +1346,11 @@ msgstr "kan bestandsnaam niet bepalen"
|
||||
msgid "reading of ELF header failed"
|
||||
msgstr "lezen van ELF-header is mislukt"
|
||||
|
||||
#: elf/sprof.c:683
|
||||
#, c-format
|
||||
msgid "too many section headers"
|
||||
msgstr "te veel sectiekoppen"
|
||||
|
||||
#: elf/sprof.c:720
|
||||
#, c-format
|
||||
msgid "*** The file `%s' is stripped: no detailed analysis possible\n"
|
||||
@@ -2931,6 +2956,12 @@ msgstr "kan status van taalregio-archief '%s' niet opvragen"
|
||||
msgid "cannot lock locale archive \"%s\""
|
||||
msgstr "kan taalregio-archief '%s' niet vergrendelen"
|
||||
|
||||
#: locale/programs/locarchive.c:642 locale/programs/locarchive.c:656
|
||||
#: locale/programs/locarchive.c:664 locale/programs/locarchive.c:685
|
||||
#, c-format
|
||||
msgid "cannot unlock archive header"
|
||||
msgstr "kan archiefkop niet ontgrendelen"
|
||||
|
||||
#: locale/programs/locarchive.c:657
|
||||
#, c-format
|
||||
msgid "cannot read archive header"
|
||||
@@ -6070,7 +6101,7 @@ msgstr "Achterhaald bestandshandvat"
|
||||
#. TRANS properly on @gnuhurdsystems{}, making this error code impossible.)
|
||||
#: sysdeps/gnu/errlist.h:479
|
||||
msgid "Object is remote"
|
||||
msgstr "Object is al elders"
|
||||
msgstr "Object is op afstand"
|
||||
|
||||
#. TRANS This is used by the file locking facilities; see
|
||||
#. TRANS @ref{File Locks}. This error is never generated by @gnuhurdsystems{}, but
|
||||
@@ -6456,6 +6487,18 @@ msgstr "?"
|
||||
msgid "RPC program not available"
|
||||
msgstr "RPC-programma is niet beschikbaar"
|
||||
|
||||
#: sysdeps/gnu/errlist.h:801
|
||||
msgid "Initialization error"
|
||||
msgstr "Initialisatiefout"
|
||||
|
||||
#: sysdeps/gnu/errlist.h:804
|
||||
msgid "Device is remote"
|
||||
msgstr "Apparaat is op afstand"
|
||||
|
||||
#: sysdeps/gnu/errlist.h:807
|
||||
msgid "Too many levels of remote in path"
|
||||
msgstr "Te veel niveaus op afstand in het pad"
|
||||
|
||||
#: sysdeps/hppa/dl-fptr.c:96
|
||||
msgid "cannot map pages for fdesc table"
|
||||
msgstr "kan pagina's voor 'fdesc'-tabel niet in het geheugen plaatsen"
|
||||
@@ -7071,11 +7114,21 @@ msgstr "ongeldige naam voor weekdag"
|
||||
#: timezone/zic.c:2435
|
||||
#, c-format
|
||||
msgid "reference clients mishandle more than %d transition times"
|
||||
msgstr "meer dan %d overgangstijden worden door referentie-clients onjuist behandeld"
|
||||
msgstr "meer dan %d overgangstijden worden door referentie-cliënten onjuist behandeld"
|
||||
|
||||
#: timezone/zic.c:2439
|
||||
msgid "pre-2014 clients may mishandle more than 1200 transition times"
|
||||
msgstr "clients van voor 2014 zouden meer dan 1200 overgangstijden onjuist kunnen behandelen"
|
||||
msgstr "cliënten van voor 2014 zouden meer dan 1200 overgangstijden onjuist kunnen behandelen"
|
||||
|
||||
#: timezone/zic.c:2480
|
||||
#, c-format
|
||||
msgid "%s: pre-2021b clients may mishandle leap second expiry"
|
||||
msgstr "%s: cliënten van voor 2021b zouden het verlopen van een schrikkelseconde onjuist kunnen behandelen"
|
||||
|
||||
#: timezone/zic.c:2488
|
||||
#, c-format
|
||||
msgid "%s: pre-2021b clients may mishandle leap second table truncation"
|
||||
msgstr "%s: cliënten van voor 2021b zouden afkapping van de schrikkelsecondetabel onjuist kunnen behandelen"
|
||||
|
||||
#: timezone/zic.c:2537
|
||||
msgid "too many transition times"
|
||||
@@ -7086,6 +7139,10 @@ msgstr "te veel overgangstijden"
|
||||
msgid "%%z UT offset magnitude exceeds 99:59:59"
|
||||
msgstr "verschuiving %%z t.o.v. UT is groter dan 99:59:59"
|
||||
|
||||
#: timezone/zic.c:3180
|
||||
msgid "no proleptic TZ string for zone"
|
||||
msgstr "er is geen proleptische TZ-tekenreeks voor de zone"
|
||||
|
||||
#: timezone/zic.c:3186
|
||||
#, c-format
|
||||
msgid "%s: pre-%d clients may mishandle distant timestamps"
|
||||
|
||||
+3
-1
@@ -327,6 +327,7 @@ tests := \
|
||||
tst-wait3 \
|
||||
tst-wait4 \
|
||||
tst-waitid \
|
||||
tst-wordexp-append \
|
||||
tst-wordexp-nocmd \
|
||||
tst-wordexp-reuse \
|
||||
tstgetopt \
|
||||
@@ -357,6 +358,7 @@ tests-internal := \
|
||||
tests-container := \
|
||||
bug-ga2 \
|
||||
tst-vfork3 \
|
||||
tst-wordexp-tilde \
|
||||
# tests-container
|
||||
|
||||
tests-time64 := \
|
||||
@@ -499,7 +501,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
|
||||
|
||||
+1
-1
@@ -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
|
||||
|
||||
@@ -0,0 +1,393 @@
|
||||
/* Test for wordexp with WRDE_APPEND 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 <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <malloc.h>
|
||||
|
||||
#include <support/check.h>
|
||||
#include <support/support.h>
|
||||
|
||||
static unsigned int relocating_reallocs;
|
||||
|
||||
/* w_addword grows we_wordv with realloc, make every call guaranteed to
|
||||
relocate the block. This makes BZ 34090 regression more deterministic. */
|
||||
void *
|
||||
realloc (void *ptr, size_t size)
|
||||
{
|
||||
if (ptr == NULL)
|
||||
return malloc (size);
|
||||
if (size == 0)
|
||||
{
|
||||
free (ptr);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void *new = malloc (size);
|
||||
if (new == NULL)
|
||||
return NULL;
|
||||
|
||||
/* Copy only what is valid in the old block to avoid reading past it. */
|
||||
size_t old = malloc_usable_size (ptr);
|
||||
memcpy (new, ptr, old < size ? old : size);
|
||||
/* Clobber the old block so that a stale we_wordv pointer restored on the
|
||||
error path reads garbage instead of the old contents, which might
|
||||
otherwise survive intact and mask the bug. */
|
||||
memset (ptr, 0x5a, old);
|
||||
free (ptr);
|
||||
relocating_reallocs++;
|
||||
return new;
|
||||
}
|
||||
|
||||
/* Verify that all words in we match the expected NULL-terminated
|
||||
array. */
|
||||
static void
|
||||
check_words (const wordexp_t *we, const char *const *expected)
|
||||
{
|
||||
size_t i;
|
||||
for (i = 0; expected[i] != NULL; i++)
|
||||
{
|
||||
TEST_VERIFY (i < we->we_wordc);
|
||||
TEST_COMPARE_STRING (we->we_wordv[we->we_offs + i], expected[i]);
|
||||
}
|
||||
TEST_COMPARE (we->we_wordc, i);
|
||||
}
|
||||
|
||||
#define CHECK_WORDS(we, ...) \
|
||||
do { \
|
||||
const char *const expected_[] = { __VA_ARGS__, NULL }; \
|
||||
check_words (we, expected_); \
|
||||
} while (0)
|
||||
|
||||
/* Test 1: WRDE_APPEND + WRDE_BADCHAR preserves we_wordc. */
|
||||
static void
|
||||
test_append_badchar_preserves_count (void)
|
||||
{
|
||||
printf ("info: test_append_badchar_preserves_count\n");
|
||||
wordexp_t we = { 0 };
|
||||
|
||||
TEST_COMPARE (wordexp ("one two three", &we, 0), 0);
|
||||
TEST_COMPARE (we.we_wordc, 3);
|
||||
|
||||
size_t saved_count = we.we_wordc;
|
||||
|
||||
/* ')' triggers WRDE_BADCHAR and "extra" would be a new word if the
|
||||
expansion succeeded, exercising the w_addword path before the error
|
||||
is detected. */
|
||||
TEST_COMPARE (wordexp ("extra )", &we, WRDE_APPEND), WRDE_BADCHAR);
|
||||
TEST_COMPARE (we.we_wordc, saved_count);
|
||||
|
||||
wordfree (&we);
|
||||
}
|
||||
|
||||
/* Test 2: WRDE_APPEND + WRDE_BADCHAR preserves the we_wordv pointer even
|
||||
when internal realloc would move the buffer. */
|
||||
static void
|
||||
test_append_badchar_preserves_pointer (void)
|
||||
{
|
||||
printf ("info: test_append_badchar_preserves_pointer\n");
|
||||
wordexp_t we = { 0 };
|
||||
|
||||
/* Use many words so that the initial we_wordv allocation is
|
||||
non-trivial and a later realloc is more likely to move it. */
|
||||
TEST_COMPARE (wordexp ("a b c d e f g h", &we, 0), 0);
|
||||
TEST_COMPARE (we.we_wordc, 8);
|
||||
|
||||
char **saved_wordv = we.we_wordv;
|
||||
size_t saved_count = we.we_wordc;
|
||||
unsigned int saved_reallocs = relocating_reallocs;
|
||||
|
||||
/* The interposed realloc guarantees the internal we_wordv buffer moves
|
||||
during parsing, so the pointer-stability check below is meaningful. */
|
||||
TEST_COMPARE (wordexp ("append )", &we, WRDE_APPEND), WRDE_BADCHAR);
|
||||
/* Verify that a relocating realloc actually happened during the failed
|
||||
call, otherwise the pointer-stability check is vacuous. */
|
||||
TEST_VERIFY (relocating_reallocs > saved_reallocs);
|
||||
TEST_COMPARE (we.we_wordc, saved_count);
|
||||
TEST_VERIFY (we.we_wordv == saved_wordv);
|
||||
|
||||
wordfree (&we);
|
||||
}
|
||||
|
||||
/* Test 3: After a failed WRDE_APPEND the original words are still accessible
|
||||
and correct. */
|
||||
static void
|
||||
test_append_badchar_words_intact (void)
|
||||
{
|
||||
printf ("info: test_append_badchar_words_intact\n");
|
||||
wordexp_t we = { 0 };
|
||||
|
||||
TEST_COMPARE (wordexp ("alpha beta gamma", &we, 0), 0);
|
||||
CHECK_WORDS (&we, "alpha", "beta", "gamma");
|
||||
|
||||
TEST_COMPARE (wordexp ("delta )", &we, WRDE_APPEND), WRDE_BADCHAR);
|
||||
|
||||
/* Words must still be intact. */
|
||||
CHECK_WORDS (&we, "alpha", "beta", "gamma");
|
||||
/* The NULL terminator must still be present. */
|
||||
TEST_VERIFY (we.we_wordv[we.we_offs + we.we_wordc] == NULL);
|
||||
|
||||
wordfree (&we);
|
||||
}
|
||||
|
||||
/* Test 4: Successful WRDE_APPEND still works (regression test). */
|
||||
static void
|
||||
test_append_success (void)
|
||||
{
|
||||
printf ("info: test_append_success\n");
|
||||
wordexp_t we = { 0 };
|
||||
|
||||
TEST_COMPARE (wordexp ("hello", &we, 0), 0);
|
||||
TEST_COMPARE (we.we_wordc, 1);
|
||||
|
||||
char **saved_wordv = we.we_wordv;
|
||||
|
||||
TEST_COMPARE (wordexp ("world", &we, WRDE_APPEND), 0);
|
||||
TEST_COMPARE (we.we_wordc, 2);
|
||||
/* A successful append works on a fresh copy of the array, so the
|
||||
caller-visible pointer must have changed. */
|
||||
TEST_VERIFY (we.we_wordv != saved_wordv);
|
||||
CHECK_WORDS (&we, "hello", "world");
|
||||
|
||||
wordfree (&we);
|
||||
}
|
||||
|
||||
/* Test 5: Successful append after a failed append — the implementation must
|
||||
recover and allow further use of the wordexp_t. */
|
||||
static void
|
||||
test_append_success_after_failure (void)
|
||||
{
|
||||
printf ("info: test_append_success_after_failure\n");
|
||||
wordexp_t we = { 0 };
|
||||
|
||||
TEST_COMPARE (wordexp ("first", &we, 0), 0);
|
||||
CHECK_WORDS (&we, "first");
|
||||
|
||||
TEST_COMPARE (wordexp ("bad |", &we, WRDE_APPEND), WRDE_BADCHAR);
|
||||
|
||||
/* State must be exactly as before the failed call. */
|
||||
CHECK_WORDS (&we, "first");
|
||||
|
||||
/* A subsequent successful append must work. */
|
||||
TEST_COMPARE (wordexp ("second third", &we, WRDE_APPEND), 0);
|
||||
CHECK_WORDS (&we, "first", "second", "third");
|
||||
|
||||
wordfree (&we);
|
||||
}
|
||||
|
||||
/* Test 6: Multiple consecutive failed appends do not corrupt state. */
|
||||
static void
|
||||
test_append_multiple_failures (void)
|
||||
{
|
||||
printf ("info: test_append_multiple_failures\n");
|
||||
wordexp_t we = { 0 };
|
||||
|
||||
TEST_COMPARE (wordexp ("keep this", &we, 0), 0);
|
||||
CHECK_WORDS (&we, "keep", "this");
|
||||
|
||||
size_t saved_count = we.we_wordc;
|
||||
char **saved_wordv = we.we_wordv;
|
||||
|
||||
/* Each of these bad characters must leave the state unchanged. */
|
||||
TEST_COMPARE (wordexp ("x )", &we, WRDE_APPEND), WRDE_BADCHAR);
|
||||
TEST_COMPARE (wordexp ("x |", &we, WRDE_APPEND), WRDE_BADCHAR);
|
||||
TEST_COMPARE (wordexp ("x ;", &we, WRDE_APPEND), WRDE_BADCHAR);
|
||||
TEST_COMPARE (wordexp ("x &", &we, WRDE_APPEND), WRDE_BADCHAR);
|
||||
TEST_COMPARE (wordexp ("x <", &we, WRDE_APPEND), WRDE_BADCHAR);
|
||||
TEST_COMPARE (wordexp ("x >", &we, WRDE_APPEND), WRDE_BADCHAR);
|
||||
|
||||
TEST_COMPARE (we.we_wordc, saved_count);
|
||||
TEST_VERIFY (we.we_wordv == saved_wordv);
|
||||
CHECK_WORDS (&we, "keep", "this");
|
||||
|
||||
wordfree (&we);
|
||||
}
|
||||
|
||||
/* Test 7: WRDE_APPEND with WRDE_SYNTAX error (unterminated quote) also
|
||||
preserves state. */
|
||||
static void
|
||||
test_append_syntax_error (void)
|
||||
{
|
||||
printf ("info: test_append_syntax_error\n");
|
||||
wordexp_t we = { 0 };
|
||||
|
||||
TEST_COMPARE (wordexp ("original", &we, 0), 0);
|
||||
CHECK_WORDS (&we, "original");
|
||||
|
||||
char **saved_wordv = we.we_wordv;
|
||||
size_t saved_count = we.we_wordc;
|
||||
|
||||
/* Unterminated double quote triggers WRDE_SYNTAX. */
|
||||
TEST_COMPARE (wordexp ("\"unterminated", &we, WRDE_APPEND), WRDE_SYNTAX);
|
||||
|
||||
TEST_COMPARE (we.we_wordc, saved_count);
|
||||
TEST_VERIFY (we.we_wordv == saved_wordv);
|
||||
CHECK_WORDS (&we, "original");
|
||||
|
||||
wordfree (&we);
|
||||
}
|
||||
|
||||
/* Test 8: Error without WRDE_APPEND still works (regression test for the
|
||||
non-APPEND code path in do_error). */
|
||||
static void
|
||||
test_no_append_error (void)
|
||||
{
|
||||
printf ("info: test_no_append_error\n");
|
||||
wordexp_t we = { 0 };
|
||||
|
||||
/* Simple failure without WRDE_APPEND. */
|
||||
TEST_COMPARE (wordexp ("bad |", &we, 0), WRDE_BADCHAR);
|
||||
|
||||
/* After failure without WRDE_APPEND the struct should be safe to
|
||||
reuse — start fresh. */
|
||||
TEST_COMPARE (wordexp ("ok", &we, 0), 0);
|
||||
CHECK_WORDS (&we, "ok");
|
||||
|
||||
wordfree (&we);
|
||||
}
|
||||
|
||||
/* Test 9: WRDE_BADCHAR on the very first character (no partial words added
|
||||
before the error). */
|
||||
static void
|
||||
test_append_badchar_immediate (void)
|
||||
{
|
||||
printf ("info: test_append_badchar_immediate\n");
|
||||
wordexp_t we = { 0 };
|
||||
|
||||
TEST_COMPARE (wordexp ("hello world", &we, 0), 0);
|
||||
CHECK_WORDS (&we, "hello", "world");
|
||||
|
||||
char **saved_wordv = we.we_wordv;
|
||||
size_t saved_count = we.we_wordc;
|
||||
|
||||
/* The bad character is the very first byte — no w_addword call happens
|
||||
before the error. */
|
||||
TEST_COMPARE (wordexp ("|", &we, WRDE_APPEND), WRDE_BADCHAR);
|
||||
TEST_COMPARE (we.we_wordc, saved_count);
|
||||
TEST_VERIFY (we.we_wordv == saved_wordv);
|
||||
|
||||
wordfree (&we);
|
||||
}
|
||||
|
||||
/* Test 10: WRDE_APPEND into an empty wordexp_t (initial call uses WRDE_APPEND
|
||||
with a zeroed struct — unusual but allowed). */
|
||||
static void
|
||||
test_append_into_empty (void)
|
||||
{
|
||||
printf ("info: test_append_into_empty\n");
|
||||
wordexp_t we = { 0 };
|
||||
|
||||
/* First call with WRDE_APPEND on a zeroed struct. The implementation
|
||||
must handle we_wordv == NULL gracefully. */
|
||||
TEST_COMPARE (wordexp ("solo", &we, WRDE_APPEND), 0);
|
||||
TEST_COMPARE (we.we_wordc, 1);
|
||||
CHECK_WORDS (&we, "solo");
|
||||
|
||||
wordfree (&we);
|
||||
}
|
||||
|
||||
/* Verify that the leading we_offs slots are all NULL. */
|
||||
static void
|
||||
check_offs_null (const wordexp_t *we)
|
||||
{
|
||||
for (size_t i = 0; i < we->we_offs; i++)
|
||||
TEST_VERIFY (we->we_wordv[i] == NULL);
|
||||
}
|
||||
|
||||
/* Test 11: successful WRDE_APPEND with WRDE_DOOFFS and a non-zero we_offs.
|
||||
The leading offset slots must stay NULL and words must land at
|
||||
we_wordv[we_offs + i] across both the initial and the appended call. */
|
||||
static void
|
||||
test_dooffs_append_success (void)
|
||||
{
|
||||
printf ("info: test_dooffs_append_success\n");
|
||||
wordexp_t we = { 0 };
|
||||
we.we_offs = 2;
|
||||
|
||||
TEST_COMPARE (wordexp ("one two", &we, WRDE_DOOFFS), 0);
|
||||
TEST_COMPARE (we.we_offs, 2);
|
||||
check_offs_null (&we);
|
||||
CHECK_WORDS (&we, "one", "two");
|
||||
|
||||
TEST_COMPARE (wordexp ("three", &we, WRDE_APPEND | WRDE_DOOFFS), 0);
|
||||
TEST_COMPARE (we.we_offs, 2);
|
||||
check_offs_null (&we);
|
||||
CHECK_WORDS (&we, "one", "two", "three");
|
||||
/* The NULL terminator must sit right after the last word. */
|
||||
TEST_VERIFY (we.we_wordv[we.we_offs + we.we_wordc] == NULL);
|
||||
|
||||
wordfree (&we);
|
||||
}
|
||||
|
||||
/* Test 12: failed WRDE_APPEND with WRDE_DOOFFS preserves we_wordc, the
|
||||
we_wordv pointer, the words and the leading NULL offset slots. This
|
||||
exercises the we_offs arithmetic in the array duplication and in the
|
||||
error-path cleanup (we_wordv[we_offs + --we_wordc]). */
|
||||
static void
|
||||
test_dooffs_append_error_preserves_state (void)
|
||||
{
|
||||
printf ("info: test_dooffs_append_error_preserves_state\n");
|
||||
wordexp_t we = { 0 };
|
||||
we.we_offs = 3;
|
||||
|
||||
TEST_COMPARE (wordexp ("alpha beta", &we, WRDE_DOOFFS), 0);
|
||||
check_offs_null (&we);
|
||||
CHECK_WORDS (&we, "alpha", "beta");
|
||||
|
||||
char **saved_wordv = we.we_wordv;
|
||||
size_t saved_count = we.we_wordc;
|
||||
unsigned int saved_reallocs = relocating_reallocs;
|
||||
|
||||
/* "gamma" is a partial word added via w_addword (forcing a relocating
|
||||
realloc of we_wordv) before ')' triggers WRDE_BADCHAR. */
|
||||
TEST_COMPARE (wordexp ("gamma )", &we, WRDE_APPEND | WRDE_DOOFFS),
|
||||
WRDE_BADCHAR);
|
||||
TEST_VERIFY (relocating_reallocs > saved_reallocs);
|
||||
|
||||
TEST_COMPARE (we.we_offs, 3);
|
||||
TEST_COMPARE (we.we_wordc, saved_count);
|
||||
TEST_VERIFY (we.we_wordv == saved_wordv);
|
||||
check_offs_null (&we);
|
||||
CHECK_WORDS (&we, "alpha", "beta");
|
||||
TEST_VERIFY (we.we_wordv[we.we_offs + we.we_wordc] == NULL);
|
||||
|
||||
wordfree (&we);
|
||||
}
|
||||
|
||||
static int
|
||||
do_test (void)
|
||||
{
|
||||
test_append_badchar_preserves_count ();
|
||||
test_append_badchar_preserves_pointer ();
|
||||
test_append_badchar_words_intact ();
|
||||
test_append_success ();
|
||||
test_append_success_after_failure ();
|
||||
test_append_multiple_failures ();
|
||||
test_append_syntax_error ();
|
||||
test_no_append_error ();
|
||||
test_append_badchar_immediate ();
|
||||
test_append_into_empty ();
|
||||
test_dooffs_append_success ();
|
||||
test_dooffs_append_error_preserves_state ();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#include <support/test-driver.c>
|
||||
@@ -0,0 +1,244 @@
|
||||
/* Test wordexp tilde expansion with large usernames (BZ 34091).
|
||||
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 <pwd.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <wordexp.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/resource.h>
|
||||
|
||||
#include <support/check.h>
|
||||
#include <support/support.h>
|
||||
#include <support/xunistd.h>
|
||||
#include <support/namespace.h>
|
||||
|
||||
typedef void (*func_callback_t)(void);
|
||||
|
||||
static void
|
||||
subprocess_small_stack (void *closure)
|
||||
{
|
||||
struct rlimit rl;
|
||||
TEST_COMPARE (getrlimit (RLIMIT_STACK, &rl), 0);
|
||||
rl.rlim_cur = 512 * 1024;
|
||||
TEST_COMPARE (setrlimit (RLIMIT_STACK, &rl), 0);
|
||||
|
||||
func_callback_t func_test = closure;
|
||||
func_test ();
|
||||
}
|
||||
|
||||
/* Build a string "~<padding>/tail" where <padding> is LEN bytes of the
|
||||
character CH. The caller must free the result. */
|
||||
static char *
|
||||
make_tilde_input (char ch, size_t len, const char *tail)
|
||||
{
|
||||
/* ~ + len + / + tail + \0 */
|
||||
size_t taillen = tail != NULL ? strlen (tail) : 0;
|
||||
size_t total = 1 + len + 1 + taillen + 1;
|
||||
char *buf = xmalloc (total);
|
||||
buf[0] = '~';
|
||||
memset (buf + 1, ch, len);
|
||||
buf[1 + len] = '/';
|
||||
if (tail != NULL)
|
||||
memcpy (buf + 1 + len + 1, tail, taillen);
|
||||
buf[total - 1] = '\0';
|
||||
return buf;
|
||||
}
|
||||
|
||||
/* Test 1: A very long username must not crash. The username will not match
|
||||
any real user, so wordexp returns ~<long>/rest. */
|
||||
static void
|
||||
test_long_username (void)
|
||||
{
|
||||
printf ("info: test_long_username_no_crash\n");
|
||||
|
||||
static const char REST[] = "rest";
|
||||
|
||||
/* 1 MiB username — well beyond any reasonable stack frame. */
|
||||
const size_t long_len = 1024 * 1024;
|
||||
char *input = make_tilde_input ('A', long_len, REST);
|
||||
|
||||
wordexp_t we = { 0 };
|
||||
int ret = wordexp (input, &we, 0);
|
||||
/* The (non-existent) username is invalid, so wordexp falls back to
|
||||
literal output: ~AAA…/rest. */
|
||||
TEST_COMPARE (ret, 0);
|
||||
TEST_COMPARE (we.we_wordc, 1);
|
||||
|
||||
/* Verify prefix: '~' followed by long_len 'A's. */
|
||||
const char *result = we.we_wordv[0];
|
||||
TEST_COMPARE (result[0], '~');
|
||||
TEST_COMPARE (strlen (result),
|
||||
1 /* ~ */ + long_len + sizeof (REST));
|
||||
for (size_t j = 1; j <= long_len; j++)
|
||||
if (result[j] != 'A')
|
||||
{
|
||||
printf (" mismatch at position %zu: expected 'A', got '%c'\n",
|
||||
j, result[j]);
|
||||
support_record_failure ();
|
||||
break;
|
||||
}
|
||||
/* Verify the tail after the username. */
|
||||
TEST_COMPARE_STRING (result + 1 + long_len, "/rest");
|
||||
|
||||
wordfree (&we);
|
||||
free (input);
|
||||
}
|
||||
|
||||
/* Test 2: A username that just exceeds the default scratch_buffer inline
|
||||
size (1024 bytes) exercises the scratch_buffer_set_array_size growth path
|
||||
without being excessively large. */
|
||||
static void
|
||||
test_scratch_buffer_growth (void)
|
||||
{
|
||||
printf ("info: test_scratch_buffer_growth\n");
|
||||
|
||||
const size_t len = 2048;
|
||||
char *input = make_tilde_input ('x', len, NULL);
|
||||
|
||||
wordexp_t we = { 0 };
|
||||
int ret = wordexp (input, &we, 0);
|
||||
TEST_COMPARE (ret, 0);
|
||||
TEST_COMPARE (we.we_wordc, 1);
|
||||
|
||||
/* ~xxx…/ — the trailing slash makes a separate empty component, but
|
||||
wordexp merges it into the single token ~xxx…/. */
|
||||
const char *result = we.we_wordv[0];
|
||||
TEST_COMPARE (result[0], '~');
|
||||
for (size_t j = 1; j <= len; j++)
|
||||
if (result[j] != 'x')
|
||||
{
|
||||
printf (" mismatch at position %zu\n", j);
|
||||
support_record_failure ();
|
||||
break;
|
||||
}
|
||||
TEST_COMPARE (result[1 + len], '/');
|
||||
|
||||
wordfree (&we);
|
||||
free (input);
|
||||
}
|
||||
|
||||
/* Test 3: ~root still resolves to the correct home directory through the
|
||||
__getpwnam_r path. */
|
||||
static void
|
||||
test_known_user (void)
|
||||
{
|
||||
printf ("info: test_known_user\n");
|
||||
|
||||
/* Look up root's home directory for comparison. */
|
||||
struct passwd *pw = getpwnam ("root");
|
||||
if (pw == NULL || pw->pw_dir == NULL)
|
||||
{
|
||||
printf (" SKIP: cannot look up root\n");
|
||||
return;
|
||||
}
|
||||
|
||||
char *expected = xasprintf ("%s/file", pw->pw_dir);
|
||||
|
||||
wordexp_t we = { 0 };
|
||||
TEST_COMPARE (wordexp ("~root/file", &we, 0), 0);
|
||||
TEST_COMPARE (we.we_wordc, 1);
|
||||
TEST_COMPARE_STRING (we.we_wordv[0], expected);
|
||||
|
||||
wordfree (&we);
|
||||
free (expected);
|
||||
}
|
||||
|
||||
/* Test 4: Bare tilde expands to $HOME. */
|
||||
static void
|
||||
test_bare_tilde (void)
|
||||
{
|
||||
printf ("info: test_bare_tilde\n");
|
||||
|
||||
const char *home = getenv ("HOME");
|
||||
if (home == NULL)
|
||||
{
|
||||
printf (" SKIP: HOME is not set\n");
|
||||
return;
|
||||
}
|
||||
|
||||
wordexp_t we = { 0 };
|
||||
TEST_COMPARE (wordexp ("~", &we, 0), 0);
|
||||
TEST_COMPARE (we.we_wordc, 1);
|
||||
TEST_COMPARE_STRING (we.we_wordv[0], home);
|
||||
|
||||
wordfree (&we);
|
||||
}
|
||||
|
||||
/* Test 5: Short non-existent username falls back to literal ~username output,
|
||||
exercising the invalid-login-name path. */
|
||||
static void
|
||||
test_unknown_user (void)
|
||||
{
|
||||
printf ("info: test_unknown_user\n");
|
||||
|
||||
/* Pick a username that is extremely unlikely to exist. */
|
||||
wordexp_t we = { 0 };
|
||||
TEST_COMPARE (wordexp ("~no_such_user_xyzzy42", &we, 0), 0);
|
||||
TEST_COMPARE (we.we_wordc, 1);
|
||||
TEST_COMPARE_STRING (we.we_wordv[0], "~no_such_user_xyzzy42");
|
||||
|
||||
wordfree (&we);
|
||||
}
|
||||
|
||||
/* Test 6: Tilde with username and WRDE_APPEND — exercises parse_tilde's
|
||||
interaction with the WRDE_APPEND word list. */
|
||||
static void
|
||||
test_tilde_with_append (void)
|
||||
{
|
||||
printf ("info: test_tilde_with_append\n");
|
||||
|
||||
const char *home = getenv ("HOME");
|
||||
if (home == NULL)
|
||||
{
|
||||
printf (" SKIP: HOME is not set\n");
|
||||
return;
|
||||
}
|
||||
|
||||
wordexp_t we = { 0 };
|
||||
TEST_COMPARE (wordexp ("first", &we, 0), 0);
|
||||
|
||||
TEST_COMPARE (wordexp ("~/path", &we, WRDE_APPEND), 0);
|
||||
TEST_COMPARE (we.we_wordc, 2);
|
||||
TEST_COMPARE_STRING (we.we_wordv[0], "first");
|
||||
|
||||
char *expected = xasprintf ("%s/path", home);
|
||||
TEST_COMPARE_STRING (we.we_wordv[1], expected);
|
||||
|
||||
wordfree (&we);
|
||||
free (expected);
|
||||
}
|
||||
|
||||
static int
|
||||
do_test (void)
|
||||
{
|
||||
test_known_user ();
|
||||
test_bare_tilde ();
|
||||
test_unknown_user ();
|
||||
test_tilde_with_append ();
|
||||
|
||||
support_isolate_in_subprocess (subprocess_small_stack,
|
||||
test_long_username);
|
||||
|
||||
support_isolate_in_subprocess (subprocess_small_stack,
|
||||
test_scratch_buffer_growth);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#include <support/test-driver.c>
|
||||
@@ -0,0 +1 @@
|
||||
root:x:0:
|
||||
@@ -0,0 +1,3 @@
|
||||
passwd: files
|
||||
group: files
|
||||
shadow: files
|
||||
@@ -0,0 +1 @@
|
||||
root:x:0:0:root:/root:/bin/sh
|
||||
+75
-15
@@ -335,17 +335,29 @@ parse_tilde (char **word, size_t *word_length, size_t *max_length,
|
||||
else
|
||||
{
|
||||
/* Look up user name in database to get home directory */
|
||||
char *user = strndupa (&words[1 + *offset], i - (1 + *offset));
|
||||
struct passwd pwd, *tpwd;
|
||||
int result;
|
||||
size_t userlen = i - (1 + *offset);
|
||||
/* tmpbuf contains both the user and the __getpwnam_r working area. */
|
||||
struct scratch_buffer tmpbuf;
|
||||
scratch_buffer_init (&tmpbuf);
|
||||
if (!scratch_buffer_set_array_size (&tmpbuf, userlen + 1, 1))
|
||||
return WRDE_NOSPACE;
|
||||
char *user = tmpbuf.data;
|
||||
memcpy (user, &words[1 + *offset], userlen);
|
||||
user[userlen] = '\0';
|
||||
|
||||
while ((result = __getpwnam_r (user, &pwd, tmpbuf.data, tmpbuf.length,
|
||||
struct passwd pwd, *tpwd;
|
||||
int result;
|
||||
while ((result = __getpwnam_r (user,
|
||||
&pwd,
|
||||
tmpbuf.data + userlen + 1,
|
||||
tmpbuf.length - userlen - 1,
|
||||
&tpwd)) != 0
|
||||
&& errno == ERANGE)
|
||||
if (!scratch_buffer_grow (&tmpbuf))
|
||||
return WRDE_NOSPACE;
|
||||
{
|
||||
if (!scratch_buffer_grow_preserve (&tmpbuf))
|
||||
return WRDE_NOSPACE;
|
||||
user = tmpbuf.data;
|
||||
}
|
||||
|
||||
if (result == 0 && tpwd != NULL && pwd.pw_dir)
|
||||
*word = w_addstr (*word, word_length, max_length, pwd.pw_dir);
|
||||
@@ -2212,6 +2224,12 @@ wordexp (const char *words, wordexp_t *pwordexp, int flags)
|
||||
char ifs_white[4];
|
||||
wordexp_t old_word = *pwordexp;
|
||||
|
||||
/* When WRDE_APPEND is set we work on a copy of the we_wordv array so that
|
||||
the caller's original pointer is never invalidated by realloc inside
|
||||
w_addword. The saved_wordv keeps the original; on success we free it,
|
||||
on non-NOSPACE error we free the working copy and restore the original. */
|
||||
char **saved_wordv = NULL;
|
||||
|
||||
if (flags & WRDE_REUSE)
|
||||
{
|
||||
/* Minimal implementation of WRDE_REUSE for now */
|
||||
@@ -2246,6 +2264,21 @@ wordexp (const char *words, wordexp_t *pwordexp, int flags)
|
||||
pwordexp->we_offs = 0;
|
||||
}
|
||||
}
|
||||
else if (pwordexp->we_wordv != NULL)
|
||||
{
|
||||
/* WRDE_APPEND with an existing word list: duplicate the array so that
|
||||
realloc during parsing does not invalidate the caller's pointer. The
|
||||
strings themselves are shared an the array already holds
|
||||
'we_offs + we_wordc + 1 pointers' (so the size computation cannot
|
||||
overflow). */
|
||||
size_t num_p = pwordexp->we_offs + pwordexp->we_wordc + 1;
|
||||
char **dup = malloc (num_p * sizeof (char *));
|
||||
if (dup == NULL)
|
||||
return WRDE_NOSPACE;
|
||||
memcpy (dup, pwordexp->we_wordv, num_p * sizeof (char *));
|
||||
saved_wordv = pwordexp->we_wordv;
|
||||
pwordexp->we_wordv = dup;
|
||||
}
|
||||
|
||||
/* Find out what the field separators are.
|
||||
* There are two types: whitespace and non-whitespace.
|
||||
@@ -2326,7 +2359,7 @@ wordexp (const char *words, wordexp_t *pwordexp, int flags)
|
||||
error = w_addword (pwordexp, NULL);
|
||||
|
||||
if (error)
|
||||
return error;
|
||||
goto do_error;
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -2344,7 +2377,7 @@ wordexp (const char *words, wordexp_t *pwordexp, int flags)
|
||||
error = w_addword (pwordexp, NULL);
|
||||
|
||||
if (error)
|
||||
return error;
|
||||
goto do_error;
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -2410,10 +2443,18 @@ wordexp (const char *words, wordexp_t *pwordexp, int flags)
|
||||
|
||||
/* There was a word separator at the end */
|
||||
if (word == NULL) /* i.e. w_newword */
|
||||
return 0;
|
||||
{
|
||||
free (saved_wordv);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* There was no field separator at the end */
|
||||
return w_addword (pwordexp, word);
|
||||
/* There was no field separator at the end. The only possible error
|
||||
from w_addword is WRDE_NOSPACE. */
|
||||
error = w_addword (pwordexp, word);
|
||||
if (error != 0)
|
||||
goto do_error;
|
||||
free (saved_wordv);
|
||||
return 0;
|
||||
|
||||
do_error:
|
||||
/* Error:
|
||||
@@ -2424,11 +2465,30 @@ do_error:
|
||||
free (word);
|
||||
|
||||
if (error == WRDE_NOSPACE)
|
||||
return WRDE_NOSPACE;
|
||||
{
|
||||
/* we_wordc and we_wordv are updated to reflect any words that were
|
||||
successfully expanded. The old array is obsolete. */
|
||||
free (saved_wordv);
|
||||
return WRDE_NOSPACE;
|
||||
}
|
||||
|
||||
if ((flags & WRDE_APPEND) == 0)
|
||||
wordfree (pwordexp);
|
||||
if (flags & WRDE_APPEND)
|
||||
{
|
||||
/* POSIX 2024 states that for in other error cases, if the WRDE_APPEND
|
||||
flag was specified, we_wordc and we_wordv shall not be modified.
|
||||
|
||||
Free strings appended during this call, discard the working copy of
|
||||
we_wordv, and restore the caller's original pointer. */
|
||||
while (pwordexp->we_wordc > old_word.we_wordc)
|
||||
free (pwordexp->we_wordv[pwordexp->we_offs + --pwordexp->we_wordc]);
|
||||
free (pwordexp->we_wordv);
|
||||
pwordexp->we_wordv = saved_wordv;
|
||||
}
|
||||
else
|
||||
{
|
||||
wordfree (pwordexp);
|
||||
*pwordexp = old_word;
|
||||
}
|
||||
|
||||
*pwordexp = old_word;
|
||||
return error;
|
||||
}
|
||||
|
||||
@@ -101,14 +101,17 @@ tests += \
|
||||
tst-ns_name \
|
||||
tst-ns_name_compress \
|
||||
tst-ns_name_pton \
|
||||
tst-ns_sprintrr \
|
||||
tst-res_hconf_reorder \
|
||||
tst-res_hnok \
|
||||
tst-resolv-aliases \
|
||||
tst-resolv-basic \
|
||||
tst-resolv-binary \
|
||||
tst-resolv-byaddr \
|
||||
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 \
|
||||
@@ -118,6 +121,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.
|
||||
@@ -301,6 +305,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
|
||||
@@ -310,6 +316,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)
|
||||
@@ -332,5 +340,6 @@ $(objpfx)tst-ns_name: $(objpfx)libresolv.so
|
||||
$(objpfx)tst-ns_name.out: tst-ns_name.data
|
||||
$(objpfx)tst-ns_name_compress: $(objpfx)libresolv.so
|
||||
$(objpfx)tst-ns_name_pton: $(objpfx)libresolv.so
|
||||
$(objpfx)tst-ns_sprintrr: $(objpfx)libresolv.so
|
||||
$(objpfx)tst-res_hnok: $(objpfx)libresolv.so
|
||||
$(objpfx)tst-p_secstodate: $(objpfx)libresolv.so
|
||||
|
||||
+53
-117
@@ -78,6 +78,24 @@ ns_sprintrr(const ns_msg *handle, const ns_rr *rr,
|
||||
}
|
||||
libresolv_hidden_def (ns_sprintrr)
|
||||
|
||||
/* Writes the class/type symbol NUMBER to *BUF, using the name from
|
||||
*SYMS if possible. If NUMBER is not found in *SYMS, print the
|
||||
number with PREFIX. */
|
||||
static int
|
||||
addsym (const struct res_sym *syms, int number, const char *prefix,
|
||||
char **buf, size_t *buflen)
|
||||
{
|
||||
for (; syms->name != NULL; syms++)
|
||||
if (number == syms->number)
|
||||
{
|
||||
T (addstr (" ", 1, buf, buflen));
|
||||
return addstr (syms->name, strlen (syms->name), buf, buflen);
|
||||
}
|
||||
char tmp[20];
|
||||
int len = snprintf (tmp, sizeof (tmp), " %s%d", prefix, number);
|
||||
return addstr (tmp, len, buf, buflen);
|
||||
}
|
||||
|
||||
/*%
|
||||
* Convert the fields of an RR into presentation format.
|
||||
*
|
||||
@@ -97,7 +115,6 @@ ns_sprintrrf(const u_char *msg, size_t msglen,
|
||||
|
||||
const char *comment;
|
||||
char tmp[100];
|
||||
char errbuf[40];
|
||||
int len, x;
|
||||
|
||||
/*
|
||||
@@ -128,11 +145,21 @@ ns_sprintrrf(const u_char *msg, size_t msglen,
|
||||
/*
|
||||
* TTL, Class, Type.
|
||||
*/
|
||||
T(x = ns_format_ttl(ttl, buf, buflen));
|
||||
addlen(x, &buf, &buflen);
|
||||
len = SPRINTF((tmp, " %s %s", p_class(class), p_type(type)));
|
||||
T(addstr(tmp, len, &buf, &buflen));
|
||||
T(spaced = addtab(x + len, 16, spaced, &buf, &buflen));
|
||||
{
|
||||
char *start = buf;
|
||||
|
||||
T (x = ns_format_ttl (ttl, buf, buflen));
|
||||
addlen (x, &buf, &buflen);
|
||||
T (addsym (__p_class_syms, class, "CLASS", &buf, &buflen));
|
||||
if (type == ns_t_a6)
|
||||
/* A6 is not part of __p_type_syms, which is exported.
|
||||
Adding A6 there would change its size. Handle it here. */
|
||||
T (addstr (" A6", 3, &buf, &buflen));
|
||||
else
|
||||
T (addsym (__p_type_syms, type, "TYPE", &buf, &buflen));
|
||||
|
||||
T (spaced = addtab(buf - start, 16, spaced, &buf, &buflen));
|
||||
}
|
||||
|
||||
/*
|
||||
* RData.
|
||||
@@ -140,8 +167,9 @@ ns_sprintrrf(const u_char *msg, size_t msglen,
|
||||
switch (type) {
|
||||
case ns_t_a:
|
||||
if (rdlen != (size_t)NS_INADDRSZ)
|
||||
goto formerr;
|
||||
(void) inet_ntop(AF_INET, rdata, buf, buflen);
|
||||
goto formerr;
|
||||
if (inet_ntop (AF_INET, rdata, buf, buflen) == NULL)
|
||||
return -1;
|
||||
addlen(strlen(buf), &buf, &buflen);
|
||||
break;
|
||||
|
||||
@@ -307,16 +335,18 @@ ns_sprintrrf(const u_char *msg, size_t msglen,
|
||||
}
|
||||
|
||||
case ns_t_aaaa:
|
||||
if (rdlen != (size_t)NS_IN6ADDRSZ)
|
||||
goto formerr;
|
||||
(void) inet_ntop(AF_INET6, rdata, buf, buflen);
|
||||
if (rdlen != (size_t)NS_IN6ADDRSZ)
|
||||
goto formerr;
|
||||
if (inet_ntop (AF_INET6, rdata, buf, buflen) == NULL)
|
||||
return -1;
|
||||
addlen(strlen(buf), &buf, &buflen);
|
||||
break;
|
||||
|
||||
case ns_t_loc: {
|
||||
char t[255];
|
||||
|
||||
/* XXX protocol format checking? */
|
||||
if (rdlen != 16)
|
||||
goto formerr;
|
||||
(void) loc_ntoa(rdata, t);
|
||||
T(addstr(t, strlen(t), &buf, &buflen));
|
||||
break;
|
||||
@@ -400,7 +430,8 @@ ns_sprintrrf(const u_char *msg, size_t msglen,
|
||||
goto formerr;
|
||||
|
||||
/* Address. */
|
||||
(void) inet_ntop(AF_INET, rdata, buf, buflen);
|
||||
if (inet_ntop (AF_INET, rdata, buf, buflen) == NULL)
|
||||
return -1;
|
||||
addlen(strlen(buf), &buf, &buflen);
|
||||
rdata += NS_INADDRSZ;
|
||||
|
||||
@@ -434,96 +465,6 @@ ns_sprintrrf(const u_char *msg, size_t msglen,
|
||||
break;
|
||||
}
|
||||
|
||||
case ns_t_cert: {
|
||||
u_int c_type, key_tag, alg;
|
||||
int n;
|
||||
unsigned int siz;
|
||||
char base64_cert[8192], tmp[40];
|
||||
const char *leader;
|
||||
|
||||
c_type = ns_get16(rdata); rdata += NS_INT16SZ;
|
||||
key_tag = ns_get16(rdata); rdata += NS_INT16SZ;
|
||||
alg = (u_int) *rdata++;
|
||||
|
||||
len = SPRINTF((tmp, "%d %d %d ", c_type, key_tag, alg));
|
||||
T(addstr(tmp, len, &buf, &buflen));
|
||||
siz = (edata-rdata)*4/3 + 4; /* "+4" accounts for trailing \0 */
|
||||
if (siz > sizeof(base64_cert) * 3/4) {
|
||||
const char *str = "record too long to print";
|
||||
T(addstr(str, strlen(str), &buf, &buflen));
|
||||
}
|
||||
else {
|
||||
len = b64_ntop(rdata, edata-rdata, base64_cert, siz);
|
||||
|
||||
if (len < 0)
|
||||
goto formerr;
|
||||
else if (len > 15) {
|
||||
T(addstr(" (", 2, &buf, &buflen));
|
||||
leader = "\n\t\t";
|
||||
spaced = 0;
|
||||
}
|
||||
else
|
||||
leader = " ";
|
||||
|
||||
for (n = 0; n < len; n += 48) {
|
||||
T(addstr(leader, strlen(leader),
|
||||
&buf, &buflen));
|
||||
T(addstr(base64_cert + n, MIN(len - n, 48),
|
||||
&buf, &buflen));
|
||||
}
|
||||
if (len > 15)
|
||||
T(addstr(" )", 2, &buf, &buflen));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case ns_t_tkey: {
|
||||
/* KJD - need to complete this */
|
||||
u_long t;
|
||||
int mode, err, keysize;
|
||||
|
||||
/* Algorithm name. */
|
||||
T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
|
||||
T(addstr(" ", 1, &buf, &buflen));
|
||||
|
||||
/* Inception. */
|
||||
t = ns_get32(rdata); rdata += NS_INT32SZ;
|
||||
len = SPRINTF((tmp, "%lu ", t));
|
||||
T(addstr(tmp, len, &buf, &buflen));
|
||||
|
||||
/* Expiration. */
|
||||
t = ns_get32(rdata); rdata += NS_INT32SZ;
|
||||
len = SPRINTF((tmp, "%lu ", t));
|
||||
T(addstr(tmp, len, &buf, &buflen));
|
||||
|
||||
/* Mode , Error, Key Size. */
|
||||
/* Priority, Weight, Port. */
|
||||
mode = ns_get16(rdata); rdata += NS_INT16SZ;
|
||||
err = ns_get16(rdata); rdata += NS_INT16SZ;
|
||||
keysize = ns_get16(rdata); rdata += NS_INT16SZ;
|
||||
len = SPRINTF((tmp, "%u %u %u ", mode, err, keysize));
|
||||
T(addstr(tmp, len, &buf, &buflen));
|
||||
|
||||
/* XXX need to dump key, print otherdata length & other data */
|
||||
break;
|
||||
}
|
||||
|
||||
case ns_t_tsig: {
|
||||
/* BEW - need to complete this */
|
||||
int n;
|
||||
|
||||
T(len = addname(msg, msglen, &rdata, origin, &buf, &buflen));
|
||||
T(addstr(" ", 1, &buf, &buflen));
|
||||
rdata += 8; /*%< time */
|
||||
n = ns_get16(rdata); rdata += INT16SZ;
|
||||
rdata += n; /*%< sig */
|
||||
n = ns_get16(rdata); rdata += INT16SZ; /*%< original id */
|
||||
sprintf(buf, "%d", ns_get16(rdata));
|
||||
rdata += INT16SZ;
|
||||
addlen(strlen(buf), &buf, &buflen);
|
||||
break;
|
||||
}
|
||||
|
||||
case ns_t_a6: {
|
||||
struct in6_addr a;
|
||||
int pbyte, pbit;
|
||||
@@ -539,12 +480,14 @@ ns_sprintrrf(const u_char *msg, size_t msglen,
|
||||
|
||||
/* address suffix: provided only when prefix len != 128 */
|
||||
if (pbit < 128) {
|
||||
if (rdata + pbyte >= edata) goto formerr;
|
||||
unsigned int bytelen = sizeof(a) - pbyte;
|
||||
if (edata - rdata < bytelen) goto formerr;
|
||||
memset(&a, 0, sizeof(a));
|
||||
memcpy(&a.s6_addr[pbyte], rdata, sizeof(a) - pbyte);
|
||||
(void) inet_ntop(AF_INET6, &a, buf, buflen);
|
||||
memcpy(&a.s6_addr[pbyte], rdata, bytelen);
|
||||
if (inet_ntop (AF_INET6, &a, buf, buflen) == NULL)
|
||||
return -1;
|
||||
addlen(strlen(buf), &buf, &buflen);
|
||||
rdata += sizeof(a) - pbyte;
|
||||
rdata += bytelen;
|
||||
}
|
||||
|
||||
/* prefix name: provided only when prefix len > 0 */
|
||||
@@ -557,25 +500,18 @@ ns_sprintrrf(const u_char *msg, size_t msglen,
|
||||
break;
|
||||
}
|
||||
|
||||
case ns_t_opt: {
|
||||
len = SPRINTF((tmp, "%u bytes", class));
|
||||
T(addstr(tmp, len, &buf, &buflen));
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
snprintf (errbuf, sizeof (errbuf), "unknown RR type %d", type);
|
||||
comment = errbuf;
|
||||
comment = "";
|
||||
goto hexify;
|
||||
}
|
||||
return (buf - obuf);
|
||||
formerr:
|
||||
comment = "RR format error";
|
||||
comment = " ; RR format error";
|
||||
hexify: {
|
||||
int n, m;
|
||||
char *p;
|
||||
|
||||
len = SPRINTF((tmp, "\\# %u%s\t; %s", (unsigned)(edata - rdata),
|
||||
len = SPRINTF((tmp, "\\# %u%s%s", (unsigned)(edata - rdata),
|
||||
rdlen != 0U ? " (" : "", comment));
|
||||
T(addstr(tmp, len, &buf, &buflen));
|
||||
while (rdata < edata) {
|
||||
|
||||
@@ -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))
|
||||
@@ -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;
|
||||
|
||||
@@ -390,8 +390,6 @@ p_fqname(const u_char *cp, const u_char *msg, FILE *file) {
|
||||
* that C_ANY is a qclass but not a class. (You can ask for records of class
|
||||
* C_ANY, but you can't have any records of that class in the database.)
|
||||
*/
|
||||
extern const struct res_sym __p_class_syms[];
|
||||
libresolv_hidden_proto (__p_class_syms)
|
||||
const struct res_sym __p_class_syms[] = {
|
||||
{C_IN, (char *) "IN"},
|
||||
{C_CHAOS, (char *) "CHAOS"},
|
||||
@@ -426,8 +424,6 @@ const struct res_sym __p_update_section_syms[] attribute_hidden = {
|
||||
* Names of RR types and qtypes. The list is incomplete because its
|
||||
* size is part of the ABI.
|
||||
*/
|
||||
extern const struct res_sym __p_type_syms[];
|
||||
libresolv_hidden_proto (__p_type_syms)
|
||||
const struct res_sym __p_type_syms[] = {
|
||||
{ns_t_a, (char *) "A", (char *) "address"},
|
||||
{ns_t_ns, (char *) "NS", (char *) "name server"},
|
||||
|
||||
@@ -0,0 +1,329 @@
|
||||
/* Tests for the ns_sprintrr function.
|
||||
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 <arpa/nameser.h>
|
||||
|
||||
#include <alloc_buffer.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <libc-diag.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <support/check.h>
|
||||
#include <support/next_to_fault.h>
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
/* Regions that test_one_record uses for input and output. */
|
||||
static struct support_next_to_fault ntf_in;
|
||||
static struct support_next_to_fault ntf_out;
|
||||
|
||||
/* This is used by test_one_record to construct the packet. */
|
||||
static const char packet_prefix[] =
|
||||
/* DNS response with one question, one answer record. */
|
||||
"AA\x81\x80\0\1\0\1\0\0\0\0"
|
||||
/* Question: www.example.org/IN/ANY. */
|
||||
"\3www\7example\3org\0\0\xff\0\1"
|
||||
/* Response: compression reference. */
|
||||
"\xc0\x0c";
|
||||
|
||||
/* Use ns_sprintrr to format a DNS record (starting with
|
||||
packet_prefix) of type RTYPE, with a record payload of RDATALEN
|
||||
bytes starting at RDATA. Check successful formatting against
|
||||
EXPECTED. Try various truncated input and output buffers to catch
|
||||
overreads and buffer overflows, using ntf_in and ntf_out above. */
|
||||
static void
|
||||
test_one_record (uint16_t rtype, const char *rdata, size_t rdatalen,
|
||||
const char *expected)
|
||||
{
|
||||
struct rr_header
|
||||
{
|
||||
uint16_t typ;
|
||||
uint16_t cls;
|
||||
uint32_t ttl;
|
||||
uint16_t rdatalen;
|
||||
uint16_t pad;
|
||||
} hdr =
|
||||
{
|
||||
.typ = htons (rtype),
|
||||
.cls = htons (ns_c_in),
|
||||
.ttl = htonl (86400), /* One day. */
|
||||
.rdatalen = htons (rdatalen),
|
||||
};
|
||||
enum { hdrlen = offsetof (struct rr_header, pad) };
|
||||
TEST_COMPARE (hdrlen, 10);
|
||||
|
||||
/* Construct the packet from packet_prefix, hdr, and rdata. */
|
||||
unsigned char packet[512];
|
||||
size_t packetlen;
|
||||
{
|
||||
struct alloc_buffer buf = alloc_buffer_create (packet, sizeof (packet));
|
||||
alloc_buffer_copy_bytes (&buf, packet_prefix, sizeof (packet_prefix) - 1);
|
||||
alloc_buffer_copy_bytes (&buf, &hdr, hdrlen);
|
||||
alloc_buffer_copy_bytes (&buf, rdata, rdatalen);
|
||||
packetlen = sizeof (packet) - alloc_buffer_size (&buf);
|
||||
}
|
||||
|
||||
/* Parse the record. */
|
||||
ns_msg msg;
|
||||
TEST_COMPARE (ns_initparse (packet, packetlen, &msg), 0);
|
||||
ns_rr rr;
|
||||
TEST_COMPARE (ns_parserr (&msg, ns_s_an, 0, &rr), 0);
|
||||
|
||||
/* Try sizes up to this limit. Go a bit beyond the expected size to
|
||||
check for errors. */
|
||||
size_t max_result_size = strlen (expected) + 16;
|
||||
|
||||
bool success = false;
|
||||
for (size_t result_size = 1; result_size <= max_result_size; ++result_size)
|
||||
{
|
||||
char *result_start = ntf_out.buffer + ntf_out.length - result_size;
|
||||
memset (result_start, 'X', result_size);
|
||||
|
||||
/* ns_sprintrr was deprecated in 2.34. */
|
||||
DIAG_PUSH_NEEDS_COMMENT;
|
||||
DIAG_IGNORE_NEEDS_COMMENT (4.9, "-Wdeprecated-declarations");
|
||||
int ret = ns_sprintrr (&msg, &rr, NULL, NULL, result_start, result_size);
|
||||
DIAG_POP_NEEDS_COMMENT;
|
||||
|
||||
if (ret > 0)
|
||||
{
|
||||
TEST_COMPARE_STRING (result_start, expected);
|
||||
TEST_COMPARE (ret, strlen (expected));
|
||||
success = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
TEST_VERIFY (!success);
|
||||
TEST_COMPARE (ret, -1);
|
||||
}
|
||||
}
|
||||
TEST_VERIFY (success);
|
||||
|
||||
/* Test with truncated RDATA. */
|
||||
for (size_t rdata_size = 0; rdata_size <= rdatalen; ++rdata_size)
|
||||
{
|
||||
size_t truncated_packet_size = packetlen - rdatalen + rdata_size;
|
||||
unsigned char *packet_start
|
||||
= ((unsigned char *) ntf_in.buffer + ntf_in.length
|
||||
- truncated_packet_size);
|
||||
memcpy (packet_start, packet, truncated_packet_size);
|
||||
/* Patch in the updated RDATA length field. */
|
||||
uint16_t new_rdatalen = htons (rdata_size);
|
||||
memcpy (packet_start + truncated_packet_size - rdata_size - 2,
|
||||
&new_rdatalen, 2);
|
||||
|
||||
ns_msg msg;
|
||||
TEST_COMPARE (ns_initparse (packet_start, truncated_packet_size, &msg),
|
||||
0);
|
||||
ns_rr rr;
|
||||
TEST_COMPARE (ns_parserr (&msg, ns_s_an, 0, &rr), 0);
|
||||
|
||||
size_t result_size = strlen (expected) + 1;
|
||||
char *result_start = ntf_out.buffer + ntf_out.length - result_size;
|
||||
memset (result_start, 'X', result_size);
|
||||
|
||||
/* ns_sprintrr was deprecated in 2.34. */
|
||||
DIAG_PUSH_NEEDS_COMMENT;
|
||||
DIAG_IGNORE_NEEDS_COMMENT (4.9, "-Wdeprecated-declarations");
|
||||
int ret = ns_sprintrr (&msg, &rr, NULL, NULL, result_start, result_size);
|
||||
DIAG_POP_NEEDS_COMMENT;
|
||||
|
||||
/* This flag indicates whether the output is syntactically
|
||||
correct. In some cases, truncation may still yield a valid
|
||||
payload. */
|
||||
bool broken = rdata_size < rdatalen;
|
||||
switch (rtype)
|
||||
{
|
||||
case ns_t_wks:
|
||||
/* WKS records use all trailing bytes for the port bitmap. */
|
||||
broken = rdata_size < 5;
|
||||
break;
|
||||
case ns_t_nsap:
|
||||
/* Uses all bytes that are available. */
|
||||
broken = false;
|
||||
break;
|
||||
case ns_t_txt:
|
||||
/* Truncation produces a valid payload if it occurs right
|
||||
after a complete string in the TXT payload. */
|
||||
broken = false;
|
||||
for (size_t pos = 0; pos < rdata_size; )
|
||||
{
|
||||
unsigned int slen = rdata[pos] & 0xff;
|
||||
if (pos + 1 + slen > rdata_size)
|
||||
{
|
||||
broken = true;
|
||||
break;
|
||||
}
|
||||
pos += 1 + slen;
|
||||
}
|
||||
break;
|
||||
case ns_t_isdn:
|
||||
/* The second field is optional. If it is present, it must
|
||||
not be truncated. */
|
||||
broken = rdata_size < 6 || (rdata_size > 6 && rdata_size < rdatalen);
|
||||
break;
|
||||
case ns_t_a6:
|
||||
/* The first A6 subtest contains a trailing domain name,
|
||||
which is ignored and not formatted. */
|
||||
if (rdata_size > 0 && rdata[0] == 0)
|
||||
broken = rdata_size < 17;
|
||||
break;
|
||||
case ns_t_cert:
|
||||
case ns_t_tkey:
|
||||
case ns_t_tsig:
|
||||
/* Only generic printing, which does not validate anything. */
|
||||
broken = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (broken)
|
||||
{
|
||||
if (strstr (result_start, "RR format error") != NULL)
|
||||
/* No further checks if an error indicator has been added
|
||||
to the output. */
|
||||
;
|
||||
else
|
||||
TEST_COMPARE (ret, -1);
|
||||
}
|
||||
else
|
||||
TEST_VERIFY (ret > 0);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
do_test (void)
|
||||
{
|
||||
ntf_in = support_next_to_fault_allocate (512);
|
||||
ntf_out = support_next_to_fault_allocate (256);
|
||||
|
||||
#define T(rtype, rdata, expected) \
|
||||
test_one_record (rtype, rdata, sizeof (rdata) - 1, expected)
|
||||
T (ns_t_a, "\xc0\0\2\1", "www.example.org.\t1D IN A\t\t192.0.2.1");
|
||||
T (ns_t_cname, "\4www1\4prod\xc0\x10",
|
||||
"www.example.org.\t1D IN CNAME\twww1.prod.example.org.");
|
||||
T (ns_t_hinfo, "\5first\6second",
|
||||
"www.example.org.\t1D IN HINFO\t\"first\" \"second\"");
|
||||
T (ns_t_isdn, "\5first\6second",
|
||||
"www.example.org.\t1D IN ISDN\t\"first\" \"second\"");
|
||||
/* Bug: Extra space at the end in the text representation of ISDN RRs. */
|
||||
T (ns_t_isdn, "\5first", "www.example.org.\t1D IN ISDN\t\"first\" ");
|
||||
T (ns_t_soa,
|
||||
"\2ns\xc0\x10\12hostmaster\xc0\x10"
|
||||
"\0\0\0\1\0\0\0\2\0\0\0\3\0\0\0\4\0\0\0\5",
|
||||
"www.example.org.\t1D IN SOA\tns.example.org. hostmaster.example.org. (\n"
|
||||
"\t\t\t\t\t1\t\t; serial\n"
|
||||
"\t\t\t\t\t2S\t\t; refresh\n"
|
||||
"\t\t\t\t\t3S\t\t; retry\n"
|
||||
"\t\t\t\t\t4S\t\t; expiry\n"
|
||||
"\t\t\t\t\t5S )\t\t; minimum\n");
|
||||
T (ns_t_mx, "\0\xa\2mx\xc0\x10",
|
||||
"www.example.org.\t1D IN MX\t10 mx.example.org.");
|
||||
T (ns_t_px, "\0\xa\3px1\xc0\x10\3px2\xc0\x10",
|
||||
"www.example.org.\t1D IN PX\t10 px1.example.org. px2.example.org.");
|
||||
T (ns_t_x25, "\4X.25",
|
||||
"www.example.org.\t1D IN X25\t\"X.25\"");
|
||||
T (ns_t_txt, "\1A\2BC\3DEF",
|
||||
"www.example.org.\t1D IN TXT\t\"A\" \"BC\" \"DEF\"");
|
||||
T (ns_t_nsap, "",
|
||||
"www.example.org.\t1D IN NSAP\t");
|
||||
T (ns_t_nsap, "\1",
|
||||
"www.example.org.\t1D IN NSAP\t01");
|
||||
T (ns_t_nsap, "\1\2",
|
||||
"www.example.org.\t1D IN NSAP\t01.02");
|
||||
T (ns_t_nsap, "\1\2\3",
|
||||
"www.example.org.\t1D IN NSAP\t01.0203");
|
||||
T (ns_t_nsap, "\1\2\3\4",
|
||||
"www.example.org.\t1D IN NSAP\t01.0203.04");
|
||||
T (ns_t_nsap,
|
||||
"\1\2\3\4\5\6\7\10\11\12\13\14\15\16\17\20\21\22\23\24\25\26\27\30\31\32"
|
||||
"\33\34\35\36\37\40\41\42\43\44\45\46\47\50\51\52\53\54\55\56\57\60\61"
|
||||
"\62\63\64\65\66\67\70\71\72\73\74\75\76\77\100\101\102\103\104\105\106"
|
||||
"\107\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127"
|
||||
"\130\131\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150"
|
||||
"\151\152\153\154\155\156\157\160\161\162\163\164\165\166\167\170\171"
|
||||
"\172\173\174\175\176\177\200\201\202\203\204\205\206\207\210\211\212"
|
||||
"\213\214\215\216\217\220\221\222\223\224\225\226\227\230\231\232\233"
|
||||
"\234\235\236\237\240\241\242\243\244\245\246\247\250\251\252\253\254"
|
||||
"\255\256\257\260\261\262\263\264\265\266\267\270\271\272\273\274\275"
|
||||
"\276\277\300\301\302\303\304\305\306\307\310\311\312\313\314\315\316"
|
||||
"\317\320\321\322\323\324\325\326\327\330\331\332\333\334\335\336\337"
|
||||
"\340\341\342\343\344\345\346\347\350\351\352\353\354\355\356\357\360"
|
||||
"\361\362\363\364\365\366\367\370\371\372\373\374\375\376\377",
|
||||
"www.example.org.\t1D IN NSAP\t"
|
||||
"01.0203.0405.0607.0809.0A0B.0C0D.0E0F.1011.1213.1415.1617.1819.1A1B"
|
||||
".1C1D.1E1F.2021.2223.2425.2627.2829.2A2B.2C2D.2E2F.3031.3233.3435.3637"
|
||||
".3839.3A3B.3C3D.3E3F.4041.4243.4445.4647.4849.4A4B.4C4D.4E4F.5051.5253"
|
||||
".5455.5657.5859.5A5B.5C5D.5E5F.6061.6263.6465.6667.6869.6A6B.6C6D.6E6F"
|
||||
".7071.7273.7475.7677.7879.7A7B.7C7D.7E7F.8081.8283.8485.8687.8889.8A8B"
|
||||
".8C8D.8E8F.9091.9293.9495.9697.9899.9A9B.9C9D.9E9F.A0A1.A2A3.A4A5.A6A7"
|
||||
".A8A9.AAAB.ACAD.AEAF.B0B1.B2B3.B4B5.B6B7.B8B9.BABB.BCBD.BEBF.C0C1.C2C3"
|
||||
".C4C5.C6C7.C8C9.CACB.CCCD.CECF.D0D1.D2D3.D4D5.D6D7.D8D9.DADB.DCDD.DEDF"
|
||||
".E0E1.E2E3.E4E5.E6E7.E8E9.EAEB.ECED.EEEF.F0F1.F2F3.F4F5.F6F7.F8F9.FAFB"
|
||||
".FCFD.FEFF");
|
||||
T (ns_t_aaaa, "\x20\x01\x0d\xb8\0\0\0\0\0\0\0\0\0\0\x12\x34",
|
||||
"www.example.org.\t1D IN AAAA\t2001:db8::1234");
|
||||
/* Example from RFC 1876. The loc_ntoa format is different from the
|
||||
official text representation. */
|
||||
T (ns_t_loc,
|
||||
"\000\063\026\023\211\027\055\320\160\276\025\360\000\230\215\040",
|
||||
"www.example.org.\t1D IN LOC"
|
||||
"\t42 21 54.000 N 71 06 18.000 W -24.00m 30.00m 10000.00m 10.00m");
|
||||
T (ns_t_naptr,
|
||||
"\0\1\0\2\5flags\7service\2.*\5naptr\xc0\x10",
|
||||
"www.example.org.\t1D IN NAPTR\t1 2 \"flags\" \"service\" \".*\""
|
||||
" naptr.example.org.");
|
||||
T (ns_t_srv,
|
||||
"\0\1\0\2\0\x50\4www1\xc0\x10",
|
||||
"www.example.org.\t1D IN SRV\t1 2 80 www1.example.org.");
|
||||
T (ns_t_rp, "\3rp1\xc0\x10\3rp2\xc0\x10",
|
||||
"www.example.org.\t1D IN RP\trp1.example.org. rp2.example.org.");
|
||||
T (ns_t_wks, "\xc0\0\2\1\6\0\0\0\0\0\0\0\0\0\0\200",
|
||||
"www.example.org.\t1D IN WKS\t192.0.2.1 6 ( \n\t\t\t\t80 )");
|
||||
T (ns_t_cert, "\0\1\x04\xd2\0blob",
|
||||
"www.example.org.\t1D IN CERT\t\\# 9 (\n"
|
||||
"\t00 01 04 d2 00 62 6c 6f 62 )\t\t\t; .....blob");
|
||||
T (ns_t_tkey, "\4algo\0\0\0\0\1\0\0\0\2\0\3\0\4"
|
||||
"\0\5\xa1\xa2\xa3\xa4\xa5\0\3\xb1\xb2\xb3",
|
||||
"www.example.org.\t1D IN TYPE249\t\\# 30 (\n"
|
||||
"\t04 61 6c 67 6f 00 00 00 00 01 00 00 00 02 00 03 ; .algo...........\n"
|
||||
"\t00 04 00 05 a1 a2 a3 a4 a5 00 03 b1 b2 b3 )\t; ..............");
|
||||
T (ns_t_tsig, "\4algo\0"
|
||||
"\0\20\xdd\xcd\x64\x10\xe9\x21\x34\x1a\x8e\xe0\xa1\x9a\x30\xfc\x3b\xd1"
|
||||
"\0\2\0\3\0\5other",
|
||||
"www.example.org.\t1D IN TSIG\t\\# 35 (\n"
|
||||
"\t04 61 6c 67 6f 00 00 10 dd cd 64 10 e9 21 34 1a ; .algo.....d..!4.\n"
|
||||
"\t8e e0 a1 9a 30 fc 3b d1 00 02 00 03 00 05 6f 74 ; ....0.;.......ot\n"
|
||||
"\t68 65 72 )\t\t\t\t\t; her");
|
||||
T (ns_t_a6,
|
||||
"\0\x20\x01\x0d\xb8\0\0\0\0\0\0\0\0\0\0\x12\x34\6prefix\xc0\x10",
|
||||
"www.example.org.\t1D IN A6\t0 2001:db8::1234");
|
||||
T (ns_t_a6,
|
||||
"\0\x20\x01\x0d\xb8\0\0\0\0\0\0\0\0\0\0\x12\x35",
|
||||
"www.example.org.\t1D IN A6\t0 2001:db8::1235");
|
||||
T (ns_t_a6, "\200\6prefix\xc0\x10",
|
||||
"www.example.org.\t1D IN A6\t128 prefix.example.org.");
|
||||
T (ns_t_a6, "\x20\0\0\0\0\0\0\0\0\0\0\x12\x36\6prefix\xc0\x10",
|
||||
"www.example.org.\t1D IN A6\t32 ::1236 prefix.example.org.");
|
||||
#undef T
|
||||
|
||||
support_next_to_fault_free (&ntf_in);
|
||||
support_next_to_fault_free (&ntf_out);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#include <support/test-driver.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>
|
||||
@@ -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>
|
||||
+1
-1
@@ -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);
|
||||
|
||||
@@ -349,6 +349,7 @@ tests := \
|
||||
tst-vfprintf-user-type \
|
||||
tst-vfprintf-width-i18n \
|
||||
tst-vfprintf-width-prec-alloc \
|
||||
tst-vfscanf-bz34008 \
|
||||
tst-wc-printf \
|
||||
tstdiomisc \
|
||||
tstgetln \
|
||||
@@ -564,6 +565,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
|
||||
|
||||
@@ -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>
|
||||
@@ -862,8 +862,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)
|
||||
@@ -936,7 +935,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));
|
||||
@@ -991,7 +990,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));
|
||||
|
||||
@@ -347,6 +347,7 @@ tests := \
|
||||
tst-stdc_leading_zeros \
|
||||
tst-stdc_trailing_ones \
|
||||
tst-stdc_trailing_zeros \
|
||||
tst-strfmon-bug34510 \
|
||||
tst-strfmon_l \
|
||||
tst-strfrom \
|
||||
tst-strfrom-locale \
|
||||
|
||||
+3
-2
@@ -549,7 +549,8 @@ __vstrfmon_l_buffer (struct __printf_buffer *buf, locale_t loc,
|
||||
/* Now test whether the output width is filled. */
|
||||
if (buf->write_ptr - startp < width)
|
||||
{
|
||||
size_t pad_width = width - (buf->write_ptr - startp);
|
||||
size_t written_width = buf->write_ptr - startp;
|
||||
size_t pad_width = width - written_width;
|
||||
__printf_buffer_pad (buf, ' ', pad_width);
|
||||
if (__printf_buffer_has_failed (buf))
|
||||
/* Implies length check. */
|
||||
@@ -558,7 +559,7 @@ __vstrfmon_l_buffer (struct __printf_buffer *buf, locale_t loc,
|
||||
Otherwise move the field contents in place. */
|
||||
if (!left)
|
||||
{
|
||||
memmove (startp + pad_width, startp, buf->write_ptr - startp);
|
||||
memmove (startp + pad_width, startp, written_width);
|
||||
memset (startp, ' ', pad_width);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
/* Test handling of right-padding in strfmon (bug 34510, CVE-2026-19499).
|
||||
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 <monetary.h>
|
||||
#include <errno.h>
|
||||
#include <support/check.h>
|
||||
#include <support/next_to_fault.h>
|
||||
|
||||
static int
|
||||
do_test (void)
|
||||
{
|
||||
struct support_next_to_fault ntf = support_next_to_fault_allocate (100);
|
||||
TEST_COMPARE (strfmon (ntf.buffer, ntf.length, "%100n", 1.23), -1);
|
||||
TEST_COMPARE (errno, E2BIG);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#include <support/test-driver.c>
|
||||
@@ -286,6 +286,7 @@ CFLAGS-wordcopy.c += $(no-stack-protector)
|
||||
# Called during static initialization
|
||||
CFLAGS-strncmp.c += $(no-stack-protector)
|
||||
CFLAGS-memset.c += $(no-stack-protector)
|
||||
CFLAGS-strlen.c += $(no-stack-protector)
|
||||
|
||||
ifeq ($(run-built-tests),yes)
|
||||
$(objpfx)tst-svc-cmp.out: tst-svc.expect $(objpfx)tst-svc.out
|
||||
|
||||
@@ -132,6 +132,12 @@ $(objpfx)tst-bti-permissive-transitive: $(objpfx)tst-bti-mod.so
|
||||
$(objpfx)tst-bti-ld-debug-shared: $(objpfx)tst-bti-mod.so
|
||||
$(objpfx)tst-bti-ld-debug-both: $(objpfx)tst-bti-mod-unprot.so
|
||||
|
||||
$(objpfx)tst-bti-dlopen-imm.out: $(objpfx)tst-bti-mod-unprot.so
|
||||
$(objpfx)tst-bti-dlopen-prot.out: $(objpfx)tst-bti-mod-prot.so
|
||||
$(objpfx)tst-bti-dlopen-transitive.out: $(objpfx)tst-bti-mod.so
|
||||
$(objpfx)tst-bti-ld-debug-dlopen.out: $(objpfx)tst-bti-mod-unprot.so
|
||||
$(objpfx)tst-bti-permissive-dlopen.out: $(objpfx)tst-bti-mod-unprot.so
|
||||
|
||||
$(objpfx)tst-bti-abort-unprot-preload.out: $(objpfx)tst-bti-mod-unprot-preload.so
|
||||
tst-bti-abort-unprot-preload-ENV = \
|
||||
GLIBC_TUNABLES=glibc.cpu.aarch64_bti=1 \
|
||||
|
||||
@@ -147,3 +147,9 @@ void _dl_gcs_enable_failed (int code)
|
||||
{
|
||||
_dl_fatal_printf ("failed to enable GCS: %d\n", -code);
|
||||
}
|
||||
|
||||
/* Used to report error when prctl system call to lock GCS fails. */
|
||||
void _dl_gcs_lock_failed (int code)
|
||||
{
|
||||
_dl_fatal_printf ("failed to lock GCS: %d\n", -code);
|
||||
}
|
||||
|
||||
@@ -35,12 +35,13 @@ ENTRY (_start)
|
||||
/* Use GL(dl_aarch64_gcs) to set the shadow stack status. */
|
||||
adrp x16, _rtld_local
|
||||
add x16, x16, :lo12:_rtld_local
|
||||
ldr x1, [x16, GL_DL_AARCH64_GCS_OFFSET]
|
||||
cbz x1, L(skip_gcs_enable)
|
||||
ldr x22, [x16, GL_DL_AARCH64_GCS_OFFSET]
|
||||
cbz x22, L(skip_gcs_enable)
|
||||
|
||||
/* Enable GCS before user code runs. Note that IFUNC resolvers and
|
||||
LD_AUDIT hooks may run before, but should not create threads. */
|
||||
#define PR_SET_SHADOW_STACK_STATUS 75
|
||||
#define PR_LOCK_SHADOW_STACK_STATUS 76
|
||||
#define PR_SHADOW_STACK_ENABLE (1UL << 0)
|
||||
mov x0, PR_SET_SHADOW_STACK_STATUS
|
||||
mov x1, PR_SHADOW_STACK_ENABLE
|
||||
@@ -50,6 +51,19 @@ ENTRY (_start)
|
||||
mov x8, #SYS_ify(prctl)
|
||||
svc 0x0
|
||||
cbnz w0, L(failed_gcs_enable)
|
||||
/* Check if we need to lock GCS features. */
|
||||
/* If the aarch64_gcs tunable is either 0 or 2 do not lock GCS. */
|
||||
tst x22, #-3
|
||||
beq L(skip_gcs_enable)
|
||||
mov x0, PR_LOCK_SHADOW_STACK_STATUS
|
||||
/* Lock everything including future operations. */
|
||||
mov x1, ~0
|
||||
mov x2, 0
|
||||
mov x3, 0
|
||||
mov x4, 0
|
||||
mov x8, #SYS_ify(prctl)
|
||||
svc 0x0
|
||||
cbnz w0, L(failed_gcs_lock)
|
||||
L(skip_gcs_enable):
|
||||
|
||||
.globl _dl_start_user
|
||||
@@ -75,4 +89,7 @@ _dl_start_user:
|
||||
L(failed_gcs_enable):
|
||||
b _dl_gcs_enable_failed
|
||||
|
||||
L(failed_gcs_lock):
|
||||
b _dl_gcs_lock_failed
|
||||
|
||||
END (_start)
|
||||
|
||||
@@ -20,5 +20,6 @@
|
||||
#define _DL_IFUNC_GENERIC_H
|
||||
|
||||
asm ("memset = __memset_generic");
|
||||
asm ("strlen = __strlen_generic");
|
||||
|
||||
#endif
|
||||
|
||||
@@ -40,3 +40,7 @@
|
||||
#endif
|
||||
|
||||
#include "../strlen.S"
|
||||
|
||||
#if IS_IN (rtld)
|
||||
strong_alias (strlen, __strlen_generic)
|
||||
#endif
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user