Compare commits

...
Author SHA1 Message Date
Hemanth Kumar M D f8f3d451ba nptl: Skip pretty-printer tests without python3 [BZ #34507]
The tests-printers-out rule in Rules wraps $(PYTHON) through
$(test-wrapper-env).  Unlike ordinary tests, which wrap a freshly built
target binary, this wraps python3, a build-host tool.  When cross-testing
with test-wrapper set (e.g. via scripts/cross-test-ssh.sh) the whole
command is forwarded to the target; if the target lacks python3 the shell
returns 127 and evaluate-test.sh reports the six nptl pretty-printer
tests as FAIL instead of UNSUPPORTED.

scripts/test_printers_common.py already exits UNSUPPORTED (77) when its
dependencies are missing, but that is unreachable when python3 itself is
absent.

Guard the invocation with a "command -v" check so the recipe exits 77
(UNSUPPORTED) when python3 is not found.  Native builds are unaffected,
as configure requires python3.

Signed-off-by: Hemanth Kumar M D <Hemanth.KumarMD@windriver.com>
Suggested-by: Adhemerval Zanella Netto <adhemerval.zanella@linaro.org>
Reviewed-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org>

(cherry picked from commit c958d789db)
2026-09-08 10:42:32 -03:00
Adhemerval Zanella d9a8ff5c01 hesiod: use booleans in parser macro calls
The swallow argument in the INT_FIELD and STRING_FIELD macros is used as a
boolean, change all callers to use false and true instead of 0 and 1.

Reviewed-by: H.J. Lu <hjl.tools@gmail.com>
(cherry picked from commit 7052455f0e)
2026-09-08 10:42:32 -03:00
Adhemerval Zanella 1c1f5103a9 hesiod: fix swapped arguments in service parser
The port number in the service file is a decimal number followed by a
single slash.

Reviewed-by: H.J. Lu <hjl.tools@gmail.com>
(cherry picked from commit 41e9457c53)
2026-09-08 10:42:32 -03:00
Andreas Schwab 049168237f nss_files: use booleans in parser macro calls
The swallow argument in the INT_FIELD and STRING_FIELD macros is used as a
boolean, change all callers to use false and true instead of 0 and 1.

(cherry picked from commit aa56ccb98b)
2026-09-08 10:37:56 -03:00
Andreas Schwab 0770e8b07c nss_files: fix swapped arguments in service parser
The port number in the service file is a decimal number followed by a
single slash.

(cherry picked from commit 66efdda2f8)
2026-09-08 10:37:56 -03:00
Shamil Abdulaev 20b3e87176 libio: Add test for fopen with an empty ", ccs=" value [BZ #34574]
This goes on top of the fix for CVE-2026-18374.  The test runs the
reproducer from the bug report, plus "w,ccs=" and "w,ccs=,", and
expects NULL with errno set to EINVAL.

Signed-off-by: Shamil Abdulaev <ashamil435@gmail.com>
Reviewed-by: Florian Weimer <fweimer@redhat.com>
(cherry picked from commit cca93e5d88)
2026-09-04 22:41:02 +02:00
Dongkyun Son 72351055c6 libio: Fix CVE-2026-18374 heap buffer overflow in ccs= handling
When fopen() is called with a ,ccs= parameter whose value becomes empty
after strip(), the code must reject it with EINVAL instead of attempting
to use it.  The original upstr() fallback could read past the ',' delimiter
and cause a heap buffer overflow.

The fix checks if the charset specification is empty after strip() and
returns EINVAL immediately, preventing the overflow and following the
approach described in BZ #34574.

CVE-2026-18374 - CVSS 4.9 (AV:L/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:L)

Reported-by: AISLE in partnership with Red Hat
Signed-off-by: Dongkyun Son <dongkyun.s@samsung.com>
Reviewed-by: Florian Weimer <fweimer@redhat.com>
(cherry picked from commit 9765a538eb)
2026-09-04 22:31:28 +02:00
Matt Turner 8dad0ee453 alpha: expect test-float32x-float64-div to fail
_Float32x and _Float64 are both binary64 on Alpha, so this narrowing
divide is a plain divide and the hardware alone decides whether to signal
underflow.

IEEE 754 determines tininess after rounding from the result rounded as if
the exponent range were unbounded, while Alpha determines it from the
delivered result.  The two differ for a quotient that is tiny but rounds
up to the smallest normal, as in DBL_MIN / (1 + 2^-52) under a rounding
mode that rounds away from zero: the binade below DBL_MIN has a finer
spacing than the subnormals, so the unbounded rounding stays below
DBL_MIN and the result is tiny, but the delivered result is DBL_MIN and
looks normal.  Alpha signals no underflow for it.

Nothing in software can correct this.  The hardware detects no underflow,
so no software completion trap is taken and the kernel emulation never
runs, and as the operation is not really narrowing there is no wider
intermediate for libm to examine.

Reviewed-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org>
(cherry picked from commit a32db99a38)
2026-08-29 14:22:28 +02:00
Matt Turner f024355965 alpha: add the denormal trap enable bit to FE_NOMASK_ENV
FE_NOMASK_ENV is the floating-point environment in which no exception is
masked, so it must enable every exception that FE_ALL_EXCEPT covers.  On
Alpha that includes the GNU extension FE_DENORMAL, whose SWCR trap enable
bit is IEEE_TRAP_ENABLE_DNO (bit 6).

The constant only set bits 1 through 5 (INV, DZE, OVF, UNF and INE), so
after fesetenv (FE_NOMASK_ENV) a subsequent fegetexcept () returned
0x3e0000 rather than FE_ALL_EXCEPT (0x7e0000), and denormal exceptions
stayed masked.  Set bit 6 as well.

Fixes math/test-fenv-return on alpha.

Reviewed-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org>
(cherry picked from commit 8e41f6008d)
2026-08-29 14:22:28 +02:00
Magnus Lindholm c4dac931ab alpha: Fix stack alignment in makecontext
The Alpha ABI requires the stack pointer to be 16-byte aligned.
However, __makecontext did not realign it after reserving space for
arguments. Depending on uc_stack.ss_size, this could leave the stack
only 8-byte aligned.

Round the new stack pointer down to a 16-byte boundary after reserving
the argument area.

This fixes stdlib/tst-makecontext2.

Signed-off-by: Magnus Lindholm <linmag7@gmail.com>
Reviewed-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org>
(cherry picked from commit 4a07bb292f)
2026-08-29 14:22:28 +02:00
Matt Turner 76115597fe alpha: fix setrlimit compat symbol for negative rlim values besides -1
Old alpha glibc defined rlim_t as signed long, making RLIM_INFINITY
equal to LONG_MAX (0x7ffffffffffffffful).  The compat symbol
__old_setrlimit64 (setrlimit@GLIBC_2.0 and setrlimit64@GLIBC_2.1) was
introduced in 0d0bc784ca [BZ #22648] to translate this old RLIM_INFINITY
to the kernel's RLIM64_INFINITY (ULONG_MAX) before the prlimit64
syscall, using an exact equality check.

Because old rlim_t was signed, any value a caller treats as negative
(e.g. -2 = 0xfffffffffffffffe unsigned) is also an "infinity or beyond"
value in the old ABI.  Such values are >= OLD_RLIM64_INFINITY and
should be translated to RLIM64_INFINITY; passing them through unchanged
causes prlimit64 to treat them as large finite limits, resulting in
unexpected failures (EPERM or silent truncation).

Change the equality check to >= OLD_RLIM64_INFINITY in
__old_setrlimit64 so that all values the old signed-rlim_t ABI would
interpret as infinity-or-more are correctly mapped to RLIM64_INFINITY.

No change is made to __old_getrlimit64: prlimit64 returns only exact
RLIM64_INFINITY for unlimited resources, so the existing equality
check against RLIM64_INFINITY is correct and mirrors the kernel's own
rlim64_is_infinity() logic.

Fixes: 0d0bc784ca ("Alpha: Add wrappers to get/setrlimit64 to fix
RLIM64_INFINITY constant [BZ #22648]")
Fixes: https://sourceware.org/bugzilla/show_bug.cgi?id=30992
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>

(cherry picked from commit c056561d31)
2026-08-29 14:22:28 +02:00
Florian Weimer c29ca5d216 iconvdata: Test case for bug 34556, bug 34568
Assisted-by: LLM
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
(cherry picked from commit 35efcffa97)
2026-08-29 14:22:01 +02:00
Florian Weimer 3ad1bbd8f9 iconvdata: EUC_JISX0213 decoding lacks pending character reset (CVE-2026-80489)
This fixes bug 34568.

Reviewed-by: Carlos O'Donell <carlos@redhat.com>
(cherry picked from commit 4dafa087ff)
2026-08-29 14:22:01 +02:00
Florian Weimer 138c43f018 iconvdata: SHIFT_JISX0213 decoding lacks pending character reset (CVE-2026-77117)
This fixes bug 34556.

Reviewed-by: Carlos O'Donell <carlos@redhat.com>
(cherry picked from commit 68d94bbe50)
2026-08-29 14:22:01 +02:00
Florian Weimer 713998bf00 stdlib: Fix right-justification in strfmon (bug 34510, CVE-2026-19499)
The memmove call did not take into account that __printf_buffer_pad
updated the buffer pointers.

Fixes commit e88b9f0e5c
("stdio-common: Convert vfprintf and related functions to buffers"),
which went into glibc 2.37.

Reviewed-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org>
(cherry picked from commit b090cf226f)
2026-08-28 21:23:09 +02:00
Adhemerval Zanella 2a35bab35b posix: Remove unnecessary overflow check in wordexp (BZ 34090)
The WRDE_APPEND path duplicates the caller's we_wordv array, which
already holds we_offs + we_wordc + 1 pointers.  Follow-up to commit
e2cefe16c3.

Checked on x86_64-linux-gnu and i686-linux-gnu.

(cherry picked from commit 53ec26f173)
2026-08-28 21:15:00 +02:00
Andreas Schwab 4964178b4d m68k: remove sysdeps/m68k/m680x0/fpu/w_fmod_compat.c (bug 34559)
This was missed from commit 6deadd4eb6.

(cherry picked from commit ff1c558061)
2026-08-24 18:35:55 +02:00
Florian Weimer 0afa34adb0 misc: Fix out-of-bounds array write in tdelete (bug 34506)
Allocate the maximum array sizes directly, instead of resizing
the arrays as needed.  This eliminates alloca usage from the
function, and fixes the out-of-bounds accesses.  The asserts
guard against the bug coming back if the balancing of the tree
turns out not to work correctly.

Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
(cherry picked from commit e2789c46e3)
2026-08-23 11:29:46 +02:00
Wilco Dijkstra 7d26579873 malloc: Show hugetlb tunable default in --list-tunables
Update the hugetlb tunable default in elf/dl-tunables.c so it is shown as 1
with /lib/ld-linux-aarch64.so.1 --list-tunables.
Move the intitialization of thp_mode/thp_pagesize to do_set_hugetlb() and
avoid accessing /sys/kernel/mm if DEFAULT_THP_PAGESIZE > 0.  Switch off THP if
glibc.malloc.hugetlb=0 is used - this behaves as if DEFAULT_THP_PAGESIZE==0.
Fix the --list-tunables testcase.

Reviewed-by: DJ Delorie <dj@redhat.com>
Signed-off-by: Alexander Sverdlin <alexander.sverdlin@siemens.com>
(cherry picked from commit e87c151130)
2026-08-14 14:18:01 +00:00
Adhemerval Zanella 8017bcfc4d m68k: Fix fmod/fmodf infinite recursion (BZ 34508)
Commits 6deadd4eb6 and ade9f30ce2 changed m68k fmod to call
__m81_u(fmod), instead of the mathimpl.h inline
__m81_u(__ieee754_fmod) (that wraps the m68k fmod instruction).
This leads to infinite recursion.

Tested-by: John Paul Adrian Glaubitz <glaubitz@physik.fu-berlin.de>

(cherry picked from commit bb213471be)
2026-08-12 13:34:03 -05:00
Adhemerval Zanella a388c4002d posix: Fix wordexp WRDE_APPEND to preserve state on non-NOSPACE errors (BZ 34090, CVE-2026-6368)
The previous implementation saved a copy of the wordexp_t struct at
entry and blindly restored it on error via (*pwordexp = old_word).
This is incorrect when WRDE_APPEND is set because w_addword may have
called realloc on we_wordv during partial processing before the error
was detected.  If realloc relocated the buffer, the saved we_wordv
pointer is dangling; restoring it causes a use-after-free in the
caller (e.g. via wordfree), and the relocated buffer is leaked.

Fix this by duplicating the we_wordv pointer array at entry when
WRDE_APPEND is set, so that all subsequent realloc calls inside
w_addword operate on the copy.

This change also fixes a POSIX conformance issue: if the WRDE_APPEND
flag is specified, pwordexp->we_wordc and pwordexp->we_wordv shall
not be modified.

Also fix two pre-existing error return paths in the '"' and '\'' cases
that returned directly from w_addword failures instead of going through
do_error, which would leak the saved array (and previously would also
skip the word cleanup).

Checked on x86_64-linux-gnu and i686-linux-gnu.

Reviewed-by: DJ Delorie <dj@redhat.com>
(cherry picked from commit e2cefe16c3)
2026-08-12 12:27:32 +02:00
Sachin Monga bc95068f5f ppc64le: Restore optimized memchr for power10 [BZ #34300]
Restore the POWER10 memchr implementation reverted in commit
a7877bb668 [BZ #33059], addressing the
actual cause:
The non-volatile vector register v20 used as the
zero vector (M_VREG_ZERO) is replaced with the volatile register v17.

Additionally, the assembler workaround used earlier for the
instructions lxvp and vextractbm is replaced with actual
instructions.

(cherry picked from commit c9b5a4a593)
2026-07-23 10:42:00 -05:00
Fabian Rast 1c9988e525 rtld: cache cpuid results on the stack for intel
dl_init_cacheinfo retrieves various information about cache
sizes, using the cpuid instruction on x86.
Previously, the same cpuid leaves were queried multiple times.
This behavior caused intel_check_word to prominently show up in
profiles of dynamic loader startup on the Intel(R) Xeon(R) Gold 6430.
The big performance impact could not be reproduced on other Intel cpus.

This patch reduces the number of cpuid queries on startup
by caching their results on the stack for reuse when searching for a
different cache size value.
This approach does not change the overall design of
the cache enumeration code (repeated calls to handle_* functions).
The values are cached on the stack instead of globally (e.g.
in the cpu_features global) because they are never needed after
early initialization.

The cache is only active for Intel cpus, because it has not yet
been shown through benchmarks that it meaningfully improves performance
for other processors.

Signed-off-by: Fabian Rast <fabian.rast@tum.de>
Reviewed-by: Sunil K Pandey <skpgkp2@gmail.com>
(cherry picked from commit df83fa8813)
2026-07-13 17:59:33 -07:00
Adhemerval Zanella dae425b554 posix: Fix stack overflow in wordexp tilde expansion (BZ 34091, CVE-2026-6791)
The parse_tilde function previously used strndupa to allocate memory
for the parsed username on the stack, and since the input is
user-defined, this can lead to a stack overflow.

This patch fixes the issue by replacing strndupa with scratch_buffer,
by reusing the buffer used in the __getpwnam_r call.

The new “tst-wordexp-tilde.c” test is a test-container to avoid using
system-defined NSS modules.

Checked on x86_64-linux-gnu and i686-linux-gnu.

(cherry picked from commit 07c24f3539)
2026-07-01 23:37:40 +02:00
Florian Weimer 8759917de5 resolv: Add test case tst-ns_sprintrr (bug 34033, bug 34069)
This test case covers both input buffer overreads and output buffer
overflows.  It should systematically cover these issues.

I used code auto-generation for updating the test expectations for
truncated RDATA in TXT, ISDN records, after writing the rest
of the test by hand.

Assisted-by: LLM
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
(cherry picked from commit 4ba0b79b95)
2026-07-01 23:35:24 +02:00
Florian Weimer 3a418da6a3 resolv: Fix buffer overreads in ns_sprintrrf (CVE-2026-6238)
Check that the RDATA payload does not require more than RDATALEN
bytes while processing it.  The fixes cover A6, LOC records.
(CERT, TKEY, TSIG were fixed before, by switching to the generic
formatter.)

The vulnerable LOC record handling was first introduced before
glibc 2.0, in commit ee188d555b.

CERT, TSIG, TKEY handling came with commit
b43b13ac25, released with glibc 2.2.

A6 record handling was introduced in commit
9163381643 ("* resolv/ns_print.c
(ns_sprintrrf): Handle ns_t_a6 and ns_t_opt."), which went into glibc
2.7.

This fixes bug 34069.

Reviewed-by: Carlos O'Donell <carlos@redhat.com>
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
(cherry picked from commit a7b60d23bb)
2026-07-01 23:35:24 +02:00
Florian Weimer e64ae5a591 resolv: More types as unknown in ns_sprintrrf (CVE-2026-5435)
Specifically, CERT, TKEY, TSIG, OPT.  This removes the buggy
implementations of TSIG, fixing bug 34033, and partially
fixing bug 34069.

Reviewed-by: Carlos O'Donell <carlos@redhat.com>
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
(cherry picked from commit ca44a6609c)
2026-07-01 23:35:24 +02:00
Florian Weimer c9225a3e73 resolv: Check for inet_ntop failure in ns_sprintrrf
This makes the output more consistent (either failure or complete
output) and helps with systematic testing with varying buffer
sizes.

Reviewed-by: Carlos O'Donell <carlos@redhat.com>
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
(cherry picked from commit cd0db208d5)
2026-07-01 23:35:24 +02:00
Florian Weimer c46f7b2fd6 resolv: Improve formatting of unknown records in ns_sprintrrf
Do not add the "unknown RR type" comment.  After adding the TYPE
prefix, the number is largely redundant.

Reviewed-by: Carlos O'Donell <carlos@redhat.com>
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
(cherry picked from commit d58415eb17)
2026-07-01 23:35:24 +02:00
Florian Weimer 1d7d1a16b0 resolv: Fix ns_sprintrrf formatting of class, type values (bug 34289)
The p_class and p_type results could overwrite each other if both
were unknown.  Format unknown values with CLASS and TYPE prefixes,
as in RFC 3597.  Handle A6 separately because it cannot be added
to __p_type_syms for ABI reasons.

Reviewed-by: Carlos O'Donell <carlos@redhat.com>
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
(cherry picked from commit f69b7f95e3)
2026-07-01 23:35:24 +02:00
Florian Weimer 349297a4eb resolv: Declare __p_class_syms, __p_type_syms for internal use
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
(cherry picked from commit 360f352c9a)
2026-07-01 23:35:24 +02:00
John David Anglin fdf10644d6 hppa: Fix missing call to __feraiseexcept (BZ 34306)
The feupdateenv function is supposed to raise exceptions after
installing the environment represented by its envp argument.
This was accidentally missed on hppa.

The failure to raise exceptions was noticed by the failure of
the math/test-narrowing-trap test.

Signed-off-by: John David Anglin <dave.anglin@bell.net>
2026-06-23 13:44:21 -04:00
Adhemerval Zanella a6fa9a9594 arm: Save/restore VFP registers in PLT trampolines (BZ 34144, BZ 15792)
_dl_runtime_resolve and _dl_runtime_profile only preserved the integer
argument registers (r0-r3) across the inner call to _dl_fixup /
_dl_profile_fixup.  Two related ABI requirements demand more:

  * Under AAPCS-VFP, d0-d7 hold the caller's double arguments to the
    function being resolved.  Recent GCC emits VFP instructions inside
    the fixup routines, clobbering them, so the resolved function sees
    corrupted arguments (BZ 34144).

  * Per RTABI32, the __aeabi_mem* helpers (and similar runtime helpers
    reachable through the dynamic linker) must only corrupt integer
    core registers.  IFUNC resolvers, audit modules, and interposed
    malloc invoked during symbol resolution may also use VFP, even on
    softfp ABI builds (BZ 15792).

Save all call-clobbered VFP state -- d0-d15 unconditionally, d16-d31
when HWCAP_ARM_VFPD32 is set, and fpscr -- around the inner fixup
call.  Whether VFP is usable is a property of the hardware, not of
the ABI glibc was built with, so the decision is gated on AT_HWCAP at
runtime in both hardfp and softfp builds; hardfp builds will always
find HWCAP_ARM_VFP set, while softfp builds running on a non-VFP CPU
correctly skip the save.

For _dl_runtime_profile the save area is slipped in just before the
bl to _dl_profile_fixup; the outgoing framesizep argument is
recomputed to account for the extra frame, and both the fast path
(no audit framesize) and the slow path (audit wraps with
pltenter/pltexit) traverse the restore before splitting.

Checked on arm-linux-gnueabihf.

Tested-by: Aurelien Jarno <aurelien@aurel32.net>
Reviewed-by: Wilco Dijkstra  <Wilco.Dijkstra@arm.com>
(cherry picked from commit 1111fbdd3e)
2026-06-17 22:28:26 +02:00
Florian Weimer fe0ccc9564 iconv: Suppress intermediate errors with //TRANSLIT (bug 34236)
When tentatively converting characters on behalf of
__gconv_transliterate, do not create a persistent error.  Just
produce a local error, and rely on __gconv_transliterate to
produce the error if all transliteration options are exhausted.

This fixes transliteration of “½” to ASCII, which cannot use the
“ 1⁄2 ” alternative.  Eventually, the “ 1/2 ” alternative is chosen,
but the error sticks.  Therefore, iconv exited with status 1 before
this change.

Adjust iconv/tst-iconv_prog.sh to test both C and en_US.UTF-8 locales.
This requires changing the way the ICONV template is defined, so that
run_program_env is evaluated multiple times.

Fixes commit 9a4b0eaf72 ("iconv: do not
report error exit with transliteration [BZ #32448]"),
commit 6cbf845fcd ("iconv: Preserve
iconv -c error exit on invalid inputs (bug 32046)"), and bug 34236.

Reviewed-by: Aurelien Jarno <aurelien@aurel32.net>
(cherry picked from commit e9325bd7d0)
2026-06-09 07:56:33 +02:00
Samuel Thibault 22f3d24a6b Hurd: restore some SIOC ioctls
We do not define struct ifreq_short and ifreq_int, but we do
define _IOT_ifreq_short and _IOT_ifreq_int, and need these for
sysdeps/gnu/ifaddrs.c and sysdeps/mach/hurd/if_index.c

(cherry picked from commit b507b6d4c6)
2026-06-08 19:10:09 +01:00
Samuel Thibault a13ebdbc7e Hurd: comment ioctls which cannot currently compile
We don't currently have struct ifreq_short, ifreq_int and ifaliasreq, so
don't let applications even try to compile these.

(cherry picked from commit 7073112263)
2026-06-08 19:10:02 +01:00
Samuel Thibault 446f708e4c Hurd: comment PF_ROUTE/AF_ROUTE defines
Comment out the PF_ROUTE and AF_ROUTE defines, since they would be used for
PF_ROUTE setsockopts, which are not available on Hurd.

(cherry picked from commit ec98b25af5)
2026-06-08 19:09:57 +01:00
Pino Toscano ced45fd472 Hurd: comment PF_LINK/AF_LINK defines
Comment out the PF_LINK and AF_LINK defines, since they are usually associated
with struct sockaddr_dl, which is not available on Hurd.

(cherry picked from commit 59a0de89ba)
2026-06-08 19:09:52 +01:00
Sam James 89cbf46693 elf: don't clobber ld.so.conf in tst-glibc-hwcaps-prepend-cache [BZ #34210]
dbe5065f21 and ae589cb84d
cater for setups where ld.so.conf{,.d} is required to find runtime support
libraries, but tst-glibc-hwcaps-prepend-cache clobbers the created ld.so.conf
with its own entry.

Fix it to instead use the ld.so.conf.d created in ae589cb84d
to co-exist with existing entries.

Bug: https://bugs.gentoo.org/976773
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=31901
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=34210
Tested-by: Andreas K. Hüttel <dilfridge@gentoo.org>
Reported-by: Eli Schwartz <eschwartz@gentoo.org>
Reviewed-by: Andreas K. Hüttel <dilfridge@gentoo.org>
(cherry picked from commit d0cc9bf859)
2026-06-08 15:40:02 +01:00
Jakub Jelinek 18b97b03b7 Rename __unused fields to __glibc_reserved.
__unused is often defined to __attribute__((unused)) in BSD
sources and furthermore libstdc++ testsuite uses it as a macro
to verify libstdc++ headers don't use __unused identifiers.
In ~2012 glibc headers have been cleaned up, but some new
uses of __unused have reappeared (s390 fenv.h already many
years ago, the rest last November).

Reviewed-by: Florian Weimer <fweimer@redhat.com>
(cherry picked from commit 243bdfec8f)
2026-05-31 18:36:12 +01:00
Adhemerval Zanella a47b5b2b3e math: Fix fma alignment when exponent difference is exactly 64 (BZ 34183)
When d (the exponent difference between z and x*y) is exactly 64,
the alignment path shifts z left by 64 bits via (zhi = nz.m, zlo = 0)
and decrements d to 0, then takes the inner 'if (d < 64)' branch
which evaluates 'rhi << (64 - d)' with d == 0.  A shift by 64 of a
64-bit value is UB in C.

Add the explicit 'if (d == 0)' empty branch (present in the
original musl implementation).

Checked on x86_64-linux-gnu with --disable-multi-arch and
arm-linux-gnueabihf.

Reviewed-by: H.J. Lu <hjl.tools@gmail.com>
(cherry picked from commit 1e7935ae87)
2026-05-28 10:34:20 -03:00
Rocket Ma 4070d808be stdio-common: Fix buffer overflow in scanf %mc [BZ #34008]
* stdio-common/vfscanf-internal.c: When enlarging allocated buffer with
format %mc or %mC, glibc allocates one byte less, leading to
user-controlled one byte overflow. This commit fixes BZ #34008, or
CVE-2026-5450.

Reviewed-by: Carlos O'Donell <carlos@redhat.com>
Signed-off-by: Rocket Ma <marocketbd@gmail.com>
Reviewed-by: H.J. Lu <hjl.tools@gmail.com>
(cherry picked from commit 8398987772)
2026-05-09 11:16:19 +02:00
Rocket Ma 2890b35cd3 libio: Fix ungetwc operating on byte stream [BZ #33998]
* libio/wgenops.c: When _IO_wdefault_pbackfail attempts to push back one
character, it accidently compare the wchar to push back with the last
char from byte stream, instead of wide stream. Under specific coding,
attacker may exploit this to leak information. This commit fix bug
33998, or CVE-2026-5928.

Signed-off-by: Rocket Ma <marocketbd@gmail.com>
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
(cherry picked from commit ef3bfb5f91)
2026-05-09 11:16:19 +02:00
H.J. Lu e9517114ac abilist.awk: Handle weak unversioned defined symbols
After

commit f685e3953f9a38a41bbd0a597f9882870cee13d5
Author: H.J. Lu <hjl.tools@gmail.com>
Date:   Wed Oct 29 09:49:57 2025 +0800

    elf: Don't set its DT_VERSYM entry for unversioned symbol

ld no longer assigns version index 1 to unversioned defined symbol.
For libmachuser.so, "objdump --dynamic-syms" reports:

0000dd30  w   DF .text	000000f8              processor_start

instead of

0000dd30  w   DF .text	000000f8 (Base)       processor_start

Also allow NF == 6 for weak unversioned dynamic symbols.  This fixes BZ
33650.

Signed-off-by: H.J. Lu <hjl.tools@gmail.com>
Reviewed-by: Sam James <sam@gentoo.org>
(cherry picked from commit ee5d1db2a8)
2026-05-03 06:52:45 +01:00
Florian Weimer 1634cc11a5 Linux: Only define OPEN_TREE_* macros in <sys/mount.h> if undefined (bug 33921)
There is a conditional inclusion of <linux/mount.h> earlier in the file.
If that defines the macros, do not redefine them.  This addresses build
problems as the token sequence used by the UAPI macro definitions
changes between Linux versions.

Reviewed-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org>
(cherry picked from commit d12b017cdd)
2026-05-02 12:52:34 +02:00
DJ Delorie d1d8d27164 include: isolate __O_CLOEXEC flag for sys/mount.h and fcntl.h
Including sys/mount.h should not implicitly include fcntl.h
as that causes namespace pollution and conflicts with kernel
headers.  It only needs O_CLOEXEC for OPEN_TREE_CLOEXEC
(although it shouldn't need that, but it's defined that way)
so we provide that define (via a private version) separately.

Reviewed-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org>
Tested-by: Florian Weimer <fweimer@redhat.com>
(cherry picked from commit 419245719c)
2026-05-02 12:52:30 +02:00
Florian Weimer 8362e8ce10 Use pending character state in IBM1390, IBM1399 character sets (CVE-2026-4046)
Follow the example in iso-2022-jp-3.c and use the __count state
variable to store the pending character.  This avoids restarting
the conversion if the output buffer ends between two 4-byte UCS-4
code points, so that the assert reported in the bug can no longer
happen.

Even though the fix is applied to ibm1364.c, the change is only
effective for the two HAS_COMBINED codecs for IBM1390, IBM1399.

The test case was mostly auto-generated using
claude-4.6-opus-high-thinking, and composer-2-fast shows up in the
log as well.  During review, gpt-5.4-xhigh flagged that the original
version of the test case was not exercising the new character
flush logic.

This fixes bug 33980.

Assisted-by: LLM
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
(cherry picked from commit d6f08d1cf0)
2026-04-19 11:32:09 +02:00
Michael Jeanson ce1013a197 tests: fix tst-rseq with Linux 7.0
A sub-test of tst-rseq is to validate the return code and errno of the
rseq syscall when attempting to register the exact same rseq area as was
done in the dynamic loader.

This involves finding the rseq area address by adding the
'__rseq_offset' to the thread pointer and calculating the area size from
the AT_RSEQ_FEATURE_SIZE auxiliary vector. However the test currently
calculates the size of the rseq area allocation in the TLS block which
must be a multiple of AT_RSEQ_ALIGN.

Up until now that happened to be the same value since the feature size
and alignment exposed by the kernel were below the minimum ABI size of
32. Starting with Linux 7.0 the feature size has reached 33 while the
alignment is now 64.

This results in the test trying to re-register the rseq area with a
different size and thus not getting the expected errno value.

Signed-off-by: Michael Jeanson <mjeanson@efficios.com>
Reviewed-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
(cherry picked from commit 67f303b47d)
2026-03-28 23:31:09 +01:00
Adhemerval Zanella Netto 60cabd0464 riscv: Resolve calls to memcpy using memcpy-generic in early startup
This patch from Adhemerval sets up the ifunc redirections so that we
resolve memcpy to memcpy_generic in early startup.  This avoids infinite
recursion for memcpy calls before the loader is fully initialized.

Tested-by: Jeff Law <jeffrey.law@oss.qualcomm.com>
(cherry picked from commit 0a9e54d40a4321ebf7d87cdbc0868c43d1e8a657)
2026-03-28 18:26:55 +01:00
Adhemerval Zanella 02ffd413cf elf: Use dl-symbol-redir-ifunc.h instead _dl_strlen
Also replace the loop with strlen And remove
-fno-tree-loop-distribute-patterns usage.

It requires redirect the strlen to the baseline implementation
for x86_64, aarch64, and loongarch64.

Checked on x86_64-linux-gnu{-v2,v3} and aarch64-linux-gnu with
both gcc-15 and clang-21.

Reviewed-by: DJ Delorie <dj@redhat.com>
(cherry picked from commit 15cc350e507101ac7b01e1343ac55087a6cd9317)
2026-03-28 18:26:49 +01:00
Xi Ruoyao 2695314378 elf: parse /proc/self/maps as the last resort to find the gap for tst-link-map-contiguous-ldso
The initialization process of libc.so calls mmap() several times and the
kernel may lay the maps into the gap.  If all pages in the gap are
occupied, the test would not be able to find the gap with mmap() and the
test would fail.

The failure reproduces most frequently on LoongArch because with the
commonly used page size (16 KiB) the gap only contains 4 pages and the
probability they are all occupied is not near to zero.

With the changes in the patch, a test run may output:

    info: ld.so link map is not contiguous
    info: object "/dev/zero" found at 0x7ffff1fe0000 - 0x7ffff1fe4000
    info: anonymous mapping found at 0x7ffff1fe4000 - 0x7ffff1fec000

Also take the chance to fix a mistake in the "object found at" message
which has puzzled me during the initial debug session.

Signed-off-by: Xi Ruoyao <xry111@xry111.site>
Reviewed-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org>
(cherry picked from commit aed8390a6a)
2026-03-28 17:42:07 +01:00
Carlos O'Donell dd9945c0ba resolv: Check hostname for validity (CVE-2026-4438)
The processed hostname in getanswer_ptr should be correctly checked to
avoid invalid characters from being allowed, including shell
metacharacters. It is a security issue to fail to check the returned
hostname for validity.

A regression test is added for invalid metacharacters and other cases
of invalid or valid characters.

No regressions on x86_64-linux-gnu.

Reviewed-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org>
(cherry picked from commit e10977481f)
2026-03-26 15:06:40 -04:00
Carlos O'Donell 5c6fca0c62 resolv: Count records correctly (CVE-2026-4437)
The answer section boundary was previously ignored, and the code in
getanswer_ptr would iterate past the last resource record, but not
beyond the end of the returned data.  This could lead to subsequent data
being interpreted as answer records, thus violating the DNS
specification.  Such resource records could be maliciously crafted and
hidden from other tooling, but processed by the glibc stub resolver and
acted upon by the application.  While we trust the data returned by the
configured recursive resolvers, we should not trust its format and
should validate it as required.  It is a security issue to incorrectly
process the DNS protocol.

A regression test is added for response section crossing.

No regressions on x86_64-linux-gnu.

Reviewed-by: Collin Funk <collin.funk1@gmail.com>
(cherry picked from commit 9f5f18aab4)
2026-03-24 07:43:56 -04:00
Florian Weimer 2be6cf2e75 posix: Run tst-wordexp-reuse-mem test
The test was not properly scheduled for execution with a Makefile
dependency.

Fixes commit 80cc58ea2d ("posix: Reset
wordexp_t fields with WRDE_REUSE (CVE-2025-15281 / BZ 33814").

(cherry picked from commit bed2db02f3)
2026-03-23 15:22:21 +01:00
Yury Khrustalev 305ce0b588 aarch64: Tests for locking GCS
Check that GCS is locked properly based on the value of the
glibc.cpu.aarch64_gcs tunable.

Test tst-gcs-execv checks that a child process can be spawned correctly
when GCS is locked for the parent process.

Test tst-gcs-fork checks that if GCS is not locked for the parent
process, the forked child can disable GCS.

Tests tst-gcs-lock and tst-gcs-lock-static check that GCS is locked
for dynamic and static executables when run with aarch64_gcs=1.

Tests tst-gcs-unlock and tst-gcs-unlock-static check that GCS is not
locked for dynamic and static executables when run with aarch64_gcs=0.

Test tst-gcs-lock-ptrace checks via ptrace that when GCS is locked,
all GCS features are locked.

Reviewed-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org>
(cherry picked from commit ad9784419e)
2026-03-10 11:01:37 +00:00
Yury Khrustalev 2ee41ba6ec aarch64: Lock GCS status at startup
If GCS is enabled (see tunable glibc.cpu.aarch64_gcs), we lock all GCS
operations (including status, write on shadow stack, and push to shadow
stack) unless OPTIONAL policy is used.

Reviewed-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org>
(cherry picked from commit 5061f524a2)
2026-03-10 10:58:44 +00:00
Yury Khrustalev fa4a40c7d4 tests: aarch64: fix makefile dependencies for dlopen tests for BTI
Some BTI tests in the sysdeps/aarch64 directory use
test shared objects via dlopen. Due to lack of direct makefile level
dependencies on these modules these tests could be run before the
required .so files would be created. This could lead to flaky test
results when running make check with -j flag. This commit fixes it.

Reviewed-by: Wilco Dijkstra  <Wilco.Dijkstra@arm.com>
(cherry picked from commit 4db97f4d04)
2026-03-10 10:57:16 +00:00
Wilco Dijkstra 9898ea58b5 malloc: Avoid accessing /sys/kernel/mm files
On AArch64 malloc always checks /sys/kernel/mm/transparent_hugepage/enabled to
set the THP mode.  However this check is quite expensive and the file may not
be accessible in containers. If DEFAULT_THP_PAGESIZE is non-zero, use
malloc_thp_mode_madvise so that we take advantage of THP in all cases.  Since
madvise is a fast systemcall, it adds only a small overhead compared to the
cost of mmap and populating the pages.

Reviewed-by: Aurelien Jarno <aurelien@aurel32.net>
(cherry picked from commit 2e8a940df1)
2026-03-08 23:53:02 +01:00
Adhemerval Zanella c3ceb93dc4 Add BZ 33904 entry to NEWS 2026-02-26 10:21:24 -03:00
Adhemerval Zanella 911bd469f8 debug: Fix build with --enable-fortify-source=1 (BZ 33904)
The libio/bits/stdio2-decl.h only defined the prototypes for
__vasprintf_chk and __vfprintf_chk for __USE_FORTIFY_LEVEL > 1.
Also defined them for the internal header regardless.

Checked with a build with --enable-fortify-source=1 and
--enable-fortify-source=2 for all afftected ABIs.

(cherry picked from commit f96e9bd2fe)
2026-02-26 10:14:06 -03:00
Florian Weimer 48f5a05a7a nss: Missing checks in __nss_configure_lookup, __nss_database_get (bug 28940)
This avoids a null pointer dereference in the
nss_database_check_reload_and_get function, and assertion failures.

Reviewed-by: Sam James <sam@gentoo.org>
(cherry picked from commit 5b713b4944)
2026-02-18 08:58:14 +01:00
Florian Weimer d6cb7ce0e9 Linux: In getlogin_r, use utmp fallback only for specific errors
Most importantly, if getwpuid_r fails, it does not make sense to retry
via utmp because the user ID obtained from there is less reliable than
the one from /proc/self/loginuid.

Reviewed-by: Sam James <sam@gentoo.org>
(cherry picked from commit 28660f4b45)
2026-02-18 08:58:14 +01:00
Florian Weimer 140c760d71 nss: Introduce dedicated struct nss_database_for_fork type
The initialized field in struct nss_database_data is rather confusing
because it is not used by the regular NSS code, only by the fork
state synchronization code.  Introduce a separate type and place
the initialized field there.

Reviewed-by: Sam James <sam@gentoo.org>
(cherry picked from commit 7bb859f419)
2026-02-18 08:58:14 +01:00
Andreas Schwab 856c426a75 Don't include <bits/openat2.h> directly (bug 33848)
Headers from bits directories should never be included directly, only via
the official headers.

(cherry picked from commit 0e47414ce8)
2026-02-04 15:32:03 -03:00
Andreas K. Hüttel 144ba30208 po: Incorporate translatins (nl updated, ar new)
Signed-off-by: Andreas K. Hüttel <dilfridge@gentoo.org>
(cherry picked from commit bad2da7f77)
2026-01-26 01:31:16 +01:00
Aurelien Jarno 022abaeacb Fix ldbl-128ibm ceill, floorl, roundl and truncl zero-sign handling
When the result of ceill, floorl, roundl and truncl is zero, the sign of
the result must match the sign of the input. For the IBM 128-bit long
double format, the sign is determined by the high part.

Ensure the correct sign when the high part is the result of
computations, by copying the sign from the input high part to the output
high part. On POWER, this conveniently maps to the fcpsgn instruction.

In addition add test for the values provided in BZ #33623, and for the
opposite value when the result is 0.

Fixes: BZ #33623

Reviewed-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org>
(cherry picked from commit 6f4b28b20a)
2026-01-24 11:57:48 +01:00
Andreas K. Hüttel 45b58d6bd1 NEWS: add new section 2.43.1
Signed-off-by: Andreas K. Hüttel <dilfridge@gentoo.org>
2026-01-24 02:32:06 +01:00
Andreas K. Hüttel f02515d8a6 Replace advisories directory with file ADVISORIES
Signed-off-by: Andreas K. Hüttel <dilfridge@gentoo.org>
2026-01-23 23:59:36 +01:00
156 changed files with 11229 additions and 1014 deletions
+2
View File
@@ -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
+14
View File
@@ -5,6 +5,20 @@ See the end for copying conditions.
Please send GNU C library bug reports via <https://sourceware.org/bugzilla/>
using `glibc' in the "product" field.
Version 2.43.1
The following bugs are resolved with this release:
[33623] [ldbl-128ibm] roundl, ceill, truncl, floorl bad sign of zero
results
[33848] build: Build fails at openat2.h, redefinition of 'struct
open_how'
[33904] build: error: '__vasprintf_chk' undeclared here
[34507] nptl: Pretty-printer tests FAIL instead of UNSUPPORTED when
cross-testing without python3 on target
[34509] libc: [m68k] Regression: Perl locks up after upgrading glibc
to 2.43
Version 2.43
Major new features:
+3 -2
View File
@@ -431,8 +431,9 @@ py-env := PYTHONPATH=$(py-const-dir):$(..)scripts:$${PYTHONPATH}
# The pretty printer files and test_common_printers.py must be present for all.
$(tests-printers-out): $(objpfx)%.out: $(objpfx)% %.py %.c $(pretty-printers) \
$(..)scripts/test_printers_common.py
$(test-wrapper-env) $(py-env) \
$(PYTHON) $*.py $*.c $(objpfx)$* $(pretty-printers) > $@; \
$(test-wrapper-env) $(py-env) sh -c \
'command -v $(firstword $(PYTHON)) > /dev/null 2>&1 || exit 77; \
exec $(PYTHON) $*.py $*.c $(objpfx)$* $(pretty-printers)' > $@; \
$(evaluate-test)
endif
-14
View File
@@ -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)
-15
View File
@@ -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)
-15
View File
@@ -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)
-16
View File
@@ -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)
-18
View File
@@ -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)
-15
View File
@@ -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)
-15
View File
@@ -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)
-13
View File
@@ -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)
-28
View File
@@ -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
-22
View File
@@ -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)
-32
View File
@@ -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)
-28
View File
@@ -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)
-26
View File
@@ -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)
-40
View File
@@ -1,40 +0,0 @@
assert: Buffer overflow when printing assertion failure message
When the assert() function fails, it does not allocate enough space for the
assertion failure message string and size information, which may lead to a
buffer overflow if the message string size aligns to page size.
This bug can be triggered when an assertion in a program fails. The assertion
failure message is allocated to allow developers to see this failure in core
dumps and it typically includes, in addition to the invariant assertion
string and function name, the name of the program. If the name of the failing
program is user controlled, for example on a local system, this could allow an
attacker to control the assertion failure to trigger this buffer overflow.
The only viable vector for exploitation of this bug is local, if a setuid
program exists that has an existing bug that results in an assertion failure.
No such program has been discovered at the time of publishing this advisory,
but the presence of custom setuid programs, although strongly discouraged as a
security practice, cannot be discounted.
CVE-Id: CVE-2025-0395
Public-Date: 2025-01-22
Vulnerable-Commit: f8a3b5bf8fa1d0c43d2458e03cc109a04fdef194 (2.13-175)
Fix-Commit: 68ee0f704cb81e9ad0a78c644a83e1e9cd2ee578 (2.41)
Fix-Commit: cdb9ba84191ce72e86346fb8b1d906e7cd930ea2 (2.42)
Fix-Commit: 69fda28279b497bd405fdd442a6d8e4d3d5f681b (2.41-7)
Fix-Commit: 7d4b6bcae91f29d7b4daf15bab06b66cf1d2217c (2.40-66)
Fix-Commit: d6c156c326999f144cb5b73d29982108d549ad8a (2.40-71)
Fix-Commit: 808a84a8b81468b517a4d721fdc62069cb8c211f (2.39-146)
Fix-Commit: f6d48470aef9264d2d56f4c4533eb76db7f9c2e4 (2.39-150)
Fix-Commit: c32fd59314c343db88c3ea4a203870481d33c3d2 (2.38-122)
Fix-Commit: f984e2d7e8299726891a1a497a3c36cd5542a0bf (2.38-124)
Fix-Commit: a3d7865b098a3a67c44f7812208d9ce4718873ba (2.37-143)
Fix-Commit: b989519fe1683c204ac24ec92830e3fe3bfaccad (2.37-146)
Fix-Commit: 7971add7ee4171fdd8dfd17e7c04c4ed77a18845 (2.36-216)
Fix-Commit: 0487893d5c5bc6710d83d7c3152d888a0339559e (2.36-219)
Fix-Commit: 8b5d4be762419c4f6176261c6fea40ac559b88dc (2.35-370)
Fix-Commit: 8b3d09dc0d350191985f9d291cc30ce96f034b49 (2.35-373)
Fix-Commit: df4e1f4a5096b385c9bcc94424cf2eaa227b3761 (2.34-500)
Fix-Commit: 31eb872cb21449832ab47ad5db83281d240e1d03 (2.34-503)
Reported-By: Qualys Security Advisory
-23
View File
@@ -1,23 +0,0 @@
elf: static setuid binary dlopen may incorrectly search LD_LIBRARY_PATH
A statically linked setuid binary that calls dlopen (including internal
dlopen calls after setlocale or calls to NSS functions such as getaddrinfo)
may incorrectly search LD_LIBRARY_PATH to determine which library to load,
leading to the execution of library code that is attacker controlled.
The only viable vector for exploitation of this bug is local, if a static
setuid program exists, and that program calls dlopen, then it may search
LD_LIBRARY_PATH to locate the SONAME to load. No such program has been
discovered at the time of publishing this advisory, but the presence of
custom setuid programs, although strongly discouraged as a security
practice, cannot be discounted.
CVE-Id: CVE-2025-4802
Public-Date: 2025-05-16
Vulnerable-Commit: 10e93d968716ab82931d593bada121c17c0a4b93 (2.27)
Fix-Commit: 5451fa962cd0a90a0e2ec1d8910a559ace02bba0 (2.39)
Fix-Commit: 3be3728df2f1912c80abd3288bc6e3a25ad679e4 (2.38-132)
Fix-Commit: 7403ede2d7752e59e0c47d5d33d73c2bf850e7be (2.37-154)
Fix-Commit: 2ef7850279b2931caf6d6d6743ebaa91839e1cf7 (2.36-227)
Fix-Commit: 621c65ccf12ddd415ceeb2234423bd1acd0fabb3 (2.35-387)
Fix-Commit: 35018c0fd20eac9ceaf60060fed2745b3177359d (2.34-517)
-30
View File
@@ -1,30 +0,0 @@
power10: strcmp fails to save and restore nonvolatile vector registers
The Power 10 implementation of strcmp in
sysdeps/powerpc/powerpc64/le/power10/strcmp.S failed to save/restore
nonvolatile vector registers in the 32-byte aligned loop path. This
results in callers reading content from those registers in a different
context, potentially altering program logic.
There could be a program context where a user controlled string could
leak through strcmp into program code, thus altering its logic. There
is also a potential for sensitive strings passed into strcmp leaking
through the clobbered registers into parts of the calling program that
should otherwise not have had access to those strings.
The impact of this flaw is limited to applications running on Power 10
hardware that use the nonvolatile vector registers, i.e. v20 to v31
assuming that they have been treated in accordance with the OpenPower
psABI. It is possible to work around the issue for those specific
applications by setting the glibc.cpu.hwcaps tunable to "-arch_3_1" like
so:
export GLIBC_TUNABLES=glibc.cpu.hwcaps=-arch_3_1
CVE-Id: CVE-2025-5702
Public-Date: 2025-06-04
Vulnerable-Commit: 3367d8e180848030d1646f088759f02b8dfe0d6f (2.39)
Fix-Commit: 15808c77b35319e67ee0dc8f984a9a1a434701bc (2.42)
Fix-Commit: 0c76c951620f9e12df2a89b2c684878b55bb6795 (2.41-60)
Fix-Commit: 7e12550b8e3a11764a4a9090ce6bd3fc23fc8a8e (2.40-139)
Fix-Commit: 06a70769fd0b2e1f2a3085ad50ab620282bd77b3 (2.39-209)
-29
View File
@@ -1,29 +0,0 @@
power10: strncmp fails to save and restore nonvolatile vector registers
The Power 10 implementation of strncmp in
sysdeps/powerpc/powerpc64/le/power10/strncmp.S failed to save/restore
nonvolatile vector registers in the 32-byte aligned loop path. This
results in callers reading content from those registers in a different
context, potentially altering program logic.
There could be a program context where a user controlled string could
leak through strncmp into program code, thus altering its logic. There
is also a potential for sensitive strings passed into strncmp leaking
through the clobbered registers into parts of the calling program that
should otherwise not have had access to those strings.
The impact of this flaw is limited to applications running on Power 10
hardware that use the nonvolatile vector registers, i.e. v20 to v31
assuming that they have been treated in accordance with the OpenPower
psABI. It is possible to work around the issue for those specific
applications by setting the glibc.cpu.hwcaps tunable to "-arch_3_1" like
so:
export GLIBC_TUNABLES=glibc.cpu.hwcaps=-arch_3_1
CVE-Id: CVE-2025-5745
Public-Date: 2025-06-05
Vulnerable-Commit: 23f0d81608d0ca6379894ef81670cf30af7fd081 (2.40)
Fix-Commit: 63c60101ce7c5eac42be90f698ba02099b41b965 (2.42)
Fix-Commit: 84bdbf8a6f2fdafd3661489dbb7f79835a52da82 (2.41-57)
Fix-Commit: 42a5a940c974d02540c8da26d6374c744d148cb9 (2.40-136)
-14
View File
@@ -1,14 +0,0 @@
posix: Fix double-free after allocation failure in regcomp
The regcomp function in the GNU C library version from 2.4 to 2.41 is
subject to a double free if some previous allocation fails. It can be
accomplished either by a malloc failure or by using an interposed
malloc that injects random malloc failures. The double free can allow
buffer manipulation depending of how the regex is constructed.
This issue affects all architectures and ABIs supported by the GNU C
library.
CVE-Id: CVE-2025-8058
Public-Date: 2025-07-22
Vulnerable-Commit: 963d8d782fc98fb6dc3a66f0068795f9920c269d (2.3.3-1596)
Fix-Commit: 7ea06e994093fa0bcca0d0ee2c1db271d8d7885d (2.42)
-41
View File
@@ -1,41 +0,0 @@
Integer overflow in memalign leads to heap corruption
Passing too large an alignment to the memalign suite of functions
(memalign, posix_memalign, aligned_alloc) in the GNU C Library version
2.30 to 2.42 may result in an integer overflow, which could consequently
result in a heap corruption.
Note that the attacker must have control over both, the size as well as
the alignment arguments of the memalign function to be able to exploit
this. The size parameter must be close enough to PTRDIFF_MAX so as to
overflow size_t along with the large alignment argument. This limits
the malicious inputs for the alignment for memalign to the range [1<<62
+ 1, 1<<63] and exactly 1<<63 for posix_memalign and aligned_alloc.
Typically the alignment argument passed to such functions is a known
constrained quantity (e.g. page size, block size, struct sizes) and is
not attacker controlled, because of which this may not be easily
exploitable in practice. An application bug could potentially result in
the input alignment being too large, e.g. due to a different buffer
overflow or integer overflow in the application or its dependent
libraries, but that is again an uncommon usage pattern given typical
sources of alignments.
CVE-Id: CVE-2026-0861
Public-Date: 2026-01-14
Vulnerable-Commit: 9bf8e29ca136094f73f69f725f15c51facc97206 (2.30)
Fix-Commit: c9188d333717d3ceb7e3020011651f424f749f93 (2.43)
Fix-Commit: 7f19ef14fbce095d4c77395e258320cad2ea2b28 (2.30-153)
Fix-Commit: f18446d7b4a423090ee5e328c36b3c2a0f26041c (2.31-166)
Fix-Commit: 8aef9e7a7af9565c0324b4ecb38b30dfa3782fd8 (2.32-151)
Fix-Commit: 011293b4fd748cdd6f95874ba2b6aba9a3df8bff (2.33-275)
Fix-Commit: 2c77e52108a58956c9f674b36e1f59a4e3fdcf4d (2.34-525)
Fix-Commit: 499d1ccafccfe64df1b88deea2fa84d8180e8e8f (2.35-399)
Fix-Commit: fb6b8822175769b5794fb6ea04f2895483a29b61 (2.36-244)
Fix-Commit: 7b913d41a07836def826f2164c52541a9835f324 (2.37-172)
Fix-Commit: 744b63026a29f7eedbbc8e3a01a7f48a6eb0a085 (2.38-212)
Fix-Commit: fb22fd3f5b415dd4cd6f7b5741c2f0412374e242 (2.39-286)
Fix-Commit: bfc4dd9e526eacf3017dd8864ba0848e9d045dd4 (2.40-216)
Fix-Commit: 1e2c1ea4307197ccece0cda574bcfebf9080894c (2.41-121)
Fix-Commit: b0ec8fb689df862171f0f78994a3bdeb51313545 (2.42-49)
Reported-by: Igor Morgenstern, Aisle Research
-36
View File
@@ -1,36 +0,0 @@
getnetbyaddr and getnetbyaddr_r leak stack contents to DNS resovler
Calling getnetbyaddr or getnetbyaddr_r with a configured nsswitch.conf
that specifies the library's DNS backend for networks and queries for a
zero-valued network in the GNU C Library version 2.0 to version 2.42
can leak stack contents to the configured DNS resolver.
A defect in the _nss_dns_getnetbyaddr_r function which implements
getnetbyaddr and getnetbyaddr_r in the dns-based network database can
pass stack contents unmodified to the configured DNS resolver as part of
the network DNS query when the network queried is the default network
i.e. net == 0x0. This stack contents leaking in the query is considered
a loss of confidentiality for the host making the query. Typically it
is rare to call these APIs with a net value of zero, and if an attacker
can control the net value it can only leak adjacent stack, and so loss
of confidentiality is spatially limited. The leak might be used to
accelerate an ASLR bypass by knowing pointer values, but also requires
network adjacent access to snoop between the application and the
DNS server; making the attack complexity higher.
CVE-Id: CVE-2026-0915
Public-Date: 2026-01-15
Vulnerable-Commit: 5f0e6fc702296840d2daa39f83f6cb1e40073d58 (1.92-1)
Fix-Commit: e56ff82d5034ec66c6a78f517af6faa427f65b0b (2.43)
Fix-Commit: 453e6b8dbab935257eb0802b0c97bca6b67ba30e (2.42-50)
Fix-Commit: 15c9839a0b853f552b4ed9047841b6223f3c104d (2.41-122)
Fix-Commit: 329c775788b2c9ff3da774ccf59fba7b6b8ff08e (2.40-217)
Fix-Commit: 831f63b94ceb92fb14c0d1a7ddad35a0d1404c71 (2.39-287)
Fix-Commit: 49125ffc8e1674dc2a100dfdc5b78796f22e16f2 (2.38-213)
Fix-Commit: ddcaed5dfb05b2c1a6ea842fd6b643501365450a (2.37-173)
Fix-Commit: a6bf47887f24b2b394acb301a3189fda04bd4d4d (2.36-245)
Fix-Commit: 66f0cb057c9b4fb1249a5fec6ef4a63511a37899 (2.35-400)
Fix-Commit: 96863dee262225cfb79f9fe45e06fd188319c7b8 (2.34-526)
Fix-Commit: d210011f1536c8322157cbb4fe4229b35c834c08 (2.33-276)
Fix-Commit: 1bc1832cfc74c2a601220969f36e789a5e9f0ebe (2.32-152)
Reported-by: Igor Morgenstern, Aisle Research
-36
View File
@@ -1,36 +0,0 @@
wordexp with WRDE_REUSE and WRDE_APPEND may return uninitialized memory
Calling wordexp with WRDE_REUSE in conjunction with WRDE_APPEND in the
GNU C Library version 2.0 to version 2.42 may cause the interface to
return uninitialized memory in the we_wordv member, which on subsequent
calls to wordfree may abort the process.
The implementation of WRDE_REUSE in conjunction with WRDE_APPEND fails
to clear the we_wordc member of the structure, and as such, when new
words are added internally, a leading we_wordc count number of entries
are skipped since they are assumed initialized. These skipped entries
are not initialized, but are the contents of a realloc-expanded array of
pointers. If the caller inspects the we_wordv array, it will
dereference invalid pointers and crash. If the caller calls wordfree,
the malloc implementation may detect the invalid pointers and abort the
process. Calls to wordexp using WRDE_REUSE and WRDE_APPEND have never
worked correctly and thus the existence of applications that make use of
this feature is unlikely.
CVE-Id: CVE-2025-15281
Public-Date: 2026-01-20
Vulnerable-Commit: 8f2ece695d8822e9ecc63ecd157e90bf17a6fe65 (1.93-260)
Fix-Commit: 80cc58ea2de214f85b0a1d902a3b668ad2ecb302 (2.43)
Fix-Commit: cbf39c26b25801e9bc88499b4fd361ac172d4125 (2.42-51)
Fix-Commit: fb4db64a04ad6c96cd1fbb7e02eb59323b1f2ac2 (2.41-123)
Fix-Commit: 9fe8576664d43b87ca19401fb6a975e217e47623 (2.40-218)
Fix-Commit: ce65d944e38a20cb70af2a48a4b8aa5d8fabe1cc (2.39-288)
Fix-Commit: d5409a1be010699794264162c551ba60f05ee6c3 (2.38-214)
Fix-Commit: ff2b172803f6bbd897755d2ce83ec4323a1a15b3 (2.37-174)
Fix-Commit: e97cfe2293ed097eb3d0b4c18274d22855e65130 (2.36-246)
Fix-Commit: bb59339d02faebac534a87eea50c83c948f35b77 (2.35-401)
Fix-Commit: 2b656ff94d72f93c84d8da2e7c76456c1994f02e (2.34-527)
Fix-Commit: 1d8ed2067a8a5d162a07670d0d063429679f17a0 (2.33-277)
Fix-Commit: 3a56c4ee4ea49b8f2391a2d8d6220013c4160a79 (2.32-153)
Fix-Commit: 28eb5caf895ced5d895cb02757e109004a2d33e5 (2.31-167)
Reported-by: Vitaly Simonovich
-77
View File
@@ -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.
-6
View File
@@ -97,12 +97,6 @@ ifeq (yesyes,$(build-shared)$(run-built-tests))
tests-special += $(objpfx)list-tunables.out
endif
# Make sure that the compiler does not insert any library calls in tunables
# code paths.
ifeq (yes,$(have-loop-to-function))
CFLAGS-dl-tunables.c += -fno-tree-loop-distribute-patterns
endif
all-dl-routines = $(dl-routines) $(sysdep-dl-routines)
# But they are absent from the shared libc, because that code is in ld.so.
elide-routines.os = \
+1
View File
@@ -25,6 +25,7 @@
#include <dl-machine.h>
#include <dl-debug.h>
#include <dl-symbol-redir-ifunc.h>
#define RESOLVE_MAP(map, scope, sym, version, flags) map
#include "dynamic-link.h"
+6 -13
View File
@@ -33,20 +33,11 @@
#include <array_length.h>
#include <dl-minimal-malloc.h>
#include <dl-symbol-redir-ifunc.h>
#include <malloc-hugepages.h>
#define TUNABLES_INTERNAL 1
#include "dl-tunables.h"
/* The function might be called before the process is self-relocated. */
static size_t
__attribute_optimization_barrier__
_dl_strlen (const char *s)
{
const char *p = s;
for (; *s != '\0'; s++);
return s - p;
}
static char **
get_next_env (char **envp, char **name, char **val, char ***prev_envp)
{
@@ -306,6 +297,10 @@ __tunables_init (char **envp)
char *envval = NULL;
char **prev_envp = envp;
/* Default to glibc.malloc.hugetlb=1 if DEFAULT_THP_PAGESIZE is non-zero. */
if (DEFAULT_THP_PAGESIZE > 0)
TUNABLE_SET (glibc, malloc, hugetlb, 1);
/* Ignore tunables for AT_SECURE programs. */
if (__libc_enable_secure)
return;
@@ -335,10 +330,8 @@ __tunables_init (char **envp)
if (tunable_is_name (name, envname))
{
/* The environment variable is always null-terminated. */
size_t envvallen = _dl_strlen (envval);
tunables_env_alias[i] =
(struct tunable_toset_t) { cur, envval, envvallen };
(struct tunable_toset_t) { cur, envval, strlen (envval) };
break;
}
}
+1 -1
View File
@@ -46,7 +46,7 @@ do_test (void)
{
/* Install the default implementation of libmarkermod1.so. */
char *conf_path = xasprintf ("%s/ld.so.conf", support_sysconfdir_prefix);
char *conf_path = xasprintf ("%s/ld.so.conf.d/hwcaps.conf", support_sysconfdir_prefix);
xmkdirp (support_sysconfdir_prefix, 0777);
support_write_file_string (conf_path, "/glibc-test/lib\n");
free (conf_path);
+62 -2
View File
@@ -18,15 +18,73 @@
#include <dlfcn.h>
#include <gnu/lib-names.h>
#include <inttypes.h>
#include <link.h>
#include <stdbool.h>
#include <stdio.h>
#include <support/check.h>
#include <support/support.h>
#include <support/xdlfcn.h>
#include <support/xunistd.h>
#include <support/xstdio.h>
#include <sys/mman.h>
#include <unistd.h>
/* Slow path in case we cannot find a gap with mmap (when the runtime has
mapped all the pages in the gap for some reason). */
static bool
find_gap_with_proc_self_map (const struct link_map *l)
{
int pagesize = getpagesize ();
support_need_proc ("Reads /proc/self/maps to find gap in ld.so mapping");
/* Parse /proc/self/maps and find all the mappings in the ld.so range
but not from ld.so. */
FILE *f = xfopen ("/proc/self/maps", "r");
char *line = NULL, *path_ldso = NULL;
size_t len;
bool found = false;
while (xgetline (&line, &len, f))
{
uintptr_t from, to;
char *path = NULL;
int r = sscanf (line, "%" SCNxPTR "-%" SCNxPTR "%*s%*s%*s%*s%ms",
&from, &to, &path);
TEST_VERIFY (r == 2 || r == 3);
TEST_COMPARE (from % pagesize, 0);
TEST_COMPARE (to % pagesize, 0);
if (path_ldso == NULL && l->l_map_start == from)
{
TEST_COMPARE (r, 3);
path_ldso = path;
continue;
}
if (from > l->l_map_start && to < l->l_map_end
&& (r == 2 || (path_ldso != NULL && strcmp (path, path_ldso))))
{
if (r == 2)
printf ("info: anonymous mapping found at 0x%" PRIxPTR " - 0x%"
PRIxPTR "\n", from, to);
else
printf ("info: object \"%s\" found at 0x%" PRIxPTR " - 0x%"
PRIxPTR "\n", path, from, to);
found = true;
}
free (path);
}
free (path_ldso);
free (line);
xfclose (f);
return found;
}
static int
do_test (void)
{
@@ -64,16 +122,18 @@ do_test (void)
if ((void *) dlfo.dlfo_link_map != (void *) l)
{
printf ("info: object \"%s\" found at %p\n",
dlfo.dlfo_link_map->l_name, ptr);
dlfo.dlfo_link_map->l_name, expected);
gap_found = true;
}
}
else
TEST_COMPARE (dlfo_ret, -1);
xmunmap (ptr, 1);
addr += pagesize;
}
if (!gap_found)
if (!gap_found && !find_gap_with_proc_self_map (l))
FAIL ("no ld.so gap found");
}
else
+2 -10
View File
@@ -26,16 +26,8 @@ run_program_env=$3
LC_ALL=C
export LC_ALL
# Unset tunables and their aliases.
GLIBC_TUNABLES=
MALLOC_ARENA_MAX=
MALLOC_ARENA_TEST=
MALLOC_CHECK_=
MALLOC_MMAP_MAX_=
MALLOC_MMAP_THRESHOLD_=
MALLOC_PERTURB_=
MALLOC_TOP_PAD_=
MALLOC_TRIM_THRESHOLD_=
# Unset tunables.
export GLIBC_TUNABLES=glibc.malloc.hugetlb=0
${test_wrapper_env} \
${run_program_env} \
+2 -2
View File
@@ -39,8 +39,8 @@ struct protoent_data {};
#include <nss/nss_files/files-parse.c>
LINE_PARSER
("#",
STRING_FIELD (result->p_name, isspace, 1);
INT_FIELD (result->p_proto, isspace, 1, 10,);
STRING_FIELD (result->p_name, isspace, true);
INT_FIELD (result->p_proto, isspace, true, 10,);
)
enum nss_status
+3 -3
View File
@@ -39,9 +39,9 @@ struct servent_data {};
#define ISSC_OR_SPACE(c) ((c) == ';' || isspace (c))
LINE_PARSER
("#",
STRING_FIELD (result->s_name, ISSC_OR_SPACE, 1);
STRING_FIELD (result->s_proto, ISSC_OR_SPACE, 1);
INT_FIELD (result->s_port, ISSC_OR_SPACE, 10, 0, htons);
STRING_FIELD (result->s_name, ISSC_OR_SPACE, true);
STRING_FIELD (result->s_proto, ISSC_OR_SPACE, true);
INT_FIELD (result->s_port, ISSC_OR_SPACE, false, 10, htons);
)
enum nss_status
+2 -1
View File
@@ -139,7 +139,8 @@ $(objpfx)test-iconvconfig.out: $(objpfx)iconvconfig
rm -f $$tmp) > $@; \
$(evaluate-test)
$(objpfx)tst-iconv_prog.out: tst-iconv_prog.sh $(objpfx)iconv_prog
$(objpfx)tst-iconv_prog.out: tst-iconv_prog.sh $(objpfx)iconv_prog \
$(gen-locales)
$(BASH) $< $(common-objdir) '$(test-wrapper-env)' \
'$(run-program-env)' '$(rpath-link)' > $@; \
$(evaluate-test)
+4 -2
View File
@@ -144,8 +144,10 @@
if (irreversible == NULL) \
{ \
/* This means we are in call from __gconv_transliterate. In this \
case we are not doing any error recovery ourselves. */ \
result = __gconv_mark_illegal_input (step_data); \
case we are not doing any error recovery ourselves. Do not create \
a persistent error state. If __gconv_transliterate exhausts all \
alternatives, it will call __gconv_mark_illegal_input itself. */ \
result = __GCONV_ILLEGAL_INPUT; \
break; \
} \
\
+20 -10
View File
@@ -29,10 +29,10 @@ LIBPATH=$codir:$codir/iconvdata
# How the start the iconv(1) program. $from is not defined/expanded yet.
ICONV='
$test_wrapper_env $run_program_env
$codir/elf/ld.so --library-path $library_path:$LIBPATH --inhibit-rpath ${from}.so
$codir/iconv/iconv_prog
'
ICONV="$test_wrapper_env $run_program_env $ICONV"
TIMEOUTFACTOR=${TIMEOUTFACTOR:-1}
@@ -220,6 +220,7 @@ testarray=(
"\x00\x00;;INVALID;UTF-8;1"
"\x00\x00;;UTF-8;INVALID;1"
"\xc3\xa9;;UTF-8;ASCII//TRANSLIT;0"
"X\xc2\xbdY;;UTF-8;ASCII//TRANSLIT;0"
)
# Requires $twobyte input, $c flag, $from, and $to to be set; sets $ret
@@ -280,12 +281,21 @@ check_errtest_result ()
fi
}
for testcommand in "${testarray[@]}"; do
twobyte="$(echo "$testcommand" | cut -d";" -f 1)"
c="$(echo "$testcommand" | cut -d";" -f 2)"
from="$(echo "$testcommand" | cut -d";" -f 3)"
to="$(echo "$testcommand" | cut -d";" -f 4)"
eret="$(echo "$testcommand" | cut -d";" -f 5)"
execute_test
check_errtest_result
done
run_test_array ()
{
for testcommand in "${testarray[@]}"; do
twobyte="$(echo "$testcommand" | cut -d";" -f 1)"
c="$(echo "$testcommand" | cut -d";" -f 2)"
from="$(echo "$testcommand" | cut -d";" -f 3)"
to="$(echo "$testcommand" | cut -d";" -f 4)"
eret="$(echo "$testcommand" | cut -d";" -f 5)"
execute_test
check_errtest_result
done
}
echo "info: testing C locale"
run_test_array
echo "info: testing en_US.UTF-8 locale"
run_program_env="$run_program_env LC_ALL=en_US.UTF-8"
run_test_array
+6 -1
View File
@@ -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)) \
+3
View File
@@ -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
View File
@@ -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) \
{ \
+3
View File
@@ -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; \
+153
View File
@@ -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>
+124
View File
@@ -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>
+2
View File
@@ -3,6 +3,8 @@
#ifndef _ISOMAC
libc_hidden_proto (__fgets_unlocked_chk)
libc_hidden_ldbl_proto (vfprintf)
extern int __vasprintf_chk (char **, int, const char *, __gnuc_va_list) __THROW;
libc_hidden_ldbl_proto (__vasprintf_chk)
extern int __vfprintf_chk (FILE *, int, const char *, __gnuc_va_list);
libc_hidden_ldbl_proto (__vfprintf_chk)
#endif
+5
View File
@@ -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;
+4
View File
@@ -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, ...)
+2
View File
@@ -84,6 +84,7 @@ tests = \
bug-ungetwc1 \
bug-ungetwc2 \
bug-wfflush \
bug-wgenops-bz33998 \
bug-wmemstream1 \
bug-wsetpos \
test-fmemopen \
@@ -107,6 +108,7 @@ tests = \
tst-fgetc-after-eof \
tst-fgetwc \
tst-fgetws \
tst-fopen-ccs-empty \
tst-fopenloc2 \
tst-fputws \
tst-freopen \
+54
View File
@@ -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
View File
@@ -339,12 +339,14 @@ _IO_new_file_fopen (FILE *fp, const char *filename, const char *mode,
*((char *) __mempcpy (ccs, cs + 5, endp - (cs + 5))) = '\0';
strip (ccs, ccs);
if (__wcsmbs_named_conv (&fcts, ccs[2] == '\0'
? upstr (ccs, cs + 5) : ccs) != 0)
/* After stripping, ccs[2] == '\0' means the charset name is empty.
This is not a valid charset and would cause problems downstream.
Reject it with EINVAL (BZ #34574, CVE-2026-18374). */
if (ccs[2] == '\0' || __wcsmbs_named_conv (&fcts, ccs) != 0)
{
/* Something went wrong, we cannot load the conversion modules.
This means we cannot proceed since the user explicitly asked
for these. */
/* Either the charset name is empty after strip(), or conversion
modules cannot be loaded. This means we cannot proceed since
the user explicitly asked for character conversion. */
(void) _IO_file_close_it (fp);
free (ccs);
__set_errno (EINVAL);
+62
View File
@@ -0,0 +1,62 @@
/* Test fopen with an empty ",ccs=" value in the mode string (bug 34574).
Copyright (C) 2026 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <support/check.h>
#include <support/support.h>
#include <support/temp_file.h>
#include <support/xunistd.h>
static void
check_fopen_fails (const char *path, const char *mode)
{
errno = 0;
FILE *fp = fopen (path, mode);
TEST_VERIFY (fp == NULL);
TEST_COMPARE (errno, EINVAL);
if (fp != NULL)
fclose (fp);
}
static int
do_test (void)
{
char *path;
xclose (create_temp_file ("tst-fopen-ccs-empty", &path));
/* The value is blank and the mode string continues well past it. */
enum { size = 1024 * 1024 };
char *mode = xmalloc (size);
memset (mode, 'X', size);
mode[size - 1] = '\0';
static const char prefix[] = "w,ccs= ,";
memcpy (mode, prefix, sizeof (prefix) - 1);
check_fopen_fails (path, mode);
free (mode);
check_fopen_fails (path, "w,ccs=");
check_fopen_fails (path, "w,ccs=,");
free (path);
return 0;
}
#include <support/test-driver.c>
+2 -2
View File
@@ -108,8 +108,8 @@ _IO_wdefault_pbackfail (FILE *fp, wint_t c)
{
if (fp->_wide_data->_IO_read_ptr > fp->_wide_data->_IO_read_base
&& !_IO_in_backup (fp)
&& (wint_t) fp->_IO_read_ptr[-1] == c)
--fp->_IO_read_ptr;
&& (wint_t) fp->_wide_data->_IO_read_ptr[-1] == c)
--fp->_wide_data->_IO_read_ptr;
else
{
/* Need to handle a filebuf in write mode (switch to read mode). FIXME!*/
+17 -19
View File
@@ -1902,26 +1902,11 @@ free_perturb (char *p, size_t n)
/* ----------- Routines dealing with transparent huge pages ----------- */
static __always_inline void
thp_init (void)
{
/* Initialize only once if DEFAULT_THP_PAGESIZE is defined. */
if (DEFAULT_THP_PAGESIZE == 0 || mp_.thp_mode != malloc_thp_mode_not_supported)
return;
/* Set thp_pagesize even if thp_mode is never. This reduces frequency
of MORECORE () invocation. */
mp_.thp_mode = __malloc_thp_mode ();
mp_.thp_pagesize = DEFAULT_THP_PAGESIZE;
}
static inline void
madvise_thp (void *p, INTERNAL_SIZE_T size)
{
#ifdef MADV_HUGEPAGE
thp_init ();
/* Only use __madvise if the system is using 'madvise' mode and the size
is at least a huge page, otherwise the call is wasteful. */
if (mp_.thp_mode != malloc_thp_mode_madvise || size < mp_.thp_pagesize)
@@ -2472,9 +2457,6 @@ sysmalloc (INTERNAL_SIZE_T nb, mstate av)
previous calls. Otherwise, we correct to page-align below.
*/
/* Ensure thp_pagesize is initialized. */
thp_init ();
if (__glibc_unlikely (mp_.thp_pagesize != 0))
{
uintptr_t lastbrk = (uintptr_t) MORECORE (0);
@@ -5132,10 +5114,26 @@ do_set_mxfast (size_t value)
static __always_inline int
do_set_hugetlb (size_t value)
{
/* Enable THP if DEFAULT_THP_PAGESIZE is non-zero. */
if (DEFAULT_THP_PAGESIZE > 0)
{
mp_.thp_mode = malloc_thp_mode_madvise;
mp_.thp_pagesize = DEFAULT_THP_PAGESIZE;
}
if (value == 0)
mp_.thp_mode = malloc_thp_mode_never;
{
/* Turn off THP support completely. */
mp_.thp_mode = malloc_thp_mode_never;
mp_.thp_pagesize = 0;
}
else if (value == 1)
{
/* Avoid querying the THP page size/mode since accessing /sys/kernel/mm
is relatively slow and might not be accessible in containers. */
if (DEFAULT_THP_PAGESIZE > 0)
return 0;
mp_.thp_mode = __malloc_thp_mode ();
if (mp_.thp_mode == malloc_thp_mode_madvise
|| mp_.thp_mode == malloc_thp_mode_always)
+33 -21
View File
@@ -620,42 +620,54 @@ This tunable controls Guarded Control Stack (GCS) for the process.
Accepted values are:
0 = disabled: do not enable GCS.
1 = enforced: check markings and fail if any binary is not marked.
2 = optional: check markings but keep GCS off if any binary is unmarked.
3 = override: enable GCS, markings are ignored.
@itemize @bullet
@item @code{0} = disabled: do not enable GCS.
@item @code{1} = enforced: check markings and abort if any binary is not
marked, otherwise enable GCS and lock all GCS features.
@item @code{2} = optional: check markings but keep GCS off if any binary
is unmarked, otherwise enable GCS but do not lock any GCS features.
@item @code{3} = override: enable GCS and lock all GCS features, markings
are ignored.
@end itemize
If unmarked binary is loaded via @code{dlopen} when GCS is enabled and
markings are not ignored (@code{aarch64_gcs == 1} or @code{2}), then
the process will be aborted.
markings are not ignored (i.e. @code{aarch64_gcs == 1} or @code{2}), then
@code{dlopen} will return an error.
Default is @code{0}, so GCS is disabled by default.
This tunable is specific to AArch64. On systems that do not support
This tunable is specific to AArch64. On systems that do not support
Guarded Control Stack this tunable has no effect.
GCS features (or operations on shadow stack) such as @code{STATUS} (i.e.
enabling and disabling GCS), @code{WRITE}, and @code{PUSH}, will be locked
for the @code{enforced} and @code{override} tunable values.
Before enabling GCS for the process the value of this tunable is checked
and depending on it the following outcomes are possible.
@code{aarch64_gcs == 0}: GCS will not be enabled and GCS markings will not be
@itemize @bullet
@item
@code{aarch64_gcs == 0}: GCS will remain disabled and GCS markings will not be
checked for any binaries.
@item
@code{aarch64_gcs == 1}: GCS markings will be checked for all binaries loaded
at startup and, only if all binaries are GCS-marked, GCS will be enabled. If
any of the binaries are not GCS-marked, the process will abort. Subsequent call
to @code{dlopen} for an unmarked binary will also result in abort.
at startup and, only if all binaries are GCS-marked, GCS will be enabled and
all GCS features will be locked. If any of the binaries are not GCS-marked,
the process will abort. Subsequent call to @code{dlopen} for an unmarked binary
will result in @code{dlopen} returning an error.
@item
@code{aarch64_gcs == 2}: GCS markings will be checked for all binaries loaded
at startup and, if any of such binaries are not GCS-marked, GCS will not be
enabled and there will be no more checks for GCS marking. If all binaries
loaded at startup are GCS-marked, then GCS will be enabled, in which case a
call to @code{dlopen} for an unmarked binary will also result in abort.
enabled and there will be no more checks for GCS marking. If all binaries
loaded at startup are GCS-marked, then GCS will be enabled but GCS features
will not be locked. In this case a call to @code{dlopen} for an unmarked binary
will result in @code{dlopen} returning an error.
@item
@code{aarch64_gcs == 3}: GCS will be enabled and all GCS features will be
locked. GCS markings will not be checked for any binaries.
@end itemize
@code{aarch64_gcs == 3}: GCS will be enabled and GCS markings will not be
checked for any binaries.
@end deftp
@node Memory Related Tunables
+2
View File
@@ -6483,6 +6483,8 @@ fma 0x1.000002p-126 -0x1.000002p-26 0x1p103
fma 0x1.000002p-126 0x1.000002p-26 -0x1p103
fma 0x1.000002p-126 -0x1.000002p-26 -0x1p103
fma 0x1.000008p+0 0x1.000008p+0 0x1p+11
fma 0x1.7fp+13 0x1.0000000000001p+0 0x1.ffep-48
fma 0x1.fffp+0 0x1.0000000000001p+0 -0x1.fffp+0
fma 0x1.0000002p+0 0x1.ffffffcp-1 0x1p-300
+25
View File
@@ -13364,6 +13364,31 @@ fma 0x1.000002p-126 -0x1.000002p-26 -0x1p103
= fma tonearest ibm128 0x4.000008p-128 -0x4.000008p-28 -0x8p+100 : -0x8p+100 : inexact
= fma towardzero ibm128 0x4.000008p-128 -0x4.000008p-28 -0x8p+100 : -0x8p+100 : inexact
= fma upward ibm128 0x4.000008p-128 -0x4.000008p-28 -0x8p+100 : -0x8p+100 : inexact
fma 0x1.000008p+0 0x1.000008p+0 0x1p+11
= fma downward binary32 0x1.000008p+0 0x1.000008p+0 0x8p+8 : 0x8.01p+8 : inexact
= fma tonearest binary32 0x1.000008p+0 0x1.000008p+0 0x8p+8 : 0x8.01p+8 : inexact
= fma towardzero binary32 0x1.000008p+0 0x1.000008p+0 0x8p+8 : 0x8.01p+8 : inexact
= fma upward binary32 0x1.000008p+0 0x1.000008p+0 0x8p+8 : 0x8.01001p+8 : inexact
= fma downward binary64 0x1.000008p+0 0x1.000008p+0 0x8p+8 : 0x8.0100001p+8 : inexact
= fma tonearest binary64 0x1.000008p+0 0x1.000008p+0 0x8p+8 : 0x8.0100001p+8 : inexact
= fma towardzero binary64 0x1.000008p+0 0x1.000008p+0 0x8p+8 : 0x8.0100001p+8 : inexact
= fma upward binary64 0x1.000008p+0 0x1.000008p+0 0x8p+8 : 0x8.0100001000008p+8 : inexact
= fma downward intel96 0x1.000008p+0 0x1.000008p+0 0x8p+8 : 0x8.0100001000004p+8 :
= fma tonearest intel96 0x1.000008p+0 0x1.000008p+0 0x8p+8 : 0x8.0100001000004p+8 :
= fma towardzero intel96 0x1.000008p+0 0x1.000008p+0 0x8p+8 : 0x8.0100001000004p+8 :
= fma upward intel96 0x1.000008p+0 0x1.000008p+0 0x8p+8 : 0x8.0100001000004p+8 :
= fma downward m68k96 0x1.000008p+0 0x1.000008p+0 0x8p+8 : 0x8.0100001000004p+8 :
= fma tonearest m68k96 0x1.000008p+0 0x1.000008p+0 0x8p+8 : 0x8.0100001000004p+8 :
= fma towardzero m68k96 0x1.000008p+0 0x1.000008p+0 0x8p+8 : 0x8.0100001000004p+8 :
= fma upward m68k96 0x1.000008p+0 0x1.000008p+0 0x8p+8 : 0x8.0100001000004p+8 :
= fma downward binary128 0x1.000008p+0 0x1.000008p+0 0x8p+8 : 0x8.0100001000004p+8 :
= fma tonearest binary128 0x1.000008p+0 0x1.000008p+0 0x8p+8 : 0x8.0100001000004p+8 :
= fma towardzero binary128 0x1.000008p+0 0x1.000008p+0 0x8p+8 : 0x8.0100001000004p+8 :
= fma upward binary128 0x1.000008p+0 0x1.000008p+0 0x8p+8 : 0x8.0100001000004p+8 :
= fma downward ibm128 0x1.000008p+0 0x1.000008p+0 0x8p+8 : 0x8.0100001000004p+8 :
= fma tonearest ibm128 0x1.000008p+0 0x1.000008p+0 0x8p+8 : 0x8.0100001000004p+8 :
= fma towardzero ibm128 0x1.000008p+0 0x1.000008p+0 0x8p+8 : 0x8.0100001000004p+8 :
= fma upward ibm128 0x1.000008p+0 0x1.000008p+0 0x8p+8 : 0x8.0100001000004p+8 :
fma 0x1.7fp+13 0x1.0000000000001p+0 0x1.ffep-48
= fma downward binary64 0x2.fep+12 0x1.0000000000001p+0 0x1.ffep-48 : 0x2.fe00000000002p+12 : inexact
= fma tonearest binary64 0x2.fep+12 0x1.0000000000001p+0 0x1.ffep-48 : 0x2.fe00000000002p+12 : inexact
+3
View File
@@ -79,6 +79,9 @@ static const struct test_f_f_data ceil_test_data[] =
TEST_f_f (ceil, -max_value, -max_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
#if MANT_DIG >= 64
/* The input value can only be represented in long double. */
TEST_f_f (ceil, -0x0.ffffffffffffffffp0L, minus_zero, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
/* The result can only be represented in long double. */
TEST_f_f (ceil, 4503599627370495.5L, 4503599627370496.0L, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
TEST_f_f (ceil, 4503599627370496.25L, 4503599627370497.0L, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
+3
View File
@@ -79,6 +79,9 @@ static const struct test_f_f_data floor_test_data[] =
TEST_f_f (floor, -max_value, -max_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
#if MANT_DIG >= 64
/* The input value can only be represented in long double. */
TEST_f_f (floor, 0x0.ffffffffffffffffp0L, plus_zero, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
/* The result can only be represented in long double. */
TEST_f_f (floor, 4503599627370495.5L, 4503599627370495.0L, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
TEST_f_f (floor, 4503599627370496.25L, 4503599627370496.0L, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
+4
View File
@@ -99,6 +99,10 @@ static const struct test_f_f_data round_test_data[] =
#endif
#if MANT_DIG >= 64
/* The input value can only be represented in long double. */
TEST_f_f (round, 0x0.ffffffffffffffffp-1L, plus_zero, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
TEST_f_f (round, -0x0.ffffffffffffffffp-1L, minus_zero, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
/* The result can only be represented in long double. */
TEST_f_f (round, 4503599627370495.5L, 4503599627370496.0L, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
TEST_f_f (round, 4503599627370496.25L, 4503599627370496.0L, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
+4
View File
@@ -91,6 +91,10 @@ static const struct test_f_f_data trunc_test_data[] =
TEST_f_f (trunc, -4294967296.625L, -4294967296.0L, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
#if MANT_DIG >= 64
/* The input value can only be represented in long double. */
TEST_f_f (trunc, 0x0.ffffffffffffffffp0L, plus_zero, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
TEST_f_f (trunc, -0x0.ffffffffffffffffp0L, minus_zero, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
/* The result can only be represented in long double. */
TEST_f_f (trunc, 4503599627370495.5L, 4503599627370495.0L, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
TEST_f_f (trunc, 4503599627370496.25L, 4503599627370496.0L, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
+11 -20
View File
@@ -85,6 +85,7 @@
#include <assert.h>
#include <stdalign.h>
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <search.h>
@@ -406,12 +407,13 @@ __tdelete (const void *key, void **vrootp, __compar_fn_t compar)
int cmp;
node *rootp = (node *) vrootp;
node root, unchained;
/* Stack of nodes so we remember the parents without recursion. It's
_very_ unlikely that there are paths longer than 40 nodes. The tree
would need to have around 250.000 nodes. */
int stacksize = 40;
/* Stack of nodes so we remember the parents without recursion. The
stack size is a conservative approximation of the maximum height
of a red-black tree, based on size of the address space.
Actual numbers are closer to 57 (32 bit) and 117 (63 bit). */
enum { stacksize = 2 * UINTPTR_WIDTH };
int sp = 0;
node **nodestack = alloca (sizeof (node *) * stacksize);
node *nodestack[stacksize];
if (rootp == NULL)
return NULL;
@@ -424,14 +426,7 @@ __tdelete (const void *key, void **vrootp, __compar_fn_t compar)
root = DEREFNODEPTR(rootp);
while ((cmp = (*compar) (key, root->key)) != 0)
{
if (sp == stacksize)
{
node **newstack;
stacksize += 20;
newstack = alloca (sizeof (node *) * stacksize);
nodestack = memcpy (newstack, nodestack, sp * sizeof (node *));
}
assert (sp < stacksize);
nodestack[sp++] = rootp;
p = DEREFNODEPTR(rootp);
if (cmp < 0)
@@ -470,13 +465,7 @@ __tdelete (const void *key, void **vrootp, __compar_fn_t compar)
node upn;
for (;;)
{
if (sp == stacksize)
{
node **newstack;
stacksize += 20;
newstack = alloca (sizeof (node *) * stacksize);
nodestack = memcpy (newstack, nodestack, sp * sizeof (node *));
}
assert (sp < stacksize);
nodestack[sp++] = parentp;
parentp = up;
upn = DEREFNODEPTR(up);
@@ -541,6 +530,7 @@ __tdelete (const void *key, void **vrootp, __compar_fn_t compar)
SETNODEPTR(pp,q);
/* Make sure pp is right if the case below tries to use
it. */
assert (sp < stacksize);
nodestack[sp++] = pp = LEFTPTR(q);
q = RIGHT(p);
}
@@ -625,6 +615,7 @@ __tdelete (const void *key, void **vrootp, __compar_fn_t compar)
SETLEFT(p,RIGHT(q));
SETRIGHT(q,p);
SETNODEPTR(pp,q);
assert (sp < stacksize);
nodestack[sp++] = pp = RIGHTPTR(q);
q = LEFT(p);
}
+1
View File
@@ -326,6 +326,7 @@ tests := \
tst-gshadow \
tst-nss-getpwent \
tst-nss-hash \
tst-nss-malloc-failure-getlogin_r \
tst-nss-test1 \
tst-nss-test2 \
tst-nss-test4 \
+13 -8
View File
@@ -56,7 +56,6 @@ global_state_allocate (void *closure)
{
result->data.nsswitch_conf.size = -1; /* Force reload. */
memset (result->data.services, 0, sizeof (result->data.services));
result->data.initialized = true;
result->data.reload_disabled = false;
__libc_lock_init (result->lock);
result->root_ino = 0;
@@ -242,9 +241,12 @@ __nss_configure_lookup (const char *dbname, const char *service_line)
/* Force any load/cache/read whatever to happen, so we can override
it. */
__nss_database_get (db, &result);
if (!__nss_database_get (db, &result))
return -1;
local = nss_database_state_get ();
if (local == NULL)
return -1;
result = __nss_action_parse (service_line);
if (result == NULL)
@@ -439,8 +441,8 @@ nss_database_check_reload_and_get (struct nss_database_state *local,
/* Avoid overwriting the global configuration until we have loaded
everything successfully. Otherwise, if the file change
information changes back to what is in the global configuration,
the lookups would use the partially-written configuration. */
struct nss_database_data staging = { .initialized = true, };
the lookups would use the partially-written configuration. */
struct nss_database_data staging = { };
bool ok = nss_database_reload (&staging, &initial);
@@ -466,6 +468,8 @@ bool
__nss_database_get (enum nss_database db, nss_action_list *actions)
{
struct nss_database_state *local = nss_database_state_get ();
if (local == NULL)
return false;
return nss_database_check_reload_and_get (local, actions, db);
}
libc_hidden_def (__nss_database_get)
@@ -491,7 +495,7 @@ __nss_database_freeres (void)
}
void
__nss_database_fork_prepare_parent (struct nss_database_data *data)
__nss_database_fork_prepare_parent (struct nss_database_for_fork *data)
{
/* Do not use allocate_once to trigger loading unnecessarily. */
struct nss_database_state *local = atomic_load_acquire (&global_database_state);
@@ -503,20 +507,21 @@ __nss_database_fork_prepare_parent (struct nss_database_data *data)
because it avoids acquiring the lock during the actual
fork. */
__libc_lock_lock (local->lock);
*data = local->data;
data->data = local->data;
__libc_lock_unlock (local->lock);
data->initialized = true;
}
}
void
__nss_database_fork_subprocess (struct nss_database_data *data)
__nss_database_fork_subprocess (struct nss_database_for_fork *data)
{
struct nss_database_state *local = atomic_load_acquire (&global_database_state);
if (data->initialized)
{
/* Restore the state at the point of the fork. */
assert (local != NULL);
local->data = *data;
local->data = data->data;
__libc_lock_init (local->lock);
}
else if (local != NULL)
+9 -3
View File
@@ -70,15 +70,21 @@ struct nss_database_data
struct file_change_detection nsswitch_conf;
nss_action_list services[NSS_DATABASE_COUNT];
int reload_disabled; /* Actually bool; int for atomic access. */
bool initialized;
};
/* Use to store a consistent state snapshot across fork. */
struct nss_database_for_fork
{
bool initialized; /* Set to true if the data field below is initialized. */
struct nss_database_data data;
};
/* Called by fork in the parent process, before forking. */
void __nss_database_fork_prepare_parent (struct nss_database_data *data)
void __nss_database_fork_prepare_parent (struct nss_database_for_fork *)
attribute_hidden;
/* Called by fork in the new subprocess, after forking. */
void __nss_database_fork_subprocess (struct nss_database_data *data)
void __nss_database_fork_subprocess (struct nss_database_for_fork *)
attribute_hidden;
#endif /* _NSS_DATABASE_H */
+3 -3
View File
@@ -36,16 +36,16 @@ LINE_PARSER
unsigned int number;
if (cnt < 5)
INT_FIELD (number, ISCOLON , 0, 16, (unsigned int))
INT_FIELD (number, ISCOLON , false, 16, (unsigned int))
else
INT_FIELD (number, isspace, 1, 16, (unsigned int))
INT_FIELD (number, isspace, true, 16, (unsigned int))
if (number > 0xff)
return 0;
result->e_addr.ether_addr_octet[cnt] = number;
}
};
STRING_FIELD (result->e_name, isspace, 1);
STRING_FIELD (result->e_name, isspace, true);
)
+2 -2
View File
@@ -53,7 +53,7 @@ LINE_PARSER
{
char *addr;
STRING_FIELD (addr, isspace, 1);
STRING_FIELD (addr, isspace, true);
/* Parse address. */
if (__inet_pton (af == AF_UNSPEC ? AF_INET : af, addr, entdata->host_addr)
@@ -96,7 +96,7 @@ LINE_PARSER
entdata->h_addr_ptrs[1] = NULL;
result->h_addr_list = entdata->h_addr_ptrs;
STRING_FIELD (result->h_name, isspace, 1);
STRING_FIELD (result->h_name, isspace, true);
})
#define EXTRA_ARGS_VALUE , AF_INET, 0
+2 -2
View File
@@ -38,9 +38,9 @@ LINE_PARSER
char *cp;
int n = 1;
STRING_FIELD (result->n_name, isspace, 1);
STRING_FIELD (result->n_name, isspace, true);
STRING_FIELD (addr, isspace, 1);
STRING_FIELD (addr, isspace, true);
/* 'inet_network' does not add zeroes at the end if the network number
does not contain four byte values. We shift result ourselves if
necessary. */
+1
View File
@@ -20,6 +20,7 @@
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <stdbool.h>
#include <stdint.h>
#include <nss_files.h>
+2 -2
View File
@@ -29,8 +29,8 @@ struct protoent_data {};
#include "files-parse.c"
LINE_PARSER
("#",
STRING_FIELD (result->p_name, isspace, 1);
INT_FIELD (result->p_proto, isspace, 1, 10,);
STRING_FIELD (result->p_name, isspace, true);
INT_FIELD (result->p_proto, isspace, true, 10,);
)
#include GENERIC
+2 -2
View File
@@ -29,8 +29,8 @@ struct rpcent_data {};
#include "files-parse.c"
LINE_PARSER
("#",
STRING_FIELD (result->r_name, isspace, 1);
INT_FIELD (result->r_number, isspace, 1, 10,);
STRING_FIELD (result->r_name, isspace, true);
INT_FIELD (result->r_number, isspace, true, 10,);
)
#include GENERIC
+3 -3
View File
@@ -31,9 +31,9 @@ struct servent_data {};
#define ISSLASH(c) ((c) == '/')
LINE_PARSER
("#",
STRING_FIELD (result->s_name, isspace, 1);
INT_FIELD (result->s_port, ISSLASH, 10, 0, htons);
STRING_FIELD (result->s_proto, isspace, 1);
STRING_FIELD (result->s_name, isspace, true);
INT_FIELD (result->s_port, ISSLASH, false, 10, htons);
STRING_FIELD (result->s_proto, isspace, true);
)
#include GENERIC
+345
View File
@@ -0,0 +1,345 @@
/* Test NSS/getlogin_r with injected allocation failures (bug 28940).
Copyright (C) 2026 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */
#include <errno.h>
#include <getopt.h>
#include <malloc.h>
#include <netdb.h>
#include <nss.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <support/check.h>
#include <support/namespace.h>
#include <support/support.h>
#include <support/xstdio.h>
#include <unistd.h>
/* This test calls getpwuid_r via getlogin_r (on Linux).
This test uses the NSS system configuration to exercise that code
path. It means that it can fail (crash) if malloc failure is not
handled by NSS modules for the passwd database. */
/* Data structure allocated via MAP_SHARED, so that writes from the
subprocess are visible. */
struct shared_data
{
/* Number of tracked allocations performed so far. */
volatile unsigned int allocation_count;
/* If this number is reached, one allocation fails. */
volatile unsigned int failing_allocation;
/* The number of allocations performed during initialization
(before the actual getlogin_r call). */
volatile unsigned int init_allocation_count;
/* Error code of an expected getlogin_r failure. */
volatile int expected_failure;
/* The subprocess stores the expected name here. */
char name[100];
};
/* Allocation count in shared mapping. */
static struct shared_data *shared;
/* Returns true if a failure should be injected for this allocation. */
static bool
fail_this_allocation (void)
{
if (shared != NULL)
{
unsigned int count = shared->allocation_count;
shared->allocation_count = count + 1;
return count == shared->failing_allocation;
}
else
return false;
}
/* Failure-injecting wrappers for allocation functions used by glibc. */
void *
malloc (size_t size)
{
if (fail_this_allocation ())
{
errno = ENOMEM;
return NULL;
}
extern __typeof (malloc) __libc_malloc;
return __libc_malloc (size);
}
void *
calloc (size_t a, size_t b)
{
if (fail_this_allocation ())
{
errno = ENOMEM;
return NULL;
}
extern __typeof (calloc) __libc_calloc;
return __libc_calloc (a, b);
}
void *
realloc (void *ptr, size_t size)
{
if (fail_this_allocation ())
{
errno = ENOMEM;
return NULL;
}
extern __typeof (realloc) __libc_realloc;
return __libc_realloc (ptr, size);
}
/* No-op subprocess to verify that support_isolate_in_subprocess does
not perform any heap allocations. */
static void
no_op (void *ignored)
{
}
/* Perform a getlogin_r call in a subprocess, to obtain the number of
allocations used and the expected result of a successful call. */
static void
initialize (void *configure_lookup)
{
shared->init_allocation_count = 0;
if (configure_lookup != NULL)
{
TEST_COMPARE (__nss_configure_lookup ("passwd", configure_lookup), 0);
shared->init_allocation_count = shared->allocation_count;
}
shared->name[0] = '\0';
int ret = getlogin_r (shared->name, sizeof (shared->name));
if (ret != 0)
{
printf ("info: getlogin_r failed: %s (%d)\n",
strerrorname_np (ret), ret);
shared->expected_failure = ret;
}
else
{
shared->expected_failure = 0;
if (shared->name[0] == '\0')
FAIL ("error: getlogin_r succeeded without result\n");
else
printf ("info: getlogin_r: \"%s\"\n", shared->name);
}
}
/* Perform getlogin_r in a subprocess with fault injection. */
static void
test_in_subprocess (void *configure_lookup)
{
if (configure_lookup != NULL
&& __nss_configure_lookup ("passwd", configure_lookup) < 0)
{
printf ("info: __nss_configure_lookup failed: %s (%d)\n",
strerrorname_np (errno), errno);
TEST_COMPARE (errno, ENOMEM);
TEST_VERIFY (shared->allocation_count <= shared->init_allocation_count);
return;
}
unsigned int inject_at = shared->failing_allocation;
char name[sizeof (shared->name)] = "name not set";
int ret = getlogin_r (name, sizeof (name));
shared->failing_allocation = ~0U;
if (ret == 0)
{
TEST_COMPARE (shared->expected_failure, 0);
TEST_COMPARE_STRING (name, shared->name);
}
else
{
printf ("info: allocation %u failure results in error %s (%d)\n",
inject_at, strerrorname_np (ret), ret);
if (ret != ENOMEM)
{
if (shared->expected_failure != 0)
TEST_COMPARE (ret, shared->expected_failure);
else if (configure_lookup == NULL)
/* The ENOENT failure can happen due to an issue related
to bug 22041: dlopen failure does not result in ENOMEM. */
TEST_COMPARE (ret, ENOENT);
else
FAIL ("unexpected getlogin_r error");
}
}
if (shared->expected_failure == 0)
{
/* The second call should succeed. */
puts ("info: about to perform second getlogin_r call");
ret = getlogin_r (name, sizeof (name));
if (configure_lookup == NULL)
{
/* This check can fail due to bug 22041 if the malloc error
injection causes a failure internally in dlopen. */
if (ret != 0)
{
printf ("warning: second getlogin_r call failed with %s (%d)\n",
strerrorname_np (ret), ret);
TEST_COMPARE (ret, ENOENT);
}
}
else
/* If __nss_configure_lookup has been called, the error caching
bug does not happen because nss_files is built-in, and the
second getlogin_r is expected to succeed. */
TEST_COMPARE (ret, 0);
if (ret == 0)
TEST_COMPARE_STRING (name, shared->name);
}
}
/* Set by the --failing-allocation command line option. Together with
--direct, this can be used to trigger an allocation failure in the
original process, which may help with debugging. */
static int option_failing_allocation = -1;
/* Set by --override, to be used with --failing-allocation. Turns on
the __nss_configure_lookup call for passwd/files, which is disabled
by default. */
static int option_override = 0;
static int
do_test (void)
{
char files[] = "files";
if (option_failing_allocation >= 0)
{
/* The test was invoked with --failing-allocation. Perform just
one test, using the original nsswitch.conf. This is a
condensed version of the probing/testing loop below. */
printf ("info: testing with failing allocation %d\n",
option_failing_allocation);
shared = support_shared_allocate (sizeof (*shared));
shared->failing_allocation = ~0U;
char *configure_lookup = option_override ? files : NULL;
support_isolate_in_subprocess (initialize, configure_lookup);
shared->allocation_count = 0;
shared->failing_allocation = option_failing_allocation;
test_in_subprocess (configure_lookup); /* No subprocess. */
support_shared_free (shared);
shared = NULL;
return 0;
}
bool any_success = false;
for (int do_configure_lookup = 0; do_configure_lookup < 2;
++do_configure_lookup)
{
if (do_configure_lookup)
puts ("info: testing with nsswitch.conf override");
else
puts ("info: testing with original nsswitch.conf");
char *configure_lookup = do_configure_lookup ? files : NULL;
shared = support_shared_allocate (sizeof (*shared));
/* Disable fault injection. */
shared->failing_allocation = ~0U;
support_isolate_in_subprocess (no_op, NULL);
TEST_COMPARE (shared->allocation_count, 0);
support_isolate_in_subprocess (initialize, configure_lookup);
if (shared->name[0] != '\0')
any_success = true;
/* The number of allocations in the successful case. Once the
number of expected allocations is exceeded, injecting further
failures does not make a difference (assuming that the number
of malloc calls is deterministic). */
unsigned int maximum_allocation_count = shared->allocation_count;
printf ("info: initial getlogin_r performed %u allocations\n",
maximum_allocation_count);
for (unsigned int inject_at = 0; inject_at <= maximum_allocation_count;
++inject_at)
{
printf ("info: running fault injection at allocation %u\n",
inject_at);
shared->allocation_count = 0;
shared->failing_allocation = inject_at;
support_isolate_in_subprocess (test_in_subprocess, configure_lookup);
}
support_shared_free (shared);
shared = NULL;
}
{
FILE *fp = fopen (_PATH_NSSWITCH_CONF, "r");
if (fp == NULL)
printf ("info: no %s file\n", _PATH_NSSWITCH_CONF);
else
{
printf ("info: %s contents follows\n", _PATH_NSSWITCH_CONF);
int last_ch = '\n';
while (true)
{
int ch = fgetc (fp);
if (ch == EOF)
break;
putchar (ch);
last_ch = ch;
}
if (last_ch != '\n')
putchar ('\n');
printf ("(end of %s contents)\n", _PATH_NSSWITCH_CONF);
xfclose (fp);
}
}
support_record_failure_barrier ();
if (!any_success)
FAIL_UNSUPPORTED ("no successful getlogin_r calls");
return 0;
}
static void
cmdline_process (int c)
{
if (c == 'F')
option_failing_allocation = atoi (optarg);
}
#define CMDLINE_OPTIONS \
{ "failing-allocation", required_argument, NULL, 'F' }, \
{ "override", no_argument, &option_override, 1 },
#define CMDLINE_PROCESS cmdline_process
#include <support/test-driver.c>
+7168
View File
File diff suppressed because it is too large Load Diff
+64 -7
View File
@@ -1,5 +1,5 @@
# Dutch translations for GNU libc.
# Copyright (C) 2025 Free Software Foundation, Inc.
# Copyright (C) 2026 Free Software Foundation, Inc.
# This file is distributed under the same license as the glibc package.
#
# "You don't get rich by treating other people well."
@@ -8,13 +8,13 @@
# Erwin Poeze <erwin.poeze@gmail.com>, 2009.
# Benno Schulenberg <benno@vertaalt.nl>, 2006, 2007, 2008, 2010, 2011, 2012.
# Benno Schulenberg <benno@vertaalt.nl>, 2013, 2014, 2015, 2017, 2018, 2019.
# Benno Schulenberg <benno@vertaalt.nl>, 2020, 2021, 2022, 2023, 2025.
# Benno Schulenberg <benno@vertaalt.nl>, 2020, 2021, 2022, 2023, 2025, 2026.
msgid ""
msgstr ""
"Project-Id-Version: libc-2.40.9000\n"
"Project-Id-Version: libc-2.42.9000\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-01-19 16:22+0100\n"
"PO-Revision-Date: 2025-01-06 15:44+0100\n"
"PO-Revision-Date: 2026-01-25 13:21+0100\n"
"Last-Translator: Benno Schulenberg <vertaling@coevern.nl>\n"
"Language-Team: Dutch <vertaling@vrijschrift.org>\n"
"Language: nl\n"
@@ -112,6 +112,16 @@ msgstr "%s: Te veel argumenten\n"
msgid "(PROGRAM ERROR) Option should have been recognized!?"
msgstr "**Interne programmafout**: optie had herkend moeten worden!?"
#: assert/assert-perr.c:45
#, c-format
msgid "%s%s%s:%s: %s%sUnexpected error: %s.\n"
msgstr "%s%s%s:%s: %s%sOnverwachte fout: %s.\n"
#: assert/assert.c:37
#, c-format
msgid "%s%s%s:%s: %s%sAssertion `%s' failed.\n"
msgstr "%s%s%s:%s: %s%sControletest '%s' faalt.\n"
#: catgets/gencat.c:112
msgid "Create C header file NAME containing symbol definitions"
msgstr "headerbestand met symbooldefinities aanmaken"
@@ -1301,6 +1311,16 @@ msgstr "kan interne descriptor niet aanmaken"
msgid "Reopening shared object `%s' failed"
msgstr "heropenen van gedeeld object '%s' is mislukt"
#: elf/sprof.c:556 elf/sprof.c:672
#, c-format
msgid "stat(%s) failure"
msgstr "stat(%s) is mislukt"
#: elf/sprof.c:573
#, c-format
msgid "read outside of file extents %zu + %jd > %jd"
msgstr "leespoging buiten de bestands-extents -- %zu + %jd > %jd"
#: elf/sprof.c:582 elf/sprof.c:689
#, c-format
msgid "reading of section headers failed"
@@ -1326,6 +1346,11 @@ msgstr "kan bestandsnaam niet bepalen"
msgid "reading of ELF header failed"
msgstr "lezen van ELF-header is mislukt"
#: elf/sprof.c:683
#, c-format
msgid "too many section headers"
msgstr "te veel sectiekoppen"
#: elf/sprof.c:720
#, c-format
msgid "*** The file `%s' is stripped: no detailed analysis possible\n"
@@ -2931,6 +2956,12 @@ msgstr "kan status van taalregio-archief '%s' niet opvragen"
msgid "cannot lock locale archive \"%s\""
msgstr "kan taalregio-archief '%s' niet vergrendelen"
#: locale/programs/locarchive.c:642 locale/programs/locarchive.c:656
#: locale/programs/locarchive.c:664 locale/programs/locarchive.c:685
#, c-format
msgid "cannot unlock archive header"
msgstr "kan archiefkop niet ontgrendelen"
#: locale/programs/locarchive.c:657
#, c-format
msgid "cannot read archive header"
@@ -6070,7 +6101,7 @@ msgstr "Achterhaald bestandshandvat"
#. TRANS properly on @gnuhurdsystems{}, making this error code impossible.)
#: sysdeps/gnu/errlist.h:479
msgid "Object is remote"
msgstr "Object is al elders"
msgstr "Object is op afstand"
#. TRANS This is used by the file locking facilities; see
#. TRANS @ref{File Locks}. This error is never generated by @gnuhurdsystems{}, but
@@ -6456,6 +6487,18 @@ msgstr "?"
msgid "RPC program not available"
msgstr "RPC-programma is niet beschikbaar"
#: sysdeps/gnu/errlist.h:801
msgid "Initialization error"
msgstr "Initialisatiefout"
#: sysdeps/gnu/errlist.h:804
msgid "Device is remote"
msgstr "Apparaat is op afstand"
#: sysdeps/gnu/errlist.h:807
msgid "Too many levels of remote in path"
msgstr "Te veel niveaus op afstand in het pad"
#: sysdeps/hppa/dl-fptr.c:96
msgid "cannot map pages for fdesc table"
msgstr "kan pagina's voor 'fdesc'-tabel niet in het geheugen plaatsen"
@@ -7071,11 +7114,21 @@ msgstr "ongeldige naam voor weekdag"
#: timezone/zic.c:2435
#, c-format
msgid "reference clients mishandle more than %d transition times"
msgstr "meer dan %d overgangstijden worden door referentie-clients onjuist behandeld"
msgstr "meer dan %d overgangstijden worden door referentie-cliënten onjuist behandeld"
#: timezone/zic.c:2439
msgid "pre-2014 clients may mishandle more than 1200 transition times"
msgstr "clients van voor 2014 zouden meer dan 1200 overgangstijden onjuist kunnen behandelen"
msgstr "cliënten van voor 2014 zouden meer dan 1200 overgangstijden onjuist kunnen behandelen"
#: timezone/zic.c:2480
#, c-format
msgid "%s: pre-2021b clients may mishandle leap second expiry"
msgstr "%s: cliënten van voor 2021b zouden het verlopen van een schrikkelseconde onjuist kunnen behandelen"
#: timezone/zic.c:2488
#, c-format
msgid "%s: pre-2021b clients may mishandle leap second table truncation"
msgstr "%s: cliënten van voor 2021b zouden afkapping van de schrikkelsecondetabel onjuist kunnen behandelen"
#: timezone/zic.c:2537
msgid "too many transition times"
@@ -7086,6 +7139,10 @@ msgstr "te veel overgangstijden"
msgid "%%z UT offset magnitude exceeds 99:59:59"
msgstr "verschuiving %%z t.o.v. UT is groter dan 99:59:59"
#: timezone/zic.c:3180
msgid "no proleptic TZ string for zone"
msgstr "er is geen proleptische TZ-tekenreeks voor de zone"
#: timezone/zic.c:3186
#, c-format
msgid "%s: pre-%d clients may mishandle distant timestamps"
+3 -1
View File
@@ -327,6 +327,7 @@ tests := \
tst-wait3 \
tst-wait4 \
tst-waitid \
tst-wordexp-append \
tst-wordexp-nocmd \
tst-wordexp-reuse \
tstgetopt \
@@ -357,6 +358,7 @@ tests-internal := \
tests-container := \
bug-ga2 \
tst-vfork3 \
tst-wordexp-tilde \
# tests-container
tests-time64 := \
@@ -499,7 +501,7 @@ tests-special += \
$(objpfx)tst-pcre-mem.out \
$(objpfx)tst-rxspencer-no-utf8-mem.out \
$(objpfx)tst-vfork3-mem.out \
$(objpfx)tst-wordexp-reuse.out \
$(objpfx)tst-wordexp-reuse-mem.out \
# tests-special
endif
endif
+1 -1
View File
@@ -50,7 +50,7 @@ __libc_fork (void)
lastrun = __run_prefork_handlers (multiple_threads);
struct nss_database_data nss_database_data;
struct nss_database_for_fork nss_database_data;
/* If we are not running multiple threads, we do not have to
preserve lock state. If fork runs from a signal handler, only
+393
View File
@@ -0,0 +1,393 @@
/* Test for wordexp with WRDE_APPEND flag.
Copyright (C) 2026 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */
#include <wordexp.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <support/check.h>
#include <support/support.h>
static unsigned int relocating_reallocs;
/* w_addword grows we_wordv with realloc, make every call guaranteed to
relocate the block. This makes BZ 34090 regression more deterministic. */
void *
realloc (void *ptr, size_t size)
{
if (ptr == NULL)
return malloc (size);
if (size == 0)
{
free (ptr);
return NULL;
}
void *new = malloc (size);
if (new == NULL)
return NULL;
/* Copy only what is valid in the old block to avoid reading past it. */
size_t old = malloc_usable_size (ptr);
memcpy (new, ptr, old < size ? old : size);
/* Clobber the old block so that a stale we_wordv pointer restored on the
error path reads garbage instead of the old contents, which might
otherwise survive intact and mask the bug. */
memset (ptr, 0x5a, old);
free (ptr);
relocating_reallocs++;
return new;
}
/* Verify that all words in we match the expected NULL-terminated
array. */
static void
check_words (const wordexp_t *we, const char *const *expected)
{
size_t i;
for (i = 0; expected[i] != NULL; i++)
{
TEST_VERIFY (i < we->we_wordc);
TEST_COMPARE_STRING (we->we_wordv[we->we_offs + i], expected[i]);
}
TEST_COMPARE (we->we_wordc, i);
}
#define CHECK_WORDS(we, ...) \
do { \
const char *const expected_[] = { __VA_ARGS__, NULL }; \
check_words (we, expected_); \
} while (0)
/* Test 1: WRDE_APPEND + WRDE_BADCHAR preserves we_wordc. */
static void
test_append_badchar_preserves_count (void)
{
printf ("info: test_append_badchar_preserves_count\n");
wordexp_t we = { 0 };
TEST_COMPARE (wordexp ("one two three", &we, 0), 0);
TEST_COMPARE (we.we_wordc, 3);
size_t saved_count = we.we_wordc;
/* ')' triggers WRDE_BADCHAR and "extra" would be a new word if the
expansion succeeded, exercising the w_addword path before the error
is detected. */
TEST_COMPARE (wordexp ("extra )", &we, WRDE_APPEND), WRDE_BADCHAR);
TEST_COMPARE (we.we_wordc, saved_count);
wordfree (&we);
}
/* Test 2: WRDE_APPEND + WRDE_BADCHAR preserves the we_wordv pointer even
when internal realloc would move the buffer. */
static void
test_append_badchar_preserves_pointer (void)
{
printf ("info: test_append_badchar_preserves_pointer\n");
wordexp_t we = { 0 };
/* Use many words so that the initial we_wordv allocation is
non-trivial and a later realloc is more likely to move it. */
TEST_COMPARE (wordexp ("a b c d e f g h", &we, 0), 0);
TEST_COMPARE (we.we_wordc, 8);
char **saved_wordv = we.we_wordv;
size_t saved_count = we.we_wordc;
unsigned int saved_reallocs = relocating_reallocs;
/* The interposed realloc guarantees the internal we_wordv buffer moves
during parsing, so the pointer-stability check below is meaningful. */
TEST_COMPARE (wordexp ("append )", &we, WRDE_APPEND), WRDE_BADCHAR);
/* Verify that a relocating realloc actually happened during the failed
call, otherwise the pointer-stability check is vacuous. */
TEST_VERIFY (relocating_reallocs > saved_reallocs);
TEST_COMPARE (we.we_wordc, saved_count);
TEST_VERIFY (we.we_wordv == saved_wordv);
wordfree (&we);
}
/* Test 3: After a failed WRDE_APPEND the original words are still accessible
and correct. */
static void
test_append_badchar_words_intact (void)
{
printf ("info: test_append_badchar_words_intact\n");
wordexp_t we = { 0 };
TEST_COMPARE (wordexp ("alpha beta gamma", &we, 0), 0);
CHECK_WORDS (&we, "alpha", "beta", "gamma");
TEST_COMPARE (wordexp ("delta )", &we, WRDE_APPEND), WRDE_BADCHAR);
/* Words must still be intact. */
CHECK_WORDS (&we, "alpha", "beta", "gamma");
/* The NULL terminator must still be present. */
TEST_VERIFY (we.we_wordv[we.we_offs + we.we_wordc] == NULL);
wordfree (&we);
}
/* Test 4: Successful WRDE_APPEND still works (regression test). */
static void
test_append_success (void)
{
printf ("info: test_append_success\n");
wordexp_t we = { 0 };
TEST_COMPARE (wordexp ("hello", &we, 0), 0);
TEST_COMPARE (we.we_wordc, 1);
char **saved_wordv = we.we_wordv;
TEST_COMPARE (wordexp ("world", &we, WRDE_APPEND), 0);
TEST_COMPARE (we.we_wordc, 2);
/* A successful append works on a fresh copy of the array, so the
caller-visible pointer must have changed. */
TEST_VERIFY (we.we_wordv != saved_wordv);
CHECK_WORDS (&we, "hello", "world");
wordfree (&we);
}
/* Test 5: Successful append after a failed append — the implementation must
recover and allow further use of the wordexp_t. */
static void
test_append_success_after_failure (void)
{
printf ("info: test_append_success_after_failure\n");
wordexp_t we = { 0 };
TEST_COMPARE (wordexp ("first", &we, 0), 0);
CHECK_WORDS (&we, "first");
TEST_COMPARE (wordexp ("bad |", &we, WRDE_APPEND), WRDE_BADCHAR);
/* State must be exactly as before the failed call. */
CHECK_WORDS (&we, "first");
/* A subsequent successful append must work. */
TEST_COMPARE (wordexp ("second third", &we, WRDE_APPEND), 0);
CHECK_WORDS (&we, "first", "second", "third");
wordfree (&we);
}
/* Test 6: Multiple consecutive failed appends do not corrupt state. */
static void
test_append_multiple_failures (void)
{
printf ("info: test_append_multiple_failures\n");
wordexp_t we = { 0 };
TEST_COMPARE (wordexp ("keep this", &we, 0), 0);
CHECK_WORDS (&we, "keep", "this");
size_t saved_count = we.we_wordc;
char **saved_wordv = we.we_wordv;
/* Each of these bad characters must leave the state unchanged. */
TEST_COMPARE (wordexp ("x )", &we, WRDE_APPEND), WRDE_BADCHAR);
TEST_COMPARE (wordexp ("x |", &we, WRDE_APPEND), WRDE_BADCHAR);
TEST_COMPARE (wordexp ("x ;", &we, WRDE_APPEND), WRDE_BADCHAR);
TEST_COMPARE (wordexp ("x &", &we, WRDE_APPEND), WRDE_BADCHAR);
TEST_COMPARE (wordexp ("x <", &we, WRDE_APPEND), WRDE_BADCHAR);
TEST_COMPARE (wordexp ("x >", &we, WRDE_APPEND), WRDE_BADCHAR);
TEST_COMPARE (we.we_wordc, saved_count);
TEST_VERIFY (we.we_wordv == saved_wordv);
CHECK_WORDS (&we, "keep", "this");
wordfree (&we);
}
/* Test 7: WRDE_APPEND with WRDE_SYNTAX error (unterminated quote) also
preserves state. */
static void
test_append_syntax_error (void)
{
printf ("info: test_append_syntax_error\n");
wordexp_t we = { 0 };
TEST_COMPARE (wordexp ("original", &we, 0), 0);
CHECK_WORDS (&we, "original");
char **saved_wordv = we.we_wordv;
size_t saved_count = we.we_wordc;
/* Unterminated double quote triggers WRDE_SYNTAX. */
TEST_COMPARE (wordexp ("\"unterminated", &we, WRDE_APPEND), WRDE_SYNTAX);
TEST_COMPARE (we.we_wordc, saved_count);
TEST_VERIFY (we.we_wordv == saved_wordv);
CHECK_WORDS (&we, "original");
wordfree (&we);
}
/* Test 8: Error without WRDE_APPEND still works (regression test for the
non-APPEND code path in do_error). */
static void
test_no_append_error (void)
{
printf ("info: test_no_append_error\n");
wordexp_t we = { 0 };
/* Simple failure without WRDE_APPEND. */
TEST_COMPARE (wordexp ("bad |", &we, 0), WRDE_BADCHAR);
/* After failure without WRDE_APPEND the struct should be safe to
reuse start fresh. */
TEST_COMPARE (wordexp ("ok", &we, 0), 0);
CHECK_WORDS (&we, "ok");
wordfree (&we);
}
/* Test 9: WRDE_BADCHAR on the very first character (no partial words added
before the error). */
static void
test_append_badchar_immediate (void)
{
printf ("info: test_append_badchar_immediate\n");
wordexp_t we = { 0 };
TEST_COMPARE (wordexp ("hello world", &we, 0), 0);
CHECK_WORDS (&we, "hello", "world");
char **saved_wordv = we.we_wordv;
size_t saved_count = we.we_wordc;
/* The bad character is the very first byte — no w_addword call happens
before the error. */
TEST_COMPARE (wordexp ("|", &we, WRDE_APPEND), WRDE_BADCHAR);
TEST_COMPARE (we.we_wordc, saved_count);
TEST_VERIFY (we.we_wordv == saved_wordv);
wordfree (&we);
}
/* Test 10: WRDE_APPEND into an empty wordexp_t (initial call uses WRDE_APPEND
with a zeroed struct unusual but allowed). */
static void
test_append_into_empty (void)
{
printf ("info: test_append_into_empty\n");
wordexp_t we = { 0 };
/* First call with WRDE_APPEND on a zeroed struct. The implementation
must handle we_wordv == NULL gracefully. */
TEST_COMPARE (wordexp ("solo", &we, WRDE_APPEND), 0);
TEST_COMPARE (we.we_wordc, 1);
CHECK_WORDS (&we, "solo");
wordfree (&we);
}
/* Verify that the leading we_offs slots are all NULL. */
static void
check_offs_null (const wordexp_t *we)
{
for (size_t i = 0; i < we->we_offs; i++)
TEST_VERIFY (we->we_wordv[i] == NULL);
}
/* Test 11: successful WRDE_APPEND with WRDE_DOOFFS and a non-zero we_offs.
The leading offset slots must stay NULL and words must land at
we_wordv[we_offs + i] across both the initial and the appended call. */
static void
test_dooffs_append_success (void)
{
printf ("info: test_dooffs_append_success\n");
wordexp_t we = { 0 };
we.we_offs = 2;
TEST_COMPARE (wordexp ("one two", &we, WRDE_DOOFFS), 0);
TEST_COMPARE (we.we_offs, 2);
check_offs_null (&we);
CHECK_WORDS (&we, "one", "two");
TEST_COMPARE (wordexp ("three", &we, WRDE_APPEND | WRDE_DOOFFS), 0);
TEST_COMPARE (we.we_offs, 2);
check_offs_null (&we);
CHECK_WORDS (&we, "one", "two", "three");
/* The NULL terminator must sit right after the last word. */
TEST_VERIFY (we.we_wordv[we.we_offs + we.we_wordc] == NULL);
wordfree (&we);
}
/* Test 12: failed WRDE_APPEND with WRDE_DOOFFS preserves we_wordc, the
we_wordv pointer, the words and the leading NULL offset slots. This
exercises the we_offs arithmetic in the array duplication and in the
error-path cleanup (we_wordv[we_offs + --we_wordc]). */
static void
test_dooffs_append_error_preserves_state (void)
{
printf ("info: test_dooffs_append_error_preserves_state\n");
wordexp_t we = { 0 };
we.we_offs = 3;
TEST_COMPARE (wordexp ("alpha beta", &we, WRDE_DOOFFS), 0);
check_offs_null (&we);
CHECK_WORDS (&we, "alpha", "beta");
char **saved_wordv = we.we_wordv;
size_t saved_count = we.we_wordc;
unsigned int saved_reallocs = relocating_reallocs;
/* "gamma" is a partial word added via w_addword (forcing a relocating
realloc of we_wordv) before ')' triggers WRDE_BADCHAR. */
TEST_COMPARE (wordexp ("gamma )", &we, WRDE_APPEND | WRDE_DOOFFS),
WRDE_BADCHAR);
TEST_VERIFY (relocating_reallocs > saved_reallocs);
TEST_COMPARE (we.we_offs, 3);
TEST_COMPARE (we.we_wordc, saved_count);
TEST_VERIFY (we.we_wordv == saved_wordv);
check_offs_null (&we);
CHECK_WORDS (&we, "alpha", "beta");
TEST_VERIFY (we.we_wordv[we.we_offs + we.we_wordc] == NULL);
wordfree (&we);
}
static int
do_test (void)
{
test_append_badchar_preserves_count ();
test_append_badchar_preserves_pointer ();
test_append_badchar_words_intact ();
test_append_success ();
test_append_success_after_failure ();
test_append_multiple_failures ();
test_append_syntax_error ();
test_no_append_error ();
test_append_badchar_immediate ();
test_append_into_empty ();
test_dooffs_append_success ();
test_dooffs_append_error_preserves_state ();
return 0;
}
#include <support/test-driver.c>
+244
View File
@@ -0,0 +1,244 @@
/* Test wordexp tilde expansion with large usernames (BZ 34091).
Copyright (C) 2026 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */
#include <pwd.h>
#include <stdio.h>
#include <string.h>
#include <wordexp.h>
#include <stdlib.h>
#include <sys/resource.h>
#include <support/check.h>
#include <support/support.h>
#include <support/xunistd.h>
#include <support/namespace.h>
typedef void (*func_callback_t)(void);
static void
subprocess_small_stack (void *closure)
{
struct rlimit rl;
TEST_COMPARE (getrlimit (RLIMIT_STACK, &rl), 0);
rl.rlim_cur = 512 * 1024;
TEST_COMPARE (setrlimit (RLIMIT_STACK, &rl), 0);
func_callback_t func_test = closure;
func_test ();
}
/* Build a string "~<padding>/tail" where <padding> is LEN bytes of the
character CH. The caller must free the result. */
static char *
make_tilde_input (char ch, size_t len, const char *tail)
{
/* ~ + len + / + tail + \0 */
size_t taillen = tail != NULL ? strlen (tail) : 0;
size_t total = 1 + len + 1 + taillen + 1;
char *buf = xmalloc (total);
buf[0] = '~';
memset (buf + 1, ch, len);
buf[1 + len] = '/';
if (tail != NULL)
memcpy (buf + 1 + len + 1, tail, taillen);
buf[total - 1] = '\0';
return buf;
}
/* Test 1: A very long username must not crash. The username will not match
any real user, so wordexp returns ~<long>/rest. */
static void
test_long_username (void)
{
printf ("info: test_long_username_no_crash\n");
static const char REST[] = "rest";
/* 1 MiB username — well beyond any reasonable stack frame. */
const size_t long_len = 1024 * 1024;
char *input = make_tilde_input ('A', long_len, REST);
wordexp_t we = { 0 };
int ret = wordexp (input, &we, 0);
/* The (non-existent) username is invalid, so wordexp falls back to
literal output: ~AAA/rest. */
TEST_COMPARE (ret, 0);
TEST_COMPARE (we.we_wordc, 1);
/* Verify prefix: '~' followed by long_len 'A's. */
const char *result = we.we_wordv[0];
TEST_COMPARE (result[0], '~');
TEST_COMPARE (strlen (result),
1 /* ~ */ + long_len + sizeof (REST));
for (size_t j = 1; j <= long_len; j++)
if (result[j] != 'A')
{
printf (" mismatch at position %zu: expected 'A', got '%c'\n",
j, result[j]);
support_record_failure ();
break;
}
/* Verify the tail after the username. */
TEST_COMPARE_STRING (result + 1 + long_len, "/rest");
wordfree (&we);
free (input);
}
/* Test 2: A username that just exceeds the default scratch_buffer inline
size (1024 bytes) exercises the scratch_buffer_set_array_size growth path
without being excessively large. */
static void
test_scratch_buffer_growth (void)
{
printf ("info: test_scratch_buffer_growth\n");
const size_t len = 2048;
char *input = make_tilde_input ('x', len, NULL);
wordexp_t we = { 0 };
int ret = wordexp (input, &we, 0);
TEST_COMPARE (ret, 0);
TEST_COMPARE (we.we_wordc, 1);
/* ~xxx…/ — the trailing slash makes a separate empty component, but
wordexp merges it into the single token ~xxx/. */
const char *result = we.we_wordv[0];
TEST_COMPARE (result[0], '~');
for (size_t j = 1; j <= len; j++)
if (result[j] != 'x')
{
printf (" mismatch at position %zu\n", j);
support_record_failure ();
break;
}
TEST_COMPARE (result[1 + len], '/');
wordfree (&we);
free (input);
}
/* Test 3: ~root still resolves to the correct home directory through the
__getpwnam_r path. */
static void
test_known_user (void)
{
printf ("info: test_known_user\n");
/* Look up root's home directory for comparison. */
struct passwd *pw = getpwnam ("root");
if (pw == NULL || pw->pw_dir == NULL)
{
printf (" SKIP: cannot look up root\n");
return;
}
char *expected = xasprintf ("%s/file", pw->pw_dir);
wordexp_t we = { 0 };
TEST_COMPARE (wordexp ("~root/file", &we, 0), 0);
TEST_COMPARE (we.we_wordc, 1);
TEST_COMPARE_STRING (we.we_wordv[0], expected);
wordfree (&we);
free (expected);
}
/* Test 4: Bare tilde expands to $HOME. */
static void
test_bare_tilde (void)
{
printf ("info: test_bare_tilde\n");
const char *home = getenv ("HOME");
if (home == NULL)
{
printf (" SKIP: HOME is not set\n");
return;
}
wordexp_t we = { 0 };
TEST_COMPARE (wordexp ("~", &we, 0), 0);
TEST_COMPARE (we.we_wordc, 1);
TEST_COMPARE_STRING (we.we_wordv[0], home);
wordfree (&we);
}
/* Test 5: Short non-existent username falls back to literal ~username output,
exercising the invalid-login-name path. */
static void
test_unknown_user (void)
{
printf ("info: test_unknown_user\n");
/* Pick a username that is extremely unlikely to exist. */
wordexp_t we = { 0 };
TEST_COMPARE (wordexp ("~no_such_user_xyzzy42", &we, 0), 0);
TEST_COMPARE (we.we_wordc, 1);
TEST_COMPARE_STRING (we.we_wordv[0], "~no_such_user_xyzzy42");
wordfree (&we);
}
/* Test 6: Tilde with username and WRDE_APPEND — exercises parse_tilde's
interaction with the WRDE_APPEND word list. */
static void
test_tilde_with_append (void)
{
printf ("info: test_tilde_with_append\n");
const char *home = getenv ("HOME");
if (home == NULL)
{
printf (" SKIP: HOME is not set\n");
return;
}
wordexp_t we = { 0 };
TEST_COMPARE (wordexp ("first", &we, 0), 0);
TEST_COMPARE (wordexp ("~/path", &we, WRDE_APPEND), 0);
TEST_COMPARE (we.we_wordc, 2);
TEST_COMPARE_STRING (we.we_wordv[0], "first");
char *expected = xasprintf ("%s/path", home);
TEST_COMPARE_STRING (we.we_wordv[1], expected);
wordfree (&we);
free (expected);
}
static int
do_test (void)
{
test_known_user ();
test_bare_tilde ();
test_unknown_user ();
test_tilde_with_append ();
support_isolate_in_subprocess (subprocess_small_stack,
test_long_username);
support_isolate_in_subprocess (subprocess_small_stack,
test_scratch_buffer_growth);
return 0;
}
#include <support/test-driver.c>
+1
View File
@@ -0,0 +1 @@
root:x:0:
@@ -0,0 +1,3 @@
passwd: files
group: files
shadow: files
+1
View File
@@ -0,0 +1 @@
root:x:0:0:root:/root:/bin/sh
+75 -15
View File
@@ -335,17 +335,29 @@ parse_tilde (char **word, size_t *word_length, size_t *max_length,
else
{
/* Look up user name in database to get home directory */
char *user = strndupa (&words[1 + *offset], i - (1 + *offset));
struct passwd pwd, *tpwd;
int result;
size_t userlen = i - (1 + *offset);
/* tmpbuf contains both the user and the __getpwnam_r working area. */
struct scratch_buffer tmpbuf;
scratch_buffer_init (&tmpbuf);
if (!scratch_buffer_set_array_size (&tmpbuf, userlen + 1, 1))
return WRDE_NOSPACE;
char *user = tmpbuf.data;
memcpy (user, &words[1 + *offset], userlen);
user[userlen] = '\0';
while ((result = __getpwnam_r (user, &pwd, tmpbuf.data, tmpbuf.length,
struct passwd pwd, *tpwd;
int result;
while ((result = __getpwnam_r (user,
&pwd,
tmpbuf.data + userlen + 1,
tmpbuf.length - userlen - 1,
&tpwd)) != 0
&& errno == ERANGE)
if (!scratch_buffer_grow (&tmpbuf))
return WRDE_NOSPACE;
{
if (!scratch_buffer_grow_preserve (&tmpbuf))
return WRDE_NOSPACE;
user = tmpbuf.data;
}
if (result == 0 && tpwd != NULL && pwd.pw_dir)
*word = w_addstr (*word, word_length, max_length, pwd.pw_dir);
@@ -2212,6 +2224,12 @@ wordexp (const char *words, wordexp_t *pwordexp, int flags)
char ifs_white[4];
wordexp_t old_word = *pwordexp;
/* When WRDE_APPEND is set we work on a copy of the we_wordv array so that
the caller's original pointer is never invalidated by realloc inside
w_addword. The saved_wordv keeps the original; on success we free it,
on non-NOSPACE error we free the working copy and restore the original. */
char **saved_wordv = NULL;
if (flags & WRDE_REUSE)
{
/* Minimal implementation of WRDE_REUSE for now */
@@ -2246,6 +2264,21 @@ wordexp (const char *words, wordexp_t *pwordexp, int flags)
pwordexp->we_offs = 0;
}
}
else if (pwordexp->we_wordv != NULL)
{
/* WRDE_APPEND with an existing word list: duplicate the array so that
realloc during parsing does not invalidate the caller's pointer. The
strings themselves are shared an the array already holds
'we_offs + we_wordc + 1 pointers' (so the size computation cannot
overflow). */
size_t num_p = pwordexp->we_offs + pwordexp->we_wordc + 1;
char **dup = malloc (num_p * sizeof (char *));
if (dup == NULL)
return WRDE_NOSPACE;
memcpy (dup, pwordexp->we_wordv, num_p * sizeof (char *));
saved_wordv = pwordexp->we_wordv;
pwordexp->we_wordv = dup;
}
/* Find out what the field separators are.
* There are two types: whitespace and non-whitespace.
@@ -2326,7 +2359,7 @@ wordexp (const char *words, wordexp_t *pwordexp, int flags)
error = w_addword (pwordexp, NULL);
if (error)
return error;
goto do_error;
}
break;
@@ -2344,7 +2377,7 @@ wordexp (const char *words, wordexp_t *pwordexp, int flags)
error = w_addword (pwordexp, NULL);
if (error)
return error;
goto do_error;
}
break;
@@ -2410,10 +2443,18 @@ wordexp (const char *words, wordexp_t *pwordexp, int flags)
/* There was a word separator at the end */
if (word == NULL) /* i.e. w_newword */
return 0;
{
free (saved_wordv);
return 0;
}
/* There was no field separator at the end */
return w_addword (pwordexp, word);
/* There was no field separator at the end. The only possible error
from w_addword is WRDE_NOSPACE. */
error = w_addword (pwordexp, word);
if (error != 0)
goto do_error;
free (saved_wordv);
return 0;
do_error:
/* Error:
@@ -2424,11 +2465,30 @@ do_error:
free (word);
if (error == WRDE_NOSPACE)
return WRDE_NOSPACE;
{
/* we_wordc and we_wordv are updated to reflect any words that were
successfully expanded. The old array is obsolete. */
free (saved_wordv);
return WRDE_NOSPACE;
}
if ((flags & WRDE_APPEND) == 0)
wordfree (pwordexp);
if (flags & WRDE_APPEND)
{
/* POSIX 2024 states that for in other error cases, if the WRDE_APPEND
flag was specified, we_wordc and we_wordv shall not be modified.
Free strings appended during this call, discard the working copy of
we_wordv, and restore the caller's original pointer. */
while (pwordexp->we_wordc > old_word.we_wordc)
free (pwordexp->we_wordv[pwordexp->we_offs + --pwordexp->we_wordc]);
free (pwordexp->we_wordv);
pwordexp->we_wordv = saved_wordv;
}
else
{
wordfree (pwordexp);
*pwordexp = old_word;
}
*pwordexp = old_word;
return error;
}
+9
View File
@@ -101,14 +101,17 @@ tests += \
tst-ns_name \
tst-ns_name_compress \
tst-ns_name_pton \
tst-ns_sprintrr \
tst-res_hconf_reorder \
tst-res_hnok \
tst-resolv-aliases \
tst-resolv-basic \
tst-resolv-binary \
tst-resolv-byaddr \
tst-resolv-dns-section \
tst-resolv-edns \
tst-resolv-invalid-cname \
tst-resolv-invalid-ptr \
tst-resolv-network \
tst-resolv-noaaaa \
tst-resolv-noaaaa-vc \
@@ -118,6 +121,7 @@ tests += \
tst-resolv-semi-failure \
tst-resolv-short-response \
tst-resolv-trailing \
# tests
# This test calls __res_context_send directly, which is not exported
# from libresolv.
@@ -301,6 +305,8 @@ $(objpfx)tst-resolv-aliases: $(objpfx)libresolv.so $(shared-thread-library)
$(objpfx)tst-resolv-basic: $(objpfx)libresolv.so $(shared-thread-library)
$(objpfx)tst-resolv-binary: $(objpfx)libresolv.so $(shared-thread-library)
$(objpfx)tst-resolv-byaddr: $(objpfx)libresolv.so $(shared-thread-library)
$(objpfx)tst-resolv-dns-section: $(objpfx)libresolv.so \
$(shared-thread-library)
$(objpfx)tst-resolv-edns: $(objpfx)libresolv.so $(shared-thread-library)
$(objpfx)tst-resolv-network: $(objpfx)libresolv.so $(shared-thread-library)
$(objpfx)tst-resolv-res_init: $(objpfx)libresolv.so
@@ -310,6 +316,8 @@ $(objpfx)tst-resolv-res_init-thread: $(objpfx)libresolv.so \
$(shared-thread-library)
$(objpfx)tst-resolv-invalid-cname: $(objpfx)libresolv.so \
$(shared-thread-library)
$(objpfx)tst-resolv-invalid-ptr: $(objpfx)libresolv.so \
$(shared-thread-library)
$(objpfx)tst-resolv-noaaaa: $(objpfx)libresolv.so $(shared-thread-library)
$(objpfx)tst-resolv-noaaaa-vc: $(objpfx)libresolv.so $(shared-thread-library)
$(objpfx)tst-resolv-nondecimal: $(objpfx)libresolv.so $(shared-thread-library)
@@ -332,5 +340,6 @@ $(objpfx)tst-ns_name: $(objpfx)libresolv.so
$(objpfx)tst-ns_name.out: tst-ns_name.data
$(objpfx)tst-ns_name_compress: $(objpfx)libresolv.so
$(objpfx)tst-ns_name_pton: $(objpfx)libresolv.so
$(objpfx)tst-ns_sprintrr: $(objpfx)libresolv.so
$(objpfx)tst-res_hnok: $(objpfx)libresolv.so
$(objpfx)tst-p_secstodate: $(objpfx)libresolv.so
+53 -117
View File
@@ -78,6 +78,24 @@ ns_sprintrr(const ns_msg *handle, const ns_rr *rr,
}
libresolv_hidden_def (ns_sprintrr)
/* Writes the class/type symbol NUMBER to *BUF, using the name from
*SYMS if possible. If NUMBER is not found in *SYMS, print the
number with PREFIX. */
static int
addsym (const struct res_sym *syms, int number, const char *prefix,
char **buf, size_t *buflen)
{
for (; syms->name != NULL; syms++)
if (number == syms->number)
{
T (addstr (" ", 1, buf, buflen));
return addstr (syms->name, strlen (syms->name), buf, buflen);
}
char tmp[20];
int len = snprintf (tmp, sizeof (tmp), " %s%d", prefix, number);
return addstr (tmp, len, buf, buflen);
}
/*%
* Convert the fields of an RR into presentation format.
*
@@ -97,7 +115,6 @@ ns_sprintrrf(const u_char *msg, size_t msglen,
const char *comment;
char tmp[100];
char errbuf[40];
int len, x;
/*
@@ -128,11 +145,21 @@ ns_sprintrrf(const u_char *msg, size_t msglen,
/*
* TTL, Class, Type.
*/
T(x = ns_format_ttl(ttl, buf, buflen));
addlen(x, &buf, &buflen);
len = SPRINTF((tmp, " %s %s", p_class(class), p_type(type)));
T(addstr(tmp, len, &buf, &buflen));
T(spaced = addtab(x + len, 16, spaced, &buf, &buflen));
{
char *start = buf;
T (x = ns_format_ttl (ttl, buf, buflen));
addlen (x, &buf, &buflen);
T (addsym (__p_class_syms, class, "CLASS", &buf, &buflen));
if (type == ns_t_a6)
/* A6 is not part of __p_type_syms, which is exported.
Adding A6 there would change its size. Handle it here. */
T (addstr (" A6", 3, &buf, &buflen));
else
T (addsym (__p_type_syms, type, "TYPE", &buf, &buflen));
T (spaced = addtab(buf - start, 16, spaced, &buf, &buflen));
}
/*
* RData.
@@ -140,8 +167,9 @@ ns_sprintrrf(const u_char *msg, size_t msglen,
switch (type) {
case ns_t_a:
if (rdlen != (size_t)NS_INADDRSZ)
goto formerr;
(void) inet_ntop(AF_INET, rdata, buf, buflen);
goto formerr;
if (inet_ntop (AF_INET, rdata, buf, buflen) == NULL)
return -1;
addlen(strlen(buf), &buf, &buflen);
break;
@@ -307,16 +335,18 @@ ns_sprintrrf(const u_char *msg, size_t msglen,
}
case ns_t_aaaa:
if (rdlen != (size_t)NS_IN6ADDRSZ)
goto formerr;
(void) inet_ntop(AF_INET6, rdata, buf, buflen);
if (rdlen != (size_t)NS_IN6ADDRSZ)
goto formerr;
if (inet_ntop (AF_INET6, rdata, buf, buflen) == NULL)
return -1;
addlen(strlen(buf), &buf, &buflen);
break;
case ns_t_loc: {
char t[255];
/* XXX protocol format checking? */
if (rdlen != 16)
goto formerr;
(void) loc_ntoa(rdata, t);
T(addstr(t, strlen(t), &buf, &buflen));
break;
@@ -400,7 +430,8 @@ ns_sprintrrf(const u_char *msg, size_t msglen,
goto formerr;
/* Address. */
(void) inet_ntop(AF_INET, rdata, buf, buflen);
if (inet_ntop (AF_INET, rdata, buf, buflen) == NULL)
return -1;
addlen(strlen(buf), &buf, &buflen);
rdata += NS_INADDRSZ;
@@ -434,96 +465,6 @@ ns_sprintrrf(const u_char *msg, size_t msglen,
break;
}
case ns_t_cert: {
u_int c_type, key_tag, alg;
int n;
unsigned int siz;
char base64_cert[8192], tmp[40];
const char *leader;
c_type = ns_get16(rdata); rdata += NS_INT16SZ;
key_tag = ns_get16(rdata); rdata += NS_INT16SZ;
alg = (u_int) *rdata++;
len = SPRINTF((tmp, "%d %d %d ", c_type, key_tag, alg));
T(addstr(tmp, len, &buf, &buflen));
siz = (edata-rdata)*4/3 + 4; /* "+4" accounts for trailing \0 */
if (siz > sizeof(base64_cert) * 3/4) {
const char *str = "record too long to print";
T(addstr(str, strlen(str), &buf, &buflen));
}
else {
len = b64_ntop(rdata, edata-rdata, base64_cert, siz);
if (len < 0)
goto formerr;
else if (len > 15) {
T(addstr(" (", 2, &buf, &buflen));
leader = "\n\t\t";
spaced = 0;
}
else
leader = " ";
for (n = 0; n < len; n += 48) {
T(addstr(leader, strlen(leader),
&buf, &buflen));
T(addstr(base64_cert + n, MIN(len - n, 48),
&buf, &buflen));
}
if (len > 15)
T(addstr(" )", 2, &buf, &buflen));
}
break;
}
case ns_t_tkey: {
/* KJD - need to complete this */
u_long t;
int mode, err, keysize;
/* Algorithm name. */
T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
T(addstr(" ", 1, &buf, &buflen));
/* Inception. */
t = ns_get32(rdata); rdata += NS_INT32SZ;
len = SPRINTF((tmp, "%lu ", t));
T(addstr(tmp, len, &buf, &buflen));
/* Expiration. */
t = ns_get32(rdata); rdata += NS_INT32SZ;
len = SPRINTF((tmp, "%lu ", t));
T(addstr(tmp, len, &buf, &buflen));
/* Mode , Error, Key Size. */
/* Priority, Weight, Port. */
mode = ns_get16(rdata); rdata += NS_INT16SZ;
err = ns_get16(rdata); rdata += NS_INT16SZ;
keysize = ns_get16(rdata); rdata += NS_INT16SZ;
len = SPRINTF((tmp, "%u %u %u ", mode, err, keysize));
T(addstr(tmp, len, &buf, &buflen));
/* XXX need to dump key, print otherdata length & other data */
break;
}
case ns_t_tsig: {
/* BEW - need to complete this */
int n;
T(len = addname(msg, msglen, &rdata, origin, &buf, &buflen));
T(addstr(" ", 1, &buf, &buflen));
rdata += 8; /*%< time */
n = ns_get16(rdata); rdata += INT16SZ;
rdata += n; /*%< sig */
n = ns_get16(rdata); rdata += INT16SZ; /*%< original id */
sprintf(buf, "%d", ns_get16(rdata));
rdata += INT16SZ;
addlen(strlen(buf), &buf, &buflen);
break;
}
case ns_t_a6: {
struct in6_addr a;
int pbyte, pbit;
@@ -539,12 +480,14 @@ ns_sprintrrf(const u_char *msg, size_t msglen,
/* address suffix: provided only when prefix len != 128 */
if (pbit < 128) {
if (rdata + pbyte >= edata) goto formerr;
unsigned int bytelen = sizeof(a) - pbyte;
if (edata - rdata < bytelen) goto formerr;
memset(&a, 0, sizeof(a));
memcpy(&a.s6_addr[pbyte], rdata, sizeof(a) - pbyte);
(void) inet_ntop(AF_INET6, &a, buf, buflen);
memcpy(&a.s6_addr[pbyte], rdata, bytelen);
if (inet_ntop (AF_INET6, &a, buf, buflen) == NULL)
return -1;
addlen(strlen(buf), &buf, &buflen);
rdata += sizeof(a) - pbyte;
rdata += bytelen;
}
/* prefix name: provided only when prefix len > 0 */
@@ -557,25 +500,18 @@ ns_sprintrrf(const u_char *msg, size_t msglen,
break;
}
case ns_t_opt: {
len = SPRINTF((tmp, "%u bytes", class));
T(addstr(tmp, len, &buf, &buflen));
break;
}
default:
snprintf (errbuf, sizeof (errbuf), "unknown RR type %d", type);
comment = errbuf;
comment = "";
goto hexify;
}
return (buf - obuf);
formerr:
comment = "RR format error";
comment = " ; RR format error";
hexify: {
int n, m;
char *p;
len = SPRINTF((tmp, "\\# %u%s\t; %s", (unsigned)(edata - rdata),
len = SPRINTF((tmp, "\\# %u%s%s", (unsigned)(edata - rdata),
rdlen != 0U ? " (" : "", comment));
T(addstr(tmp, len, &buf, &buflen));
while (rdata < edata) {
+2 -2
View File
@@ -820,7 +820,7 @@ getanswer_ptr (unsigned char *packet, size_t packetlen,
/* expected_name may be updated to point into this buffer. */
unsigned char name_buffer[NS_MAXCDNAME];
while (ancount > 0)
for (; ancount > 0; --ancount)
{
struct ns_rr_wire rr;
if (!__ns_rr_cursor_next (&c, &rr))
@@ -866,7 +866,7 @@ getanswer_ptr (unsigned char *packet, size_t packetlen,
char hname[MAXHOSTNAMELEN + 1];
if (__ns_name_unpack (c.begin, c.end, rr.rdata,
name_buffer, sizeof (name_buffer)) < 0
|| !__res_binary_hnok (expected_name)
|| !__res_binary_hnok (name_buffer)
|| __ns_name_ntop (name_buffer, hname, sizeof (hname)) < 0)
{
*h_errnop = NO_RECOVERY;
-4
View File
@@ -390,8 +390,6 @@ p_fqname(const u_char *cp, const u_char *msg, FILE *file) {
* that C_ANY is a qclass but not a class. (You can ask for records of class
* C_ANY, but you can't have any records of that class in the database.)
*/
extern const struct res_sym __p_class_syms[];
libresolv_hidden_proto (__p_class_syms)
const struct res_sym __p_class_syms[] = {
{C_IN, (char *) "IN"},
{C_CHAOS, (char *) "CHAOS"},
@@ -426,8 +424,6 @@ const struct res_sym __p_update_section_syms[] attribute_hidden = {
* Names of RR types and qtypes. The list is incomplete because its
* size is part of the ABI.
*/
extern const struct res_sym __p_type_syms[];
libresolv_hidden_proto (__p_type_syms)
const struct res_sym __p_type_syms[] = {
{ns_t_a, (char *) "A", (char *) "address"},
{ns_t_ns, (char *) "NS", (char *) "name server"},
+329
View File
@@ -0,0 +1,329 @@
/* Tests for the ns_sprintrr function.
Copyright (C) 2026 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */
#include <arpa/nameser.h>
#include <alloc_buffer.h>
#include <arpa/inet.h>
#include <libc-diag.h>
#include <stdbool.h>
#include <string.h>
#include <support/check.h>
#include <support/next_to_fault.h>
#include <stdio.h>
/* Regions that test_one_record uses for input and output. */
static struct support_next_to_fault ntf_in;
static struct support_next_to_fault ntf_out;
/* This is used by test_one_record to construct the packet. */
static const char packet_prefix[] =
/* DNS response with one question, one answer record. */
"AA\x81\x80\0\1\0\1\0\0\0\0"
/* Question: www.example.org/IN/ANY. */
"\3www\7example\3org\0\0\xff\0\1"
/* Response: compression reference. */
"\xc0\x0c";
/* Use ns_sprintrr to format a DNS record (starting with
packet_prefix) of type RTYPE, with a record payload of RDATALEN
bytes starting at RDATA. Check successful formatting against
EXPECTED. Try various truncated input and output buffers to catch
overreads and buffer overflows, using ntf_in and ntf_out above. */
static void
test_one_record (uint16_t rtype, const char *rdata, size_t rdatalen,
const char *expected)
{
struct rr_header
{
uint16_t typ;
uint16_t cls;
uint32_t ttl;
uint16_t rdatalen;
uint16_t pad;
} hdr =
{
.typ = htons (rtype),
.cls = htons (ns_c_in),
.ttl = htonl (86400), /* One day. */
.rdatalen = htons (rdatalen),
};
enum { hdrlen = offsetof (struct rr_header, pad) };
TEST_COMPARE (hdrlen, 10);
/* Construct the packet from packet_prefix, hdr, and rdata. */
unsigned char packet[512];
size_t packetlen;
{
struct alloc_buffer buf = alloc_buffer_create (packet, sizeof (packet));
alloc_buffer_copy_bytes (&buf, packet_prefix, sizeof (packet_prefix) - 1);
alloc_buffer_copy_bytes (&buf, &hdr, hdrlen);
alloc_buffer_copy_bytes (&buf, rdata, rdatalen);
packetlen = sizeof (packet) - alloc_buffer_size (&buf);
}
/* Parse the record. */
ns_msg msg;
TEST_COMPARE (ns_initparse (packet, packetlen, &msg), 0);
ns_rr rr;
TEST_COMPARE (ns_parserr (&msg, ns_s_an, 0, &rr), 0);
/* Try sizes up to this limit. Go a bit beyond the expected size to
check for errors. */
size_t max_result_size = strlen (expected) + 16;
bool success = false;
for (size_t result_size = 1; result_size <= max_result_size; ++result_size)
{
char *result_start = ntf_out.buffer + ntf_out.length - result_size;
memset (result_start, 'X', result_size);
/* ns_sprintrr was deprecated in 2.34. */
DIAG_PUSH_NEEDS_COMMENT;
DIAG_IGNORE_NEEDS_COMMENT (4.9, "-Wdeprecated-declarations");
int ret = ns_sprintrr (&msg, &rr, NULL, NULL, result_start, result_size);
DIAG_POP_NEEDS_COMMENT;
if (ret > 0)
{
TEST_COMPARE_STRING (result_start, expected);
TEST_COMPARE (ret, strlen (expected));
success = true;
}
else
{
TEST_VERIFY (!success);
TEST_COMPARE (ret, -1);
}
}
TEST_VERIFY (success);
/* Test with truncated RDATA. */
for (size_t rdata_size = 0; rdata_size <= rdatalen; ++rdata_size)
{
size_t truncated_packet_size = packetlen - rdatalen + rdata_size;
unsigned char *packet_start
= ((unsigned char *) ntf_in.buffer + ntf_in.length
- truncated_packet_size);
memcpy (packet_start, packet, truncated_packet_size);
/* Patch in the updated RDATA length field. */
uint16_t new_rdatalen = htons (rdata_size);
memcpy (packet_start + truncated_packet_size - rdata_size - 2,
&new_rdatalen, 2);
ns_msg msg;
TEST_COMPARE (ns_initparse (packet_start, truncated_packet_size, &msg),
0);
ns_rr rr;
TEST_COMPARE (ns_parserr (&msg, ns_s_an, 0, &rr), 0);
size_t result_size = strlen (expected) + 1;
char *result_start = ntf_out.buffer + ntf_out.length - result_size;
memset (result_start, 'X', result_size);
/* ns_sprintrr was deprecated in 2.34. */
DIAG_PUSH_NEEDS_COMMENT;
DIAG_IGNORE_NEEDS_COMMENT (4.9, "-Wdeprecated-declarations");
int ret = ns_sprintrr (&msg, &rr, NULL, NULL, result_start, result_size);
DIAG_POP_NEEDS_COMMENT;
/* This flag indicates whether the output is syntactically
correct. In some cases, truncation may still yield a valid
payload. */
bool broken = rdata_size < rdatalen;
switch (rtype)
{
case ns_t_wks:
/* WKS records use all trailing bytes for the port bitmap. */
broken = rdata_size < 5;
break;
case ns_t_nsap:
/* Uses all bytes that are available. */
broken = false;
break;
case ns_t_txt:
/* Truncation produces a valid payload if it occurs right
after a complete string in the TXT payload. */
broken = false;
for (size_t pos = 0; pos < rdata_size; )
{
unsigned int slen = rdata[pos] & 0xff;
if (pos + 1 + slen > rdata_size)
{
broken = true;
break;
}
pos += 1 + slen;
}
break;
case ns_t_isdn:
/* The second field is optional. If it is present, it must
not be truncated. */
broken = rdata_size < 6 || (rdata_size > 6 && rdata_size < rdatalen);
break;
case ns_t_a6:
/* The first A6 subtest contains a trailing domain name,
which is ignored and not formatted. */
if (rdata_size > 0 && rdata[0] == 0)
broken = rdata_size < 17;
break;
case ns_t_cert:
case ns_t_tkey:
case ns_t_tsig:
/* Only generic printing, which does not validate anything. */
broken = false;
break;
}
if (broken)
{
if (strstr (result_start, "RR format error") != NULL)
/* No further checks if an error indicator has been added
to the output. */
;
else
TEST_COMPARE (ret, -1);
}
else
TEST_VERIFY (ret > 0);
}
}
static int
do_test (void)
{
ntf_in = support_next_to_fault_allocate (512);
ntf_out = support_next_to_fault_allocate (256);
#define T(rtype, rdata, expected) \
test_one_record (rtype, rdata, sizeof (rdata) - 1, expected)
T (ns_t_a, "\xc0\0\2\1", "www.example.org.\t1D IN A\t\t192.0.2.1");
T (ns_t_cname, "\4www1\4prod\xc0\x10",
"www.example.org.\t1D IN CNAME\twww1.prod.example.org.");
T (ns_t_hinfo, "\5first\6second",
"www.example.org.\t1D IN HINFO\t\"first\" \"second\"");
T (ns_t_isdn, "\5first\6second",
"www.example.org.\t1D IN ISDN\t\"first\" \"second\"");
/* Bug: Extra space at the end in the text representation of ISDN RRs. */
T (ns_t_isdn, "\5first", "www.example.org.\t1D IN ISDN\t\"first\" ");
T (ns_t_soa,
"\2ns\xc0\x10\12hostmaster\xc0\x10"
"\0\0\0\1\0\0\0\2\0\0\0\3\0\0\0\4\0\0\0\5",
"www.example.org.\t1D IN SOA\tns.example.org. hostmaster.example.org. (\n"
"\t\t\t\t\t1\t\t; serial\n"
"\t\t\t\t\t2S\t\t; refresh\n"
"\t\t\t\t\t3S\t\t; retry\n"
"\t\t\t\t\t4S\t\t; expiry\n"
"\t\t\t\t\t5S )\t\t; minimum\n");
T (ns_t_mx, "\0\xa\2mx\xc0\x10",
"www.example.org.\t1D IN MX\t10 mx.example.org.");
T (ns_t_px, "\0\xa\3px1\xc0\x10\3px2\xc0\x10",
"www.example.org.\t1D IN PX\t10 px1.example.org. px2.example.org.");
T (ns_t_x25, "\4X.25",
"www.example.org.\t1D IN X25\t\"X.25\"");
T (ns_t_txt, "\1A\2BC\3DEF",
"www.example.org.\t1D IN TXT\t\"A\" \"BC\" \"DEF\"");
T (ns_t_nsap, "",
"www.example.org.\t1D IN NSAP\t");
T (ns_t_nsap, "\1",
"www.example.org.\t1D IN NSAP\t01");
T (ns_t_nsap, "\1\2",
"www.example.org.\t1D IN NSAP\t01.02");
T (ns_t_nsap, "\1\2\3",
"www.example.org.\t1D IN NSAP\t01.0203");
T (ns_t_nsap, "\1\2\3\4",
"www.example.org.\t1D IN NSAP\t01.0203.04");
T (ns_t_nsap,
"\1\2\3\4\5\6\7\10\11\12\13\14\15\16\17\20\21\22\23\24\25\26\27\30\31\32"
"\33\34\35\36\37\40\41\42\43\44\45\46\47\50\51\52\53\54\55\56\57\60\61"
"\62\63\64\65\66\67\70\71\72\73\74\75\76\77\100\101\102\103\104\105\106"
"\107\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127"
"\130\131\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150"
"\151\152\153\154\155\156\157\160\161\162\163\164\165\166\167\170\171"
"\172\173\174\175\176\177\200\201\202\203\204\205\206\207\210\211\212"
"\213\214\215\216\217\220\221\222\223\224\225\226\227\230\231\232\233"
"\234\235\236\237\240\241\242\243\244\245\246\247\250\251\252\253\254"
"\255\256\257\260\261\262\263\264\265\266\267\270\271\272\273\274\275"
"\276\277\300\301\302\303\304\305\306\307\310\311\312\313\314\315\316"
"\317\320\321\322\323\324\325\326\327\330\331\332\333\334\335\336\337"
"\340\341\342\343\344\345\346\347\350\351\352\353\354\355\356\357\360"
"\361\362\363\364\365\366\367\370\371\372\373\374\375\376\377",
"www.example.org.\t1D IN NSAP\t"
"01.0203.0405.0607.0809.0A0B.0C0D.0E0F.1011.1213.1415.1617.1819.1A1B"
".1C1D.1E1F.2021.2223.2425.2627.2829.2A2B.2C2D.2E2F.3031.3233.3435.3637"
".3839.3A3B.3C3D.3E3F.4041.4243.4445.4647.4849.4A4B.4C4D.4E4F.5051.5253"
".5455.5657.5859.5A5B.5C5D.5E5F.6061.6263.6465.6667.6869.6A6B.6C6D.6E6F"
".7071.7273.7475.7677.7879.7A7B.7C7D.7E7F.8081.8283.8485.8687.8889.8A8B"
".8C8D.8E8F.9091.9293.9495.9697.9899.9A9B.9C9D.9E9F.A0A1.A2A3.A4A5.A6A7"
".A8A9.AAAB.ACAD.AEAF.B0B1.B2B3.B4B5.B6B7.B8B9.BABB.BCBD.BEBF.C0C1.C2C3"
".C4C5.C6C7.C8C9.CACB.CCCD.CECF.D0D1.D2D3.D4D5.D6D7.D8D9.DADB.DCDD.DEDF"
".E0E1.E2E3.E4E5.E6E7.E8E9.EAEB.ECED.EEEF.F0F1.F2F3.F4F5.F6F7.F8F9.FAFB"
".FCFD.FEFF");
T (ns_t_aaaa, "\x20\x01\x0d\xb8\0\0\0\0\0\0\0\0\0\0\x12\x34",
"www.example.org.\t1D IN AAAA\t2001:db8::1234");
/* Example from RFC 1876. The loc_ntoa format is different from the
official text representation. */
T (ns_t_loc,
"\000\063\026\023\211\027\055\320\160\276\025\360\000\230\215\040",
"www.example.org.\t1D IN LOC"
"\t42 21 54.000 N 71 06 18.000 W -24.00m 30.00m 10000.00m 10.00m");
T (ns_t_naptr,
"\0\1\0\2\5flags\7service\2.*\5naptr\xc0\x10",
"www.example.org.\t1D IN NAPTR\t1 2 \"flags\" \"service\" \".*\""
" naptr.example.org.");
T (ns_t_srv,
"\0\1\0\2\0\x50\4www1\xc0\x10",
"www.example.org.\t1D IN SRV\t1 2 80 www1.example.org.");
T (ns_t_rp, "\3rp1\xc0\x10\3rp2\xc0\x10",
"www.example.org.\t1D IN RP\trp1.example.org. rp2.example.org.");
T (ns_t_wks, "\xc0\0\2\1\6\0\0\0\0\0\0\0\0\0\0\200",
"www.example.org.\t1D IN WKS\t192.0.2.1 6 ( \n\t\t\t\t80 )");
T (ns_t_cert, "\0\1\x04\xd2\0blob",
"www.example.org.\t1D IN CERT\t\\# 9 (\n"
"\t00 01 04 d2 00 62 6c 6f 62 )\t\t\t; .....blob");
T (ns_t_tkey, "\4algo\0\0\0\0\1\0\0\0\2\0\3\0\4"
"\0\5\xa1\xa2\xa3\xa4\xa5\0\3\xb1\xb2\xb3",
"www.example.org.\t1D IN TYPE249\t\\# 30 (\n"
"\t04 61 6c 67 6f 00 00 00 00 01 00 00 00 02 00 03 ; .algo...........\n"
"\t00 04 00 05 a1 a2 a3 a4 a5 00 03 b1 b2 b3 )\t; ..............");
T (ns_t_tsig, "\4algo\0"
"\0\20\xdd\xcd\x64\x10\xe9\x21\x34\x1a\x8e\xe0\xa1\x9a\x30\xfc\x3b\xd1"
"\0\2\0\3\0\5other",
"www.example.org.\t1D IN TSIG\t\\# 35 (\n"
"\t04 61 6c 67 6f 00 00 10 dd cd 64 10 e9 21 34 1a ; .algo.....d..!4.\n"
"\t8e e0 a1 9a 30 fc 3b d1 00 02 00 03 00 05 6f 74 ; ....0.;.......ot\n"
"\t68 65 72 )\t\t\t\t\t; her");
T (ns_t_a6,
"\0\x20\x01\x0d\xb8\0\0\0\0\0\0\0\0\0\0\x12\x34\6prefix\xc0\x10",
"www.example.org.\t1D IN A6\t0 2001:db8::1234");
T (ns_t_a6,
"\0\x20\x01\x0d\xb8\0\0\0\0\0\0\0\0\0\0\x12\x35",
"www.example.org.\t1D IN A6\t0 2001:db8::1235");
T (ns_t_a6, "\200\6prefix\xc0\x10",
"www.example.org.\t1D IN A6\t128 prefix.example.org.");
T (ns_t_a6, "\x20\0\0\0\0\0\0\0\0\0\0\x12\x36\6prefix\xc0\x10",
"www.example.org.\t1D IN A6\t32 ::1236 prefix.example.org.");
#undef T
support_next_to_fault_free (&ntf_in);
support_next_to_fault_free (&ntf_out);
return 0;
}
#include <support/test-driver.c>
+162
View File
@@ -0,0 +1,162 @@
/* Test handling of invalid section transitions (bug 34014).
Copyright (C) 2022-2026 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */
#include <array_length.h>
#include <errno.h>
#include <netdb.h>
#include <resolv.h>
#include <stdlib.h>
#include <string.h>
#include <support/check.h>
#include <support/format_nss.h>
#include <support/resolv_test.h>
#include <support/support.h>
/* Name of test, and the second section type. */
struct item {
const char *test;
int ns_section;
};
static const struct item test_items[] =
{
{ "Test crossing from ns_s_an to ns_s_ar.", ns_s_ar },
{ "Test crossing from ns_s_an to ns_s_an.", ns_s_ns },
{ NULL, 0 },
};
/* The response is designed to contain the following:
- An Answer section with one T_PTR record that is skipped.
- A second section with a semantically invalid T_PTR record.
The original defect is that the response parsing would cross
section boundaries and handle the additional section T_PTR
as if it were an answer. A conforming implementation would
stop as soon as it reaches the end of the section. */
static void
response (const struct resolv_response_context *ctx,
struct resolv_response_builder *b,
const char *qname, uint16_t qclass, uint16_t qtype)
{
TEST_COMPARE (qclass, C_IN);
/* We only test PTR. */
TEST_COMPARE (qtype, T_PTR);
unsigned int count;
char *tail = NULL;
if (strstr (qname, "in-addr.arpa") != NULL
&& sscanf (qname, "%u.%ms", &count, &tail) == 2)
TEST_COMPARE_STRING (tail, "0.168.192.in-addr.arpa");
else if (sscanf (qname, "%x.%ms", &count, &tail) == 2)
{
TEST_COMPARE_STRING (tail, "\
0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2.ip6.arpa");
}
else
FAIL_EXIT1 ("invalid QNAME: %s\n", qname);
free (tail);
/* We have a bounded number of possible tests. */
TEST_VERIFY (count >= 0);
TEST_VERIFY (count <= 15);
struct resolv_response_flags flags = {};
resolv_response_init (b, flags);
resolv_response_add_question (b, qname, qclass, qtype);
resolv_response_section (b, ns_s_an);
/* Actual answer record, but the wrong name (skipped). */
resolv_response_open_record (b, "1.0.0.10.in-addr.arpa", qclass, qtype, 60);
/* Record the answer. */
resolv_response_add_name (b, "test.ptr.example.net");
resolv_response_close_record (b);
/* Add a second section to test section boundary crossing. */
resolv_response_section (b, test_items[count].ns_section);
/* Semantically incorrect, but hide a T_PTR entry. */
resolv_response_open_record (b, qname, qclass, qtype, 60);
resolv_response_add_name (b, "wrong.ptr.example.net");
resolv_response_close_record (b);
}
/* Perform one check using a reverse lookup. */
static void
check_reverse (int af, int count)
{
TEST_VERIFY (af == AF_INET || af == AF_INET6);
TEST_VERIFY (count < array_length (test_items));
char addr[sizeof (struct in6_addr)] = { 0 };
socklen_t addrlen;
if (af == AF_INET)
{
addr[0] = (char) 192;
addr[1] = (char) 168;
addr[2] = (char) 0;
addr[3] = (char) count;
addrlen = 4;
}
else
{
addr[0] = 0x20;
addr[1] = 0x01;
addr[2] = 0x0d;
addr[3] = 0xb8;
addr[4] = addr[5] = addr[6] = addr[7] = 0x0;
addr[8] = addr[9] = addr[10] = addr[11] = 0x0;
addr[12] = 0x0;
addr[13] = 0x0;
addr[14] = 0x0;
addr[15] = count;
addrlen = 16;
}
h_errno = 0;
struct hostent *answer = gethostbyaddr (addr, addrlen, af);
TEST_VERIFY (answer == NULL);
TEST_VERIFY (h_errno == NO_RECOVERY);
if (answer != NULL)
printf ("error: unexpected success: %s\n",
support_format_hostent (answer));
}
static int
do_test (void)
{
struct resolv_test *obj = resolv_test_start
((struct resolv_redirect_config)
{
.response_callback = response
});
for (int i = 0; test_items[i].test != NULL; i++)
{
check_reverse (AF_INET, i);
check_reverse (AF_INET6, i);
}
resolv_test_end (obj);
return 0;
}
#include <support/test-driver.c>
+255
View File
@@ -0,0 +1,255 @@
/* Test handling of invalid T_PTR results (bug 34015).
Copyright (C) 2022-2026 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */
#include <array_length.h>
#include <errno.h>
#include <netdb.h>
#include <resolv.h>
#include <stdlib.h>
#include <string.h>
#include <support/check.h>
#include <support/format_nss.h>
#include <support/resolv_test.h>
#include <support/support.h>
/* Name of test, the answer, the expected error return, and if we
expect the call to fail. */
struct item {
const char *test;
const char *answer;
int expected;
bool fail;
};
static const struct item test_items[] =
{
/* Test for invalid characters. */
{ "Invalid use of \"|\"",
"test.|.ptr.example", NO_RECOVERY, true },
{ "Invalid use of \"&\"",
"test.&.ptr.example", NO_RECOVERY, true },
{ "Invalid use of \";\"",
"test.;.ptr.example", NO_RECOVERY, true },
{ "Invalid use of \"<\"",
"test.<.ptr.example", NO_RECOVERY, true },
{ "Invalid use of \">\"",
"test.>.ptr.example", NO_RECOVERY, true },
{ "Invalid use of \"(\"",
"test.(.ptr.example", NO_RECOVERY, true },
{ "Invalid use of \")\"",
"test.).ptr.example", NO_RECOVERY, true },
{ "Invalid use of \"$\"",
"test.$.ptr.example", NO_RECOVERY, true },
{ "Invalid use of \"`\"",
"test.`.ptr.example", NO_RECOVERY, true },
{ "Invalid use of \"\\\"",
"test.\\.ptr.example", NO_RECOVERY, true },
{ "Invalid use of \"\'\"",
"test.'.ptr.example", NO_RECOVERY, true },
{ "Invalid use of \"\"\"",
"test.\".ptr.example", NO_RECOVERY, true },
{ "Invalid use of \" \"",
"test. .ptr.example", NO_RECOVERY, true },
{ "Invalid use of \"\\t\"",
"test.\t.ptr.example", NO_RECOVERY, true },
{ "Invalid use of \"\\n\"",
"test.\n.ptr.example", NO_RECOVERY, true },
{ "Invalid use of \"\\r\"",
"test.\r.ptr.example", NO_RECOVERY, true },
{ "Invalid use of \"*\"",
"test.*.ptr.example", NO_RECOVERY, true },
{ "Invalid use of \"?\"",
"test.?.ptr.example", NO_RECOVERY, true },
{ "Invalid use of \"[\"",
"test.[.ptr.example", NO_RECOVERY, true },
{ "Invalid use of \"]\"",
"test.].ptr.example", NO_RECOVERY, true },
{ "Invalid use of \",\"",
"test.,.ptr.example", NO_RECOVERY, true },
{ "Invalid use of \"~\"",
"test.~.ptr.example", NO_RECOVERY, true },
{ "Invalid use of \":\"",
"test.:.ptr.example", NO_RECOVERY, true },
{ "Invalid use of \"!\"",
"test.!.ptr.example", NO_RECOVERY, true },
{ "Invalid use of \"@\"",
"test.@.ptr.example", NO_RECOVERY, true },
{ "Invalid use of \"#\"",
"test.#.ptr.example", NO_RECOVERY, true },
{ "Invalid use of \"%\"",
"test.%%.ptr.example", NO_RECOVERY, true },
{ "Invalid use of \"^\"",
"test.^.ptr.example", NO_RECOVERY, true },
/* Test for invalid UTF-8 characters (2-byte, 4-byte, 6-byte). */
{ "Invalid use of UTF-8 (2-byte, U+00C0-U+00C2)",
"ÁÂÃ.test.ptr.example", NO_RECOVERY, true },
{ "Invalid use of UTF-8 (4-byte, U+0750-U+0752)",
"ݐݑݒ.test.ptr.example", NO_RECOVERY, true },
{ "Invalid use of UTF-8 (6-byte, U+0904-U+0906)",
"ऄअआ.test.ptr.example", NO_RECOVERY, true },
/* Test for "-" which may be valid depending on position. */
{ "Invalid leading \"-\"",
"-test.ptr.example", NO_RECOVERY, true },
{ "Valid trailing \"-\"",
"test-.ptr.example", 0, false },
{ "Valid mid-label use of \"-\"",
"te-st.ptr.example", 0, false },
/* Test for "_" which is always valid in any position. */
{ "Valid leading use of \"_\"",
"_test.ptr.example", 0, false },
{ "Valid mid-label use of \"_\"",
"te_st.ptr.example", 0, false },
{ "Valid trailing use of \"_\"",
"test_.ptr.example", 0, false },
/* Sanity test the broader set [A-Za-z0-9_-] of valid characters. */
{ "Valid \"[A-Z]\"",
"test.ABCDEFGHIJKLMNOPQRSTUVWXYZ.ptr.example", 0, false },
{ "Valid \"[a-z]\"",
"test.abcdefghijklmnopqrstuvwxyz.ptr.example", 0, false },
{ "Valid \"[0-9]\"",
"test.0123456789.ptr.example", 0, false },
{ "Valid mixed use of \"[A-Za-z0-9_-]\"",
"test.012abcABZ_-.ptr.example", 0, false },
};
static void
response (const struct resolv_response_context *ctx,
struct resolv_response_builder *b,
const char *qname, uint16_t qclass, uint16_t qtype)
{
TEST_COMPARE (qclass, C_IN);
/* We only test PTR. */
TEST_COMPARE (qtype, T_PTR);
unsigned int count, count1;
char *tail = NULL;
/* The test implementation can handle up to 255 tests. */
if (strstr (qname, "in-addr.arpa") != NULL
&& sscanf (qname, "%u.%ms", &count, &tail) == 2)
TEST_COMPARE_STRING (tail, "0.168.192.in-addr.arpa");
else if (sscanf (qname, "%x.%x.%ms", &count, &count1, &tail) == 3)
{
TEST_COMPARE_STRING (tail, "\
0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2.ip6.arpa");
count |= count1 << 4;
}
else
FAIL_EXIT1 ("invalid QNAME: %s\n", qname);
free (tail);
/* Cross check. Count has a fixed bound (soft limit). */
TEST_VERIFY (count >= 0 && count <= 255);
/* We have a fixed number of tests (hard limit). */
TEST_VERIFY_EXIT (count < array_length (test_items));
struct resolv_response_flags flags = {};
resolv_response_init (b, flags);
resolv_response_add_question (b, qname, qclass, qtype);
resolv_response_section (b, ns_s_an);
/* Actual answer record. */
resolv_response_open_record (b, qname, qclass, qtype, 60);
/* Record the answer. */
resolv_response_add_name (b, test_items[count].answer);
resolv_response_close_record (b);
}
/* Perform one check using a reverse lookup. */
static void
check_reverse (int af, int count)
{
TEST_VERIFY (af == AF_INET || af == AF_INET6);
TEST_VERIFY_EXIT (count < array_length (test_items));
/* Generate an address to query for each test. */
char addr[sizeof (struct in6_addr)] = { 0 };
socklen_t addrlen;
if (af == AF_INET)
{
addr[0] = (char) 192;
addr[1] = (char) 168;
addr[2] = (char) 0;
addr[3] = (char) count;
addrlen = 4;
}
else
{
addr[0] = 0x20;
addr[1] = 0x01;
addr[2] = 0x0d;
addr[3] = 0xb8;
addr[4] = addr[5] = addr[6] = addr[7] = 0x0;
addr[8] = addr[9] = addr[10] = addr[11] = 0x0;
addr[12] = 0x0;
addr[13] = 0x0;
addr[14] = 0x0;
addr[15] = (char) count;
addrlen = 16;
}
h_errno = 0;
struct hostent *answer = gethostbyaddr (addr, addrlen, af);
/* Verify h_errno is as expected. */
TEST_COMPARE (h_errno, test_items[count].expected);
if (h_errno != test_items[count].expected)
/* And print more information if it's not. */
printf ("INFO: %s\n", test_items[count].test);
if (test_items[count].fail)
{
/* We expected a failure so verify answer is NULL. */
TEST_VERIFY (answer == NULL);
/* If it's not NULL we should print out what we received. */
if (answer != NULL)
printf ("error: unexpected success: %s\n",
support_format_hostent (answer));
}
else
/* We don't expect a failure so answer must be valid. */
TEST_COMPARE_STRING (answer->h_name, test_items[count].answer);
}
static int
do_test (void)
{
struct resolv_test *obj = resolv_test_start
((struct resolv_redirect_config)
{
.response_callback = response
});
for (int i = 0; i < array_length (test_items); i++)
{
check_reverse (AF_INET, i);
check_reverse (AF_INET6, i);
}
resolv_test_end (obj);
return 0;
}
#include <support/test-driver.c>
+1 -1
View File
@@ -38,7 +38,7 @@ $4 == "*UND*" { next }
$2 == "l" { next }
# If the target uses ST_OTHER, it will be output before the symbol name.
$2 == "g" || $2 == "w" && (NF == 7 || NF == 8) {
$2 == "g" || $2 == "w" && (NF == 6 || NF == 7 || NF == 8) {
type = $3;
size = $5;
sub(/^0*/, "", size);
+4
View File
@@ -349,6 +349,7 @@ tests := \
tst-vfprintf-user-type \
tst-vfprintf-width-i18n \
tst-vfprintf-width-prec-alloc \
tst-vfscanf-bz34008 \
tst-wc-printf \
tstdiomisc \
tstgetln \
@@ -564,6 +565,9 @@ tst-printf-bz18872-ENV = MALLOC_TRACE=$(objpfx)tst-printf-bz18872.mtrace \
tst-vfprintf-width-prec-ENV = \
MALLOC_TRACE=$(objpfx)tst-vfprintf-width-prec.mtrace \
LD_PRELOAD=$(common-objpfx)/malloc/libc_malloc_debug.so
tst-vfscanf-bz34008-ENV = \
MALLOC_CHECK_=3 \
LD_PRELOAD=$(common-objpfx)/malloc/libc_malloc_debug.so
tst-printf-bz25691-ENV = \
MALLOC_TRACE=$(objpfx)tst-printf-bz25691.mtrace \
LD_PRELOAD=$(common-objpfx)/malloc/libc_malloc_debug.so
+48
View File
@@ -0,0 +1,48 @@
/* Regression test for vfscanf %Nmc out-of-bound write (BZ #34008)
Copyright (C) 2026 The GNU Toolchain Authors.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */
#include "malloc/mcheck.h"
#include <stddef.h>
#include <stdio.h>
#include <string.h>
#include <wchar.h>
#include <stdlib.h>
#include <malloc.h>
#include <support/check.h>
#define WIDTH 0x410
#define SCANFSTR "%1040mc"
static int
do_test (void)
{
mcheck_pedantic (NULL);
char *input = malloc (WIDTH + 1);
TEST_VERIFY (input != NULL);
memset (input, 'A', WIDTH);
input[WIDTH] = '\0';
char *buf = NULL;
TEST_VERIFY (sscanf (input, SCANFSTR, &buf) != -1);
TEST_VERIFY (buf != NULL);
free (buf);
free (input);
return 0;
}
#include <support/test-driver.c>
+3 -4
View File
@@ -862,8 +862,7 @@ __vfscanf_internal (FILE *s, const char *format, va_list argptr,
{
/* Enlarge the buffer. */
size_t newsize
= strsize
+ (strsize >= width ? width - 1 : strsize);
= strsize + (strsize >= width ? width : strsize);
str = (char *) realloc (*strptr, newsize);
if (str == NULL)
@@ -936,7 +935,7 @@ __vfscanf_internal (FILE *s, const char *format, va_list argptr,
&& wstr == (wchar_t *) *strptr + strsize)
{
size_t newsize
= strsize + (strsize > width ? width - 1 : strsize);
= strsize + (strsize >= width ? width : strsize);
/* Enlarge the buffer. */
wstr = (wchar_t *) realloc (*strptr,
newsize * sizeof (wchar_t));
@@ -991,7 +990,7 @@ __vfscanf_internal (FILE *s, const char *format, va_list argptr,
&& wstr == (wchar_t *) *strptr + strsize)
{
size_t newsize
= strsize + (strsize > width ? width - 1 : strsize);
= strsize + (strsize >= width ? width : strsize);
/* Enlarge the buffer. */
wstr = (wchar_t *) realloc (*strptr,
newsize * sizeof (wchar_t));
+1
View File
@@ -347,6 +347,7 @@ tests := \
tst-stdc_leading_zeros \
tst-stdc_trailing_ones \
tst-stdc_trailing_zeros \
tst-strfmon-bug34510 \
tst-strfmon_l \
tst-strfrom \
tst-strfrom-locale \
+3 -2
View File
@@ -549,7 +549,8 @@ __vstrfmon_l_buffer (struct __printf_buffer *buf, locale_t loc,
/* Now test whether the output width is filled. */
if (buf->write_ptr - startp < width)
{
size_t pad_width = width - (buf->write_ptr - startp);
size_t written_width = buf->write_ptr - startp;
size_t pad_width = width - written_width;
__printf_buffer_pad (buf, ' ', pad_width);
if (__printf_buffer_has_failed (buf))
/* Implies length check. */
@@ -558,7 +559,7 @@ __vstrfmon_l_buffer (struct __printf_buffer *buf, locale_t loc,
Otherwise move the field contents in place. */
if (!left)
{
memmove (startp + pad_width, startp, buf->write_ptr - startp);
memmove (startp + pad_width, startp, written_width);
memset (startp, ' ', pad_width);
}
}
+33
View File
@@ -0,0 +1,33 @@
/* Test handling of right-padding in strfmon (bug 34510, CVE-2026-19499).
Copyright (C) 2026 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */
#include <monetary.h>
#include <errno.h>
#include <support/check.h>
#include <support/next_to_fault.h>
static int
do_test (void)
{
struct support_next_to_fault ntf = support_next_to_fault_allocate (100);
TEST_COMPARE (strfmon (ntf.buffer, ntf.length, "%100n", 1.23), -1);
TEST_COMPARE (errno, E2BIG);
return 0;
}
#include <support/test-driver.c>
+1
View File
@@ -286,6 +286,7 @@ CFLAGS-wordcopy.c += $(no-stack-protector)
# Called during static initialization
CFLAGS-strncmp.c += $(no-stack-protector)
CFLAGS-memset.c += $(no-stack-protector)
CFLAGS-strlen.c += $(no-stack-protector)
ifeq ($(run-built-tests),yes)
$(objpfx)tst-svc-cmp.out: tst-svc.expect $(objpfx)tst-svc.out
+6
View File
@@ -132,6 +132,12 @@ $(objpfx)tst-bti-permissive-transitive: $(objpfx)tst-bti-mod.so
$(objpfx)tst-bti-ld-debug-shared: $(objpfx)tst-bti-mod.so
$(objpfx)tst-bti-ld-debug-both: $(objpfx)tst-bti-mod-unprot.so
$(objpfx)tst-bti-dlopen-imm.out: $(objpfx)tst-bti-mod-unprot.so
$(objpfx)tst-bti-dlopen-prot.out: $(objpfx)tst-bti-mod-prot.so
$(objpfx)tst-bti-dlopen-transitive.out: $(objpfx)tst-bti-mod.so
$(objpfx)tst-bti-ld-debug-dlopen.out: $(objpfx)tst-bti-mod-unprot.so
$(objpfx)tst-bti-permissive-dlopen.out: $(objpfx)tst-bti-mod-unprot.so
$(objpfx)tst-bti-abort-unprot-preload.out: $(objpfx)tst-bti-mod-unprot-preload.so
tst-bti-abort-unprot-preload-ENV = \
GLIBC_TUNABLES=glibc.cpu.aarch64_bti=1 \
+6
View File
@@ -147,3 +147,9 @@ void _dl_gcs_enable_failed (int code)
{
_dl_fatal_printf ("failed to enable GCS: %d\n", -code);
}
/* Used to report error when prctl system call to lock GCS fails. */
void _dl_gcs_lock_failed (int code)
{
_dl_fatal_printf ("failed to lock GCS: %d\n", -code);
}
+19 -2
View File
@@ -35,12 +35,13 @@ ENTRY (_start)
/* Use GL(dl_aarch64_gcs) to set the shadow stack status. */
adrp x16, _rtld_local
add x16, x16, :lo12:_rtld_local
ldr x1, [x16, GL_DL_AARCH64_GCS_OFFSET]
cbz x1, L(skip_gcs_enable)
ldr x22, [x16, GL_DL_AARCH64_GCS_OFFSET]
cbz x22, L(skip_gcs_enable)
/* Enable GCS before user code runs. Note that IFUNC resolvers and
LD_AUDIT hooks may run before, but should not create threads. */
#define PR_SET_SHADOW_STACK_STATUS 75
#define PR_LOCK_SHADOW_STACK_STATUS 76
#define PR_SHADOW_STACK_ENABLE (1UL << 0)
mov x0, PR_SET_SHADOW_STACK_STATUS
mov x1, PR_SHADOW_STACK_ENABLE
@@ -50,6 +51,19 @@ ENTRY (_start)
mov x8, #SYS_ify(prctl)
svc 0x0
cbnz w0, L(failed_gcs_enable)
/* Check if we need to lock GCS features. */
/* If the aarch64_gcs tunable is either 0 or 2 do not lock GCS. */
tst x22, #-3
beq L(skip_gcs_enable)
mov x0, PR_LOCK_SHADOW_STACK_STATUS
/* Lock everything including future operations. */
mov x1, ~0
mov x2, 0
mov x3, 0
mov x4, 0
mov x8, #SYS_ify(prctl)
svc 0x0
cbnz w0, L(failed_gcs_lock)
L(skip_gcs_enable):
.globl _dl_start_user
@@ -75,4 +89,7 @@ _dl_start_user:
L(failed_gcs_enable):
b _dl_gcs_enable_failed
L(failed_gcs_lock):
b _dl_gcs_lock_failed
END (_start)
@@ -20,5 +20,6 @@
#define _DL_IFUNC_GENERIC_H
asm ("memset = __memset_generic");
asm ("strlen = __strlen_generic");
#endif
@@ -40,3 +40,7 @@
#endif
#include "../strlen.S"
#if IS_IN (rtld)
strong_alias (strlen, __strlen_generic)
#endif

Some files were not shown because too many files have changed in this diff Show More