mirror of
git://sourceware.org/git/glibc.git
synced 2026-09-09 23:58:37 +08:00
Compare commits
161
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5dd252cf1d | ||
|
|
f806c45178 | ||
|
|
3d141c2389 | ||
|
|
ec116a0fbe | ||
|
|
e43e46f943 | ||
|
|
5256941bc8 | ||
|
|
6826bb0ed0 | ||
|
|
9318c25715 | ||
|
|
dfc8ef388e | ||
|
|
965b580070 | ||
|
|
ca40a19768 | ||
|
|
05e1eaea61 | ||
|
|
0e8c56b386 | ||
|
|
1c77f57252 | ||
|
|
6448c1174a | ||
|
|
2b789d4ca9 | ||
|
|
127d20da1c | ||
|
|
30164ba504 | ||
|
|
fc7a48bc9e | ||
|
|
1a74f82eed | ||
|
|
248f5e876f | ||
|
|
372a64662f | ||
|
|
b214eb550e | ||
|
|
8941538b92 | ||
|
|
b676adadbc | ||
|
|
df2d5e2361 | ||
|
|
61737f43b1 | ||
|
|
47c0cc364d | ||
|
|
c812169b57 | ||
|
|
502861645b | ||
|
|
dbd8335c8c | ||
|
|
81e8f4e08b | ||
|
|
61a5190ee5 | ||
|
|
e494d26262 | ||
|
|
8c00f7809b | ||
|
|
872728982d | ||
|
|
3136abefc5 | ||
|
|
16e03cec84 | ||
|
|
fb4db64a04 | ||
|
|
15c9839a0b | ||
|
|
1e2c1ea430 | ||
|
|
c96b4ed1e2 | ||
|
|
6b74a7c444 | ||
|
|
d07b87d766 | ||
|
|
473359f17a | ||
|
|
6bcdbc7dfd | ||
|
|
6a0b8e3665 | ||
|
|
f8cdc03e1e | ||
|
|
040256e79b | ||
|
|
5c6445672a | ||
|
|
1e16b570bb | ||
|
|
442cc3901b | ||
|
|
ca489fc802 | ||
|
|
360f60fb63 | ||
|
|
215e9155ea | ||
|
|
75b6b263e9 | ||
|
|
5bf8ee7ad5 | ||
|
|
e4ffcf32b9 | ||
|
|
889ae4bdbb | ||
|
|
1a0ee26714 | ||
|
|
97076e0cf1 | ||
|
|
1f57ffdf35 | ||
|
|
580746904b | ||
|
|
7c0632472d | ||
|
|
4b1f8c90f9 | ||
|
|
cf926cd7fb | ||
|
|
9867e44cdc | ||
|
|
a52c9b75c7 | ||
|
|
ed4672abb5 | ||
|
|
7aa907241c | ||
|
|
c1bec0b52d | ||
|
|
aa5dbd5332 | ||
|
|
42f9c70ac2 | ||
|
|
3f3b4fdd0b | ||
|
|
e2d9e9eb26 | ||
|
|
dd87fcda43 | ||
|
|
85780b6055 | ||
|
|
b05ce0de3d | ||
|
|
9d6577fdff | ||
|
|
4a3e5f1e4c | ||
|
|
940d821afb | ||
|
|
5d8614b284 | ||
|
|
f409ec073f | ||
|
|
330cd035df | ||
|
|
c467918138 | ||
|
|
6db0f659c8 | ||
|
|
503f7a7d33 | ||
|
|
307a8a4434 | ||
|
|
2a0b52fdd6 | ||
|
|
0bb6dad5af | ||
|
|
daa4de5253 | ||
|
|
1502c248d5 | ||
|
|
513629b14d | ||
|
|
f48de98bce | ||
|
|
62928cf7d8 | ||
|
|
373408c19f | ||
|
|
e7c419a295 | ||
|
|
1e16d0096d | ||
|
|
6e489c17f8 | ||
|
|
11e634ccf3 | ||
|
|
61e461ed0c | ||
|
|
0c76c95162 | ||
|
|
b48d7ab036 | ||
|
|
55cdcadf73 | ||
|
|
84bdbf8a6f | ||
|
|
d952c6efaa | ||
|
|
515d4166f4 | ||
|
|
899dd3ab2f | ||
|
|
624285af3b | ||
|
|
2ca34d7627 | ||
|
|
dab44a3b2b | ||
|
|
5cf17ebc65 | ||
|
|
5b4c461701 | ||
|
|
5cb575ca9a | ||
|
|
046b33800c | ||
|
|
a53e764657 | ||
|
|
aca31d2712 | ||
|
|
f68b407d4b | ||
|
|
d6d56af6e7 | ||
|
|
b861755a84 | ||
|
|
200d20123c | ||
|
|
80cd656649 | ||
|
|
a282e2c0ae | ||
|
|
bcd4cf9d5f | ||
|
|
7e72fa7577 | ||
|
|
6a3a4a5e58 | ||
|
|
ce9b765522 | ||
|
|
98c712855d | ||
|
|
e22c132484 | ||
|
|
33bfd9020f | ||
|
|
66fc3bd758 | ||
|
|
1a3083b999 | ||
|
|
91f8cff2c4 | ||
|
|
fd202462c5 | ||
|
|
746ef8e939 | ||
|
|
56609f8df1 | ||
|
|
89be78704e | ||
|
|
c47c3890f1 | ||
|
|
e0bc5f64ea | ||
|
|
009c5a2dca | ||
|
|
8d98ee8d70 | ||
|
|
61ba3cdfa9 | ||
|
|
fda5730898 | ||
|
|
6d1f97bb06 | ||
|
|
7774a9d07a | ||
|
|
2025e27a81 | ||
|
|
f3d9c116cb | ||
|
|
94859e8680 | ||
|
|
7c9a086807 | ||
|
|
30992cb5e9 | ||
|
|
07288c7445 | ||
|
|
2cb04444b9 | ||
|
|
a900dbaf70 | ||
|
|
1e0e33e1b1 | ||
|
|
69fda28279 | ||
|
|
cf88351b68 | ||
|
|
cb7f206537 | ||
|
|
d85a771953 | ||
|
|
bdccbfbc52 | ||
|
|
0a7c7a3e28 | ||
|
|
9f48a8abb2 |
@@ -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
|
||||
+1
-1
@@ -633,7 +633,7 @@ link-libc-printers-tests = $(link-libc-rpath) \
|
||||
$(link-libc-tests-after-rpath-link)
|
||||
|
||||
# This is how to find at build-time things that will be installed there.
|
||||
rpath-dirs = math elf dlfcn nss nis rt resolv mathvec support
|
||||
rpath-dirs = math elf dlfcn nss nis rt resolv mathvec support misc
|
||||
rpath-link = \
|
||||
$(common-objdir):$(subst $(empty) ,:,$(patsubst ../$(subdir),.,$(rpath-dirs:%=$(common-objpfx)%)))
|
||||
else # build-static
|
||||
|
||||
@@ -5,6 +5,47 @@ 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.41.1
|
||||
|
||||
Deprecated and removed features, and other changes affecting compatibility:
|
||||
|
||||
* The glibc.rtld.execstack now supports a compatibility mode to allow
|
||||
programs that require an executable stack through dynamic loaded
|
||||
shared libraries.
|
||||
|
||||
The following bugs were resolved with this release:
|
||||
|
||||
[19341] ctype: Fallback initialization of TLS using relocations
|
||||
[29190] Fix handling of symbol versions which hash to zero
|
||||
[31943] _dl_find_object can fail if ld.so contains gaps between load segments
|
||||
[32483] ctype macros segfault in multithreaded programs with multiple libc.so
|
||||
[32269] RISC-V IFUNC resolver cannot access gp pointer
|
||||
[32626] math: math: log10p1f is not correctly rounded
|
||||
[32627] math: math: sinhf is not correctly rounded
|
||||
[32630] math: math: tanf is not correctly rounded for all rounding
|
||||
modes
|
||||
[32653] dynamic-link: Review options for improving both security and
|
||||
backwards compatibility of glibc 2.41 dlopen / execstack handling
|
||||
[32781] Linux: Remove attribute access from sched_getattr
|
||||
[32782] nptl: Race conditions in pthread cancellation causing crash
|
||||
[32786] nptl: PTHREAD_COND_INITIALIZER compatibility with pre-2.41 versions
|
||||
[32810] Crash on x86-64 if XSAVEC disable via tunable
|
||||
[32882] tst-audit10 fails with SIGILL on CPUs without AVX
|
||||
[32897] dynamic-link: pthread_getattr_np fails when executable stack
|
||||
tunable is set
|
||||
[32981] ports: elf/tst-execstack-prog-static-tunable fails on
|
||||
sparc64-linux-gnu
|
||||
[32987] elf: Fix subprocess status handling for tst-dlopen-sgid
|
||||
[32994] stdlib: resolve a double lock init issue after fork
|
||||
[33164] iconv -o should not create executable files
|
||||
[33185] Fix double-free after allocation failure in regcomp
|
||||
[33234] Use TLS initial-exec model for __libc_tsd_CTYPE_* thread variables
|
||||
[33245] nptl: nptl: error in internal cancellation syscall handling
|
||||
[33361] nss: Group merge does not react to ERANGE during merge
|
||||
[33601] aarch64: Do not link conform tests with -Wl,-z,force-bti
|
||||
[33814] glob: wordexp with WRDE_REUSE and WRDE_APPEND may return
|
||||
uninitialized memory
|
||||
|
||||
Version 2.41
|
||||
|
||||
Major new features:
|
||||
|
||||
@@ -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,25 +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: 7d4b6bcae91f29d7b4daf15bab06b66cf1d2217c (2.40-66)
|
||||
Reported-By: Qualys Security Advisory
|
||||
@@ -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.
|
||||
@@ -39,6 +39,7 @@ tests := \
|
||||
test-assert-perr \
|
||||
tst-assert-c++ \
|
||||
tst-assert-g++ \
|
||||
tst-assert-sa-2025-0001 \
|
||||
# tests
|
||||
|
||||
ifeq ($(have-cxx-thread_local),yes)
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
/* Test for CVE-2025-0395.
|
||||
Copyright 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/>. */
|
||||
|
||||
/* Test that a large enough __progname does not result in a buffer overflow
|
||||
when printing an assertion failure. This was CVE-2025-0395. */
|
||||
#include <assert.h>
|
||||
#include <inttypes.h>
|
||||
#include <signal.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <sys/mman.h>
|
||||
#include <support/check.h>
|
||||
#include <support/support.h>
|
||||
#include <support/xstdio.h>
|
||||
#include <support/xunistd.h>
|
||||
|
||||
extern const char *__progname;
|
||||
|
||||
int
|
||||
do_test (int argc, char **argv)
|
||||
{
|
||||
|
||||
support_need_proc ("Reads /proc/self/maps to add guards to writable maps.");
|
||||
ignore_stderr ();
|
||||
|
||||
/* XXX assumes that the assert is on a 2 digit line number. */
|
||||
const char *prompt = ": %s:99: do_test: Assertion `argc < 1' failed.\n";
|
||||
|
||||
int ret = fprintf (stderr, prompt, __FILE__);
|
||||
if (ret < 0)
|
||||
FAIL_EXIT1 ("fprintf failed: %m\n");
|
||||
|
||||
size_t pagesize = getpagesize ();
|
||||
size_t namesize = pagesize - 1 - ret;
|
||||
|
||||
/* Alter the progname so that the assert message fills the entire page. */
|
||||
char progname[namesize];
|
||||
memset (progname, 'A', namesize - 1);
|
||||
progname[namesize - 1] = '\0';
|
||||
__progname = progname;
|
||||
|
||||
FILE *f = xfopen ("/proc/self/maps", "r");
|
||||
char *line = NULL;
|
||||
size_t len = 0;
|
||||
uintptr_t prev_to = 0;
|
||||
|
||||
/* Pad the beginning of every writable mapping with a PROT_NONE map. This
|
||||
ensures that the mmap in the assert_fail path never ends up below a
|
||||
writable map and will terminate immediately in case of a buffer
|
||||
overflow. */
|
||||
while (xgetline (&line, &len, f))
|
||||
{
|
||||
uintptr_t from, to;
|
||||
char perm[4];
|
||||
|
||||
sscanf (line, "%" SCNxPTR "-%" SCNxPTR " %c%c%c%c ",
|
||||
&from, &to,
|
||||
&perm[0], &perm[1], &perm[2], &perm[3]);
|
||||
|
||||
bool writable = (memchr (perm, 'w', 4) != NULL);
|
||||
|
||||
if (prev_to != 0 && from - prev_to > pagesize && writable)
|
||||
xmmap ((void *) from - pagesize, pagesize, PROT_NONE,
|
||||
MAP_ANONYMOUS | MAP_PRIVATE, 0);
|
||||
|
||||
prev_to = to;
|
||||
}
|
||||
|
||||
xfclose (f);
|
||||
|
||||
assert (argc < 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define EXPECTED_SIGNAL SIGABRT
|
||||
#define TEST_FUNCTION_ARGV do_test
|
||||
#include <support/test-driver.c>
|
||||
@@ -1,6 +1,7 @@
|
||||
## args: double
|
||||
## ret: double
|
||||
## includes: math.h
|
||||
## name: workload-random
|
||||
0x1.5a2730bacd94ap-1
|
||||
-0x1.b57eb40fc048ep-21
|
||||
-0x1.c0b185fb450e2p-17
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
## args: double
|
||||
## ret: double
|
||||
## includes: math.h
|
||||
## name: workload-random
|
||||
0x1.bcb6129b5ff2bp8
|
||||
-0x1.63057386325ebp9
|
||||
0x1.62f1d7dc4e8bfp9
|
||||
|
||||
@@ -53,6 +53,7 @@ c++-bits-std_abs-h = @CXX_BITS_STD_ABS_H@
|
||||
enable-werror = @enable_werror@
|
||||
|
||||
have-z-execstack = @libc_cv_z_execstack@
|
||||
have-no-error-execstack = @libc_cv_no_error_execstack@
|
||||
have-protected-data = @libc_cv_protected_data@
|
||||
have-insert = @libc_cv_insert@
|
||||
have-glob-dat-reloc = @libc_cv_has_glob_dat@
|
||||
|
||||
@@ -659,6 +659,7 @@ libc_cv_has_glob_dat
|
||||
libc_cv_fpie
|
||||
libc_cv_test_static_pie
|
||||
libc_cv_z_execstack
|
||||
libc_cv_no_error_execstack
|
||||
ASFLAGS_config
|
||||
libc_cv_cc_with_libunwind
|
||||
libc_cv_insert
|
||||
@@ -4928,6 +4929,9 @@ with_fp_cond=1
|
||||
# A preconfigure script may define another name to TLS descriptor variant
|
||||
mtls_descriptor=gnu2
|
||||
|
||||
# A preconfigure script may define another name to traditional TLS variant
|
||||
mtls_traditional=gnu
|
||||
|
||||
if frags=`ls -d $srcdir/sysdeps/*/preconfigure 2> /dev/null`
|
||||
then
|
||||
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for sysdeps preconfigure fragments" >&5
|
||||
@@ -7114,6 +7118,40 @@ if test $libc_cv_as_noexecstack = yes; then
|
||||
fi
|
||||
|
||||
|
||||
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for linker that supports --no-error-execstack" >&5
|
||||
printf %s "checking for linker that supports --no-error-execstack... " >&6; }
|
||||
libc_linker_feature=no
|
||||
cat > conftest.c <<EOF
|
||||
int _start (void) { return 42; }
|
||||
EOF
|
||||
if { ac_try='${CC-cc} $CFLAGS $CPPFLAGS $LDFLAGS $no_ssp
|
||||
-Wl,--no-error-execstack -nostdlib -nostartfiles
|
||||
-fPIC -shared -o conftest.so conftest.c
|
||||
1>&5'
|
||||
{ { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
|
||||
(eval $ac_try) 2>&5
|
||||
ac_status=$?
|
||||
printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
|
||||
test $ac_status = 0; }; }
|
||||
then
|
||||
if ${CC-cc} $CFLAGS $CPPFLAGS $LDFLAGS $no_ssp -Wl,--no-error-execstack -nostdlib \
|
||||
-nostartfiles -fPIC -shared -o conftest.so conftest.c 2>&1 \
|
||||
| grep "warning: --no-error-execstack ignored" > /dev/null 2>&1; then
|
||||
true
|
||||
else
|
||||
libc_linker_feature=yes
|
||||
fi
|
||||
fi
|
||||
rm -f conftest*
|
||||
if test $libc_linker_feature = yes; then
|
||||
libc_cv_no_error_execstack=yes
|
||||
else
|
||||
libc_cv_no_error_execstack=no
|
||||
fi
|
||||
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $libc_linker_feature" >&5
|
||||
printf "%s\n" "$libc_linker_feature" >&6; }
|
||||
|
||||
|
||||
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for linker that supports -z execstack" >&5
|
||||
printf %s "checking for linker that supports -z execstack... " >&6; }
|
||||
libc_linker_feature=no
|
||||
@@ -7452,6 +7490,41 @@ rm -f conftest*
|
||||
config_vars="$config_vars
|
||||
have-test-mtls-descriptor = $libc_cv_test_mtls_descriptor"
|
||||
|
||||
|
||||
cat > conftest.c <<EOF
|
||||
$conftest_code
|
||||
EOF
|
||||
|
||||
saved_CC="$CC"
|
||||
CC="$TEST_CC"
|
||||
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for traditional tls support in testing" >&5
|
||||
printf %s "checking for traditional tls support in testing... " >&6; }
|
||||
if test ${libc_cv_test_mtls_traditional+y}
|
||||
then :
|
||||
printf %s "(cached) " >&6
|
||||
else case e in #(
|
||||
e) if { ac_try='${CC-cc} $CFLAGS $CPPFLAGS -fPIC -mtls-dialect=$mtls_traditional -nostdlib -nostartfiles -shared conftest.c -o conftest 1>&5'
|
||||
{ { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
|
||||
(eval $ac_try) 2>&5
|
||||
ac_status=$?
|
||||
printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
|
||||
test $ac_status = 0; }; }
|
||||
then
|
||||
libc_cv_test_mtls_traditional=$mtls_traditional
|
||||
else
|
||||
libc_cv_test_mtls_traditional=no
|
||||
fi ;;
|
||||
esac
|
||||
fi
|
||||
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $libc_cv_test_mtls_traditional" >&5
|
||||
printf "%s\n" "$libc_cv_test_mtls_traditional" >&6; }
|
||||
|
||||
CC="$saved_CC"
|
||||
|
||||
rm -f conftest*
|
||||
config_vars="$config_vars
|
||||
have-test-mtls-traditional = $libc_cv_test_mtls_traditional"
|
||||
|
||||
conftest_code="
|
||||
void __foo (void)
|
||||
{
|
||||
@@ -8643,6 +8716,35 @@ if test $libc_cv_builtin_trap = yes; then
|
||||
|
||||
fi
|
||||
|
||||
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports __attribute__ ((aligned (65536)))" >&5
|
||||
printf %s "checking whether the compiler supports __attribute__ ((aligned (65536)))... " >&6; }
|
||||
if test ${libc_cv_aligned_65536+y}
|
||||
then :
|
||||
printf %s "(cached) " >&6
|
||||
else case e in #(
|
||||
e)
|
||||
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
||||
/* end confdefs.h. */
|
||||
|
||||
char bss0xb5dce8 __attribute__ ((aligned (65536)));
|
||||
|
||||
_ACEOF
|
||||
if ac_fn_c_try_compile "$LINENO"
|
||||
then :
|
||||
libc_cv_aligned_65536=yes
|
||||
else case e in #(
|
||||
e) libc_cv_aligned_65536=no ;;
|
||||
esac
|
||||
fi
|
||||
rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $libc_cv_aligned_65536" >&5
|
||||
printf "%s\n" "$libc_cv_aligned_65536" >&6; }
|
||||
config_vars="$config_vars
|
||||
aligned-65536 = $libc_cv_aligned_65536"
|
||||
|
||||
ac_ext=cpp
|
||||
ac_cpp='$CXXCPP $CPPFLAGS'
|
||||
ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
|
||||
@@ -8908,6 +9010,104 @@ printf "%s\n" "$libc_linker_feature" >&6; }
|
||||
config_vars="$config_vars
|
||||
load-address-ldflag = $libc_cv_load_address_ldflag"
|
||||
|
||||
# Check if compilers support GCS in branch protection:
|
||||
|
||||
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if compiler supports -mbranch-protection=gcs" >&5
|
||||
printf %s "checking if compiler supports -mbranch-protection=gcs... " >&6; }
|
||||
if test ${libc_cv_cc_gcs+y}
|
||||
then :
|
||||
printf %s "(cached) " >&6
|
||||
else case e in #(
|
||||
e) if { ac_try='${CC-cc} -Werror -mbranch-protection=gcs -xc /dev/null -S -o /dev/null'
|
||||
{ { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
|
||||
(eval $ac_try) 2>&5
|
||||
ac_status=$?
|
||||
printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
|
||||
test $ac_status = 0; }; }
|
||||
then :
|
||||
libc_cv_cc_gcs=yes
|
||||
else case e in #(
|
||||
e) libc_cv_cc_gcs=no ;;
|
||||
esac
|
||||
fi ;;
|
||||
esac
|
||||
fi
|
||||
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $libc_cv_cc_gcs" >&5
|
||||
printf "%s\n" "$libc_cv_cc_gcs" >&6; }
|
||||
if test "$TEST_CC" = "$CC"; then
|
||||
libc_cv_test_cc_gcs=$libc_cv_cc_gcs
|
||||
else
|
||||
|
||||
saved_CC="$CC"
|
||||
CC="$TEST_CC"
|
||||
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if compiler supports -mbranch-protection=gcs in testing" >&5
|
||||
printf %s "checking if compiler supports -mbranch-protection=gcs in testing... " >&6; }
|
||||
if test ${libc_cv_test_cc_gcs+y}
|
||||
then :
|
||||
printf %s "(cached) " >&6
|
||||
else case e in #(
|
||||
e) if { ac_try='${CC-cc} -Werror -mbranch-protection=gcs -xc /dev/null -S -o /dev/null'
|
||||
{ { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
|
||||
(eval $ac_try) 2>&5
|
||||
ac_status=$?
|
||||
printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
|
||||
test $ac_status = 0; }; }
|
||||
then :
|
||||
libc_cv_test_cc_gcs=yes
|
||||
else case e in #(
|
||||
e) libc_cv_test_cc_gcs=no ;;
|
||||
esac
|
||||
fi ;;
|
||||
esac
|
||||
fi
|
||||
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $libc_cv_test_cc_gcs" >&5
|
||||
printf "%s\n" "$libc_cv_test_cc_gcs" >&6; }
|
||||
|
||||
CC="$saved_CC"
|
||||
|
||||
fi
|
||||
|
||||
config_vars="$config_vars
|
||||
have-cc-gcs = $libc_cv_cc_gcs"
|
||||
config_vars="$config_vars
|
||||
have-test-cc-gcs = $libc_cv_test_cc_gcs"
|
||||
|
||||
# Check if linker supports GCS marking
|
||||
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for linker that supports -z gcs=always" >&5
|
||||
printf %s "checking for linker that supports -z gcs=always... " >&6; }
|
||||
libc_linker_feature=no
|
||||
cat > conftest.c <<EOF
|
||||
int _start (void) { return 42; }
|
||||
EOF
|
||||
if { ac_try='${CC-cc} $CFLAGS $CPPFLAGS $LDFLAGS $no_ssp
|
||||
-Wl,-z,gcs=always -nostdlib -nostartfiles
|
||||
-fPIC -shared -o conftest.so conftest.c
|
||||
1>&5'
|
||||
{ { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
|
||||
(eval $ac_try) 2>&5
|
||||
ac_status=$?
|
||||
printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
|
||||
test $ac_status = 0; }; }
|
||||
then
|
||||
if ${CC-cc} $CFLAGS $CPPFLAGS $LDFLAGS $no_ssp -Wl,-z,gcs=always -nostdlib \
|
||||
-nostartfiles -fPIC -shared -o conftest.so conftest.c 2>&1 \
|
||||
| grep "warning: -z gcs=always ignored" > /dev/null 2>&1; then
|
||||
true
|
||||
else
|
||||
libc_linker_feature=yes
|
||||
fi
|
||||
fi
|
||||
rm -f conftest*
|
||||
if test $libc_linker_feature = yes; then
|
||||
libc_cv_ld_gcs=yes
|
||||
else
|
||||
libc_cv_ld_gcs=no
|
||||
fi
|
||||
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $libc_linker_feature" >&5
|
||||
printf "%s\n" "$libc_linker_feature" >&6; }
|
||||
config_vars="$config_vars
|
||||
have-ld-gcs = $libc_cv_ld_gcs"
|
||||
|
||||
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if we can build programs as PIE" >&5
|
||||
printf %s "checking if we can build programs as PIE... " >&6; }
|
||||
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
||||
|
||||
@@ -483,6 +483,9 @@ with_fp_cond=1
|
||||
# A preconfigure script may define another name to TLS descriptor variant
|
||||
mtls_descriptor=gnu2
|
||||
|
||||
# A preconfigure script may define another name to traditional TLS variant
|
||||
mtls_traditional=gnu
|
||||
|
||||
dnl Let sysdeps/*/preconfigure act here.
|
||||
LIBC_PRECONFIGURE([$srcdir], [for sysdeps])
|
||||
|
||||
@@ -1318,6 +1321,10 @@ if test $libc_cv_as_noexecstack = yes; then
|
||||
fi
|
||||
AC_SUBST(ASFLAGS_config)
|
||||
|
||||
LIBC_LINKER_FEATURE([--no-error-execstack], [-Wl,--no-error-execstack],
|
||||
[libc_cv_no_error_execstack=yes], [libc_cv_no_error_execstack=no])
|
||||
AC_SUBST(libc_cv_no_error_execstack)
|
||||
|
||||
LIBC_LINKER_FEATURE([-z execstack], [-Wl,-z,execstack],
|
||||
[libc_cv_z_execstack=yes], [libc_cv_z_execstack=no])
|
||||
AC_SUBST(libc_cv_z_execstack)
|
||||
@@ -1396,6 +1403,16 @@ LIBC_TRY_TEST_CC_COMMAND([for tls descriptor support],
|
||||
LIBC_CONFIG_VAR([have-test-mtls-descriptor],
|
||||
[$libc_cv_test_mtls_descriptor])
|
||||
|
||||
dnl Check if TEST_CC support traditional tls.
|
||||
LIBC_TRY_TEST_CC_COMMAND([for traditional tls support],
|
||||
[$conftest_code],
|
||||
[-fPIC -mtls-dialect=$mtls_traditional -nostdlib -nostartfiles -shared],
|
||||
libc_cv_test_mtls_traditional,
|
||||
[libc_cv_test_mtls_traditional=$mtls_traditional],
|
||||
[libc_cv_test_mtls_traditional=no])
|
||||
LIBC_CONFIG_VAR([have-test-mtls-traditional],
|
||||
[$libc_cv_test_mtls_traditional])
|
||||
|
||||
dnl clang emits an warning for a double alias redirection, to warn the
|
||||
dnl original symbol is sed even when weak definition overrides it.
|
||||
dnl It is a usual pattern for weak_alias, where multiple alias point to
|
||||
@@ -1820,6 +1837,17 @@ if test $libc_cv_builtin_trap = yes; then
|
||||
AC_DEFINE([HAVE_BUILTIN_TRAP])
|
||||
fi
|
||||
|
||||
dnl Check if
|
||||
AC_CACHE_CHECK([whether the compiler supports __attribute__ ((aligned (65536)))],
|
||||
libc_cv_aligned_65536, [
|
||||
AC_COMPILE_IFELSE([AC_LANG_SOURCE([
|
||||
char bss[0xb5dce8] __attribute__ ((aligned (65536)));
|
||||
])],
|
||||
[libc_cv_aligned_65536=yes],
|
||||
[libc_cv_aligned_65536=no])
|
||||
])
|
||||
LIBC_CONFIG_VAR([aligned-65536], [$libc_cv_aligned_65536])
|
||||
|
||||
dnl C++ feature tests.
|
||||
AC_LANG_PUSH([C++])
|
||||
|
||||
@@ -1992,6 +2020,23 @@ LIBC_LINKER_FEATURE([-Ttext-segment=$libc_cv_pde_load_address],
|
||||
[libc_cv_load_address_ldflag=])
|
||||
LIBC_CONFIG_VAR([load-address-ldflag], [$libc_cv_load_address_ldflag])
|
||||
|
||||
# Check if compilers support GCS in branch protection:
|
||||
LIBC_TRY_CC_AND_TEST_CC_OPTION([if compiler supports -mbranch-protection=gcs],
|
||||
[-Werror -mbranch-protection=gcs],
|
||||
libc_cv_cc_gcs,
|
||||
[libc_cv_cc_gcs=yes],
|
||||
[libc_cv_cc_gcs=no],
|
||||
libc_cv_test_cc_gcs,
|
||||
[libc_cv_test_cc_gcs=yes],
|
||||
[libc_cv_test_cc_gcs=no])
|
||||
LIBC_CONFIG_VAR([have-cc-gcs], [$libc_cv_cc_gcs])
|
||||
LIBC_CONFIG_VAR([have-test-cc-gcs], [$libc_cv_test_cc_gcs])
|
||||
|
||||
# Check if linker supports GCS marking
|
||||
LIBC_LINKER_FEATURE([-z gcs=always], [-Wl,-z,gcs=always],
|
||||
[libc_cv_ld_gcs=yes], [libc_cv_ld_gcs=no])
|
||||
LIBC_CONFIG_VAR([have-ld-gcs], [$libc_cv_ld_gcs])
|
||||
|
||||
AC_MSG_CHECKING(if we can build programs as PIE)
|
||||
AC_COMPILE_IFELSE([AC_LANG_SOURCE([[#ifdef PIE_UNSUPPORTED
|
||||
# error PIE is not supported
|
||||
|
||||
@@ -36,6 +36,23 @@ aux := ctype-info
|
||||
|
||||
tests := \
|
||||
test_ctype \
|
||||
tst-ctype-tls-dlmopen \
|
||||
tst-ctype-tls-dlopen-static \
|
||||
# tests
|
||||
|
||||
tests-static := \
|
||||
tst-ctype-tls-dlopen-static \
|
||||
# tests-static
|
||||
|
||||
modules-names := \
|
||||
tst-ctype-tls-mod \
|
||||
# modules-names
|
||||
|
||||
include ../Rules
|
||||
|
||||
$(objpfx)tst-ctype-tls-dlmopen: $(shared-thread-library)
|
||||
$(objpfx)tst-ctype-tls-dlmopen.out: $(objpfx)tst-ctype-tls-mod.so
|
||||
$(objpfx)tst-ctype-tls-dlopen-static: $(static-thread-library)
|
||||
$(objpfx)tst-ctype-tls-dlopen-static.out: $(objpfx)tst-ctype-tls-mod.so
|
||||
tst-ctype-tls-dlopen-static-ENV = \
|
||||
LD_LIBRARY_PATH=$(ld-library-path):$(common-objpfx):$(common-objpfx)elf
|
||||
|
||||
+17
-12
@@ -19,20 +19,28 @@
|
||||
#include <ctype.h>
|
||||
#include <locale/localeinfo.h>
|
||||
|
||||
__libc_tsd_define (, const uint16_t *, CTYPE_B)
|
||||
__libc_tsd_define (, const int32_t *, CTYPE_TOLOWER)
|
||||
__libc_tsd_define (, const int32_t *, CTYPE_TOUPPER)
|
||||
/* Fallback initialization using relocations. See the _nl_C_locobj
|
||||
initializers in locale/xlocale.c. Usually, this is overwritten by
|
||||
__ctype_init before user code runs, but this does not happen for
|
||||
threads in secondary namespaces. With the initializers, secondary
|
||||
namespaces at least get locale data from the C locale. */
|
||||
__thread const uint16_t * __libc_tsd_CTYPE_B attribute_tls_model_ie
|
||||
= (const uint16_t *) _nl_C_LC_CTYPE_class + 128;
|
||||
__thread const int32_t * __libc_tsd_CTYPE_TOLOWER attribute_tls_model_ie
|
||||
= (const int32_t *) _nl_C_LC_CTYPE_tolower + 128;
|
||||
__thread const int32_t * __libc_tsd_CTYPE_TOUPPER attribute_tls_model_ie
|
||||
= (const int32_t *) _nl_C_LC_CTYPE_toupper + 128;
|
||||
|
||||
|
||||
void
|
||||
__ctype_init (void)
|
||||
{
|
||||
const uint16_t **bp = __libc_tsd_address (const uint16_t *, CTYPE_B);
|
||||
*bp = (const uint16_t *) _NL_CURRENT (LC_CTYPE, _NL_CTYPE_CLASS) + 128;
|
||||
const int32_t **up = __libc_tsd_address (const int32_t *, CTYPE_TOUPPER);
|
||||
*up = ((int32_t *) _NL_CURRENT (LC_CTYPE, _NL_CTYPE_TOUPPER) + 128);
|
||||
const int32_t **lp = __libc_tsd_address (const int32_t *, CTYPE_TOLOWER);
|
||||
*lp = ((int32_t *) _NL_CURRENT (LC_CTYPE, _NL_CTYPE_TOLOWER) + 128);
|
||||
__libc_tsd_CTYPE_B
|
||||
= ((const uint16_t *) _NL_CURRENT (LC_CTYPE, _NL_CTYPE_CLASS)) + 128;
|
||||
__libc_tsd_CTYPE_TOUPPER
|
||||
= ((const int32_t *) _NL_CURRENT (LC_CTYPE, _NL_CTYPE_TOUPPER)) + 128;
|
||||
__libc_tsd_CTYPE_TOLOWER =
|
||||
((const int32_t *) _NL_CURRENT (LC_CTYPE, _NL_CTYPE_TOLOWER)) + 128;
|
||||
}
|
||||
libc_hidden_def (__ctype_init)
|
||||
|
||||
@@ -41,10 +49,7 @@ libc_hidden_def (__ctype_init)
|
||||
#if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_3)
|
||||
|
||||
/* Defined in locale/C-ctype.c. */
|
||||
extern const char _nl_C_LC_CTYPE_class[] attribute_hidden;
|
||||
extern const char _nl_C_LC_CTYPE_class32[] attribute_hidden;
|
||||
extern const char _nl_C_LC_CTYPE_toupper[] attribute_hidden;
|
||||
extern const char _nl_C_LC_CTYPE_tolower[] attribute_hidden;
|
||||
extern const char _nl_C_LC_CTYPE_class_upper[] attribute_hidden;
|
||||
extern const char _nl_C_LC_CTYPE_class_lower[] attribute_hidden;
|
||||
extern const char _nl_C_LC_CTYPE_class_alpha[] attribute_hidden;
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
#define DO_STATIC_TEST 0
|
||||
#include "tst-ctype-tls-skeleton.c"
|
||||
@@ -0,0 +1,2 @@
|
||||
#define DO_STATIC_TEST 1
|
||||
#include "tst-ctype-tls-skeleton.c"
|
||||
@@ -1,5 +1,5 @@
|
||||
/* Optimized memchr implementation for POWER10/PPC64.
|
||||
Copyright (C) 2016-2025 Free Software Foundation, Inc.
|
||||
/* Wrappers for <ctype.h> macros in a secondary namespace.
|
||||
Copyright (C) 2025 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
@@ -16,13 +16,22 @@
|
||||
License along with the GNU C Library; if not, see
|
||||
<https://www.gnu.org/licenses/>. */
|
||||
|
||||
#if defined __LITTLE_ENDIAN__ && IS_IN (libc)
|
||||
#define MEMCHR __memchr_power10
|
||||
#include <ctype.h>
|
||||
|
||||
#undef libc_hidden_builtin_def
|
||||
#define libc_hidden_builtin_def(name)
|
||||
#undef weak_alias
|
||||
#define weak_alias(name,alias)
|
||||
int
|
||||
my_isalpha (int ch)
|
||||
{
|
||||
return isalpha (ch);
|
||||
}
|
||||
|
||||
#include <sysdeps/powerpc/powerpc64/le/power10/memchr.S>
|
||||
#endif
|
||||
int
|
||||
my_toupper (int ch)
|
||||
{
|
||||
return toupper (ch);
|
||||
}
|
||||
|
||||
int
|
||||
my_tolower (int ch)
|
||||
{
|
||||
return tolower (ch);
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
/* Test that <ctype.h> in a secondary namespace works.
|
||||
Copyright (C) 2025 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the GNU C Library; if not, see
|
||||
<https://www.gnu.org/licenses/>. */
|
||||
|
||||
/* Before this file is included, define DO_STATIC_TEST to 0 or 1.
|
||||
With 0, dlmopen is used for the test. With 1, dlopen is used. */
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <support/check.h>
|
||||
#include <support/support.h>
|
||||
#include <support/xdlfcn.h>
|
||||
#include <support/xthread.h>
|
||||
|
||||
static int (*my_isalpha) (int);
|
||||
static int (*my_toupper) (int);
|
||||
static int (*my_tolower) (int);
|
||||
|
||||
static void *
|
||||
checks (void *ignore)
|
||||
{
|
||||
TEST_VERIFY (my_isalpha ('a'));
|
||||
TEST_VERIFY (!my_isalpha ('0'));
|
||||
TEST_COMPARE (my_toupper ('a'), 'A');
|
||||
TEST_COMPARE (my_toupper ('A'), 'A');
|
||||
TEST_COMPARE (my_tolower ('a'), 'a');
|
||||
TEST_COMPARE (my_tolower ('A'), 'a');
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int
|
||||
do_test (void)
|
||||
{
|
||||
char *dso = xasprintf ("%s/ctype/tst-ctype-tls-mod.so", support_objdir_root);
|
||||
#if DO_STATIC_TEST
|
||||
void *handle = xdlopen (dso, RTLD_LAZY);
|
||||
#else
|
||||
void *handle = xdlmopen (LM_ID_NEWLM, dso, RTLD_LAZY);
|
||||
#endif
|
||||
my_isalpha = xdlsym (handle, "my_isalpha");
|
||||
my_toupper = xdlsym (handle, "my_toupper");
|
||||
my_tolower = xdlsym (handle, "my_tolower");
|
||||
|
||||
checks (NULL);
|
||||
xpthread_join (xpthread_create (NULL, checks, NULL));
|
||||
|
||||
xdlclose (handle);
|
||||
free (dso);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#include <support/test-driver.c>
|
||||
+92
-2
@@ -34,7 +34,6 @@ routines = \
|
||||
dl-addr \
|
||||
dl-addr-obj \
|
||||
dl-early_allocate \
|
||||
dl-find_object \
|
||||
dl-iteratephdr \
|
||||
dl-libc \
|
||||
dl-origin \
|
||||
@@ -58,9 +57,12 @@ dl-routines = \
|
||||
dl-close \
|
||||
dl-debug \
|
||||
dl-debug-symbols \
|
||||
dl-debug_state \
|
||||
dl-deps \
|
||||
dl-exception \
|
||||
dl-execstack \
|
||||
dl-execstack-tunable \
|
||||
dl-find_object \
|
||||
dl-fini \
|
||||
dl-init \
|
||||
dl-load \
|
||||
@@ -266,6 +268,7 @@ tests-static-normal := \
|
||||
tst-array1-static \
|
||||
tst-array5-static \
|
||||
tst-dl-iter-static \
|
||||
tst-dlopen-sgid \
|
||||
tst-dst-static \
|
||||
tst-env-setuid-static \
|
||||
tst-getauxval-static \
|
||||
@@ -379,6 +382,7 @@ tests += \
|
||||
tst-align3 \
|
||||
tst-audit-tlsdesc \
|
||||
tst-audit-tlsdesc-dlopen \
|
||||
tst-audit-tlsdesc-dlopen2 \
|
||||
tst-audit1 \
|
||||
tst-audit2 \
|
||||
tst-audit8 \
|
||||
@@ -415,7 +419,10 @@ tests += \
|
||||
tst-dlmopen1 \
|
||||
tst-dlmopen3 \
|
||||
tst-dlmopen4 \
|
||||
tst-dlmopen4-nonpic \
|
||||
tst-dlmopen4-pic \
|
||||
tst-dlopen-auditdup \
|
||||
tst-dlopen-constructor-null \
|
||||
tst-dlopen-self \
|
||||
tst-dlopen-tlsmodid \
|
||||
tst-dlopen-tlsreinit1 \
|
||||
@@ -490,6 +497,7 @@ tests += \
|
||||
tst-tls21 \
|
||||
tst-tls22 \
|
||||
tst-tls22-gnu2 \
|
||||
tst-tls23 \
|
||||
tst-tlsalign \
|
||||
tst-tlsalign-extern \
|
||||
tst-tlsgap \
|
||||
@@ -497,6 +505,7 @@ tests += \
|
||||
tst-unique2 \
|
||||
tst-unwind-ctor \
|
||||
tst-unwind-main \
|
||||
tst-version-hash-zero \
|
||||
unload3 \
|
||||
unload4 \
|
||||
unload5 \
|
||||
@@ -532,6 +541,8 @@ tests-internal += \
|
||||
tst-dl_find_object-threads \
|
||||
tst-dlmopen2 \
|
||||
tst-hash-collision3 \
|
||||
tst-link-map-contiguous-ldso \
|
||||
tst-link-map-contiguous-libc \
|
||||
tst-ptrguard1 \
|
||||
tst-stackguard1 \
|
||||
tst-tls-surplus \
|
||||
@@ -543,6 +554,10 @@ tests-internal += \
|
||||
unload2 \
|
||||
# tests-internal
|
||||
|
||||
ifeq ($(build-hardcoded-path-in-tests),yes)
|
||||
tests-internal += tst-link-map-contiguous-main
|
||||
endif
|
||||
|
||||
tests-container += \
|
||||
tst-dlopen-self-container \
|
||||
tst-dlopen-tlsmodid-container \
|
||||
@@ -567,9 +582,11 @@ tests-execstack-yes = \
|
||||
tst-execstack \
|
||||
tst-execstack-needed \
|
||||
tst-execstack-prog \
|
||||
tst-execstack-tunable \
|
||||
# tests-execstack-yes
|
||||
tests-execstack-static-yes = \
|
||||
tst-execstack-prog-static
|
||||
tst-execstack-prog-static \
|
||||
tst-execstack-prog-static-tunable \
|
||||
# tests-execstack-static-yes
|
||||
ifeq (yes,$(run-built-tests))
|
||||
tests-execstack-special-yes = \
|
||||
@@ -863,6 +880,7 @@ modules-names += \
|
||||
tst-auditmanymod8 \
|
||||
tst-auditmanymod9 \
|
||||
tst-auditmod-tlsdesc \
|
||||
tst-auditmod-tlsdesc2 \
|
||||
tst-auditmod1 \
|
||||
tst-auditmod11 \
|
||||
tst-auditmod12 \
|
||||
@@ -905,6 +923,9 @@ modules-names += \
|
||||
tst-dlmopen1mod \
|
||||
tst-dlopen-auditdup-auditmod \
|
||||
tst-dlopen-auditdupmod \
|
||||
tst-dlopen-constructor-null-mod1 \
|
||||
tst-dlopen-constructor-null-mod2 \
|
||||
tst-dlopen-sgid-mod \
|
||||
tst-dlopen-tlsreinitmod1 \
|
||||
tst-dlopen-tlsreinitmod2 \
|
||||
tst-dlopen-tlsreinitmod3 \
|
||||
@@ -1003,6 +1024,7 @@ modules-names += \
|
||||
tst-tls22-mod1-gnu2 \
|
||||
tst-tls22-mod2 \
|
||||
tst-tls22-mod2-gnu2 \
|
||||
tst-tls23-mod \
|
||||
tst-tlsalign-lib \
|
||||
tst-tlsgap-mod0 \
|
||||
tst-tlsgap-mod1 \
|
||||
@@ -1033,6 +1055,9 @@ modules-names += \
|
||||
tst-unique2mod1 \
|
||||
tst-unique2mod2 \
|
||||
tst-unwind-ctor-lib \
|
||||
tst-version-hash-zero-linkmod \
|
||||
tst-version-hash-zero-mod \
|
||||
tst-version-hash-zero-refmod \
|
||||
unload2dep \
|
||||
unload2mod \
|
||||
unload3mod1 \
|
||||
@@ -1144,6 +1169,10 @@ tests-pie += \
|
||||
tst-pie1 \
|
||||
tst-pie2 \
|
||||
# tests-pie
|
||||
ifeq (yes,$(aligned-65536))
|
||||
tests += tst-pie-bss
|
||||
tests-pie += tst-pie-bss
|
||||
endif
|
||||
ifneq (,$(load-address-ldflag))
|
||||
tests += \
|
||||
tst-pie-address \
|
||||
@@ -1159,6 +1188,10 @@ tests += \
|
||||
tests-static += \
|
||||
tst-pie-address-static \
|
||||
# tests-static
|
||||
ifeq (yes,$(aligned-65536))
|
||||
tests += tst-pie-bss-static
|
||||
tests-static += tst-pie-bss-static
|
||||
endif
|
||||
LDFLAGS-tst-pie-address-static += \
|
||||
$(load-address-ldflag)=$(pde-load-address)
|
||||
endif
|
||||
@@ -1988,6 +2021,9 @@ $(objpfx)tst-execstack.out: $(objpfx)tst-execstack-mod.so
|
||||
CPPFLAGS-tst-execstack.c += -DUSE_PTHREADS=0
|
||||
LDFLAGS-tst-execstack = -Wl,-z,noexecstack
|
||||
LDFLAGS-tst-execstack-mod.so = -Wl,-z,execstack
|
||||
ifeq ($(have-no-error-execstack),yes)
|
||||
LDFLAGS-tst-execstack-mod.so += -Wl,--no-error-execstack
|
||||
endif
|
||||
|
||||
$(objpfx)tst-execstack-needed: $(objpfx)tst-execstack-mod.so
|
||||
LDFLAGS-tst-execstack-needed = -Wl,-z,noexecstack
|
||||
@@ -1996,7 +2032,18 @@ LDFLAGS-tst-execstack-prog = -Wl,-z,execstack
|
||||
CFLAGS-tst-execstack-prog.c += -Wno-trampolines
|
||||
CFLAGS-tst-execstack-mod.c += -Wno-trampolines
|
||||
|
||||
# It expects loading a module with executable stack to work.
|
||||
CFLAGS-tst-execstack-tunable.c += -DUSE_PTHREADS=0 -DDEFAULT_RWX_STACK=1
|
||||
$(objpfx)tst-execstack-tunable.out: $(objpfx)tst-execstack-mod.so
|
||||
tst-execstack-tunable-ENV = GLIBC_TUNABLES=glibc.rtld.execstack=2
|
||||
|
||||
LDFLAGS-tst-execstack-prog-static-tunable = -Wl,-z,noexecstack
|
||||
tst-execstack-prog-static-tunable-ENV = GLIBC_TUNABLES=glibc.rtld.execstack=2
|
||||
|
||||
LDFLAGS-tst-execstack-prog-static = -Wl,-z,execstack
|
||||
ifeq ($(have-no-error-execstack),yes)
|
||||
LDFLAGS-tst-execstack-prog-static += -Wl,--no-error-execstack
|
||||
endif
|
||||
CFLAGS-tst-execstack-prog-static.c += -Wno-trampolines
|
||||
|
||||
ifeq (yes,$(build-hardcoded-path-in-tests))
|
||||
@@ -2074,6 +2121,7 @@ $(objpfx)tst-array5-static-cmp.out: tst-array5-static.exp \
|
||||
|
||||
CFLAGS-tst-pie1.c += $(pie-ccflag)
|
||||
CFLAGS-tst-pie2.c += $(pie-ccflag)
|
||||
CFLAGS-tst-pie-bss.c += $(pie-ccflag)
|
||||
CFLAGS-tst-pie-address.c += $(pie-ccflag)
|
||||
|
||||
$(objpfx)tst-piemod1.so: $(libsupport)
|
||||
@@ -2206,6 +2254,13 @@ $(objpfx)tst-dlmopen3.out: $(objpfx)tst-dlmopen1mod.so
|
||||
|
||||
$(objpfx)tst-dlmopen4.out: $(objpfx)tst-dlmopen1mod.so
|
||||
|
||||
CFLAGS-tst-dlmopen4-pic.c += -fPIC
|
||||
$(objpfx)tst-dlmopen4-pic.out: $(objpfx)tst-dlmopen1mod.so
|
||||
|
||||
CFLAGS-tst-dlmopen4-nonpic.c += -fno-pie
|
||||
tst-dlmopen4-nonpic-no-pie = yes
|
||||
$(objpfx)tst-dlmopen4-nonpic.out: $(objpfx)tst-dlmopen1mod.so
|
||||
|
||||
$(objpfx)tst-audit1.out: $(objpfx)tst-auditmod1.so
|
||||
tst-audit1-ENV = LD_AUDIT=$(objpfx)tst-auditmod1.so
|
||||
|
||||
@@ -3189,6 +3244,9 @@ $(objpfx)tst-audit-tlsdesc.out: $(objpfx)tst-auditmod-tlsdesc.so
|
||||
tst-audit-tlsdesc-ENV = LD_AUDIT=$(objpfx)tst-auditmod-tlsdesc.so
|
||||
$(objpfx)tst-audit-tlsdesc-dlopen.out: $(objpfx)tst-auditmod-tlsdesc.so
|
||||
tst-audit-tlsdesc-dlopen-ENV = LD_AUDIT=$(objpfx)tst-auditmod-tlsdesc.so
|
||||
$(objpfx)tst-audit-tlsdesc-dlopen2.out: $(objpfx)tst-auditmod-tlsdesc2.so \
|
||||
$(patsubst %, $(objpfx)%.so, $(tlsmod17a-modules))
|
||||
tst-audit-tlsdesc-dlopen2-ENV = LD_AUDIT=$(objpfx)tst-auditmod-tlsdesc2.so
|
||||
|
||||
$(objpfx)tst-dlmopen-twice.out: \
|
||||
$(objpfx)tst-dlmopen-twice-mod1.so \
|
||||
@@ -3354,6 +3412,13 @@ tst-tls22-mod1-gnu2.so-no-z-defs = yes
|
||||
tst-tls22-mod2.so-no-z-defs = yes
|
||||
tst-tls22-mod2-gnu2.so-no-z-defs = yes
|
||||
|
||||
$(objpfx)tst-tls23: $(shared-thread-library)
|
||||
$(objpfx)tst-tls23.out: $(objpfx)tst-tls23-mod.so
|
||||
|
||||
ifneq (no,$(have-test-mtls-traditional))
|
||||
CFLAGS-tst-tls23-mod.c += -mtls-dialect=$(have-test-mtls-traditional)
|
||||
endif
|
||||
|
||||
ifeq ($(have-test-cc-cflags-fsemantic-interposition),yes)
|
||||
# Compiler may default to -fno-semantic-interposition. These modules
|
||||
# must be compiled with -fsemantic-interposition.
|
||||
@@ -3392,3 +3457,28 @@ $(objpfx)tst-nolink-libc-2: $(objpfx)tst-nolink-libc.o
|
||||
-Wl,--dynamic-linker=$(objpfx)ld.so
|
||||
$(objpfx)tst-nolink-libc-2.out: $(objpfx)tst-nolink-libc-2 $(objpfx)ld.so
|
||||
$< > $@ 2>&1; $(evaluate-test)
|
||||
|
||||
$(objpfx)tst-dlopen-sgid.out: $(objpfx)tst-dlopen-sgid-mod.so
|
||||
|
||||
$(objpfx)tst-version-hash-zero.out: \
|
||||
$(objpfx)tst-version-hash-zero-mod.so \
|
||||
$(objpfx)tst-version-hash-zero-refmod.so
|
||||
LDFLAGS-tst-version-hash-zero-mod.so = \
|
||||
-Wl,--version-script=tst-version-hash-zero-mod.map
|
||||
# The run-time test module tst-version-hash-zero-refmod.so is linked
|
||||
# to a stub module, tst-version-hash-zero-linkmod.so, to produce an
|
||||
# expected relocation error.
|
||||
$(objpfx)tst-version-hash-zero-refmod.so: \
|
||||
$(objpfx)tst-version-hash-zero-linkmod.so
|
||||
LDFLAGS-tst-version-hash-zero-linkmod.so = \
|
||||
-Wl,--version-script=tst-version-hash-zero-linkmod.map \
|
||||
-Wl,--soname=tst-version-hash-zero-mod.so
|
||||
$(objpfx)tst-version-hash-zero-refmod.so: \
|
||||
$(objpfx)tst-version-hash-zero-linkmod.so
|
||||
tst-version-hash-zero-refmod.so-no-z-defs = yes
|
||||
|
||||
$(objpfx)tst-dlopen-constructor-null: \
|
||||
$(objpfx)tst-dlopen-constructor-null-mod1.so \
|
||||
$(objpfx)tst-dlopen-constructor-null-mod2.so
|
||||
$(objpfx)tst-dlopen-constructor-null-mod2.so: \
|
||||
$(objpfx)tst-dlopen-constructor-null-mod1.so
|
||||
|
||||
+2
-4
@@ -433,8 +433,7 @@ _dl_close_worker (struct link_map *map, bool force)
|
||||
/* Notify the debugger we are about to remove some loaded objects.
|
||||
LA_ACT_DELETE has already been signalled above for !unload_any. */
|
||||
struct r_debug *r = _dl_debug_update (nsid);
|
||||
r->r_state = RT_DELETE;
|
||||
_dl_debug_state ();
|
||||
_dl_debug_change_state (r, RT_DELETE);
|
||||
LIBC_PROBE (unmap_start, 2, nsid, r);
|
||||
|
||||
if (unload_global)
|
||||
@@ -726,8 +725,7 @@ _dl_close_worker (struct link_map *map, bool force)
|
||||
__rtld_lock_unlock_recursive (GL(dl_load_tls_lock));
|
||||
|
||||
/* Notify the debugger those objects are finalized and gone. */
|
||||
r->r_state = RT_CONSISTENT;
|
||||
_dl_debug_state ();
|
||||
_dl_debug_change_state (r, RT_CONSISTENT);
|
||||
LIBC_PROBE (unmap_complete, 2, nsid, r);
|
||||
|
||||
#ifdef SHARED
|
||||
|
||||
@@ -38,3 +38,4 @@
|
||||
_r_debug:
|
||||
_r_debug_extended:
|
||||
.zero R_DEBUG_EXTENDED_SIZE
|
||||
rtld_hidden_def (_r_debug)
|
||||
|
||||
+103
-52
@@ -16,6 +16,7 @@
|
||||
License along with the GNU C Library; if not, see
|
||||
<https://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <assert.h>
|
||||
#include <ldsodefs.h>
|
||||
|
||||
|
||||
@@ -30,23 +31,86 @@ extern const int verify_link_map_members[(VERIFY_MEMBER (l_addr)
|
||||
&& VERIFY_MEMBER (l_prev))
|
||||
? 1 : -1];
|
||||
|
||||
#ifdef SHARED
|
||||
/* r_debug structs for secondary namespaces. The first namespace is
|
||||
handled separately because its r_debug structure must overlap with
|
||||
the public _r_debug symbol, so the first array element corresponds
|
||||
to LM_ID_BASE + 1. See elf/dl-debug-symbols.S. */
|
||||
struct r_debug_extended _r_debug_array[DL_NNS - 1];
|
||||
|
||||
/* If not null, pointer to the _r_debug in the main executable. */
|
||||
static struct r_debug *_r_debug_main;
|
||||
|
||||
void
|
||||
_dl_debug_post_relocate (struct link_map *main_map)
|
||||
{
|
||||
/* Perform a full symbol search in all objects, to maintain
|
||||
compatibility if interposed _r_debug definitions. The lookup
|
||||
cannot fail because there is a definition in ld.so, and this
|
||||
function is only called if the ld.so search scope is not empty. */
|
||||
const ElfW(Sym) *sym = NULL;
|
||||
lookup_t result =_dl_lookup_symbol_x ("_r_debug", main_map, &sym,
|
||||
main_map->l_scope, NULL, 0, 0, NULL);
|
||||
if (sym->st_size >= sizeof (struct r_debug))
|
||||
{
|
||||
struct r_debug *main_r_debug = DL_SYMBOL_ADDRESS (result, sym);
|
||||
if (main_r_debug != &_r_debug_extended.base)
|
||||
{
|
||||
/* The extended version of the struct is not available in
|
||||
the main executable because a copy relocation has been
|
||||
used. r_map etc. have already been copied as part of the
|
||||
copy relocation processing. */
|
||||
main_r_debug->r_version = 1;
|
||||
|
||||
/* Record that dual updates of the initial link map are
|
||||
required. */
|
||||
_r_debug_main = main_r_debug;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Return the r_debug object for the namespace NS. */
|
||||
static inline struct r_debug_extended *
|
||||
get_rdebug (Lmid_t ns)
|
||||
{
|
||||
if (ns == LM_ID_BASE)
|
||||
return &_r_debug_extended;
|
||||
else
|
||||
return &_r_debug_array[ns - 1];
|
||||
}
|
||||
#else /* !SHARED */
|
||||
static inline struct r_debug_extended *
|
||||
get_rdebug (Lmid_t ns)
|
||||
{
|
||||
return &_r_debug_extended; /* There is just one namespace. */
|
||||
}
|
||||
#endif /* !SHARED */
|
||||
|
||||
/* Update the `r_map' member and return the address of `struct r_debug'
|
||||
of the namespace NS. */
|
||||
|
||||
struct r_debug *
|
||||
_dl_debug_update (Lmid_t ns)
|
||||
{
|
||||
struct r_debug_extended *r;
|
||||
if (ns == LM_ID_BASE)
|
||||
r = &_r_debug_extended;
|
||||
else
|
||||
r = &GL(dl_ns)[ns]._ns_debug;
|
||||
struct r_debug_extended *r = get_rdebug (ns);
|
||||
if (r->base.r_map == NULL)
|
||||
atomic_store_release (&r->base.r_map,
|
||||
(void *) GL(dl_ns)[ns]._ns_loaded);
|
||||
return &r->base;
|
||||
}
|
||||
|
||||
void
|
||||
_dl_debug_change_state (struct r_debug *r, int state)
|
||||
{
|
||||
atomic_store_release (&r->r_state, state);
|
||||
#ifdef SHARED
|
||||
if (r == &_r_debug_extended.base && _r_debug_main != NULL)
|
||||
/* Update the copy-relocation of _r_debug. */
|
||||
atomic_store_release (&_r_debug_main->r_state, state);
|
||||
#endif
|
||||
_dl_debug_state ();
|
||||
}
|
||||
|
||||
/* Initialize _r_debug_extended for the namespace NS. LDBASE is the
|
||||
run-time load address of the dynamic linker, to be put in
|
||||
_r_debug_extended.r_ldbase. Return the address of _r_debug. */
|
||||
@@ -54,34 +118,7 @@ _dl_debug_update (Lmid_t ns)
|
||||
struct r_debug *
|
||||
_dl_debug_initialize (ElfW(Addr) ldbase, Lmid_t ns)
|
||||
{
|
||||
struct r_debug_extended *r, **pp = NULL;
|
||||
|
||||
if (ns == LM_ID_BASE)
|
||||
{
|
||||
r = &_r_debug_extended;
|
||||
/* Initialize r_version to 1. */
|
||||
if (_r_debug_extended.base.r_version == 0)
|
||||
_r_debug_extended.base.r_version = 1;
|
||||
}
|
||||
else if (DL_NNS > 1)
|
||||
{
|
||||
r = &GL(dl_ns)[ns]._ns_debug;
|
||||
if (r->base.r_brk == 0)
|
||||
{
|
||||
/* Add the new namespace to the linked list. After a namespace
|
||||
is initialized, r_brk becomes non-zero. A namespace becomes
|
||||
empty (r_map == NULL) when it is unused. But it is never
|
||||
removed from the linked list. */
|
||||
struct r_debug_extended *p;
|
||||
for (pp = &_r_debug_extended.r_next;
|
||||
(p = *pp) != NULL;
|
||||
pp = &p->r_next)
|
||||
;
|
||||
|
||||
r->base.r_version = 2;
|
||||
}
|
||||
}
|
||||
|
||||
struct r_debug_extended *r = get_rdebug (ns);
|
||||
if (r->base.r_brk == 0)
|
||||
{
|
||||
/* Tell the debugger where to find the map of loaded objects.
|
||||
@@ -89,30 +126,44 @@ _dl_debug_initialize (ElfW(Addr) ldbase, Lmid_t ns)
|
||||
only once. */
|
||||
r->base.r_ldbase = ldbase ?: _r_debug_extended.base.r_ldbase;
|
||||
r->base.r_brk = (ElfW(Addr)) &_dl_debug_state;
|
||||
r->r_next = NULL;
|
||||
|
||||
#ifdef SHARED
|
||||
/* Add the new namespace to the linked list. This assumes that
|
||||
namespaces are allocated in increasing order. After a
|
||||
namespace is initialized, r_brk becomes non-zero. A
|
||||
namespace becomes empty (r_map == NULL) when it is unused.
|
||||
But it is never removed from the linked list. */
|
||||
|
||||
if (ns != LM_ID_BASE)
|
||||
{
|
||||
r->base.r_version = 2;
|
||||
if (ns - 1 == LM_ID_BASE)
|
||||
{
|
||||
atomic_store_release (&_r_debug_extended.r_next, r);
|
||||
/* Now there are multiple namespaces. Note that this
|
||||
deliberately does not update the copy in the main
|
||||
executable (if it exists). */
|
||||
atomic_store_release (&_r_debug_extended.base.r_version, 2);
|
||||
}
|
||||
else
|
||||
/* Update r_debug_extended of the previous namespace. */
|
||||
atomic_store_release (&_r_debug_array[ns - 2].r_next, r);
|
||||
}
|
||||
else
|
||||
#endif /* SHARED */
|
||||
r->base.r_version = 1;
|
||||
}
|
||||
|
||||
if (r->base.r_map == NULL)
|
||||
atomic_store_release (&r->base.r_map,
|
||||
(void *) GL(dl_ns)[ns]._ns_loaded);
|
||||
|
||||
if (pp != NULL)
|
||||
{
|
||||
atomic_store_release (pp, r);
|
||||
/* Bump r_version to 2 for the new namespace. */
|
||||
atomic_store_release (&_r_debug_extended.base.r_version, 2);
|
||||
struct link_map_public *l = (void *) GL(dl_ns)[ns]._ns_loaded;
|
||||
atomic_store_release (&r->base.r_map, l);
|
||||
#ifdef SHARED
|
||||
if (ns == LM_ID_BASE && _r_debug_main != NULL)
|
||||
/* Update the copy-relocation of _r_debug. */
|
||||
atomic_store_release (&_r_debug_main->r_map, l);
|
||||
#endif
|
||||
}
|
||||
|
||||
return &r->base;
|
||||
}
|
||||
|
||||
|
||||
/* This function exists solely to have a breakpoint set on it by the
|
||||
debugger. The debugger is supposed to find this function's address by
|
||||
examining the r_brk member of struct r_debug, but GDB 4.15 in fact looks
|
||||
for this particular symbol name in the PT_INTERP file. */
|
||||
void
|
||||
_dl_debug_state (void)
|
||||
{
|
||||
}
|
||||
rtld_hidden_def (_dl_debug_state)
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
/* Debugger hook called after dynamic linker updates.
|
||||
Copyright (C) 1996-2025 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the GNU C Library; if not, see
|
||||
<https://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <ldsodefs.h>
|
||||
|
||||
/* This function exists solely to have a breakpoint set on it by the
|
||||
debugger. The debugger is supposed to find this function's address by
|
||||
examining the r_brk member of struct r_debug, but GDB 4.15 in fact looks
|
||||
for this particular symbol name in the PT_INTERP file. Therefore,
|
||||
this function must not be inlined. */
|
||||
void
|
||||
_dl_debug_state (void)
|
||||
{
|
||||
}
|
||||
rtld_hidden_def (_dl_debug_state)
|
||||
@@ -0,0 +1,39 @@
|
||||
/* Stack executability handling for GNU dynamic linker.
|
||||
Copyright (C) 2025 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the GNU C Library; if not, see
|
||||
<https://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <ldsodefs.h>
|
||||
#include <dl-tunables.h>
|
||||
|
||||
void
|
||||
_dl_handle_execstack_tunable (void)
|
||||
{
|
||||
switch (TUNABLE_GET (glibc, rtld, execstack, int32_t, NULL))
|
||||
{
|
||||
case stack_tunable_mode_disable:
|
||||
if ((__glibc_unlikely (GL(dl_stack_flags)) & PF_X))
|
||||
_dl_fatal_printf (
|
||||
"Fatal glibc error: executable stack is not allowed\n");
|
||||
break;
|
||||
|
||||
case stack_tunable_mode_force:
|
||||
if (_dl_make_stack_executable (__libc_stack_end) != 0)
|
||||
_dl_fatal_printf (
|
||||
"Fatal glibc error: cannot enable executable stack as tunable requires");
|
||||
break;
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -23,7 +23,7 @@
|
||||
so as to mprotect it. */
|
||||
|
||||
int
|
||||
_dl_make_stack_executable (void **stack_endp)
|
||||
_dl_make_stack_executable (const void *stack_endp)
|
||||
{
|
||||
return ENOSYS;
|
||||
}
|
||||
|
||||
+47
-32
@@ -356,7 +356,7 @@ _dlfo_lookup (uintptr_t pc, struct dl_find_object_internal *first1, size_t size)
|
||||
}
|
||||
|
||||
int
|
||||
__dl_find_object (void *pc1, struct dl_find_object *result)
|
||||
_dl_find_object (void *pc1, struct dl_find_object *result)
|
||||
{
|
||||
uintptr_t pc = (uintptr_t) pc1;
|
||||
|
||||
@@ -463,8 +463,38 @@ __dl_find_object (void *pc1, struct dl_find_object *result)
|
||||
return -1;
|
||||
} /* Transaction retry loop. */
|
||||
}
|
||||
hidden_def (__dl_find_object)
|
||||
weak_alias (__dl_find_object, _dl_find_object)
|
||||
rtld_hidden_def (_dl_find_object)
|
||||
|
||||
/* Subroutine of _dlfo_process_initial to split out noncontigous link
|
||||
maps. NODELETE is the number of used _dlfo_nodelete_mappings
|
||||
elements. It is incremented as needed, and the new NODELETE value
|
||||
is returned. */
|
||||
static size_t
|
||||
_dlfo_process_initial_noncontiguous_map (struct link_map *map,
|
||||
size_t nodelete)
|
||||
{
|
||||
struct dl_find_object_internal dlfo;
|
||||
_dl_find_object_from_map (map, &dlfo);
|
||||
|
||||
/* PT_LOAD segments for a non-contiguous link map are added to the
|
||||
non-closeable mappings. */
|
||||
const ElfW(Phdr) *ph = map->l_phdr;
|
||||
const ElfW(Phdr) *ph_end = map->l_phdr + map->l_phnum;
|
||||
for (; ph < ph_end; ++ph)
|
||||
if (ph->p_type == PT_LOAD)
|
||||
{
|
||||
if (_dlfo_nodelete_mappings != NULL)
|
||||
{
|
||||
/* Second pass only. */
|
||||
_dlfo_nodelete_mappings[nodelete] = dlfo;
|
||||
ElfW(Addr) start = ph->p_vaddr + map->l_addr;
|
||||
_dlfo_nodelete_mappings[nodelete].map_start = start;
|
||||
_dlfo_nodelete_mappings[nodelete].map_end = start + ph->p_memsz;
|
||||
}
|
||||
++nodelete;
|
||||
}
|
||||
return nodelete;
|
||||
}
|
||||
|
||||
/* _dlfo_process_initial is called twice. First to compute the array
|
||||
sizes from the initial loaded mappings. Second to fill in the
|
||||
@@ -477,29 +507,8 @@ _dlfo_process_initial (void)
|
||||
|
||||
size_t nodelete = 0;
|
||||
if (!main_map->l_contiguous)
|
||||
{
|
||||
struct dl_find_object_internal dlfo;
|
||||
_dl_find_object_from_map (main_map, &dlfo);
|
||||
|
||||
/* PT_LOAD segments for a non-contiguous are added to the
|
||||
non-closeable mappings. */
|
||||
for (const ElfW(Phdr) *ph = main_map->l_phdr,
|
||||
*ph_end = main_map->l_phdr + main_map->l_phnum;
|
||||
ph < ph_end; ++ph)
|
||||
if (ph->p_type == PT_LOAD)
|
||||
{
|
||||
if (_dlfo_nodelete_mappings != NULL)
|
||||
{
|
||||
/* Second pass only. */
|
||||
_dlfo_nodelete_mappings[nodelete] = dlfo;
|
||||
_dlfo_nodelete_mappings[nodelete].map_start
|
||||
= ph->p_vaddr + main_map->l_addr;
|
||||
_dlfo_nodelete_mappings[nodelete].map_end
|
||||
= _dlfo_nodelete_mappings[nodelete].map_start + ph->p_memsz;
|
||||
}
|
||||
++nodelete;
|
||||
}
|
||||
}
|
||||
/* Contiguous case already handled in _dl_find_object_init. */
|
||||
nodelete = _dlfo_process_initial_noncontiguous_map (main_map, nodelete);
|
||||
|
||||
size_t loaded = 0;
|
||||
for (Lmid_t ns = 0; ns < GL(dl_nns); ++ns)
|
||||
@@ -511,11 +520,18 @@ _dlfo_process_initial (void)
|
||||
/* lt_library link maps are implicitly NODELETE. */
|
||||
if (l->l_type == lt_library || l->l_nodelete_active)
|
||||
{
|
||||
if (_dlfo_nodelete_mappings != NULL)
|
||||
/* Second pass only. */
|
||||
_dl_find_object_from_map
|
||||
(l, _dlfo_nodelete_mappings + nodelete);
|
||||
++nodelete;
|
||||
/* The kernel may have loaded ld.so with gaps. */
|
||||
if (!l->l_contiguous && is_rtld_link_map (l))
|
||||
nodelete
|
||||
= _dlfo_process_initial_noncontiguous_map (l, nodelete);
|
||||
else
|
||||
{
|
||||
if (_dlfo_nodelete_mappings != NULL)
|
||||
/* Second pass only. */
|
||||
_dl_find_object_from_map
|
||||
(l, _dlfo_nodelete_mappings + nodelete);
|
||||
++nodelete;
|
||||
}
|
||||
}
|
||||
else if (l->l_type == lt_loaded)
|
||||
{
|
||||
@@ -765,7 +781,6 @@ _dl_find_object_update_1 (struct link_map **loaded, size_t count)
|
||||
/* Prefer newly loaded link map. */
|
||||
assert (loaded_index1 > 0);
|
||||
_dl_find_object_from_map (loaded[loaded_index1 - 1], dlfo);
|
||||
loaded[loaded_index1 - 1]->l_find_object_processed = 1;
|
||||
--loaded_index1;
|
||||
}
|
||||
|
||||
|
||||
@@ -87,7 +87,7 @@ _dl_find_object_to_external (struct dl_find_object_internal *internal,
|
||||
}
|
||||
|
||||
/* Extract the object location data from a link map and writes it to
|
||||
*RESULT using relaxed MO stores. */
|
||||
*RESULT using relaxed MO stores. Set L->l_find_object_processed. */
|
||||
static void __attribute__ ((unused))
|
||||
_dl_find_object_from_map (struct link_map *l,
|
||||
struct dl_find_object_internal *result)
|
||||
@@ -100,6 +100,8 @@ _dl_find_object_from_map (struct link_map *l,
|
||||
atomic_store_relaxed (&result->eh_dbase, (void *) l->l_info[DT_PLTGOT]);
|
||||
#endif
|
||||
|
||||
l->l_find_object_processed = 1;
|
||||
|
||||
for (const ElfW(Phdr) *ph = l->l_phdr, *ph_end = l->l_phdr + l->l_phnum;
|
||||
ph < ph_end; ++ph)
|
||||
if (ph->p_type == DLFO_EH_SEGMENT_TYPE)
|
||||
|
||||
+3
-4
@@ -921,8 +921,7 @@ _dl_notify_new_object (int mode, Lmid_t nsid, struct link_map *l)
|
||||
/* Notify the debugger we have added some objects. We need to
|
||||
call _dl_debug_initialize in a static program in case dynamic
|
||||
linking has not been used before. */
|
||||
r->r_state = RT_ADD;
|
||||
_dl_debug_state ();
|
||||
_dl_debug_change_state (r, RT_ADD);
|
||||
LIBC_PROBE (map_start, 2, nsid, r);
|
||||
}
|
||||
else
|
||||
@@ -945,7 +944,7 @@ struct link_map *
|
||||
_dl_map_object_from_fd (const char *name, const char *origname, int fd,
|
||||
struct filebuf *fbp, char *realname,
|
||||
struct link_map *loader, int l_type, int mode,
|
||||
void **stack_endp, Lmid_t nsid)
|
||||
const void *stack_endp, Lmid_t nsid)
|
||||
{
|
||||
struct link_map *l = NULL;
|
||||
const ElfW(Ehdr) *header;
|
||||
@@ -2180,7 +2179,7 @@ _dl_map_object (struct link_map *loader, const char *name,
|
||||
|
||||
void *stack_end = __libc_stack_end;
|
||||
return _dl_map_object_from_fd (name, origname, fd, &fb, realname, loader,
|
||||
type, mode, &stack_end, nsid);
|
||||
type, mode, stack_end, nsid);
|
||||
}
|
||||
|
||||
struct add_path_state
|
||||
|
||||
+16
-6
@@ -100,12 +100,22 @@ check_match (const char *const undef_name,
|
||||
/* We can match the version information or use the
|
||||
default one if it is not hidden. */
|
||||
ElfW(Half) ndx = verstab[symidx] & 0x7fff;
|
||||
if ((map->l_versions[ndx].hash != version->hash
|
||||
|| strcmp (map->l_versions[ndx].name, version->name))
|
||||
&& (version->hidden || map->l_versions[ndx].hash
|
||||
|| (verstab[symidx] & 0x8000)))
|
||||
/* It's not the version we want. */
|
||||
return NULL;
|
||||
if (map->l_versions[ndx].hash == version->hash
|
||||
&& strcmp (map->l_versions[ndx].name, version->name) == 0)
|
||||
/* This is an exact version match. Return the symbol below. */
|
||||
;
|
||||
else
|
||||
{
|
||||
if (!version->hidden
|
||||
&& map->l_versions[ndx].name[0] == '\0'
|
||||
&& (verstab[symidx] & 0x8000) == 0
|
||||
&& (*num_versions)++ == 0)
|
||||
/* This is the global default version. Store it as a
|
||||
fallback match. */
|
||||
*versioned_sym = sym;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
+12
-3
@@ -594,6 +594,16 @@ dl_open_worker_begin (void *a)
|
||||
if ((mode & RTLD_GLOBAL) && new->l_global == 0)
|
||||
add_to_global_update (new);
|
||||
|
||||
/* It is not possible to run the ELF constructor for the new
|
||||
link map if it has not executed yet: If this dlopen call came
|
||||
from an ELF constructor that has not put that object into a
|
||||
consistent state, completing initialization for the entire
|
||||
scope will expose objects that have this partially
|
||||
constructed object among its dependencies to this
|
||||
inconsistent state. This could happen even with a benign
|
||||
dlopen (NULL, RTLD_LAZY) call from a constructor of an
|
||||
initially loaded shared object. */
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -771,8 +781,7 @@ dl_open_worker (void *a)
|
||||
#ifdef SHARED
|
||||
bool was_not_consistent = r->r_state != RT_CONSISTENT;
|
||||
#endif
|
||||
r->r_state = RT_CONSISTENT;
|
||||
_dl_debug_state ();
|
||||
_dl_debug_change_state (r, RT_CONSISTENT);
|
||||
LIBC_PROBE (map_complete, 3, nsid, r, args->map);
|
||||
|
||||
#ifdef SHARED
|
||||
@@ -841,7 +850,7 @@ no more namespaces available for dlmopen()"));
|
||||
}
|
||||
|
||||
GL(dl_ns)[nsid].libc_map = NULL;
|
||||
_dl_debug_update (nsid)->r_state = RT_CONSISTENT;
|
||||
_dl_debug_change_state (_dl_debug_update (nsid), RT_CONSISTENT);
|
||||
}
|
||||
/* Never allow loading a DSO in a namespace which is empty. Such
|
||||
direct placements is only causing problems. Also don't allow
|
||||
|
||||
@@ -51,7 +51,8 @@ _dl_relocate_static_pie (void)
|
||||
switch (ph->p_type)
|
||||
{
|
||||
case PT_LOAD:
|
||||
if (ph->p_offset == 0)
|
||||
/* Skip the empty PT_LOAD segment at offset 0. */
|
||||
if (ph->p_filesz != 0 && ph->p_offset == 0)
|
||||
file_p_vaddr = ph->p_vaddr;
|
||||
break;
|
||||
case PT_DYNAMIC:
|
||||
|
||||
+1
-3
@@ -332,9 +332,7 @@ _dl_non_dynamic_init (void)
|
||||
break;
|
||||
}
|
||||
|
||||
if ((__glibc_unlikely (GL(dl_stack_flags)) & PF_X)
|
||||
&& TUNABLE_GET (glibc, rtld, execstack, int32_t, NULL) == 0)
|
||||
_dl_fatal_printf ("Fatal glibc error: executable stack is not allowed\n");
|
||||
_dl_handle_execstack_tunable ();
|
||||
|
||||
call_function_static_weak (_dl_find_object_init);
|
||||
|
||||
|
||||
@@ -560,6 +560,13 @@ _dl_resize_dtv (dtv_t *dtv, size_t max_modid)
|
||||
if (newp == NULL)
|
||||
oom ();
|
||||
memcpy (newp, &dtv[-1], (2 + oldsize) * sizeof (dtv_t));
|
||||
#ifdef SHARED
|
||||
/* Auditors can trigger a DTV resize event while the full malloc
|
||||
is not yet in use. Mark the new DTV allocation as the
|
||||
initial allocation. */
|
||||
if (!__rtld_malloc_is_complete ())
|
||||
GL(dl_initial_dtv) = &newp[1];
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -138,7 +138,7 @@ glibc {
|
||||
execstack {
|
||||
type: INT_32
|
||||
minval: 0
|
||||
maxval: 1
|
||||
maxval: 2
|
||||
default: 1
|
||||
}
|
||||
}
|
||||
|
||||
@@ -357,6 +357,13 @@ _dl_check_map_versions (struct link_map *map, int verbose, int trace_mode)
|
||||
ent = (ElfW(Verdef) *) ((char *) ent + ent->vd_next);
|
||||
}
|
||||
}
|
||||
|
||||
/* The empty string has ELF hash zero. This avoids a NULL check
|
||||
before the version string comparison in check_match in
|
||||
dl-lookup.c. */
|
||||
for (unsigned int i = 0; i < map->l_nversions; ++i)
|
||||
if (map->l_versions[i].name == NULL)
|
||||
map->l_versions[i].name = "";
|
||||
}
|
||||
|
||||
/* When there is a DT_VERNEED entry with libc.so on DT_NEEDED, issue
|
||||
|
||||
+63
-34
@@ -1242,6 +1242,60 @@ rtld_setup_main_map (struct link_map *main_map)
|
||||
return has_interp;
|
||||
}
|
||||
|
||||
/* Set up the program header information for the dynamic linker
|
||||
itself. It can be accessed via _r_debug and dl_iterate_phdr
|
||||
callbacks, and it is used by _dl_find_object. */
|
||||
static void
|
||||
rtld_setup_phdr (void)
|
||||
{
|
||||
/* Starting from binutils-2.23, the linker will define the magic
|
||||
symbol __ehdr_start to point to our own ELF header if it is
|
||||
visible in a segment that also includes the phdrs. */
|
||||
|
||||
const ElfW(Ehdr) *rtld_ehdr = &__ehdr_start;
|
||||
assert (rtld_ehdr->e_ehsize == sizeof *rtld_ehdr);
|
||||
assert (rtld_ehdr->e_phentsize == sizeof (ElfW(Phdr)));
|
||||
|
||||
const ElfW(Phdr) *rtld_phdr = (const void *) rtld_ehdr + rtld_ehdr->e_phoff;
|
||||
|
||||
_dl_rtld_map.l_phdr = rtld_phdr;
|
||||
_dl_rtld_map.l_phnum = rtld_ehdr->e_phnum;
|
||||
|
||||
|
||||
_dl_rtld_map.l_contiguous = 1;
|
||||
/* The linker may not have produced a contiguous object. The kernel
|
||||
will load the object with actual gaps (unlike the glibc loader
|
||||
for shared objects, which always produces a contiguous mapping).
|
||||
See similar logic in rtld_setup_main_map above. */
|
||||
{
|
||||
ElfW(Addr) expected_load_address = 0;
|
||||
for (const ElfW(Phdr) *ph = rtld_phdr; ph < &rtld_phdr[rtld_ehdr->e_phnum];
|
||||
++ph)
|
||||
if (ph->p_type == PT_LOAD)
|
||||
{
|
||||
ElfW(Addr) mapstart = ph->p_vaddr & ~(GLRO(dl_pagesize) - 1);
|
||||
if (_dl_rtld_map.l_contiguous && expected_load_address != 0
|
||||
&& expected_load_address != mapstart)
|
||||
_dl_rtld_map.l_contiguous = 0;
|
||||
ElfW(Addr) allocend = ph->p_vaddr + ph->p_memsz;
|
||||
/* The next expected address is the page following this load
|
||||
segment. */
|
||||
expected_load_address = ((allocend + GLRO(dl_pagesize) - 1)
|
||||
& ~(GLRO(dl_pagesize) - 1));
|
||||
}
|
||||
}
|
||||
|
||||
/* PT_GNU_RELRO is usually the last phdr. */
|
||||
size_t cnt = rtld_ehdr->e_phnum;
|
||||
while (cnt-- > 0)
|
||||
if (rtld_phdr[cnt].p_type == PT_GNU_RELRO)
|
||||
{
|
||||
_dl_rtld_map.l_relro_addr = rtld_phdr[cnt].p_vaddr;
|
||||
_dl_rtld_map.l_relro_size = rtld_phdr[cnt].p_memsz;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Adjusts the contents of the stack and related globals for the user
|
||||
entry point. The ld.so processed skip_args arguments and bumped
|
||||
_dl_argv and _dl_argc accordingly. Those arguments are removed from
|
||||
@@ -1626,9 +1680,9 @@ dl_main (const ElfW(Phdr) *phdr,
|
||||
|
||||
bool has_interp = rtld_setup_main_map (main_map);
|
||||
|
||||
if ((__glibc_unlikely (GL(dl_stack_flags)) & PF_X)
|
||||
&& TUNABLE_GET (glibc, rtld, execstack, int32_t, NULL) == 0)
|
||||
_dl_fatal_printf ("Fatal glibc error: executable stack is not allowed\n");
|
||||
/* Handle this after PT_GNU_STACK parse, because it updates dl_stack_flags
|
||||
if required. */
|
||||
_dl_handle_execstack_tunable ();
|
||||
|
||||
/* If the current libname is different from the SONAME, add the
|
||||
latter as well. */
|
||||
@@ -1710,33 +1764,7 @@ dl_main (const ElfW(Phdr) *phdr,
|
||||
++GL(dl_ns)[LM_ID_BASE]._ns_nloaded;
|
||||
++GL(dl_load_adds);
|
||||
|
||||
/* Starting from binutils-2.23, the linker will define the magic symbol
|
||||
__ehdr_start to point to our own ELF header if it is visible in a
|
||||
segment that also includes the phdrs. If that's not available, we use
|
||||
the old method that assumes the beginning of the file is part of the
|
||||
lowest-addressed PT_LOAD segment. */
|
||||
|
||||
/* Set up the program header information for the dynamic linker
|
||||
itself. It is needed in the dl_iterate_phdr callbacks. */
|
||||
const ElfW(Ehdr) *rtld_ehdr = &__ehdr_start;
|
||||
assert (rtld_ehdr->e_ehsize == sizeof *rtld_ehdr);
|
||||
assert (rtld_ehdr->e_phentsize == sizeof (ElfW(Phdr)));
|
||||
|
||||
const ElfW(Phdr) *rtld_phdr = (const void *) rtld_ehdr + rtld_ehdr->e_phoff;
|
||||
|
||||
_dl_rtld_map.l_phdr = rtld_phdr;
|
||||
_dl_rtld_map.l_phnum = rtld_ehdr->e_phnum;
|
||||
|
||||
|
||||
/* PT_GNU_RELRO is usually the last phdr. */
|
||||
size_t cnt = rtld_ehdr->e_phnum;
|
||||
while (cnt-- > 0)
|
||||
if (rtld_phdr[cnt].p_type == PT_GNU_RELRO)
|
||||
{
|
||||
_dl_rtld_map.l_relro_addr = rtld_phdr[cnt].p_vaddr;
|
||||
_dl_rtld_map.l_relro_size = rtld_phdr[cnt].p_memsz;
|
||||
break;
|
||||
}
|
||||
rtld_setup_phdr ();
|
||||
|
||||
/* Add the dynamic linker to the TLS list if it also uses TLS. */
|
||||
if (_dl_rtld_map.l_tls_blocksize != 0)
|
||||
@@ -1783,8 +1811,7 @@ dl_main (const ElfW(Phdr) *phdr,
|
||||
elf_setup_debug_entry (main_map, r);
|
||||
|
||||
/* We start adding objects. */
|
||||
r->r_state = RT_ADD;
|
||||
_dl_debug_state ();
|
||||
_dl_debug_change_state (r, RT_ADD);
|
||||
LIBC_PROBE (init_start, 2, LM_ID_BASE, r);
|
||||
|
||||
/* Auditing checkpoint: we are ready to signal that the initial map
|
||||
@@ -2319,6 +2346,9 @@ dl_main (const ElfW(Phdr) *phdr,
|
||||
|
||||
__rtld_mutex_init ();
|
||||
__rtld_malloc_init_real (main_map);
|
||||
|
||||
/* Update copy-relocated _r_debug if necessary. */
|
||||
_dl_debug_post_relocate (main_map);
|
||||
}
|
||||
|
||||
/* All ld.so initialization is complete. Apply RELRO. */
|
||||
@@ -2339,8 +2369,7 @@ dl_main (const ElfW(Phdr) *phdr,
|
||||
/* Notify the debugger all new objects are now ready to go. We must re-get
|
||||
the address since by now the variable might be in another object. */
|
||||
r = _dl_debug_update (LM_ID_BASE);
|
||||
r->r_state = RT_CONSISTENT;
|
||||
_dl_debug_state ();
|
||||
_dl_debug_change_state (r, RT_CONSISTENT);
|
||||
LIBC_PROBE (init_complete, 2, LM_ID_BASE, r);
|
||||
|
||||
/* Auditing checkpoint: we have added all objects. */
|
||||
|
||||
+40
-1
@@ -38,6 +38,7 @@
|
||||
#include <sys/mman.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/stat.h>
|
||||
#include <intprops.h>
|
||||
|
||||
/* Get libc version number. */
|
||||
#include "../version.h"
|
||||
@@ -410,6 +411,7 @@ load_shobj (const char *name)
|
||||
int fd;
|
||||
ElfW(Shdr) *shdr;
|
||||
size_t pagesize = getpagesize ();
|
||||
struct stat st;
|
||||
|
||||
/* Since we use dlopen() we must be prepared to work around the sometimes
|
||||
strange lookup rules for the shared objects. If we have a file foo.so
|
||||
@@ -553,14 +555,39 @@ load_shobj (const char *name)
|
||||
error (EXIT_FAILURE, errno, _("Reopening shared object `%s' failed"),
|
||||
map->l_name);
|
||||
|
||||
if (fstat (fd, &st) < 0)
|
||||
error (EXIT_FAILURE, errno, _("stat(%s) failure"), map->l_name);
|
||||
|
||||
/* We're depending on data that's being read from the file, so be a
|
||||
bit paranoid here and make sure the requests are reasonable -
|
||||
i.e. both size and offset are nonnegative and smaller than the
|
||||
file size, as well as the offset of the end of the data. PREAD
|
||||
would have failed anyway, but this is more robust and explains
|
||||
what happened better. Note that SZ must be unsigned and OFF may
|
||||
be signed or unsigned. */
|
||||
#define PCHECK(sz1,off1) { \
|
||||
size_t sz = sz1, end_off; \
|
||||
off_t off = off1; \
|
||||
if (sz > st.st_size \
|
||||
|| off < 0 || off > st.st_size \
|
||||
|| INT_ADD_WRAPV (sz, off, &end_off) \
|
||||
|| end_off > st.st_size) \
|
||||
error (EXIT_FAILURE, ERANGE, \
|
||||
_("read outside of file extents %zu + %jd > %jd"), \
|
||||
sz, (intmax_t) off, (intmax_t) st.st_size); \
|
||||
}
|
||||
|
||||
/* Map the section header. */
|
||||
size_t size = ehdr->e_shnum * sizeof (ElfW(Shdr));
|
||||
shdr = (ElfW(Shdr) *) alloca (size);
|
||||
PCHECK (size, ehdr->e_shoff);
|
||||
if (pread (fd, shdr, size, ehdr->e_shoff) != size)
|
||||
error (EXIT_FAILURE, errno, _("reading of section headers failed"));
|
||||
|
||||
/* Get the section header string table. */
|
||||
char *shstrtab = (char *) alloca (shdr[ehdr->e_shstrndx].sh_size);
|
||||
PCHECK (shdr[ehdr->e_shstrndx].sh_size,
|
||||
shdr[ehdr->e_shstrndx].sh_offset);
|
||||
if (pread (fd, shstrtab, shdr[ehdr->e_shstrndx].sh_size,
|
||||
shdr[ehdr->e_shstrndx].sh_offset)
|
||||
!= shdr[ehdr->e_shstrndx].sh_size)
|
||||
@@ -588,6 +615,7 @@ load_shobj (const char *name)
|
||||
size_t size = debuglink_entry->sh_size;
|
||||
char *debuginfo_fname = (char *) alloca (size + 1);
|
||||
debuginfo_fname[size] = '\0';
|
||||
PCHECK (size, debuglink_entry->sh_offset);
|
||||
if (pread (fd, debuginfo_fname, size, debuglink_entry->sh_offset)
|
||||
!= size)
|
||||
{
|
||||
@@ -641,21 +669,32 @@ load_shobj (const char *name)
|
||||
if (fd2 != -1)
|
||||
{
|
||||
ElfW(Ehdr) ehdr2;
|
||||
struct stat st;
|
||||
|
||||
if (fstat (fd2, &st) < 0)
|
||||
error (EXIT_FAILURE, errno, _("stat(%s) failure"), workbuf);
|
||||
|
||||
/* Read the ELF header. */
|
||||
PCHECK (sizeof (ehdr2), 0);
|
||||
if (pread (fd2, &ehdr2, sizeof (ehdr2), 0) != sizeof (ehdr2))
|
||||
error (EXIT_FAILURE, errno,
|
||||
_("reading of ELF header failed"));
|
||||
|
||||
/* Map the section header. */
|
||||
size_t size = ehdr2.e_shnum * sizeof (ElfW(Shdr));
|
||||
size_t size;
|
||||
if (INT_MULTIPLY_WRAPV (ehdr2.e_shnum, sizeof (ElfW(Shdr)), &size))
|
||||
error (EXIT_FAILURE, errno, _("too many section headers"));
|
||||
|
||||
ElfW(Shdr) *shdr2 = (ElfW(Shdr) *) alloca (size);
|
||||
PCHECK (size, ehdr2.e_shoff);
|
||||
if (pread (fd2, shdr2, size, ehdr2.e_shoff) != size)
|
||||
error (EXIT_FAILURE, errno,
|
||||
_("reading of section headers failed"));
|
||||
|
||||
/* Get the section header string table. */
|
||||
shstrtab = (char *) alloca (shdr2[ehdr2.e_shstrndx].sh_size);
|
||||
PCHECK (shdr2[ehdr2.e_shstrndx].sh_size,
|
||||
shdr2[ehdr2.e_shstrndx].sh_offset);
|
||||
if (pread (fd2, shstrtab, shdr2[ehdr2.e_shstrndx].sh_size,
|
||||
shdr2[ehdr2.e_shstrndx].sh_offset)
|
||||
!= shdr2[ehdr2.e_shstrndx].sh_size)
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
/* Loading TLS-using modules from auditors (bug 32412). Main program.
|
||||
Copyright (C) 2021-2025 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the GNU C Library; if not, see
|
||||
<https://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <support/xdlfcn.h>
|
||||
#include <stdio.h>
|
||||
|
||||
static int
|
||||
do_test (void)
|
||||
{
|
||||
puts ("info: start of main program");
|
||||
|
||||
/* Load TLS-using modules, to trigger DTV resizing. The dynamic
|
||||
linker will load them again (requiring their own TLS) because the
|
||||
dlopen calls from the auditor were in the auditing namespace. */
|
||||
for (int i = 1; i <= 19; ++i)
|
||||
{
|
||||
char dso[30];
|
||||
snprintf (dso, sizeof (dso), "tst-tlsmod17a%d.so", i);
|
||||
char sym[30];
|
||||
snprintf (sym, sizeof(sym), "tlsmod17a%d", i);
|
||||
|
||||
void *handle = xdlopen (dso, RTLD_LAZY);
|
||||
int (*func) (void) = xdlsym (handle, sym);
|
||||
/* Trigger TLS allocation. */
|
||||
func ();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#include <support/test-driver.c>
|
||||
@@ -0,0 +1,59 @@
|
||||
/* Loading TLS-using modules from auditors (bug 32412). Audit module.
|
||||
Copyright (C) 2021-2025 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the GNU C Library; if not, see
|
||||
<https://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include <link.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
unsigned int
|
||||
la_version (unsigned int version)
|
||||
{
|
||||
/* Open some modules, to trigger DTV resizing before the switch to
|
||||
the main malloc. */
|
||||
for (int i = 1; i <= 19; ++i)
|
||||
{
|
||||
char dso[30];
|
||||
snprintf (dso, sizeof (dso), "tst-tlsmod17a%d.so", i);
|
||||
char sym[30];
|
||||
snprintf (sym, sizeof(sym), "tlsmod17a%d", i);
|
||||
|
||||
void *handle = dlopen (dso, RTLD_LAZY);
|
||||
if (handle == NULL)
|
||||
{
|
||||
printf ("error: dlmopen from auditor: %s\n", dlerror ());
|
||||
fflush (stdout);
|
||||
_exit (1);
|
||||
}
|
||||
int (*func) (void) = dlsym (handle, sym);
|
||||
if (func == NULL)
|
||||
{
|
||||
printf ("error: dlsym from auditor: %s\n", dlerror ());
|
||||
fflush (stdout);
|
||||
_exit (1);
|
||||
}
|
||||
/* Trigger TLS allocation. */
|
||||
func ();
|
||||
}
|
||||
|
||||
puts ("info: TLS-using modules loaded from auditor");
|
||||
fflush (stdout);
|
||||
|
||||
return LAV_CURRENT;
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
#define BUILD_FOR_NONPIC
|
||||
#include "tst-dlmopen4.c"
|
||||
@@ -0,0 +1,2 @@
|
||||
#define BUILD_FOR_PIC
|
||||
#include "tst-dlmopen4.c"
|
||||
@@ -46,6 +46,15 @@ do_test (void)
|
||||
TEST_COMPARE (debug->base.r_version, 1);
|
||||
TEST_VERIFY_EXIT (debug->r_next == NULL);
|
||||
|
||||
#ifdef BUILD_FOR_PIC
|
||||
/* In a PIC build, using _r_debug directly should give us the same
|
||||
object. */
|
||||
TEST_VERIFY (&_r_debug == &debug->base);
|
||||
#endif
|
||||
#ifdef BUILD_FOR_NONPIC
|
||||
TEST_COMPARE (_r_debug.r_version, 1);
|
||||
#endif
|
||||
|
||||
void *h = xdlmopen (LM_ID_NEWLM, "$ORIGIN/tst-dlmopen1mod.so",
|
||||
RTLD_LAZY);
|
||||
|
||||
@@ -57,6 +66,19 @@ do_test (void)
|
||||
const char *name = basename (debug->r_next->base.r_map->l_name);
|
||||
TEST_COMPARE_STRING (name, "tst-dlmopen1mod.so");
|
||||
|
||||
#ifdef BUILD_FOR_NONPIC
|
||||
/* If a copy relocation is used, it must be at version 1. */
|
||||
if (&_r_debug != &debug->base)
|
||||
{
|
||||
TEST_COMPARE (_r_debug.r_version, 1);
|
||||
TEST_COMPARE ((uintptr_t) _r_debug.r_map,
|
||||
(uintptr_t) debug->base.r_map);
|
||||
TEST_COMPARE (_r_debug.r_brk, debug->base.r_brk);
|
||||
TEST_COMPARE (_r_debug.r_state, debug->base.r_state);
|
||||
TEST_COMPARE (_r_debug.r_ldbase, debug->base.r_ldbase);
|
||||
}
|
||||
#endif
|
||||
|
||||
xdlclose (h);
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
/* Module calling dlopen (NULL, RTLD_LAZY) to obtain the global scope.
|
||||
Copyright (C) 2024 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the GNU C Library; if not, see
|
||||
<https://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
int mod1_status;
|
||||
|
||||
static void __attribute__ ((constructor))
|
||||
init (void)
|
||||
{
|
||||
puts ("info: tst-dlopen-constructor-null-mod1.so constructor");
|
||||
|
||||
void *handle = dlopen (NULL, RTLD_LAZY);
|
||||
if (handle == NULL)
|
||||
{
|
||||
printf ("error: %s\n", dlerror ());
|
||||
exit (1);
|
||||
}
|
||||
puts ("info: dlopen returned");
|
||||
if (dlsym (handle, "malloc") != malloc)
|
||||
{
|
||||
puts ("error: dlsym did not produce expected result");
|
||||
exit (1);
|
||||
}
|
||||
dlclose (handle);
|
||||
|
||||
/* Check that the second module's constructor has not executed. */
|
||||
if (getenv ("mod2_status") != NULL)
|
||||
{
|
||||
printf ("error: mod2_status environment variable set: %s\n",
|
||||
getenv ("mod2_status"));
|
||||
exit (1);
|
||||
}
|
||||
|
||||
/* Communicate to the second module that the constructor executed. */
|
||||
mod1_status = 1;
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/* Module whose constructor should not be invoked by dlopen (NULL, RTLD_LAZY).
|
||||
Copyright (C) 2024 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the GNU C Library; if not, see
|
||||
<https://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
extern int mod1_status;
|
||||
int mod2_status;
|
||||
|
||||
static void __attribute__ ((constructor))
|
||||
init (void)
|
||||
{
|
||||
printf ("info: tst-dlopen-constructor-null-mod2.so constructor"
|
||||
" (mod1_status=%d)", mod1_status);
|
||||
if (!(mod1_status == 1 && mod2_status == 0))
|
||||
{
|
||||
puts ("error: mod1_status == 1 && mod2_status == 0 expected");
|
||||
exit (1);
|
||||
}
|
||||
setenv ("mod2_status", "constructed", 1);
|
||||
mod2_status = 1;
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/* Verify that dlopen (NULL, RTLD_LAZY) does not complete initialization.
|
||||
Copyright (C) 2024 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the GNU C Library; if not, see
|
||||
<https://www.gnu.org/licenses/>. */
|
||||
|
||||
/* This test mimics what the glvndSetupPthreads function in libglvnd
|
||||
does. */
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <support/check.h>
|
||||
|
||||
/* Defined and initialized in the shared objects. */
|
||||
extern int mod1_status;
|
||||
extern int mod2_status;
|
||||
|
||||
static int
|
||||
do_test (void)
|
||||
{
|
||||
TEST_COMPARE (mod1_status, 1);
|
||||
TEST_COMPARE (mod2_status, 1);
|
||||
TEST_COMPARE_STRING (getenv ("mod2_status"), "constructed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
#include <support/test-driver.c>
|
||||
@@ -0,0 +1 @@
|
||||
/* Opening this object should not succeed. */
|
||||
@@ -0,0 +1,106 @@
|
||||
/* Test case for ignored LD_LIBRARY_PATH in static startug (bug 32976).
|
||||
Copyright (C) 2025 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the GNU C Library; if not, see
|
||||
<https://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include <gnu/lib-names.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <support/capture_subprocess.h>
|
||||
#include <support/check.h>
|
||||
#include <support/support.h>
|
||||
#include <support/temp_file.h>
|
||||
#include <support/test-driver.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/* This is the name of our test object. Use a custom module for
|
||||
testing, so that this object does not get picked up from the system
|
||||
path. */
|
||||
static const char dso_name[] = "tst-dlopen-sgid-mod.so";
|
||||
|
||||
/* Used to mark the recursive invocation. */
|
||||
static const char magic_argument[] = "run-actual-test";
|
||||
|
||||
static int
|
||||
do_test (void)
|
||||
{
|
||||
/* Pathname of the directory that receives the shared objects this
|
||||
test attempts to load. */
|
||||
char *libdir = support_create_temp_directory ("tst-dlopen-sgid-");
|
||||
|
||||
/* This is supposed to be ignored and stripped. */
|
||||
TEST_COMPARE (setenv ("LD_LIBRARY_PATH", libdir, 1), 0);
|
||||
|
||||
/* Copy of libc.so.6. */
|
||||
{
|
||||
char *from = xasprintf ("%s/%s", support_objdir_root, LIBC_SO);
|
||||
char *to = xasprintf ("%s/%s", libdir, LIBC_SO);
|
||||
add_temp_file (to);
|
||||
support_copy_file (from, to);
|
||||
free (to);
|
||||
free (from);
|
||||
}
|
||||
|
||||
/* Copy of the test object. */
|
||||
{
|
||||
char *from = xasprintf ("%s/elf/%s", support_objdir_root, dso_name);
|
||||
char *to = xasprintf ("%s/%s", libdir, dso_name);
|
||||
add_temp_file (to);
|
||||
support_copy_file (from, to);
|
||||
free (to);
|
||||
free (from);
|
||||
}
|
||||
|
||||
free (libdir);
|
||||
|
||||
support_capture_subprogram_self_sgid (magic_argument);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
alternative_main (int argc, char **argv)
|
||||
{
|
||||
if (argc == 2 && strcmp (argv[1], magic_argument) == 0)
|
||||
{
|
||||
if (getgid () == getegid ())
|
||||
/* This can happen if the file system is mounted nosuid. */
|
||||
FAIL_UNSUPPORTED ("SGID failed: GID and EGID match (%jd)\n",
|
||||
(intmax_t) getgid ());
|
||||
|
||||
/* Should be removed due to SGID. */
|
||||
TEST_COMPARE_STRING (getenv ("LD_LIBRARY_PATH"), NULL);
|
||||
|
||||
TEST_VERIFY (dlopen (dso_name, RTLD_NOW) == NULL);
|
||||
{
|
||||
const char *message = dlerror ();
|
||||
TEST_COMPARE_STRING (message,
|
||||
"tst-dlopen-sgid-mod.so:"
|
||||
" cannot open shared object file:"
|
||||
" No such file or directory");
|
||||
}
|
||||
|
||||
support_record_failure_barrier ();
|
||||
exit (EXIT_SUCCESS);
|
||||
}
|
||||
}
|
||||
|
||||
#define PREPARE alternative_main
|
||||
#include <support/test-driver.c>
|
||||
@@ -105,10 +105,7 @@ do_test (int argc, char **argv)
|
||||
|
||||
if (ret != 0)
|
||||
exit (1);
|
||||
|
||||
/* Special return code to make sure that the child executed all the way
|
||||
through. */
|
||||
exit (42);
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -127,18 +124,7 @@ do_test (int argc, char **argv)
|
||||
continue;
|
||||
}
|
||||
|
||||
int status = support_capture_subprogram_self_sgid (buf);
|
||||
|
||||
/* Bail out early if unsupported. */
|
||||
if (WEXITSTATUS (status) == EXIT_UNSUPPORTED)
|
||||
return EXIT_UNSUPPORTED;
|
||||
|
||||
if (WEXITSTATUS (status) != 42)
|
||||
{
|
||||
printf (" [%d] child failed with status %d\n", i,
|
||||
WEXITSTATUS (status));
|
||||
support_record_failure ();
|
||||
}
|
||||
support_capture_subprogram_self_sgid (buf);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
+2
-15
@@ -147,10 +147,7 @@ do_test (int argc, char **argv)
|
||||
|
||||
if (ret != 0)
|
||||
exit (1);
|
||||
|
||||
/* Special return code to make sure that the child executed all the way
|
||||
through. */
|
||||
exit (42);
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -174,17 +171,7 @@ do_test (int argc, char **argv)
|
||||
free (profilepath);
|
||||
}
|
||||
|
||||
int status = support_capture_subprogram_self_sgid (SETGID_CHILD);
|
||||
|
||||
if (WEXITSTATUS (status) == EXIT_UNSUPPORTED)
|
||||
exit (EXIT_UNSUPPORTED);
|
||||
|
||||
if (WEXITSTATUS (status) != 42)
|
||||
{
|
||||
printf (" child failed with status %d\n",
|
||||
WEXITSTATUS (status));
|
||||
support_record_failure ();
|
||||
}
|
||||
support_capture_subprogram_self_sgid (SETGID_CHILD);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
#include <tst-execstack-prog-static.c>
|
||||
@@ -0,0 +1 @@
|
||||
#include <tst-execstack.c>
|
||||
@@ -0,0 +1,158 @@
|
||||
/* Check that _dl_find_object behavior matches up with gaps.
|
||||
Copyright (C) 2025 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the GNU C Library; if not, see
|
||||
<https://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include <gnu/lib-names.h>
|
||||
#include <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)
|
||||
{
|
||||
struct link_map *l = xdlopen (LD_SO, RTLD_NOW);
|
||||
if (!l->l_contiguous)
|
||||
{
|
||||
puts ("info: ld.so link map is not contiguous");
|
||||
|
||||
/* Try to find holes by probing with mmap. */
|
||||
int pagesize = getpagesize ();
|
||||
bool gap_found = false;
|
||||
ElfW(Addr) addr = l->l_map_start;
|
||||
TEST_COMPARE (addr % pagesize, 0);
|
||||
while (addr < l->l_map_end)
|
||||
{
|
||||
void *expected = (void *) addr;
|
||||
void *ptr = xmmap (expected, 1, PROT_READ | PROT_WRITE,
|
||||
MAP_PRIVATE | MAP_ANONYMOUS, -1);
|
||||
struct dl_find_object dlfo;
|
||||
int dlfo_ret = _dl_find_object (expected, &dlfo);
|
||||
if (ptr == expected)
|
||||
{
|
||||
if (dlfo_ret < 0)
|
||||
{
|
||||
TEST_COMPARE (dlfo_ret, -1);
|
||||
printf ("info: hole without mapping data found at %p\n", ptr);
|
||||
}
|
||||
else
|
||||
FAIL ("object \"%s\" found in gap at %p",
|
||||
dlfo.dlfo_link_map->l_name, ptr);
|
||||
gap_found = true;
|
||||
}
|
||||
else if (dlfo_ret == 0)
|
||||
{
|
||||
if ((void *) dlfo.dlfo_link_map != (void *) l)
|
||||
{
|
||||
printf ("info: object \"%s\" found at %p\n",
|
||||
dlfo.dlfo_link_map->l_name, expected);
|
||||
gap_found = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
TEST_COMPARE (dlfo_ret, -1);
|
||||
|
||||
xmunmap (ptr, 1);
|
||||
addr += pagesize;
|
||||
}
|
||||
|
||||
if (!gap_found && !find_gap_with_proc_self_map (l))
|
||||
FAIL ("no ld.so gap found");
|
||||
}
|
||||
else
|
||||
{
|
||||
puts ("info: ld.so link map is contiguous");
|
||||
|
||||
/* Assert that ld.so is truly contiguous in memory. */
|
||||
volatile long int *p = (volatile long int *) l->l_map_start;
|
||||
volatile long int *end = (volatile long int *) l->l_map_end;
|
||||
while (p < end)
|
||||
{
|
||||
*p;
|
||||
++p;
|
||||
}
|
||||
}
|
||||
|
||||
xdlclose (l);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#include <support/test-driver.c>
|
||||
@@ -0,0 +1,57 @@
|
||||
/* Check that the entire libc.so program image is readable if contiguous.
|
||||
Copyright (C) 2025 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the GNU C Library; if not, see
|
||||
<https://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <gnu/lib-names.h>
|
||||
#include <link.h>
|
||||
#include <support/check.h>
|
||||
#include <support/xdlfcn.h>
|
||||
#include <support/xunistd.h>
|
||||
#include <sys/mman.h>
|
||||
#include <unistd.h>
|
||||
|
||||
static int
|
||||
do_test (void)
|
||||
{
|
||||
struct link_map *l = xdlopen (LIBC_SO, RTLD_NOW);
|
||||
|
||||
/* The dynamic loader fills holes with PROT_NONE mappings. */
|
||||
if (!l->l_contiguous)
|
||||
FAIL_EXIT1 ("libc.so link map is not contiguous");
|
||||
|
||||
/* Direct probing does not work because not everything is readable
|
||||
due to PROT_NONE mappings. */
|
||||
int pagesize = getpagesize ();
|
||||
ElfW(Addr) addr = l->l_map_start;
|
||||
TEST_COMPARE (addr % pagesize, 0);
|
||||
while (addr < l->l_map_end)
|
||||
{
|
||||
void *expected = (void *) addr;
|
||||
void *ptr = xmmap (expected, 1, PROT_READ | PROT_WRITE,
|
||||
MAP_PRIVATE | MAP_ANONYMOUS, -1);
|
||||
if (ptr == expected)
|
||||
FAIL ("hole in libc.so memory image after %lu bytes",
|
||||
(unsigned long int) (addr - l->l_map_start));
|
||||
xmunmap (ptr, 1);
|
||||
addr += pagesize;
|
||||
}
|
||||
|
||||
xdlclose (l);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#include <support/test-driver.c>
|
||||
@@ -0,0 +1,45 @@
|
||||
/* Check that the entire main program image is readable if contiguous.
|
||||
Copyright (C) 2025 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the GNU C Library; if not, see
|
||||
<https://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <link.h>
|
||||
#include <support/check.h>
|
||||
#include <support/xdlfcn.h>
|
||||
|
||||
static int
|
||||
do_test (void)
|
||||
{
|
||||
struct link_map *l = xdlopen ("", RTLD_NOW);
|
||||
if (!l->l_contiguous)
|
||||
FAIL_UNSUPPORTED ("main link map is not contiguous");
|
||||
|
||||
/* This check only works if the kernel loaded the main program. The
|
||||
dynamic loader replaces gaps with PROT_NONE mappings, resulting
|
||||
in faults. */
|
||||
volatile long int *p = (volatile long int *) l->l_map_start;
|
||||
volatile long int *end = (volatile long int *) l->l_map_end;
|
||||
while (p < end)
|
||||
{
|
||||
*p;
|
||||
++p;
|
||||
}
|
||||
|
||||
xdlclose (l);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#include <support/test-driver.c>
|
||||
@@ -0,0 +1,19 @@
|
||||
/* Test static PIE with an empty PT_LOAD segment at offset 0.
|
||||
Copyright (C) 2025 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the GNU C Library; if not, see
|
||||
<https://www.gnu.org/licenses/>. */
|
||||
|
||||
#include "tst-pie-bss.c"
|
||||
@@ -0,0 +1,30 @@
|
||||
/* Test PIE with an empty PT_LOAD segment at offset 0.
|
||||
Copyright (C) 2025 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the GNU C Library; if not, see
|
||||
<https://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
char bss[0xb5dce8] __attribute__ ((aligned (65536)));
|
||||
|
||||
static int
|
||||
do_test (void)
|
||||
{
|
||||
printf ("Hello\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
#include <support/test-driver.c>
|
||||
@@ -13,6 +13,6 @@ glibc.malloc.top_pad: 0x20000 (min: 0x0, max: 0x[f]+)
|
||||
glibc.malloc.trim_threshold: 0x0 (min: 0x0, max: 0x[f]+)
|
||||
glibc.rtld.dynamic_sort: 2 (min: 1, max: 2)
|
||||
glibc.rtld.enable_secure: 0 (min: 0, max: 1)
|
||||
glibc.rtld.execstack: 1 (min: 0, max: 1)
|
||||
glibc.rtld.execstack: 1 (min: 0, max: 2)
|
||||
glibc.rtld.nns: 0x4 (min: 0x1, max: 0x10)
|
||||
glibc.rtld.optional_static_tls: 0x200 (min: 0x0, max: 0x[f]+)
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
/* DSO used by tst-tls23.
|
||||
Copyright (C) 2025 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the GNU C Library; if not, see
|
||||
<https://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <tst-tls23.h>
|
||||
|
||||
__thread struct tls tls_var0 __attribute__ ((visibility ("hidden")));
|
||||
|
||||
struct tls *
|
||||
apply_tls (struct tls *p)
|
||||
{
|
||||
INIT_TLS_CALL ();
|
||||
BEFORE_TLS_CALL ();
|
||||
tls_var0 = *p;
|
||||
struct tls *ret = &tls_var0;
|
||||
AFTER_TLS_CALL ();
|
||||
return ret;
|
||||
}
|
||||
+106
@@ -0,0 +1,106 @@
|
||||
/* Test that __tls_get_addr preserves caller-saved registers.
|
||||
Copyright (C) 2025 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the GNU C Library; if not, see
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <dlfcn.h>
|
||||
#include <pthread.h>
|
||||
#include <support/xdlfcn.h>
|
||||
#include <support/xthread.h>
|
||||
#include <support/check.h>
|
||||
#include <support/test-driver.h>
|
||||
#include <tst-tls23.h>
|
||||
|
||||
#ifndef IS_SUPPORTED
|
||||
# define IS_SUPPORTED() true
|
||||
#endif
|
||||
|
||||
/* An architecture can define it to clobber caller-saved registers in
|
||||
malloc below to verify that __tls_get_addr won't change caller-saved
|
||||
registers. */
|
||||
#ifndef PREPARE_MALLOC
|
||||
# define PREPARE_MALLOC()
|
||||
#endif
|
||||
|
||||
extern void * __libc_malloc (size_t);
|
||||
|
||||
size_t malloc_counter = 0;
|
||||
|
||||
void *
|
||||
malloc (size_t n)
|
||||
{
|
||||
PREPARE_MALLOC ();
|
||||
malloc_counter++;
|
||||
return __libc_malloc (n);
|
||||
}
|
||||
|
||||
static void *mod;
|
||||
static const char *modname = "tst-tls23-mod.so";
|
||||
|
||||
static void
|
||||
open_mod (void)
|
||||
{
|
||||
mod = xdlopen (modname, RTLD_LAZY);
|
||||
printf ("open %s\n", modname);
|
||||
}
|
||||
|
||||
static void
|
||||
close_mod (void)
|
||||
{
|
||||
xdlclose (mod);
|
||||
mod = NULL;
|
||||
printf ("close %s\n", modname);
|
||||
}
|
||||
|
||||
static void
|
||||
access_mod (const char *sym)
|
||||
{
|
||||
struct tls var = { -4, -4, -4, -4 };
|
||||
struct tls *(*f) (struct tls *) = xdlsym (mod, sym);
|
||||
/* Check that our malloc is called. */
|
||||
malloc_counter = 0;
|
||||
struct tls *p = f (&var);
|
||||
TEST_VERIFY (malloc_counter != 0);
|
||||
printf ("access %s: %s() = %p\n", modname, sym, p);
|
||||
TEST_VERIFY_EXIT (memcmp (p, &var, sizeof (var)) == 0);
|
||||
++(p->a);
|
||||
}
|
||||
|
||||
static void *
|
||||
start (void *arg)
|
||||
{
|
||||
access_mod ("apply_tls");
|
||||
return arg;
|
||||
}
|
||||
|
||||
static int
|
||||
do_test (void)
|
||||
{
|
||||
if (!IS_SUPPORTED ())
|
||||
return EXIT_UNSUPPORTED;
|
||||
|
||||
open_mod ();
|
||||
pthread_t t = xpthread_create (NULL, start, NULL);
|
||||
xpthread_join (t);
|
||||
close_mod ();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#include <support/test-driver.c>
|
||||
@@ -1,5 +1,5 @@
|
||||
/* x86-64 PLT trampoline register save macros.
|
||||
Copyright (C) 2024-2025 Free Software Foundation, Inc.
|
||||
/* Test that __tls_get_addr preserves caller-saved registers.
|
||||
Copyright (C) 2025 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
@@ -16,19 +16,25 @@
|
||||
License along with the GNU C Library; if not, see
|
||||
<https://www.gnu.org/licenses/>. */
|
||||
|
||||
#ifndef DL_STACK_ALIGNMENT
|
||||
/* Due to GCC bug:
|
||||
#include <stdint.h>
|
||||
|
||||
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=58066
|
||||
struct tls
|
||||
{
|
||||
int64_t a, b, c, d;
|
||||
};
|
||||
|
||||
__tls_get_addr may be called with 8-byte stack alignment. Although
|
||||
this bug has been fixed in GCC 4.9.4, 5.3 and 6, we can't assume
|
||||
that stack will be always aligned at 16 bytes. */
|
||||
# define DL_STACK_ALIGNMENT 8
|
||||
extern struct tls *apply_tls (struct tls *);
|
||||
|
||||
/* An architecture can define them to verify that caller-saved registers
|
||||
aren't changed by __tls_get_addr. */
|
||||
#ifndef INIT_TLS_CALL
|
||||
# define INIT_TLS_CALL()
|
||||
#endif
|
||||
|
||||
/* True if _dl_runtime_resolve should align stack for STATE_SAVE or align
|
||||
stack to 16 bytes before calling _dl_fixup. */
|
||||
#define DL_RUNTIME_RESOLVE_REALIGN_STACK \
|
||||
(STATE_SAVE_ALIGNMENT > DL_STACK_ALIGNMENT \
|
||||
|| 16 > DL_STACK_ALIGNMENT)
|
||||
#ifndef BEFORE_TLS_CALL
|
||||
# define BEFORE_TLS_CALL()
|
||||
#endif
|
||||
|
||||
#ifndef AFTER_TLS_CALL
|
||||
# define AFTER_TLS_CALL()
|
||||
#endif
|
||||
@@ -0,0 +1,22 @@
|
||||
/* Stub module for linking tst-version-hash-zero-refmod.so.
|
||||
Copyright (C) 2025 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation; either version 2.1 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the GNU C Library; see the file COPYING.LIB. If
|
||||
not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
/* The version script assigns a different symbol version for the stub
|
||||
module. Loading the module with the incorrect version is expected
|
||||
to fail. */
|
||||
#include "tst-version-hash-zero-mod.c"
|
||||
@@ -0,0 +1,7 @@
|
||||
Base {
|
||||
local: *;
|
||||
};
|
||||
|
||||
OTHER_VERSION {
|
||||
global: global_variable;
|
||||
} Base;
|
||||
@@ -0,0 +1,20 @@
|
||||
/* Test module with a zero version symbol hash.
|
||||
Copyright (C) 2025 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation; either version 2.1 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the GNU C Library; see the file COPYING.LIB. If
|
||||
not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
/* The symbol version is assigned by version script. */
|
||||
int global_variable;
|
||||
@@ -0,0 +1,13 @@
|
||||
Base {
|
||||
local: *;
|
||||
};
|
||||
|
||||
/* Define the version so that tst-version-hash-zero-refmod.so passes
|
||||
the initial symbol version check. */
|
||||
OTHER_VERSION {
|
||||
} Base;
|
||||
|
||||
/* This version string hashes to zero. */
|
||||
PPPPPPPPPPPP {
|
||||
global: global_variable;
|
||||
} Base;
|
||||
@@ -0,0 +1,23 @@
|
||||
/* Test module that triggers a relocation failure in tst-version-hash-zero.
|
||||
Copyright (C) 2025 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation; either version 2.1 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the GNU C Library; see the file COPYING.LIB. If
|
||||
not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
/* This is bound to global_variable@@OTHER_VERSION via
|
||||
tst-version-hash-zero-linkmod.so, but at run time, only
|
||||
global_variable@PPPPPPPPPPPP exists. */
|
||||
extern int global_variable;
|
||||
int *pointer_variable = &global_variable;
|
||||
@@ -0,0 +1,56 @@
|
||||
/* Symbols with version hash zero should not match any version (bug 29190).
|
||||
Copyright (C) 2025 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation; either version 2.1 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the GNU C Library; see the file COPYING.LIB. If
|
||||
not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <support/check.h>
|
||||
#include <support/xdlfcn.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
|
||||
static int
|
||||
do_test (void)
|
||||
{
|
||||
void *handle = xdlopen ("tst-version-hash-zero-mod.so", RTLD_NOW);
|
||||
|
||||
/* This used to crash because some struct r_found_version entries
|
||||
with hash zero did not have valid version strings. */
|
||||
TEST_VERIFY (xdlvsym (handle, "global_variable", "PPPPPPPPPPPP") != NULL);
|
||||
|
||||
/* Consistency check. */
|
||||
TEST_VERIFY (xdlsym (handle, "global_variable")
|
||||
== xdlvsym (handle, "global_variable", "PPPPPPPPPPPP"));
|
||||
|
||||
/* This symbol version is supposed to be missing. */
|
||||
TEST_VERIFY (dlvsym (handle, "global_variable", "OTHER_VERSION") == NULL);
|
||||
|
||||
/* tst-version-hash-zero-refmod.so references
|
||||
global_variable@@OTHER_VERSION and is expected to fail to load.
|
||||
dlvsym sets the hidden flag during lookup. Relocation does not,
|
||||
so this exercises a different failure case. */
|
||||
TEST_VERIFY_EXIT (dlopen ("tst-version-hash-zero-refmod.so", RTLD_NOW)
|
||||
== NULL);
|
||||
const char *message = dlerror ();
|
||||
if (strstr (message,
|
||||
": undefined symbol: global_variable, version OTHER_VERSION")
|
||||
== NULL)
|
||||
FAIL_EXIT1 ("unexpected dlopen failure: %s", message);
|
||||
|
||||
xdlclose (handle);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#include <support/test-driver.c>
|
||||
+2
-1
@@ -138,7 +138,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)' > $@; \
|
||||
$(evaluate-test)
|
||||
|
||||
+2
-2
@@ -436,7 +436,7 @@ input_error (const char *path)
|
||||
static void
|
||||
open_output_direct (void)
|
||||
{
|
||||
output_fd = open64 (output_file, O_WRONLY | O_CREAT | O_TRUNC, 0777);
|
||||
output_fd = open64 (output_file, O_WRONLY | O_CREAT | O_TRUNC, 0666);
|
||||
if (output_fd < 0)
|
||||
output_error ();
|
||||
}
|
||||
@@ -457,7 +457,7 @@ prepare_output_file (char **argv)
|
||||
else
|
||||
{
|
||||
/* If iconv creates the output file, no overlap is possible. */
|
||||
output_fd = open64 (output_file, O_WRONLY | O_CREAT | O_EXCL, 0777);
|
||||
output_fd = open64 (output_file, O_WRONLY | O_CREAT | O_EXCL, 0666);
|
||||
if (output_fd >= 0)
|
||||
output_buffer_size = copy_buffer_size;
|
||||
else
|
||||
|
||||
+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; \
|
||||
} \
|
||||
\
|
||||
|
||||
@@ -75,6 +75,10 @@ run_iconv () {
|
||||
}
|
||||
|
||||
check_out_expected () {
|
||||
if test -x "$tmp/out" ; then
|
||||
echo "error: iconv output file is executable"
|
||||
failure=true
|
||||
fi
|
||||
if ! cmp -s "$tmp/out" "$tmp/expected" ; then
|
||||
echo "error: iconv output difference" >&$logfd
|
||||
echo "*** expected ***" >&$logfd
|
||||
|
||||
+20
-10
@@ -27,10 +27,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 $LIBPATH --inhibit-rpath ${from}.so
|
||||
$codir/iconv/iconv_prog
|
||||
'
|
||||
ICONV="$test_wrapper_env $run_program_env $ICONV"
|
||||
|
||||
TIMEOUTFACTOR=${TIMEOUTFACTOR:-1}
|
||||
|
||||
@@ -218,6 +218,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
|
||||
@@ -278,12 +279,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)) \
|
||||
|
||||
@@ -407,7 +407,7 @@ static const char from_ucs4[][2] =
|
||||
is also available. */ \
|
||||
uint32_t ch2; \
|
||||
\
|
||||
if (inptr + 1 >= inend) \
|
||||
if (inend - inptr <= 1) \
|
||||
{ \
|
||||
/* The second character is not available. */ \
|
||||
result = __GCONV_INCOMPLETE_INPUT; \
|
||||
|
||||
@@ -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>
|
||||
+14
-7
@@ -24,33 +24,35 @@ libc_hidden_proto (toupper)
|
||||
NL_CURRENT_INDIRECT. */
|
||||
|
||||
# include "../locale/localeinfo.h"
|
||||
# include <libc-tsd.h>
|
||||
|
||||
# ifndef CTYPE_EXTERN_INLINE /* Used by ctype/ctype-info.c, which see. */
|
||||
# define CTYPE_EXTERN_INLINE extern inline
|
||||
# endif
|
||||
|
||||
__libc_tsd_define (extern, const uint16_t *, CTYPE_B)
|
||||
__libc_tsd_define (extern, const int32_t *, CTYPE_TOUPPER)
|
||||
__libc_tsd_define (extern, const int32_t *, CTYPE_TOLOWER)
|
||||
extern __thread const uint16_t * __libc_tsd_CTYPE_B
|
||||
attribute_hidden attribute_tls_model_ie;
|
||||
extern __thread const int32_t * __libc_tsd_CTYPE_TOUPPER
|
||||
attribute_hidden attribute_tls_model_ie;
|
||||
extern __thread const int32_t * __libc_tsd_CTYPE_TOLOWER
|
||||
attribute_hidden attribute_tls_model_ie;
|
||||
|
||||
|
||||
CTYPE_EXTERN_INLINE const uint16_t ** __attribute__ ((const))
|
||||
__ctype_b_loc (void)
|
||||
{
|
||||
return __libc_tsd_address (const uint16_t *, CTYPE_B);
|
||||
return &__libc_tsd_CTYPE_B;
|
||||
}
|
||||
|
||||
CTYPE_EXTERN_INLINE const int32_t ** __attribute__ ((const))
|
||||
__ctype_toupper_loc (void)
|
||||
{
|
||||
return __libc_tsd_address (const int32_t *, CTYPE_TOUPPER);
|
||||
return &__libc_tsd_CTYPE_TOUPPER;
|
||||
}
|
||||
|
||||
CTYPE_EXTERN_INLINE const int32_t ** __attribute__ ((const))
|
||||
__ctype_tolower_loc (void)
|
||||
{
|
||||
return __libc_tsd_address (const int32_t *, CTYPE_TOLOWER);
|
||||
return &__libc_tsd_CTYPE_TOLOWER;
|
||||
}
|
||||
|
||||
# ifndef __NO_CTYPE
|
||||
@@ -64,6 +66,11 @@ __ctype_tolower_loc (void)
|
||||
# define __isdigit_l(c, l) ({ int __c = (c); __c >= '0' && __c <= '9'; })
|
||||
# endif /* Not __NO_CTYPE. */
|
||||
|
||||
/* For use in initializers. */
|
||||
extern const char _nl_C_LC_CTYPE_class[] attribute_hidden;
|
||||
extern const uint32_t _nl_C_LC_CTYPE_toupper[] attribute_hidden;
|
||||
extern const uint32_t _nl_C_LC_CTYPE_tolower[] attribute_hidden;
|
||||
|
||||
# endif /* IS_IN (libc). */
|
||||
#endif /* Not _ISOMAC. */
|
||||
|
||||
|
||||
+1
-2
@@ -4,8 +4,7 @@
|
||||
#include <link.h> /* For ElfW. */
|
||||
#include <stdbool.h>
|
||||
|
||||
extern __typeof (_dl_find_object) __dl_find_object;
|
||||
hidden_proto (__dl_find_object)
|
||||
rtld_hidden_proto (_dl_find_object)
|
||||
|
||||
/* Internally used flag. */
|
||||
#define __RTLD_DLOPEN 0x80000000
|
||||
|
||||
@@ -365,6 +365,8 @@ struct auditstate
|
||||
dynamic linker. */
|
||||
extern struct r_debug_extended _r_debug_extended attribute_hidden;
|
||||
|
||||
rtld_hidden_proto (_r_debug)
|
||||
|
||||
#if __ELF_NATIVE_CLASS == 32
|
||||
# define symbind symbind32
|
||||
# define LA_SYMBIND "la_symbind32"
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
+2
-3
@@ -3,8 +3,6 @@
|
||||
|
||||
# ifndef _ISOMAC
|
||||
|
||||
#include <libc-tsd.h>
|
||||
|
||||
/* Now define the internal interfaces. */
|
||||
extern unsigned long _create_xid (void);
|
||||
|
||||
@@ -47,7 +45,8 @@ extern void __rpc_thread_key_cleanup (void) attribute_hidden;
|
||||
|
||||
extern void __rpc_thread_destroy (void) attribute_hidden;
|
||||
|
||||
__libc_tsd_define (extern, struct rpc_thread_variables *, RPC_VARS)
|
||||
extern __thread struct rpc_thread_variables *__libc_tsd_RPC_VARS
|
||||
attribute_hidden attribute_tls_model_ie;
|
||||
|
||||
#define RPC_THREAD_VARIABLE(x) (__rpc_thread_variables()->x)
|
||||
|
||||
|
||||
@@ -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, ...)
|
||||
|
||||
@@ -83,6 +83,7 @@ tests = \
|
||||
bug-ungetwc1 \
|
||||
bug-ungetwc2 \
|
||||
bug-wfflush \
|
||||
bug-wgenops-bz33998 \
|
||||
bug-wmemstream1 \
|
||||
bug-wsetpos \
|
||||
test-fmemopen \
|
||||
@@ -104,6 +105,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
@@ -306,12 +306,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);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user