Compare commits

..
Author SHA1 Message Date
H.J. Lu f34a321219 x86: Set AVX10 active only if XMM/YMM/ZMM are supported
AVX10_XMM, AVX10_YMM and AVX10_ZMM feature bits were from the earlier
version of AVX10 specification.  Intel AVX10 specification published in
June 2026:

https://www.intel.com/content/www/us/en/developer/articles/technical/intel-sdm.html

support both AVX2 and AVX512.  These bits are reserved now and should
be 1.  Set AVX10 active only if XMM/YMM/ZMM are supported and set
AVX10_VERSION active only if AVX10 is active.

This fixes BZ #34554.

Signed-off-by: H.J. Lu <hjl.tools@gmail.com>
Reviewed-by: Arjun Shankar <arjun@redhat.com>
2026-09-10 17:03:09 +08:00
Andreas Schwab c6fd4ceffa time: handle ^ and # modifiers with %Z in wcsftime (bug 34611)
Fixes a regression in 79b2667d1e ("time: strftime_l: Avoid an unbounded
alloca").
2026-09-09 18:53:54 +02:00
H.J. Lu 23aae72744 x86: Detect APX_NCI_NDD_NF
Detect APX_NCI_NDD_NF specified in Intel APX specification published in
January 2026:

https://www.intel.com/content/www/us/en/developer/articles/technical/intel-sdm.html

Signed-off-by: H.J. Lu <hjl.tools@gmail.com>
Reviewed-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org>
2026-09-09 05:18:21 +08:00
Matt Turner 76c3d4472f math: let architectures signal underflow after narrowing
IEEE 754 determines tininess after rounding from the result rounded to
the precision of the destination with an unbounded exponent range. Alpha
determines it from the delivered result instead, and the two differ
where a value is tiny but reaches the smallest normal once rounded,
since the spacing below the smallest normal is twice that of the binade
the unbounded rounding lands in. Alpha signals no underflow for such a
result, and the narrowing functions cannot recover it: no trap is taken,
so the kernel emulation never sees the operation, and the final
narrowing is a single conversion instruction that has already decided
the question.

Add a CHECK_NARROW_TINY hook, in a sysdeps header that generic code
defines to do nothing, and use it in the round-to-odd narrowing macros
and in fmaf. Round-to-odd already gives the right answer wherever
tininess follows IEEE 754, so nothing changes for architectures that do.

The narrowing macros bound the round-to-odd value only as a temporary,
so add, subtract, multiply and divide now name it; fused multiply-add
already did. NARROW_MIN_NORMAL selects the smallest normal of the result
type rather than taking it as a macro argument, which would have to be
threaded through every narrowing function. On architectures where the
hook is empty the preprocessor discards both arguments, so neither is
expanded.

fmaf is not a narrowing function but converts its double result to float
on return, and so has the same problem; route its returns through one
helper.

On x86_64 the generated code is unchanged: s_fdiv and s_fmaf are
identical with and without this, in both the static and shared builds,
once debug information is stripped.

On Alpha this fixes the twenty remaining math failures, all of the form
Exception "Underflow" not set, leaving math with no failures.

Reviewed-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org>
2026-09-08 13:48:25 -03:00
Ruslan Valiyev e474366724 locale: fix memory leaks in write_locales and write_charmaps
Fix multiple memory leaks in the locale program:

1. PUT (xstrdup (...)) leaks when tsearch finds a duplicate entry,
   since tsearch returns the existing node and the newly allocated
   string is orphaned.  Introduce PUT_UNIQUE, which looks the name up
   with GET first and only allocates when it is actually inserted.

2. String literals "POSIX" and "C" passed to PUT cannot be freed by
   tdestroy.  They now go through PUT_UNIQUE, which duplicates them,
   so tdestroy (all_data, free) is safe.

3. Add tdestroy (all_data, free) at the end of write_locales and
   write_charmaps to free the search trees.

4. Free dirents[cnt] entries in the scandir loop (only the dirents
   array pointer was freed, not the individual entries).

5. Free alias_path allocated by argz_create_sep in write_locales.

Before this change "locale -a" leaked 74 bytes in 3 blocks directly
and 835 bytes in 49 blocks indirectly, and "locale -m" leaked 2190
bytes in 227 blocks.  Both are valgrind-clean afterwards.

These leaks were reported by Arjun Shankar via GCC -fanalyzer
(OpenScanHub/Fedora).

Resolves: BZ #33972
Signed-off-by: Ruslan Valiyev <linuxoid@gmail.com>
Reviewed-by: Arjun Shankar <arjun@redhat.com>
2026-09-07 20:11:52 +02:00
Shamil Abdulaev 9e1a0b152b math: Set errno to ERANGE for logb (+-0) [BZ #6793]
logb (+-0) is a pole error: it returns -Inf and raises the
divide-by-zero exception, but it never set errno, even though glibc
defines math_errhandling to include MATH_ERRNO.

Set errno in the zero branch that already exists in every logb
implementation, instead of adding a w_logb wrapper; the
USE_LOGB*_BUILTIN paths have no such branch, so add one there.  The
double and float versions use __math_divzero and __math_divzerof.
There is no long double equivalent, so those keep the explicit
division and use math_opt_barrier to stop the compiler from folding
it away.

The i386 fxtract implementations of logb and logbf cannot set errno,
and adding the error handling to the assembly is not worthwhile, so
they are removed in favour of the generic C ones.  s_logbl.c moves to
sysdeps/x86/fpu, replacing the x86_64 copy that only included it.

The manual described logb (0) as returning +Inf without signalling,
which was wrong in both respects.

Tested on x86_64-linux-gnu.

Signed-off-by: Shamil Abdulaev <ashamil435@gmail.com>
Reviewed-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org>
2026-09-07 11:38:48 -03:00
Matt Turner 9ef758c501 alpha: Use a comdat group for the shared divide-by-zero handler [BZ #20543]
DO_DIVBYZERO placed __divbyzero in .gnu.linkonce.t.divbyzero so that,
when building the PIC libc.so, every divide routine's copy collapses to
one. .gnu.linkonce is a pre-comdat-group GNU convention that no current
toolchain emits and that upstream lld has declined to support in full
generality, since a linked-to section from outside a group is not valid
ELF and every non-GNU-as producer has used SHT_GROUP comdat groups
instead for 25+ years.

BZ #20543 tracked this migration across glibc; i386's PIC-thunk section
was converted, but alpha's divide-by-zero handler was missed. Switch it
to the same "axG",@progbits,<sym>,comdat idiom already used by the i386
and sparc PIC-thunk sections, so it is deduplicated via a real ELF group
rather than section-name matching.

Divide routines reach the handler via `beq Y, DIVBYZERO`, a 21-bit
word-displacement branch (+-4MB range). The old .gnu.linkonce.t.* name
put the section in the default linker script's last .text bucket,
guaranteeing it trailed all other code; .text.__divbyzero lands one
bucket earlier alongside other .text.* input sections, so "last in
.text" is no longer guaranteed (PIC libc.so only; libc.a keeps per-file
copies). Measured on an alpha-unknown-linux-gnu build, __divbyzero
landed a few hundred bytes from the end of a ~1.6MB .text. An
out-of-range branch would fail the link with "relocation truncated to
fit" rather than produce a silently broken libc.

Reviewed-by: H.J. Lu <hjl.tools@gmail.com>
2026-09-07 11:38:44 -03:00
Hemanth Kumar M D c958d789db 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>
2026-09-07 11:38:18 -03:00
Florian Weimer fe03757f67 Record CVE-2026-18374 fix
Reviewed-by: Siddhesh Poyarekar <siddhesh@gotplt.org>
2026-09-04 20:18:07 +02:00
Shamil Abdulaev cca93e5d88 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>
2026-09-04 14:52:22 +02:00
Dongkyun Son 9765a538eb 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>
2026-09-04 14:52:05 +02:00
Ondrej MarekandFrantisek Cech 058c1c63e9 getrusage: Add smoke test for getrusage
Add smoke test verifying that getrusage returns non-negative user time and fails with invalid who value.

Co-authored-by: Frantisek Cech <fr.cech@proton.me>
Signed-off-by: Ondrej Marek <ondrejm4rek@gmail.com>
Reviewed-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org>
2026-09-03 16:29:35 -03:00
Michael Pfeifroth 10b1efb3cc powerpc: Restore NULL check on _rtld_global_ro in INIT_ARCH [BZ #34503]
Commit 21841f0d56 ("PowerPC: Influence cpu/arch hwcap features via
GLIBC_TUNABLES") changed the INIT_ARCH() macro used by powerpc32/power4
and (via a one-line include) powerpc64 multiarch IFUNC resolvers to
read hwcap and hwcap2 through a direct

    &GLRO(dl_powerpc_cpu_features)

reference, instead of the previous __GLRO() wrapper.  The __GLRO() macro
performs a volatile NULL check on _rtld_global_ro, which matters because
IFUNC resolvers can run before _rtld_global_ro has been relocated for the
current library.

This regression triggers when a shared library's IFUNC symbol from libm
is resolved via BIND_NOW (full RELRO) before libm's own GOT is relocated:
the resolver's INIT_ARCH() then dereferences a NULL _rtld_global_ro and
segfaults at the hwcap load.  The concrete failure seen was rsyslogd
crashing on startup on powerpc64 (e5500, BE) with

    rsyslogd -> librsyslog -> libfastjson -> modf() IFUNC in libm

when libfastjson lacked a DT_NEEDED on libm, so libm was relocated after
libfastjson's IFUNC resolvers ran.

Restore the __GLRO()-based access for both hwcap and hwcap2, matching
the pre-2.41 behaviour and how use_cached_memopt is already read in the
same macro.  This is a no-op once _rtld_global_ro is fully initialised
and simply reinstates the early-startup NULL guard.

Add a regression test (ppc64 only; ppc32 has additional early-startup
constraints that make the same test infeasible there).  The module is
linked with -z,now and intentionally has no DT_NEEDED on libm, so the
IFUNC resolver for modf() runs before libm is fully relocated.

Signed-off-by: Michael Pfeifroth <micpf@westermo.com>
Reviewed-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org>
2026-09-03 13:51:05 -03:00
Matt Turner 548997eb13 stdio-common: Skip the a and A conversions for the IBM extended format
The reference implementation renders the a and A conversions by
splitting the value into a significand of the width the type has and a
power of two. That presumes the type is a single binary floating-point
format.  The IBM extended format is a pair of doubles instead, whose
combined significand has no fixed width and whose subnormals are those
of the low double rather than of the type, so what glibc produces for it
does not follow from PREC and MINEXP: LDBL_MAX comes out as
0x1.fffffffffffff7ffffffffffff8p+1023 with twenty-eight fractional
digits where the value has at most twenty-six worth of significand, and
LDBL_TRUE_MIN as 0x0.0000000000001p-1022, which is the smallest
subnormal double and nowhere near LDBL_MIN_EXP.

The remaining conversions are unaffected, as they work from the value
rather than from a decomposition of it, and were verified to be.

Add an UNSUPPORTED_CONVS definition to the skeleton for conversions that
cannot be modeled for the type at hand, and set it to the a and A pair
where long double has that format, the generator then producing no
records and an unsupported status which the long double wrapper reports.

Tested on x86_64-linux-gnu and powerpc64le-linux-gnu, where all 672
results pass, and with the long double conversions forced to the IBM
extended format, where the a and A ones report unsupported and the rest
continue to pass.

Reviewed-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org>
2026-09-02 12:37:51 -05:00
Matt Turner 71e40f25cf stdio-common: Handle subnormal values in the printf format tests
The reference implementation used to verify the a and A conversions
assumed the value it was given was normal, splitting it into a
significand of the full width and an exponent.  That is not true below
the smallest normal value, where the exponent can go no lower and the
significand loses bits from the top instead, which is what makes the
leading hexadecimal digit of a subnormal come out as zero.  Given a
subnormal it would have produced a normalized result such as 0x1p-1070
where we print 0x0.000000000001p-1022.

Telling the two apart needs the minimum exponent for the type, which was
not among the data the test program supplies, so add it as a MINEXP
definition reported in a record of its own next to the working
precision. Then stop normalizing once that exponent is reached, and pad
the digits produced on the left, as there are no longer enough of them
to fill the field on their own.  The remaining conversions are
unaffected: they work from the value itself and never needed it
decomposed.

How far the exponent has to be shifted to sit after the significand
depends on the working precision, so hold MINEXP as reported and combine
the two only once a value is due to be converted, rather than requiring
the records to arrive in a particular order.  Where no MINEXP record
arrives the type has no subnormals and no clamping is applied.

None of the values iterated over were subnormal, so this could not be
observed.  Add DBL_TRUE_MIN and LDBL_TRUE_MIN to cover it, which also
exercises the smallest exponent with the remaining conversions.  How
many bits the leading hexadecimal digit holds varies with the type, one
for a 53 bit significand and four for a 64 bit one, so both are needed:
the wider case lands on a different exponent than the minimum for the
type, with LDBL_TRUE_MIN coming out as 0x0.000000000000001p-16385 rather
than at the p-16382 that the leading digit of a normal value would sit
at.  One sign is enough for either, as nothing in the sign handling
depends on the value being subnormal, and the records these produce are
among the most expensive in the test suite.

Tested on x86_64-linux-gnu, where all 672 results pass.

Reviewed-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org>
2026-09-02 12:37:47 -05:00
Matt Turner 1d2f28b459 stdio-common: Add printf format tests for the a and A conversions
The a and A conversions were left out when the formatted printf output
tests were added, because gawk produces output that differs from ours,
using insufficient precision where none has been given and choosing a
different exponent otherwise.  Verification no longer goes through AWK,
and computing the reference output directly makes them straightforward,
so cover them now.

The significand is written out as it stands, which means the leading
hexadecimal digit holds whatever bits are left over once the remaining
ones are grouped into whole digits: one bit for a 53 bit significand, so
the digit is 1, and four for a 64 bit one, so it runs from 8 to f.
Rounding to a requested precision can carry out of that digit, in which
case the result is re-expressed with one digit fewer and the exponent
raised by four rather than the integer part being widened.  The 0x
prefix precedes any '0' flag padding, as it does for the integer
hexadecimal conversions.

Unlike the remaining floating-point conversions these produce different
digits for an omitted precision than for one of 6, so key the memoized
digits on the precision as given rather than as defaulted.

Tested on x86_64-linux-gnu, where all 672 results pass.

Reviewed-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org>
2026-09-02 12:37:44 -05:00
Matt Turner d3902f1bdf stdio-common: Add printf format tests for the b and B conversions
The b and B conversions were left out when the formatted printf output
tests were added, because gawk does not handle them at all.
Verification no longer goes through AWK, so cover them now.

They follow the existing integer conversions, with the alternative form
producing the 0b or 0B prefix for a nonzero value.

Note that B was listed for neither the '#' and '0' flags nor precision,
so add it to those lists next to b, as otherwise most of its records
would never be produced.

Tested on x86_64-linux-gnu, where all 576 results pass.

Reviewed-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org>
2026-09-02 12:37:40 -05:00
Matt Turner dc6e310e79 stdio-common: Verify printf format tests with Python rather than AWK
The formatted printf output tests verify their records against GNU AWK,
relying on it to provide an implementation of format processing that is
independent from ours.

AWK has to run in the bignum mode for the floating-point conversions,
because otherwise it uses the system sprintf(3) internally and we end up
verifying our code against itself.  That in turn makes gawk compiled
with MPFR support a requirement for testing the library at all.  Beyond
that gawk mishandles a number of cases which the AWK script then has to
undo by hand: the extraneous leading 0 produced for the alternative form
with the octal conversion, the 0 produced where no characters are
expected for the hexadecimal conversions, the missing + and space
characters for a zero value with the precision of zero, and a collection
of sign, flag and field width anomalies for Inf and NaN values.  Each
such workaround suppresses whatever we might get wrong in the same
place.  The a, A, b, and B conversions cannot be verified at all,
because gawk either does not handle them or produces different output.

Replace the AWK script with an equivalent one written in Python, which
is already a requirement for building the library.  Rather than calling
into any formatting routine it computes the reference output directly,
using exact integer and rational arithmetic.  Working exactly means the
result does not depend on the range or precision of any host
floating-point type, so the wider types are handled without
arbitrary-precision arithmetic having to be built into the interpreter,
and none of the workarounds listed above are needed: the corner cases
they cover are computed correctly.  The same property removes the reason
the a, A, b, and B conversions had to be left out; adding them is left
for the commits that follow.  Rendered digits are memoized per value,
without which the exact arithmetic makes the long double conversions
slower than AWK.

As the capability probes only ever detected gawk build options, they go
away along with the unsupported status they could produce, so the f and
F conversions are now always verified rather than silently skipped where
gawk was built without them.  Drop the corresponding note on MPFR from
the installation instructions.

Tested on x86_64-linux-gnu, where all 576 results continue to pass.

Reviewed-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org>
2026-09-02 12:37:19 -05:00
Samuel Thibault e1643c8df3 hurd: Make __file_name_lookup_at apply upmask for O_TMPFILE (BZ 34493)
The file does not actually show up as reachable until getting linkat'ed,
which makes it 000 with the current ext2fs, but better make the filesystem
record proper mode anyway.
2026-09-02 02:14:24 +02:00
Samuel Thibault 3c8d50abeb hurd: Make readlinkat check bogus length returned by translator (BZ 34504) 2026-09-02 01:58:02 +02:00
Samuel Thibault ecb6cded89 hurd: Fix setreuid/setregid setting saved ID to new effective ID (BZ 34505)
As documented by posix & linux, if the real ID is set or the effective ID is
set to a value not equal to the previous real ID, the saved ID shall be set
to the new effective ID.
2026-09-02 01:50:17 +02:00
Shamil Abdulaev 10ed541ad1 stdlib, wcsmbs: Add missing __nonnull to strto*/wcsto* [BZ #33053]
The strto* declarations in stdlib.h are marked __nonnull, but the
corresponding declarations in inttypes.h and wchar.h are not.  Add the
attribute there as well, covering the __REDIRECT and __isoc23_* variants
and the _l forms, matching stdlib.h.

Signed-off-by: Shamil Abdulaev <ashamil435@gmail.com>
Reviewed-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org>
2026-09-01 16:19:43 -03:00
Adhemerval Zanella ed0c137b97 elf: Open the normalized $ORIGIN rpath in AT_SECURE programs (BZ 34360)
For AT_SECURE programs the loader honors $ORIGIN in DT_RPATH only when the
expansion is rooted in a trusted directory, but it validated the lexically
normalized path while opening the raw expansion.  As "a/b/../c" only names
"a/c" when "b" is not a symlink, an attacker who controls a component of
$ORIGIN -- e.g. by hard-linking the setuid binary into an attacker-owned
directory -- can make the opened path escape the trusted directory even
though the check passed, loading an attacker-controlled object.

Normalize the expansion in place and open that, so the path that is opened
is exactly the path that was validated.  _dl_normalize_path rewrites the
string in place without ever advancing its write cursor past its read
cursor or appending, so it stays within the original storage.

Add elf/tst-origin-secure as a regression test.

Reviewed-by: Florian Weimer <fweimer@redhat.com>
2026-09-01 15:40:28 -03:00
Yury Khrustalev 8fb6751ec7 test: Fix tst-personality
Fix check for -1 return on 32-bit hosts.

Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
2026-09-01 14:28:10 +01:00
Collin Funk e4c00c0a90 manual: adjust reference to man-pages following proc(5) split-up
The reference to MAP_NORESERVE and /proc/sys/vm/overcommit_memory was
moved from proc(5) to proc_sys(5) in man-pages commit bfc1299e7 (proc.5,
proc_sys.5: Split /proc/sys/ from proc(5), 2023-08-15). It was
subsequently moved to proc_sys_vm(5) in man-pages commit
b06cd070f (proc_sys.5, proc_sys_vm.5: Split /proc/sys/vm/ from
proc_sys(5), 2023-09-30).

Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
2026-08-31 23:54:44 -07:00
Jiayuan Chen 13c114c10b Updates udp.h from Linux 6.19 to netinet/udp.h
This patch updates udp.h from Linux 6.19.

Suggested-by: Florian Weimer <fweimer@redhat.com>
Signed-off-by: Jiayuan Chen <jiayuan.chen@linux.dev>
Reviewed-by: Florian Weimer <fweimer@redhat.com>
2026-09-01 08:34:08 +02:00
Florian Weimer 65b0a5da76 nptl: Test case for bug 34546
Largely auto-generated, using glibc-specific interfaces, and
following (manually-written) sysdeps/pthread/tst-robust12.c.

Assisted-by: LLM
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
2026-09-01 08:24:24 +02:00
Florian Weimer c7591e1c11 nptl: Use FAIL_UNSUPPORTED in init_tpp_test in tst-tpp.h
This allows priority-protect tests to be regular tests.  They
exit with EXIT_UNSUPPORTED if the process does not have sufficient
privileges.

Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
2026-09-01 08:24:24 +02:00
Florian Weimer 4effbd3679 nptl: Revert TPP updates on pthread_mutex_*lock failure (bug 34546)
Also fix __pthread_tpp_change_priority to undo changes to the priomap
array if any of the scheduler system calls fail.

Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
2026-09-01 08:24:24 +02:00
Florian Weimer 44bc1706d8 nptl: Fix test error reporting in CHECK_TPP_PRIORITY in tst-tpp.h
The middle case (unexpected priority) did not change the test outcome
to failure.

Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
2026-09-01 08:24:24 +02:00
Florian Weimer 69841bbaa5 nptl: Revert robust list head on pthread_mutex_timedlock failure (bug 34542)
For some error scenarios, the robust list head is left pointed at
the mutex after the return.  This can cause the kernel to update
the mutex lock field after it has been reallocated for something
else.

Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
2026-09-01 08:24:24 +02:00
Florian Weimer 67a152711e nptl: Treat negative times as timed out in PI futex locking (bug 34543)
The non-PI case already does this:

/* Work around the fact that the kernel rejects negative timeout
     values despite them being valid.  */
  if (__glibc_unlikely (abstime->tv_sec < 0))
    return ETIMEDOUT;

Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
2026-09-01 08:24:24 +02:00
Matt Turner 19e50d60ec stdio-common: Keep trailing zeros where %#g rounds into a new decade (BZ 34578)
The g and G conversions choose between the f and e styles according to
the exponent the value has once rounded to the requested number of
significant digits.  Where the value is small enough for the f style but
rounding then carries into a new decade, printf_fp rewrites the digits
it has already produced into the e style, recomputing along the way how
many fractional digits the leading digit now leaves room for.

FRACDIG_MIN, which the alternative form sets to the number of fractional
digits that have to be retained rather than stripped, was left behind at
the value computed for the f style.  Where the value filled the whole
integer part that is zero, so all the fractional digits were then
stripped from a result the '#' flag requires to keep them:

  printf ("%#.2g", 99.9)    gave "1.e+02" rather than "1.0e+02"
  printf ("%#g", 999999.9)  gave "1.e+06" rather than "1.00000e+06"

Update FRACDIG_MIN along with FRACDIG_MAX.  Without the alternative form
nothing retains trailing zeros, so the outcome is unchanged there.

None of the values the conversion tests iterate over round this way, so
add one that does at a precision they cover.

Tested on x86_64-linux-gnu.

Reviewed-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org>
2026-08-31 15:43:44 -03:00
Matt Turner 1cd5d3bba7 stdio-common: Iterate over the huge width for one printf function only
HUGE_WIDTH is chosen so that none of the strings produced are truncated,
which for the floating-point types means every record it takes part in
carries hundreds or thousands of digits.  Those records dominate the
cost of this whole family of tests: for the long double conversions they
are 99% of the bytes produced, and the long double targets alone account
for 92% of the time the tests take.

The digits being checked are produced by the same conversion code
whichever of the printf family of functions is used; what differs
between the twelve of them is the sink the result is written to, which
the smaller widths cover already.

Iterate over HUGE_WIDTH for a single function then, chosen as printf,
and let the remaining eleven stop at MID_WIDTH.  This applies to the
double and long double conversions only; for the other types
full-precision output is short and costs nothing, so they keep iterating
over it as before.

Together with the switch to verifying in Python this takes the tests
from 935s to 375s of processor time on x86_64-linux-gnu, with all 576
results continuing to pass.  What remains is mostly intrinsic: the f and
F conversions print the whole integer part regardless of the precision
requested, so LDBL_MAX runs to some 4932 digits even at MID_WIDTH.

Reviewed-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org>
2026-08-31 15:43:44 -03:00
Adhemerval Zanella b539947e15 elf: Remove dead l_need_tls_init static-TLS init path
Since af34b1376a ("elf: Initialize static TLS before relocation
processing", BZ 34164) dropped the 'defer-if-not-relocated' branch in
_dl_try_allocate_static_tls, nothing sets l_need_tls_init any more.  The
second pass in update_tls_slotinfo, guarded by l_need_tls_init, is
therefore dead: its _dl_update_slotinfo / _dl_init_static_tls calls never
run, and the static TLS image is initialised inline during relocation (IE
model) or lazily on first dynamic-TLS access instead.

Remove the dead loop, the now write-only l_need_tls_init field and its
clear in _dl_allocate_tls_init.  No functional change.

Checked on aarch64-linux-gnu, x86_64-linux-gnu, and i686-linux-gnu.
I also run the elf tests on armv7-a, alpha, loongarch64, mips64le,
powerpc, riscv, and s390x using qemu system.

Reviewed-by: Florian Weimer <fweimer@redhat.com>
2026-08-31 15:43:44 -03:00
Adhemerval Zanella b077f23933 elf: Remove __chk_fail from dl-minimal.c
The elf/rtld-Rules adds $(no-fortify-source) on rtld object, so
__chk_fail is never used.

Reviewed-by: Florian Weimer <fweimer@redhat.com>
2026-08-31 15:43:44 -03:00
Adhemerval Zanella d179e02998 elf: Allow RPATH/RUNPATH for static-pie (BZ 33326)
The initial static-pie support (commit 9d7a3741c9) reused
ld.so ELF parsing logic, even though RPATH/RUNPATH should not appear
in the static-pie bootstrap.  With static PIE, RPATH/RUNPATH on the
loader typically indicates a toolchain misconfiguration.  However,
for static PIE, the presence of RPATH/RUNPATH has no impact because
these binaries do not use dynamic linking at runtime.

Fully static binaries have no dynamic section, so RPATH/RUNPATH can not
appear there at all; for static PIE the only consumer is dlopen.  If
static dlopen support is ever removed, this change becomes a no-op.

This change also simplifies elf_get_dynamic_info and removes a
difference between dynamic and static binaries, along with the now
unused STATIC_PIE_BOOTSTRAP.

Tested on aarch64-linux-gnu and x86_64-linux-gnu.

Reviewed-by: Florian Weimer <fweimer@redhat.com>
2026-08-31 15:43:44 -03:00
Adhemerval Zanella 99e9c5d1ca Fix assert during static startup (BZ 33326)
The BZ#33326 testcase triggers an assertion during process startup,
which results in a segmentation fault instead of an error message
and process termination with a SIGABRT.  The assert issues
__libc_message_impl, which in turn might call string functions
depending on the ABI (strchrnul, strlen, memcpy/mempcpy), system
calls (writev and mmap), and finally the abort call.

The dl-symbol-redir-ifunc.h is also expanded to cover strchrnul on
x86_64, s390, powerpc64 (both endianness) and loongarch, mempcpy on
powerpc64be, and memcpy on aarch64.  On s390 the redirection is only
issued if the ifunc variant is built, since strchrnul-c.c only renames
the C implementation to STRCHRNUL_DEFAULT when HAVE_STRCHRNUL_IFUNC is
set.

The buffer that backs up the assert message is now allocated through
_dl_mmap, which issues the syscall directly instead of calling __mmap
(setting errno on failure requires the thread pointer).

The abort call now issues __raise_direct instead of raise (the Hurd
port aliases __raise_direct to raise).

On i386, syscalls should not use the vDSO during program startup because
the thread pointer is not yet initialized.  This requires __raise_direct,
_dl_writev, and _dl_mmap to be built with I386_USE_SYSENTER set to 0.

Creating a test case is challenging. For static-pie, the assert is only
called for ill-formed ELF files on elf_get_dynamic_info and by some targets
on ELF_DYNAMIC_RELOCATE (although not all targets use assert in their
dl-machine.h).  Some targets also issue __libc_fatal on ARCH_SETUP_IREL,
but also only for ill-formatted ELF files.

The test employs a different strategy and overrides the __tunables_init
symbol, which is invoked immediately before self-relocation and TLS setup.
The test is built with -Wl,-z,muldefs to avoid linker issues.

I checked on aarch64, x86_64, i686, s390x (qemu), sparc (qemu),
mips64el (qemu), armhf, riscv, and powerpc.

Reviewed-by: Florian Weimer <fweimer@redhat.com>
2026-08-31 15:43:44 -03:00
Adhemerval Zanella f9df2bbcf5 Use _dl_writev on __libc_message_impl
And change _dl_writev to return a negative errno in case of failure.
This keeps the required semantics for not setting errno on failure
and allows removing the Linux libc_fatal.c implementation.

It also makes it simple to use the writev syscall during process
startup, especially on i386, where it requires disabling vDSO.

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

Reviewed-by: Florian Weimer <fweimer@redhat.com>
2026-08-31 15:43:44 -03:00
Adhemerval Zanella a770631302 nptl: Add __raise_direct
The function sends a signal to current thread using raw syscalls.

Reviewed-by: Florian Weimer <fweimer@redhat.com>
2026-08-31 15:43:44 -03:00
Samuel Thibault 4e3ac0e7b7 tst-backtrace5: split long line 2026-08-31 20:06:38 +02:00
Samuel Thibault b7a63154b0 tst-backtrace5: Fix on hurd
hurd has intermediate io_read and read_nocancel functions, skip them down to
the actual read call from the test.
2026-08-31 00:39:16 +02:00
Sam James f750ffab2f fcntl: drop nonnull attribute for openat, openat2's path argument [BZ #34313]
.. and openat64.

Linux 7.2 (31cf44efa6df72a524b40adefb80539f3a4e13ba) allows openat, openat2
to take a NULL path with the new O_EMPTYPATH flag, so the nonnull attribute
is no longer sound. Drop it.

Bug: https://sourceware.org/PR34313
Reviewed-by: Paul Eggert <eggert@cs.ucla.edu>
2026-08-30 03:50:13 +01:00
Sam James 5bcfeca12b io: drop nonnull attribute for fchmodat, faccessat, fchownat's path argument [BZ #34313]
Since Linux 6.11, AT_EMPTY_PATH can be used for a NULL path argument, so
the nonnull attribute is no longer sound. Drop it.

This bug was worked around in gnulib's 6db27b4dd36eda618db20e997ff56bbed7fce3cb.

See also 55618e1396 which fixed fstatat
in glibc.

Bug: https://sourceware.org/PR34313
Reviewed-by: Paul Eggert <eggert@cs.ucla.edu>
2026-08-30 03:50:06 +01:00
Samuel Thibault 81f3dfabc9 hurd: Move SINGLE_THREAD_P / RTLD_SINGLE_THREAD_P to single-thread.h
Like on Linux
2026-08-29 20:43:35 +02:00
Collin Funk 6a46a9b6ec stdlib: merge some tests from gnulib
This makes the tests the same in both places. The changes in Gnulib
brought in by this patch also silence -Woverflow when using gcc 16.1.1
on i686.

Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
2026-08-28 19:08:05 -07:00
Moritz Klammler 0e30e9ce27 nptl: Propagate EDEADLK from FUTEX_LOCK_PI for errror-checking mutexes
This patch changes the behavior of pthread_mutex_lock in case of
non-trivial deadlock.  The user-space code doesn't detect the case
where two or more threads would mutually deadlock each other, but the
Linux kernel can.  NPTL's previous behavior, if the syscall returns
EDEADLK, was to run into an assertion.

With this patch:

 - For error-checking PI mutexes; the error code will be propagated to
   the caller who might then, at its own discretion and with knowledge
   about the application-level logic, use it to attempt resolving the
   situation gracefully or terminate the process after all.  Since
   error-checking mutexes are specified to possibly return EDEADLK,
   and the only reason to use them in the first place is for the sake
   of these additional error checks, any calling code failing to check
   the return code in this case may legitimately be considered broken
   already.

 - For recursive mutexes; the thread will actually deadlock instead of
   failing the assertion.  It has been discussed (see below) that this
   might be more conservative as, unfortunately, lots of existing code
   might be guilty of not always checking the return code.  So
   returning at all in this case might cause (arguably questionable)
   code to continue executing undefined behavior by falsely assuming
   that the thread successfully acquired a lock, which it didn't.

 - For all other mutex types; the behavior is not changed.  They will
   continue to actually deadlock the calling thread as they did prior
   to this patch.

A new test is added to assert the expected behavior of all mutex
types.

Since POSIX doesn't seem to mandate any particular behavior for this situation,
and no existing code should have a dependency of running into an assertion,
changing this behavior to what is presumably the most useful one seems to be
justified.

The previous (design) discussions can be seen here:
https://sourceware.org/pipermail/libc-alpha/2025-December/173431.html
https://sourceware.org/pipermail/libc-alpha/2026-April/176406.html

Signed-off-by: Moritz Klammler <moritz.klammler.ext@siemens.com>
2026-08-28 09:45:45 -03:00
Rolf Eike Beer f41f893b94 advisories: fix typo in README
Signed-off-by: Rolf Eike Beer <eb@emlix.com>
Reviewed-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org>
Reviewed-by: Siddhesh Poyarekar <siddhesh@gotplt.org>
2026-08-28 09:43:51 -03:00
Matt Turner a8f593ca4d Use __attribute_optimization_barrier__ for the remaining noclone users
Commit a2b0ff98a0 added __attribute_optimization_barrier__ and converted the
users of __attribute__ ((noinline, noclone)) to it, so that Clang, which does
not implement noclone, gets optnone instead of an unknown-attribute warning
that is an error under -Werror.

Twelve users were missed, all of them in code that a plain x86_64 build never
preprocesses, which is why they survived the sweep:

  - libio/tst-stderr-compat.c is inside
    #if TEST_COMPAT (libc, GLIBC_2_0, GLIBC_2_1), so it is compiled only on
    ports that still have GLIBC_2.0 compat symbols -- i686 and alpha among
    them, but not x86_64.  Building it with Clang fails.

  - The eleven sysdeps/x86_64/x32/tst-size_t-*.c tests are built only for the
    x32 ABI.

No functional change for GCC, which still gets noinline and noclone.

Checked that both shapes -- the weak function in libio and the static function
in the x32 tests -- compile with GCC and with Clang after the change, and that
the pre-change shape is an error under Clang with -Werror.
Reviewed-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org>
2026-08-28 09:43:42 -03:00
Magnus Lindholm a0eae67721 io: Do not alias fts and fts64 when inode types differ
The fts and fts64 interfaces can share an implementation only when
both their offset and inode types have matching layouts.

The existing conditions check only whether off_t and off64_t match.
On Alpha, these types match, but ino_t and ino64_t differ.
Consequently, FTSENT and FTSENT64 have different layouts.

The ordinary fts implementation is therefore omitted on Alpha, and
the ordinary fts symbols are instead aliased to the fts64
implementation. This causes the ordinary interface to operate on an
incompatible FTSENT64 layout and corrupts traversal state.

Build the ordinary implementation unless both the offset and inode
types match. Likewise, alias the ordinary symbols to the fts64
implementation only when both types match.

An audit of the bits/typesizes.h implementations shows that Alpha is
the only ABI where __OFF_T_MATCHES_OFF64_T is defined but
__INO_T_MATCHES_INO64_T is not. Therefore, this changes the
implementation selection only on Alpha.

This fixes io/tst-fts, io/tst-fts-bz22944, and io/tst-fts-newflags on
Alpha.

Signed-off-by: Magnus Lindholm <linmag7@gmail.com>
Reviewed-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org>
2026-08-28 09:43:35 -03:00
Sam James 7997d202a6 Use FAIL_UNSUPPORTED more
In a few places, we weren't exiting w/ 77 when skipping. Fix that by using
our standard macro for it.

Reviewed-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org>
2026-08-28 12:54:02 +01:00
Florian Weimer 35efcffa97 iconvdata: Test case for bug 34556, bug 34568
Assisted-by: LLM
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
2026-08-28 10:26:07 +02:00
Florian Weimer 4dafa087ff iconvdata: EUC_JISX0213 decoding lacks pending character reset (CVE-2026-80489)
This fixes bug 34568.

Reviewed-by: Carlos O'Donell <carlos@redhat.com>
2026-08-28 10:26:07 +02:00
Florian Weimer 68d94bbe50 iconvdata: SHIFT_JISX0213 decoding lacks pending character reset (CVE-2026-77117)
This fixes bug 34556.

Reviewed-by: Carlos O'Donell <carlos@redhat.com>
2026-08-28 10:26:07 +02:00
Azharul Haque ea99fc77ea localedata: bn_BD, bn_IN: use full Gregorian month names for abmon
Bangla has no conventional abbreviated form for month names. The
existing abmon entries only truncated January and February ("জানু",
"ফেব"), while March through December were already spelled out in
full -- an inconsistent and non-standard %b output that native
speakers do not recognize as valid abbreviations. "জানু" is also an
unrelated, existing Bengali word meaning "knee".

Use the full month name for abmon as well as mon in both bn_BD and
bn_IN, matching the informal convention already used for the other
ten months and consistent with CLDR's bn Gregorian calendar data,
which likewise leaves several months unabbreviated for the same
reason (see CLDR-19739, filed separately for the CLDR side of this:
https://unicode-org.atlassian.net/browse/CLDR-19739).

Signed-off-by: Azharul Haque <haque@azharul.com>
Reviewed-by: Mike FABIAN <mfabian@redhat.com>
2026-08-28 10:03:27 +02:00
Collin Funk 655656fcc6 manual: Fix some typos in the Low-Level Input/Output chapter 2026-08-27 20:44:59 -07:00
H.J. Lu 56f3aed8bb x86: Update AVX10 support
Update AVX10 support for Intel AVX10 specification published in June 2026:

https://www.intel.com/content/www/us/en/developer/articles/technical/intel-sdm.html

and AI Compute Extensions (ACE) Specification:

https://x86ecosystem.org/resource/ai-compute-extensions-ace-specification/

1. Add x86_get_avx10_version to return AVX10 version.
2. Detect AVX10_V1_AUX and AVX10_V2_AUX features.
3. Remove AVX10_XMM, AVX10_YMM, AVX10_ZMM documentations.

This fixes BZ #34554.

Signed-off-by: H.J. Lu <hjl.tools@gmail.com>
Reviewed-by: Sunil K Pandey <skpgkp2@gmail.com>
2026-08-28 05:27:07 +08:00
Siddhesh Poyarekar 15d39cffc8 Document CVE-2026-18374 and new CVSS tag
The security team has been scoring issues recently, so also add the
score to the advisory file as the single source of truth.  Document the
new tag in README.

Signed-off-by: Siddhesh Poyarekar <siddhesh@gotplt.org>
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
2026-08-27 15:16:51 -04:00
Yury Khrustalev 1441595762 aarch64: Add memory clobber to pkey_write
Add memory clobber for writing to the POR_EL0 register since a change
to this register affects subsequent memory accesses.

Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
2026-08-27 14:00:16 +01:00
Florian Weimer b090cf226f 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>
2026-08-27 13:34:54 +02:00
Samuel Thibault 47dd7e0dac hurd: Set _TIME_BITS=32 for installed programs on i386/Hurd
We do not plan to take the time to implement the compatibility layer.
Other 32b Hurd ports will be able to directly use 64b time_t.
2026-08-27 11:41:22 +02:00
H.J. Lu 0e57c798c6 Add check-symbol-version.awk
commit 6deadd4eb6
Author: Adhemerval Zanella <adhemerval.zanella@linaro.org>
Date:   Wed Oct 8 10:55:05 2025 -0300

didn't remove sysdeps/m68k/m680x0/fpu/w_fmod_compat.c.  As the result,
due to a linker bug:

https://sourceware.org/bugzilla/show_bug.cgi?id=34550

there were 2 default versions of fmod in m68k libm:

   996: 0001433c   174 FUNC    WEAK   DEFAULT   12 fmod@@GLIBC_2.0
   997: 000307d4   214 FUNC    GLOBAL DEFAULT   12 fmod@@GLIBC_2.43

Add check-symbol-version.awk to verify that versioned symbols only have
one default version in dynamic symbol table.

Signed-off-by: H.J. Lu <hjl.tools@gmail.com>
Reviewed-by: Sam James <sam@gentoo.org>
2026-08-26 17:27:52 +08:00
mengqinggang b3d14eff4f LoongArch: Add standard search paths for 32-bit
Previously, add_system_dir added different paths depending on the ABI:
  ilp32d: /lib32
  ilp32s: /lib32/sf

Now, add_sysmtem_dir adds all of the following directories to standard
search path for both ilp32d ABI and ilp32s ABI:
  /lib
  /lib32
  /lib32/sf
  /lib64
  /lib64/sf

This change fixes elf/tst-ptrguard-static-dlopen on ilp32s ABI.
The test is a statically linked executable with dlopen
tst-ptrguard-static-dlopen-mod.so. Without this patch, the test fails
because it looks for ld.so in /lib32/sf, but the file is actually
in /lib32.
2026-08-26 10:22:53 +08:00
mengqinggang dd63105d1b LoongArch: Support pointer guard on LoongArch32
LoongArch32 Reduced has no rotri.d/rotri.w instructions.
Use slli.w/srli.w/or to synthesize the rotation on LoongArch32
and LoongArch32 Reduced.

Reported-by: Haiyong Sun <sunhaiyong@loongson.cn>
2026-08-26 10:22:53 +08:00
Samuel Thibault d93ebd7f85 hurd: Warn about setting _TIME_BITS=64 on i386 GNU Hurd
We do not plan to implement compatibility layers etc.

Other 32b Hurd ports will always use 64b time_t.
2026-08-25 21:21:57 +02:00
Adhemerval Zanella 70cc22b19c math: Update tanh from CORE-MATH (revision bb39e4fa)
The bug only exists in the non-FMA-contracted compilation of that
branch. On x86_64 it can be triggered with:

  GLIBC_TUNABLES=glibc.cpu.hwcaps=-AVX2 math/test-double-tanh

Or by building without ifunc support.

Checked on aarch64-linux-gnu and x86_64-linux-gnu with
--disable-multi-arch.
2026-08-25 14:36:35 -03:00
Yury Khrustalev 9c86ea03aa tests: elf: Fix flaky thp tests
Several tests rely on a madvise syscall to appear in strace output
(or not appear in case of 'disable' tests). This syscall may occur
in malloc. To avoid this from happening, we use malloc tunable to
disable hugetlb for these tests.

Suggested-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
2026-08-25 14:01:12 +01:00
Sam James 53e5f02a6b support: fix typo in support_readdir [BZ #34564]
The symbols are '...@GLIBC', not '...'@GBLIC'.

Noticed when looking at BZ #34564.

Fixes: 1251e9ea49
2026-08-24 23:45:55 +01:00
Adhemerval Zanella 38abaa0b21 stdlib: Fix tst-stdbit-builtins.c build on clang-23
The 00e797cc20 used a wrong ifdef
for clang.
2026-08-24 16:49:30 -03:00
Adhemerval Zanella 3923b80921 elf: Make string tunables startup-only
A string tunable value usually references the GLIBC_TUNABLES (or alias)
environment string, which lives in the environment block the kernel places
on the initial stack.  That memory is owned by the application, which may
overwrite it (e.g. setproctitle), so the reference is only safe while no
application code has run (a value coming from the system-wide tunables
cache is a copy instead, but the rule is applied uniformly).

This patch make the lifetime explicit and enforced without copying the value
or allocating any memory by adding __tunable_seal_strings, which drops every
string tunable reference once early startup is complete.

The seal is applied after the only string tunable consumer and before any
code outside of the startup sequence runs.

Checked on aarch64-linux-gnu and x86_64-linux-gnu.  I also run the elf
tests on powerpc64le-linux-gnu, loongarch64-linux-gnuf64, and
s390x-linux-gnu.
2026-08-24 13:49:12 -03:00
Adhemerval Zanella 53ec26f173 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.
2026-08-24 13:48:57 -03:00
Adhemerval Zanella dfacfbbdbb Revert "tests: Remove target-specific huge-page size definition for THP-aware load segment alignment"
This reverts commit 224cb4a8dd.  The
change broke the build of some THP tests on arc and or1k [1].

[1] https://sourceware.org/pipermail/libc-testresults/2026q3/014918.html
2026-08-24 13:48:15 -03:00
Adhemerval Zanella 5f5bc63a4d powerpc: Fix preprocessor conditional in soft-float __longjmp (bug 34530)
Commit 24d188a2a1 left a stray #endif in
the powerpc32 soft-float __longjmp-common.S. Remove it, matching the
fpu variant.

Checked with a build for powerpc32-linux-gnu-soft.
2026-08-24 13:48:15 -03:00
Andreas Schwab ff1c558061 m68k: remove sysdeps/m68k/m680x0/fpu/w_fmod_compat.c (bug 34559)
This was missed from commit 6deadd4eb6.
2026-08-24 18:29:41 +02:00
Samuel Thibault a367c5da61 hurd: Make __pthread_timedblock update relative timeout on signal
We should not let __mach_msg handle it, otherwise if we keep receiving
signals faster than the computed relative timeout, we will never time out.
2026-08-23 17:22:12 +02:00
Tiago Dinis a1e333203a Makerules/Makeconfig: Add rtlddir-build for the libc.so loader reference
The libc.so linker script generated by "make install" references the
dynamic linker via an AS_NEEDED entry so the linker can resolve it
while building against libc.  Previously this used \$(rtlddir), which
is also the path compiled into ld-linux as its self-identification
string (-DRTLD in elf/Makefile) and used for the PT_INTERP of glibc's
own binaries (installed-rtld-LDFLAGS in Makeconfig).

These two uses legitimately differ when glibc is built to run on a
different environment with a different filesystem structure than the
build system: the loader is installed under the build tree, but the
resulting binaries must reference it via the runtime path of the
target environment.  Setting \$(rtlddir) to that runtime path makes
libc.so point at a loader that is not present at build time, breaking
linking against libc and later consumers such as binutils.

Introduce \$(rtlddir-build), defaulting to \$(rtlddir), and use it for
the libc.so AS_NEEDED entry so it tracks where the loader is actually
installed.  \$(rtlddir) keeps driving the runtime path
(self-identification and PT_INTERP).  This is a no-op for the default
configuration, where rtlddir-build == rtlddir == slibdir.

Reviewed-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org>
2026-08-21 14:34:41 -03:00
Xi Ruoyao 224cb4a8dd tests: Remove target-specific huge-page size definition for THP-aware load segment alignment
On MIPS64 and AArch64 systems with 16-KiB pages, the PMD size is 32MB.
As we already have multiple platforms requiring such a large size and
it's the maximum THP size we support to align the load segments, it's
easier to raise the default instead of adding more special cases.

Link: https://sourceware.org/glibc/wiki/Testing/Tests/elf/tst-thp-1
Signed-off-by: Xi Ruoyao <xry111@xry111.site>
Reviewed-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org>
2026-08-21 14:34:36 -03:00
Matthias Goergens 7820b97b7a string: Declare Issue 8 functions for POSIX.1-2024 [BZ #34466]
POSIX.1-2024 requires memmem, strlcpy, and strlcat in <string.h>, and
wcslcpy and wcslcat in <wchar.h>. Expose these declarations and their
fortified wrappers under __USE_XOPEN2K24 as well as __USE_MISC. Keep
mempcpy restricted to __USE_MISC.

Add declaration tests for POSIX and X/Open Issue 8 modes, including
fortified headers.

Signed-off-by: Matthias Goergens <matthias.goergens@gmail.com>
Reviewed-by: DJ Delorie <dj@redhat.com>
2026-08-21 14:34:34 -03:00
Ross Burton 3f4ccc3e0f nscd: replace echo with printf builtin in nscd init script
The nscd init script calls for #! /bin/bash interpreter since it uses
bash specific extentions namely (translated strings) and echo -n
command, replace echo with printf and switch the shell interpreter to

Reviewed-by: Sam James <sam@gentoo.org>
2026-08-21 14:34:31 -03:00
Matt Turner 38b2b3f3a8 string: vectorize strspn single-accept-char case
The single-accept-character fast path was a byte-at-a-time scalar loop.
Scan a word at a time instead, using find_ne_all () to locate the first
byte that differs from the broadcast accept character.  ACCEPT[0] is not
NUL here, so a NUL byte differs from it and the search for inequality
also stops at the end of the string.

The word loop compares against the broadcast character directly rather
than building a mask each iteration, and calls find_ne_all () once at the
end.  Where find_ne_all () is an exclusive or the compiler already
generated this, but alpha builds the mask with cmpbge, and the comparison
halves its loop.

The multi-character case keeps the existing bitmap-table scan.

Checked against strspn () for lengths 0 to 300 at every byte alignment,
for several accept characters, with the run ended both by NUL and by a
differing byte.  Run on alpha (EV68CB), powerpc64 big-endian, 32-bit arm,
aarch64 and x86_64, covering the cmpbge, cmpb, uqsub8 and generic C
string-fza.h implementations.  The riscv ones were built but not run.

Speedup over the scalar loop it replaces:

  length        8    32   128   512    2K    8K   32K
  Alpha EV68  1.3x  3.3x  5.2x 11.7x 15.2x 16.4x 16.9x
  i7-1370P    1.9x  2.8x  5.5x  4.0x  5.2x  6.9x  7.6x

Both are the best of seven timed runs of each implementation, each run
calibrated to at least 0.3 s so that the millisecond clock granularity on
alpha does not quantize the result, and built with -falign-functions=64
so that code placement does not dominate the short lengths.  The i7-1370P
reaches this code only where SSE4.2 is unavailable, since the generic C
string-fza.h is what it would use there.

Suggested-by: Wilco Dijkstra <Wilco.Dijkstra@arm.com>
Reviewed-by: Wilco Dijkstra  <Wilco.Dijkstra@arm.com>
2026-08-21 14:34:23 -03:00
Matt Turner 40cf4504a8 string: simplify find_zero_ne_all
Build the mask from the raw difference, as find_ne_all () now does.
index_first () and index_last () only need to know which byte holds the
first or the last set bit, and find_zero_all () marks only the bytes that
were zero, so each term of the or marks only its own bytes.

That drops one of the two carry chains from strcmp () and strncmp () on
targets using the generic string-fza.h, and one of the two uqsub8 on
armv6t2.  As in find_ne_all (), only the generic implementation tests
HAVE_BITOPTS_WORKING.

powerpc keeps its existing form, where orc folds the complement of cmpb
into the or and the raw difference saves nothing.  alpha and riscv do not
reach this code with the generic index_first ().

Reviewed-by: Wilco Dijkstra  <Wilco.Dijkstra@arm.com>
2026-08-21 14:34:20 -03:00
Matt Turner de5a4687c0 string: add find_ne_all to string-fza.h
find_zero_ne_all () searches for a zero byte in X1 or a byte that differs
between X1 and X2.  A caller that knows X2 contains no NUL byte does not
need the zero test, since a NUL byte in X1 already differs from every
byte of X2.

Add find_ne_all (), which searches for inequality alone, to the generic
implementation and to each target that provides its own string-fza.h.
Dropping the zero test makes it cheaper than find_zero_ne_all () on every
target.

Return the difference unreduced wherever index_first () and index_last ()
come from the generic string-fzi.h, which uses stdc_trailing_zeros () and
stdc_leading_zeros () and so only needs to know which byte holds the first
or the last set bit.  That covers armv6t2, powerpc and riscv with the
bitmap extensions, as well as the generic implementation.  Only the
generic one tests HAVE_BITOPTS_WORKING, since its fallback ctzb () and
clzb () isolate a single bit and expect it at 0x80; the target masks are
already incompatible with that fallback and cannot use it either way.

riscv without the bitmap extensions takes its string-fza.h from the
generic implementation while defining its own index_first () and
index_last (), which tested bit 7 of each byte.  Test the whole byte
instead, so that they accept the unreduced difference.

alpha keeps a reduced form, its find_t being a cmpbge mask of one bit per
byte throughout.

Reviewed-by: Wilco Dijkstra  <Wilco.Dijkstra@arm.com>
2026-08-21 14:34:15 -03:00
litenglong 6af4d48a91 elf: Remove __glibc_likely from _dl_sort_maps
_dl_sort_maps is only called during shared object loading and
unloading, not on any hot path. The branch predictor hint has no
measurable benefit, and removing it simplifies the code and avoids
future maintenance when the default algorithm changes.

Suggested-by: Wilco Dijkstra <wilco.dijkstra@arm.com>
Reviewed-by: Wilco Dijkstra  <Wilco.Dijkstra@arm.com>
2026-08-21 14:34:13 -03:00
Yury Khrustalev 82944350ad malloc: aarch64: Add ifuncs for malloc functions
Introduce ifuncs and resolvers for functions pertinent to the
malloc interface on the AArch64 target: malloc, calloc, free,
realloc, memalign, valloc, pvalloc, posix_memalign, aligned_alloc,
free_sized, free_aligned_sized, malloc_usable_size.

A target can define the USE_MULTIARCH_MALLOC macro. In this case
it must provide alternative aliases for the malloc functions that
point to the ifuncs.

This implementation respects the --disable-multi-arch configure
flag. If multi-arch support is disabled, the generic aliases
are used on aarch64.

This patch contains aarch64-specific resolvers. At this point they
return core implementations but in the future they can be changed
to support for features, e.g. to handle memory tagging.

Reviewed-by: Wilco Dijkstra <Wilco.Dijkstra@arm.com>
2026-08-20 10:04:49 +01:00
Yury Khrustalev 5d7828bd5e malloc: Refactor malloc API into a separate header
This commit moves declarations for various malloc functions from
the malloc.c file to a separate header that can be used to include
these declarations in other source files.

No functional change intended.

Reviewed-by: Wilco Dijkstra <Wilco.Dijkstra@arm.com>
2026-08-20 10:04:49 +01:00
Florian Weimer 6467136459 stdio-common: Remove fallback realloc calls from vfscanf
These merely delay the inevitable on 32-bit architectures.
Growing a buffer one character at a time is very slow, so this
could lead to even more processing time for very large inputs.

Reviewed-by: Collin Funk <collin.funk1@gmail.com>
2026-08-20 09:20:55 +02:00
Florian Weimer b2d944913a stdio-common: Use reallocarray for wide strings in vfscanf (bug 34531)
This avoids theoretical integer overflow issues on 32-bit
architectures.  The overflow is not reachable since glibc 2.30
because doubling reaches a size larger than PTRDIFF_MAX, at which
point realloc fails due to commit 9bf8e29ca1 ("malloc:
make malloc fail with requests larger than PTRDIFF_MAX (BZ#23741)").
The non-doubling path is used instead.  Eventually, the size
increments also pass PTRDIFF_MAX, so the fallback realloc fails, too.
This means that in current glibc, there is no crash.

Reviewed-by: Collin Funk <collin.funk1@gmail.com>
2026-08-20 09:20:55 +02:00
Florian Weimer a0faa928b0 time: Fix integer truncation in strftime (bug 34538)
Extremely large time zone names were not processed correctly.
2026-08-19 09:33:31 +02:00
Florian Weimer 24d188a2a1 powerpc: Fix non-atomic stack pointer update in fortified longjmp (bug 34530)
After commit 78f1f0e39c ("Consolidate
the C pointer guard and align the assembly implementations"),
PTR_DEMANGLE3 on POWER no longer atomically updates the destination
register. The fortified longjmp relies on atomic update of the
stack pointer (r1) in sysdeps/powerpc/powerpc64/__longjmp-common.S
and parallel files:

#ifdef PTR_DEMANGLE
# ifdef CHECK_SP
        PTR_DEMANGLE3 (r22, r22, r25)
# else
        PTR_DEMANGLE3 (r1, r22, r25)
# endif
#endif

Fix this by using PTR_DEMANGLE instead of PTR_DEMANGLE3.  Remove
PTR_MANGLE3 and PTR_DEMANGLE3 as unused.

An alternate fix would store the pointer guard cookie rotated,
but this would go against the unification in the commit that
introduced the regression.

Reviewed-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org>
2026-08-18 21:48:34 +02:00
Wilco Dijkstra a3439ac139 Arm: Remove inline assembler from string-fza.h
Use __uqsub8 since minimum GCC supports it now.

Reviewed-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org>
2026-08-17 15:44:50 +00:00
Wilco Dijkstra c5c47f1b86 benchtests: Increase iterations for strpbrk/strspn
Increase iterations for strpbrk/strspn so they run for at least 0.5s.
Reduce iterations for the much slower wcs* variants since they take over 10s.

Reviewed-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org>
2026-08-17 15:43:52 +00:00
Arjun Shankar 06baff3553 manual: Use string values for glibc.cpu.x86_shstk in tunables example
The documentation for system-wide tunables had an example for
overridability that used 0/1 as values for glibc.cpu.x86_shstk.  Use the
correct on/off string values instead.

Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
2026-08-17 17:08:32 +02:00
Florian Weimer 6144ef0896 stdlib: Remove cache from rpmatch (bug 34526)
It is not thread-safe.  Furthermore, the cache invalidation logic did
not account for deallocation in uselocale (which could change the regexp
without changing its pointer).

Given that this code is unlikely to be performance-senstive
(it is for interactive use) and the regular expressions are very
short, allocate and deallocate the regular expressions on each
call.

Reviewed-by: Collin Funk <collin.funk1@gmail.com>
2026-08-15 15:39:17 +02:00
Florian Weimer 40ddd85420 resolv: Test case for accepting mismatching, corrupted packets
The test skeleton was auto-generated.  I think this is fine because
the harness is so specific to glibc.

Assisted-by: LLM
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
2026-08-15 12:03:35 +02:00
Florian Weimer ab4b07d2ac resolv: Fix __libc_res_queriesmatch buffer size argument in send_dg (bug 34346)
Pass the number of bytes written by recvfrom, not the entire size
of the buffer.

This is not a security vulnerability because it only allows
confirmation of previously existing buffer values.  All reads stay
within the specified buffer bounds.  The buffer contents may not have
been initialized.  Subsequent processing is correctly capped at buffer
bounds, too.

Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
2026-08-15 12:03:35 +02:00
Florian Weimer 1960326bb6 resolv: Handle ternary return value in __libc_res_queriesmatch (bug 34345)
The __libc_res_nameinquery function returns -1 for corrupted packets.
The previous code treated those as matching.

This is not a security vulnerability because the transaction ID is
still checked.  The bug does not  make off-path attacks substantially
easier.  Furthermore, most users of the DNS stub resolver parse the
question name again, and do not simply skip over it using dn_skipname
or similar (which would hide the corruption).  This means that the
packet is still rejected at a later stage.

Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
2026-08-15 12:03:35 +02:00
Florian Weimer 1b0cb41cfa support: Add resolv_response_set_buffer
This can be used to mangle the response data to exercise the
DNS client with corrupted packets.

Also change resolv_response_buffer not to allocate.  Instead,
just return a pointer to the internal buffer.  The function is
currently unused.

Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
2026-08-15 12:03:35 +02:00
Florian Weimer e2789c46e3 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>
2026-08-14 13:41:16 +02:00
Adhemerval Zanella bb213471be 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>
2026-08-12 15:19:39 -03:00
jb2170 8280625a2c inet/arpa/inet.h: Fix typo in documentation of inet_ntop
Reviewed-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org>
2026-08-12 15:08:02 -03:00
Matt Turner e6f3cc4246 elf: build the IFUNC resolver stack protector tests only with ssp
The three resolver translation units are compiled with
-fstack-protector-all so that the canary code is emitted whatever the
default is.  A target whose compiler has no stack protector at all cannot
do that, and on alpha the build stopped:

  cc1: error: '-fstack-protector' not supported for this target [-Werror]

taking the rest of the elf tests with it.  Guard the tests on $(have-ssp),
which configure already sets from the compiler's own answer.  That is the
answer for -fstack-protector rather than for -fstack-protector-all, which
has its own configure test, but only the former reaches config.make, and a
compiler that has one has the other.

Reviewed-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org>
2026-08-12 15:08:02 -03:00
Magnus Lindholm b9ff43bdfe nscd: Define nscd_ssize_t as int32_t unconditionally
alpha was the only target that overrode sysdeps/generic/nscd-types.h,
defining nscd_ssize_t as int64_t rather than int32_t. The file dated back
to the initial import and had only ever received licence and copyright
updates.

nscd's response headers are a wire format, shared between the daemon and
its clients through a socket and through the persistent cache. A 64-bit
nscd_ssize_t gives four of them 8-byte alignment while their last member is
32 bits, so they acquire four bytes of tail padding: hst_response_header,
ai_response_header, serv_response_header and innetgroup_response_header.

For the hosts cache that is fatal. cache_addhst() asserts that the string
data follows the header with no gap, and on alpha it does not:

  nscd: hstcache.c:269: cache_addhst: Assertion
    `(char *) (&dataset->resp.error + 1) == dataset->strdata' failed.

The daemon aborts, and nscd/tst-nscd-basic fails with 58 errors. With the
override removed it passes.

The padding is also never initialised. cache_addhst() assigns the header
fields individually and nothing clears the record, yet the response is sent
with writeall (fd, &dataset->resp, ...) covering the full
sizeof (hst_response_header), so four uninitialised bytes reach every
client.

With alpha gone there is no target left overriding the type, so the sysdeps
indirection has no purpose. Delete both headers and define nscd_ssize_t
directly in nscd/nscd-client.h alongside the wire format it describes.

This changes nscd's protocol and persistent cache layout on alpha; the
daemon and its clients always come from the same build, so the exposure is
a daemon left running or a cache file left behind across the upgrade.

Signed-off-by: Magnus Lindholm <linmag7@gmail.com>
Reviewed-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org>
2026-08-12 15:08:02 -03:00
Adhemerval Zanella 91d60ade97 elf: Fix tst-nodelete-dlclose-dso.c on clang-23
clang-23 enables -Wunused-but-set-global by default, which flags
variables that are set but never read.
2026-08-12 15:08:02 -03:00
Adhemerval Zanella b4d9c2d67c gnulib: Fix tst-gcc.c build with clang-23
clang-23 changed its uninitialized-use analysis to consider the operand
used.
2026-08-12 15:08:02 -03:00
Adhemerval Zanella 3cd88a6952 malloc: Fix malloc/tst-mallocfork3.c on clang-23
clang-23 enables -Wunused-but-set-global by default, which flags
variables that are set but never read.
2026-08-12 15:08:02 -03:00
Adhemerval Zanella 7d9be3fa30 rt: Fix tst-aio{9,10}.c on clang-23
clang-23 enables -Wunused-but-set-global by default, which flags
variables that are set but never read.
2026-08-12 15:08:01 -03:00
Adhemerval Zanella 06659e7cb1 stdio-common: Fix tst-setvbuf2.c on clang-23
clang-23 enables -Wunused-but-set-global by default, which flags
variables that are set but never read.  Also remove the fstat call,
which was only used to set the removed variable.
2026-08-12 15:08:01 -03:00
Adhemerval Zanella 00e797cc20 stdlib: Adapt tst-stdbit-builtins.c _BitInt tests on clang
Two issues with clang-23:

1. -std=gnu11 triggers warnings with the 'uwb' suffix due to
   -Wc23-extensions being enabled by default.

2. an ICE with __builtin_stdc_bit_ceil with a non-constant
   unsigned _BitInt(1) argument [1]

This patch disables the warning for 1. and disables the affected
stdc_bit_ceil tests for clang.

[1] https://github.com/llvm/llvm-project/issues/214478
2026-08-12 15:08:01 -03:00
Adhemerval Zanella f510065b70 elf: Fix dl-cache.c build with clang-23
clang-23 warns that the variable 'ext' set but not used:

  dl-cache.c:42:47: error: variable 'ext' set but not used
  [-Werror,-Wunused-but-set-global]

The variable is set unconditionally by _dl_load_cache_lookup, but it
is only read by glibc_hwcaps_priorities_init (which is compiled only
for SHARED).
2026-08-12 15:08:01 -03:00
Matt Turner 059e1cd67b linux: align the ancillary buffer in tst-socket-timestamp
The test places the ancillary buffer so that it ends against a PROT_NONE
page, at cmsg - (CMSG_SPACE (tsize) + slack).  CMSG_SPACE (sizeof (struct
timeval)) is a multiple of the alignment of struct cmsghdr, so the start of
the buffer inherits the alignment of the slack, and one of the slack sizes
the test uses is 4.

msg_control has to be suitably aligned for struct cmsghdr: recvmsg and the
CMSG_* macros both read cmsg_len from the start of the buffer, and it is a
size_t.  On a target that does not fix up unaligned accesses in hardware,
reading it from a misaligned address traps into the kernel.  On alpha each
one is reported:

  ld-linux.so.2(48878): unaligned trap at 0000000120001e3c: ... 29 2

five per run, all from the loop over the control messages in
do_recvmsg_slack_ancillary.  The test still passes, since the kernel
completes the access and returns.

Round the start of the buffer down to the alignment, and add the alignment
minus one to the requested allocation so the rounding cannot move the start
outside it.  A slack that is not a multiple of the alignment then leaves the
buffer ending a few bytes short of the guard page rather than against it; the
overruns the guard page is there to catch are a whole timestamp rather than a
few bytes, so they are still caught.

Reviewed-by: Florian Weimer <fweimer@redhat.com>
2026-08-12 10:39:13 +02:00
Adhemerval Zanella ae646973c5 elf: Fix clang-18 build of elf/tst-ifunc-fault-mod.c test
clang-18 errors on the static ifunc resolvers seen as unused.
2026-08-11 10:51:36 -03:00
Adhemerval Zanella 0113b90a91 elf: Fix tunconf.c build with clang
clang enables -Wsingle-bit-bitfield-constant-conversion with -Werror
and it triggers:

tunconf.c:338:32: error: implicit truncation from 'int' to a one-bit wide bit-field changes value from 1 to -1 [-Werror,-Wsingle-bit-bitfield-constant-conversion]
  338 |       entry->value_is_negative = 1;

Change both value_is_negative and value_was_parsed to unsigned.

Checked on x86_64-linux-gnu and i686-linux-gnu.
2026-08-11 10:51:36 -03:00
Yury Khrustalev 87a79abe92 aarch64: Use __glibc_likely macro in comment in dl-tlsdesc.S
This is to have uniform code style across all code in sysdeps/aarch64.

Reviewed-by: Wilco Dijkstra  <Wilco.Dijkstra@arm.com>
2026-08-11 14:18:47 +01:00
caiyinyu 78e3de9ecd aarch64: Standardize code by using macros __glibc_{un,}likely
Improves code readability by using the same macros across code
in the sysdeps/aarch64 directory.

Reviewed-by: Wilco Dijkstra  <Wilco.Dijkstra@arm.com>
2026-08-11 14:18:40 +01:00
H.J. Lu 2be733e9e0 strace-tst-thp.sh: Allow unsupported THP tests
Change strace-tst-thp.sh to check the command exit status so that
unsupported THP tests exit with status 77.

Signed-off-by: H.J. Lu <hjl.tools@gmail.com>
Reviewed-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org>
2026-08-11 12:18:21 +08:00
Florian Weimer b589bd672c stdio-common: Restore while (1) loop in printf_positional
The old condition is misleading because it is never evaluated.
Switch back to the original approach before the printf buffer
rewrite.
2026-08-10 16:10:34 +02:00
Magnus Lindholm 9d7d648088 alpha: Use the generic gethostname
alpha was the only target implementing gethostname with the syscall
rather than through uname. Its only behavioural difference was the errno
for a too-small buffer: it reported EOVERFLOW where the generic
implementation, gethostname(2) and misc/tst-gethostname expect
ENAMETOOLONG, so alpha failed that test:

  tst-gethostname.c:96: numeric comparison failure
     left: 112 (0x70, EOVERFLOW); from: errno
    right: 63 (0x3f); from: ENAMETOOLONG

The file contains nothing but that function, so removing it lets the
sysdeps search fall through to sysdeps/posix/gethostname.c, which
produces the same buffer contents and the expected errno.
misc/tst-gethostname passes on alpha with it.

Suggested-by: Florian Weimer <fw@deneb.enyo.de>
Signed-off-by: Magnus Lindholm <linmag7@gmail.com>
Reviewed-by: Florian Weimer <fweimer@redhat.com>
2026-08-10 11:26:21 +02:00
Adhemerval Zanella bd57d3231d posix: Do not recurse once per pattern component in glob [BZ #34453]
glob splits the pattern at its rightmost slash and calls itself on
the part before it, so a pattern needs one stack frame per directory
component.  It also calls itself once per brace expression.  Either can
be made as deep as the pattern is long, so glob overflows the stack
before it can answer.  The descent is on the pattern alone, so the
leading component, which is what decides whether anything can match at
all, is only reached at the bottom of the recursion:

  glob ("__nonexistent__/*/*/.../*/x", 0, NULL, &g)

with a few thousand components crashes with an default stack (usually
8MB on Linux).

Expand the components in a loop instead.  glob_dir_pattern collects
what each component has to do into a heap-allocated array, then matches
them from left to right, and glob_brace walks the brace expansions with
an explicit stack.  Both arrays are sized from the pattern up front:
there is no more than one step per slash and no more than one brace
level per brace, since each consumes one.

Matching left to right also means a leading directory that does not
exist ends the expansion at the first component rather than after
descending through all of them.

Stack usage no longer depends on the pattern: a pattern with 100000
components now resolves on a 64 KiB thread stack, where before 4096
components overflowed 8 MiB.

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

Reviewed-by: Collin Funk <collin.funk1@gmail.com>
2026-08-09 08:53:55 -03:00
Adhemerval Zanella 6288139c32 posix: Remove the alloca uses from glob_in_dir
What is left are the name used to stat a component without
metacharacters and the blocks holding the matched names.  With those on
the heap the alloca budget can go as well.

Also treat the size overflow as an error.  It used to fall through
to malloc with the wrapped size and then copy the full length
into it.

alloca is now used only by the MSDOS and Windows paths, which glibc
does not build, so move its header out of the way as well.

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

Reviewed-by: Collin Funk <collin.funk1@gmail.com>
2026-08-09 08:53:55 -03:00
Adhemerval Zanella 563f02a6aa posix: Use malloc instead of alloca for the glob brace expansion
The last alloca in __glob is the buffer holding one expansion of a
brace expression.  As with the directory and user names, the stack it
takes is not bounded by the call itself.

Use malloc unconditionally.  __glob no longer uses alloca; glob_in_dir
still does, so the accounting stays for now.

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

Reviewed-by: Collin Funk <collin.funk1@gmail.com>
2026-08-09 08:53:55 -03:00
Adhemerval Zanella d0084cbd18 posix: Use malloc instead of alloca for the glob user name
Use malloc unconditionally.  The name is only needed for the passwd
lookup that follows, which is far more expensive than the allocation.

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

Reviewed-by: Collin Funk <collin.funk1@gmail.com>
2026-08-09 08:53:55 -03:00
Adhemerval Zanella c31848f01b posix: Move the glob home directory lookups out of __glob
Expanding "~" or "~user" needs a struct scratch_buffer to call
getpwnam_r through, where the code might reserve extra stack in
every glob frame (around 1224 bytes on x86_64).  Even though the
lookups only run when the caller passed GLOB_TILDE or
GLOB_TILDE_CHECK.

Move the two lookups into glob_current_home_dir and glob_user_home_dir,
which return the directory as a malloc'ed string.  The frame of each
glob call drops to around 184 bytes.

This also fixes a small leak: the ~user path returned GLOB_NOSPACE
without freeing user_name when scratch_buffer_grow failed.

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

Reviewed-by: Collin Funk <collin.funk1@gmail.com>
2026-08-09 08:53:55 -03:00
Adhemerval Zanella dd40146613 posix: Use malloc instead of alloca for the glob directory name
Use malloc unconditionally instead.  These are one-off allocations
whose cost is dwarfed by the readdir and fnmatch work that follows.

The amount of stack this can take is not bounded by these calls alone,
glob recursively calls itself per pattern component, and each call
starts a fresh alloca budget.

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

Reviewed-by: Collin Funk <collin.funk1@gmail.com>
2026-08-09 08:53:55 -03:00
mengqinggang 4b0c2842a8 LoongArch: Fix intermittent nptl/tst-cancel32 failure
The nptl/tst-cancel32 test fails intermittently on LoongArch
with SIGSEGV at __longjmp:

0x7ffff7de7f6c <__longjmp+28>   rotri.d         $sp, $t0, 0x11
0x7ffff7de7f70 <__longjmp+32>   xor             $sp, $sp, $t1

rotri.d and xor are expanded from PTR_DEMANGLE2.
If the thread is cancelled between the rotri.d and xor,
an incomplete sp register causes the SIGSEGV.

Change the destination register of rotri.d to avoid an incomplete sp.
2026-08-09 10:13:03 +08:00
Adhemerval Zanella 16ad6a1539 elf: Use the effective lazy mode for the deferred IRELATIVE pass
The 63b31c05a8 split relocation processing must agree for the lazy
flag, a mismatch would change the .rel.plt handling.

This is not an issue for any port currently, but on hppa it may return
a different value: if hppa implements IFUNC support, the second pass would
route PLT entries to its empty lazy handler and leave the descriptors
unrelocated, silently.

Make ELF_DYNAMIC_RELOCATE_PASS take lazy as an int lvalue and store the
effective mode back into it, so the DL_RELOC_IRELATIVE call reuses the
same variable instead of a separately threaded copy.  The two passes can no
longer disagree about the partitioning.  elf_machine_runtime_setup has side
effects, so it must stay a single call.

Checked on x86_64-linux-gnu, and built for all supported architectures.

Reviewed-by: Sam James <sam@gentoo.org>
2026-08-08 10:00:59 -03:00
Adhemerval Zanella 2f2e9bae40 elf: Honour skip_ifunc for cross-object IFUNC relocations [BZ #34428]
Commit 63b31c05a8 ("elf: Defer all IRELATIVE relocations until after PLT
setup") dropped the skip_ifunc argument from elf_dynamic_do_Rel, assuming
the new deferred elf_dynamic_do_Rel_irelative pass handles every relocation
that may run an IFUNC resolver.  That only holds for IFUNC symbols defined
in the object being relocated: a reference to an IFUNC in another object is
an ordinary JMP_SLOT or GLOB_DAT against an undefined symbol, and its IFUNC
nature is only known after symbol resolution inside elf_machine_rel.  Those
relocations stay in the regular pass, which no longer propagated
skip_ifunc, so __RTLD_NOIFUNC was ignored for them.

ldd -u forces non-lazy binding (GLRO(dl_lazy) = 0 for DL_DEBUG_UNUSED), so
the resolver was called and the diagnostic emitted:

  $ ldd -u /bin/ls
  /bin/ls: Relink `' with `/usr/lib64/libc.so.6' for IFUNC symbol `__mempcpy_chk'

ldd -r with LD_BIND_NOW is affected in the same way.

Restore the skip_ifunc parameter and thread it through _ELF_DYNAMIC_DO_RELOC.

This new semantic shows that ELF_DYNAMIC_RELOCATE_NOIFUNC naming is misleading
(it reads as "do not process IFUNC", yet it takes a skip_ifunc
argument). Replace it to:

  DL_RELOC_BOTH     -> DL_RELOC_ALL
  DL_RELOC_NOIFUNC  -> DL_RELOC_NORMAL
  DL_RELOC_IFUNC    -> DL_RELOC_IRELATIVE

ELF_DYNAMIC_RELOCATE_NOIFUNC and ELF_DYNAMIC_RELOCATE_IFUNC become a single
ELF_DYNAMIC_RELOCATE_PASS taking the pass as its first argument, and
ELF_DYNAMIC_DO_REL/ELF_DYNAMIC_DO_RELA take the pass instead of having three
near-identical variants each.

Checked on x86_64-linux-gnu, and built for all supported architectures.

Reviewed-by: Sam James <sam@gentoo.org>
2026-08-08 10:00:50 -03:00
Sam James e053ceaa66 elf: preserve exit code in tests
Use $fail when we set it rather than just '1' (we already checked
that it is non-zero) to make logs more meaningful.

(Also, use $rc when we already checked it svalue.)
2026-08-08 01:05:01 +01:00
Adhemerval Zanella 666c2acb7d nss: Use test resolver for tst-getaddrinfo4
Rewrite the BZ#15339 test to use the resolv_test framework instead of
querying the network, so it can run as a regular test.

Reviewed-by: Florian Weimer <fweimer@redhat.com>
2026-08-07 15:01:47 -03:00
Ryota Saito 279206dffd sysdeps: Remove duplicated INTERNAL_SYSCALL_NCS macros
Commit 89b53077d2 ("nptl: Fix Race conditions in pthread cancellation
[BZ#12683]") added a second copy of the __INTERNAL_SYSCALL_NCS{0-7}
and INTERNAL_SYSCALL_NCS_CALL macros, which had already been defined
earlier in the same file by commit 00baddbb93 ("linux: Add generic
syscall implementation").  Remove the second copy.

Signed-off-by: Ryota Saito <saito.ryota.23@shizuoka.ac.jp>
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
2026-08-07 15:01:47 -03:00
Marcus Poller c1e0787b56 nss: Use reallocarray to prevent integer overflow in getaddrinfo (bug 33977)
replacing realloc by reallocarray introduces a basic overflow check.
(old + count) might still overflow, but since the NSS backend is trusted,
we do not consider this to be a valid case.

Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
2026-08-07 15:01:38 -03:00
Magnus Lindholm c1fb5d0e6b string: Speed up strcasecmp test data initialization
The strcasecmp and strncasecmp tests repeatedly initialize large
buffers for many combinations of lengths and alignments.  The existing
loops perform a remainder operation and call toupper and tolower for
every element.

Generate at most max_char elements using an additive recurrence and
apply the case conversions while creating this initial pattern.  The
recurrence produces the same sequence as the existing multiplication
and remainder expression.  Expand the completed pattern using bulk
copies.

This preserves the generated test data and locale-dependent case
conversion while substantially reducing the initialization cost on
slower systems.

Signed-off-by: Magnus Lindholm <linmag7@gmail.com>
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
2026-08-07 10:47:23 -03:00
Magnus Lindholm 9b323b9556 string: Speed up strcmp test data initialization
The strcmp and strncmp tests repeatedly initialize large buffers for
many combinations of lengths and alignments.  The existing loops
perform a remainder operation and two individual stores for every
element.

Generate at most max_char elements using an additive recurrence.  The
recurrence produces the same sequence as the existing multiplication
and remainder expression.  Expand this initial pattern using bulk
copies, and then copy the completed first buffer to the second buffer.

This preserves the generated test data while substantially reducing
the initialization cost on slower systems.

The change also applies to the wcscmp and wcsncmp tests, which include
the same test sources.

Signed-off-by: Magnus Lindholm <linmag7@gmail.com>
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
2026-08-07 10:47:15 -03:00
Adhemerval Zanella a33ceb6e96 arm: Order the rtld link after libgcc-stubs.a
The librtld.map and librtld.os link recipes use $(gnulib), which on arm
contains libgcc-stubs.a through gnulib-arch.  But the archive is only a
prerequisite of lib-noranlib so the rtld link can run before the archive
exists:

  ld.bfd: cannot find .../elf/libgcc-stubs.a: No such file or directory

The race seems to predates the parallel subdirectory recursion, which
only made it observable.

Add the order-only dependency in sysdeps/arm/Makefile rather than in
elf/Makefile.  Theprerequisite lists expand when the rule is parsed,
and gnulib-arch is only defined once Makerules includes the sysdeps
makefiles.

Verified with a build for arm-linux-gnueabihf.
Reviewed-by: Sam James <sam@gentoo.org>
2026-08-07 08:43:02 -03:00
Adhemerval Zanella 25c42d04c4 Makefile: Order the top-level stamp files before the subdirectory fan-out
The archive rules in Makerules list every stamp file as a prerequisite,
including the top level's own, and the elf sub-make evaluates them to
build libc_pic.a for the librtld.map link.  A sub-make can only create
the stamp files of its own directory, so when the top-level ones do not
exist yet it fails with:

  make[2]: *** No rule to make target '.../stamp.os', needed by
  '.../libc_pic.a'.  Stop.

The serial recursion created them before the subdirectories through the
prerequisite order of subdir_lib; the parallel recursion (commit
7cac99621e) does not.  Add them as prerequisites of the object-building
per-subdirectory targets.
Reviewed-by: Sam James <sam@gentoo.org>
2026-08-07 08:43:02 -03:00
Adhemerval Zanella ba8c8801be Makerules: Make the .dt to .d conversion safe against concurrent sub-makes
The %.d: %.dt rule seds its input into a fixed temporary name, renames
it into place and removes the input.  Two makes converting the same
file trip over each other:

  mv: cannot stat '.../test-double-libmvec-sincos-avx512f.o.T': No such file or directory
  sed: can't read .../test-float-libmvec-acosf-avx512f.o.dt: No such file or directory

That happens because the elf rtld-Rules recursion runs a sub-make over
every $(rtld-subdirs) directory, which converts that directory's .dt
files, and the parallel subdirectory recursion (commit 7cac99621e)
runs it concurrently with those subdirectories' own sub-makes.

Add the PID of the shell to the temporary name and claim the input with
a rename: only the run that wins converts and installs the target.
Reviewed-by: Sam James <sam@gentoo.org>
2026-08-07 08:43:02 -03:00
Adhemerval Zanella 96a9a09d7d Makefile: Only print the test summary in the second pass of 'make check'
The build-only first pass of the two-pass 'make check' still runs the
static checks (abi, conformtest, installed headers, etc.), and the
top-level tests recipe merged and summarized their results.

An unexpected FAIL there (e.g. check-abi) aborted 'check' before the
second pass ran any built test, and even a clean run printed a misleading
partial summary.

Pass tests-summary=no in the first pass to skip the merge and summary;
the .test-result files persist, so the second pass folds those results
into the one complete summary at the end, restoring the single-pass
reporting behavior.
Reviewed-by: Sam James <sam@gentoo.org>
2026-08-07 08:43:02 -03:00
Rudi Heitbaum 82c0a96b8e Makerules: Only install the ABI lib-names header from the top level (BZ 34439)
The $(inst_includedir)/%.h install rules exist only where $(headers) is
non-empty, so in a subdir without headers (e.g. csu) the prerequisite
added on install-others-nosubdir has no rule.

It only worked because .NOTPARALLEL made the top level install the header
first, which the parallel subdir recursion no longer guarantees.
Reviewed-by: Sam James <sam@gentoo.org>
2026-08-07 08:43:02 -03:00
Adhemerval Zanella 60c9ed0e6b Fix gen-as-const-headers races with the parallel subdir recursion (BZ 34438)
The parallel subdirectory recursion (commit 7cac99621e) only orders
csu (and mach/hurd on Hurd) before the parallel fan-out plus the edges
the Depend files request.  A header generated from gen-as-const-headers
is only ordered before the compilations of the subdirectory that
adds the .sym (through before-compile), so a header consumed by a
different subdirectory may not exist yet when its consumer is
compiled.

That is the case for <sigaltstack-offsets.h>: it is generated when
building misc, while its only consumer, ____longjmp_chk.S (x86_64 and
sh), is built in debug.  The serial recursion always ran misc before
debug in the sorted order, hiding the missing dependency.

Move the generate the header to 'debug' instead.

The same class of problem exists on Hurd: jmp_buf-ssp.h that is used
by ____longjmp_chk.S in debug, and signal-defines.h that is sued
by debug and setjmp.

Deterministically reproduced with 'make debug/subdir_lib' from a clean
build tree (which orders only csu before debug), and verified with
builds for x86_64-linux-gnu, sh4-linux-gnu, i686-gnu, and x86_64-gnu.
Reviewed-by: Sam James <sam@gentoo.org>
2026-08-07 08:43:02 -03:00
Matt Turner a32db99a38 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>
2026-08-07 08:43:02 -03:00
Matt Turner 8e41f6008d 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>
2026-08-07 08:43:02 -03:00
Adhemerval Zanella 1b5ff009fa linux: Inline syscall cancellation to keep wrapper frames observable (BZ 34338)
The cancellable syscall wrappers end with a tail call to __syscall_cancel,
the wrapper frame is then elided, so when the syscall executes the wrapper
is no longer present on the stack.  Tools that unwind from CFI alone, such
as valgrind, perf and sampling profilers, cannot observe it. On gdb, it
only recovers it from DWARF call site information, which reduced-debuginfo
libc builds usually omit.

The behaviour is target dependent: for a shared (PIC) the tail call is
emitted on aarch64, arc, loongarch and riscv.  It is not emitted on i386,
x86_64, arm, s390x, sparc and alpha, where the seventh argument is passed
on the stack or fewer argument registers are available, nor on powerpc
and mips, where the TOC/GOT pointer must be restored after the call.
This is why the problem was originally reported as aarch64 specific while
x86_64 was unaffected.

Rather than only inhibiting the tail call [1] (which keeps the wrapper frame
but still leaves the __syscall_cancel and __internal_syscall_cancel
frames), move the cancellation logic back into the wrappers.  In the
single-threaded case the syscall is now issued directly from the wrapper;
only the multi-threaded path still calls the out-of-line __syscall_cancel_arch.

This keeps the wrapper observable and removes the extra frames, mimicking
how cancellation was handled before 89b53077d2.

The result is a small libc.so .text increase (size, first column):

  ABI            master      patched      diff    increase
  aarch64       1635880     1647424      11544      0.71%
  x86_64        1981081     1992257      11176      0.56%
  powerpc64le   2364336     2376964      12628      0.53%
  riscv64       1368386     1376704       8318      0.61%
  loongarch64   1741385     1755601      14216      0.82%

The tst-backtrace5 was suppose to track this issue, but due wrong
loop variable check it does not take this in account.  This patch also fixes
it.

Checked on aarch64-linux-gnu, x86_64-linux-gnu, i686-linux-gnu,
arm-linux-gnueabihf, and powerpc64le-linux-gnu.

[1] https://sourceware.org/pipermail/libc-alpha/2025-March/165395.html
2026-08-07 08:43:02 -03:00
Matt Turner 0cc3f9b3f3 stdio-common: avoid repeated regexp matches in tst-printf-format.awk
Whether the value is an infinity, a NaN or zero does not change between
the conversions applied to it, but was determined again for each one.
Determine it where the value is read.

Also look for the '#' flag with index() before matching the expressions
that need it, and test the value first where both have to hold.

For the %f conversion for double, in the C locale, as the median of five
runs:

  x86_64, gawk 5.4.1    1.248s -> 1.184s
  x86_64, gawk 5.3.2    0.703s -> 0.708s
  alpha,  gawk 5.4.60    26.6s ->  25.8s

So this only helps with the regular expression engine that gawk 5.4
brought in; under 5.3.2 it is lost in the noise.  Output and exit status
are unchanged for the e, f and g conversions for double under both
gawk versions and both locales.

Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
2026-08-06 23:13:36 +01:00
Matt Turner 866a70167b stdio-common: run AWK in the C locale in the printf format tests
The program under test runs in the C locale, through the test program
prefix, but AWK inherits whatever locale the build was started in.  They
agree today only because the locale in use shares its decimal point with
the C locale.

It is also faster.  gawk takes a single byte path in its regular
expression engine when MB_CUR_MAX is 1, and the script matches several
expressions against every line.  For the %f conversion for double, the
largest of these tests, as the median of five runs:

  x86_64, gawk 5.4.1    1.482s -> 1.248s
  x86_64, gawk 5.3.2    0.911s -> 0.703s
  alpha,  gawk 5.4.60    30.9s ->  26.6s

Worth noting that gawk 5.4 is a good deal slower here than 5.3 was, at
1.248s against 0.703s for the same input in the C locale, so these tests
have become more expensive than they used to be.

Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
2026-08-06 23:13:26 +01:00
Matt Turner 559d0f77f3 powerpc: Fix -mlong-double-128 IBM format configure test for Clang
The check for -mlong-double-128 IBM extended format support wrapped its
test code in AC_LANG_PROGRAM, which places the body inside main().  The
body defines a function, so it became a nested function definition -- a
GCC extension that Clang does not implement, making the test fail with
Clang.

Use AC_LANG_SOURCE so the function is defined at file scope, and
regenerate configure.

Reviewed-by: Sam James <sam@gentoo.org>
2026-08-06 23:12:25 +01:00
Matt Turner e7a14f03b8 ldbl-opt: Fix -mlong-double-128 configure test for Clang
The check for -mlong-double-128 support wrapped its test code in
AC_LANG_PROGRAM, which places the body inside main().  The body defines
a function, so it became a nested function definition -- a GCC extension
that Clang does not implement, making the test fail (and thus the whole
build error out) with Clang even though it supports -mlong-double-128.

Use AC_LANG_SOURCE so the function is defined at file scope, matching the
pattern already used by the powerpc64le compiler checks, and regenerate
configure.

Reviewed-by: Sam James <sam@gentoo.org>
2026-08-06 23:12:14 +01:00
Frédéric Bérat 97f74c6781 elf: Improve diagnostics for static TLS exhaustion
Improve the error diagnostics printed when static TLS allocation fails
during dlopen.

The CHECK_STATIC_TLS macro is updated to pass the fully resolved sym and
the referencing map over to _dl_allocate_static_tls, modifying its
signature.

When _dl_allocate_static_tls is called, it now attempts to reconstruct
what failed using _dl_exception_create_format. It displays:
* The name of the symbol that triggers this.
* Whether this is due to static TLS space being exhausted, or if the
  symbol has previously been used as global-dynamic and is now being
  tried to use as initial-exec.
* If the symbol-defining map is different from the referencing map, it
  includes its name as well.
* If static TLS is exhausted, includes requested size and available
  size.

The change cascades through all architecture variants modifying their
dl-machine calls to CHECK_STATIC_TLS to conform to the new prototype.

Reviewed-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org>
2026-08-06 12:02:00 +02:00
Adhemerval Zanella d6031665c3 hurd: Fix build after the ftw kernel_stat.h inclusion
Commit 6758def717 changed the generic ftw{64}.c to include
kernel_stat.h, which is Linux specific.

Add a Hurd version of kernel_stat.h defining XSTAT_IS_XSTAT64 to 0,
since struct stat and struct stat64 never share a layout on Hurd: on
32-bit ABIs st_ino, st_size, and st_blocks are narrower in struct stat,
and on 64-bit ABIs the two structures still differ in size because
_SPARE_SIZE in bits/stat.h reserves three more ints of spare space in
struct stat than in struct stat64.

This keeps the ftw/ftw64 symbols exactly as before the change, where
the aliasing check on __OFF_T_MATCHES_OFF64_T was always false because
the Hurd bits/typesizes.h does not define it.

Checked with a full build for i686-gnu and x86_64-gnu.
2026-08-04 13:45:18 -03:00
Mark Wielaard c89d20dd52 rt: skip nanosleep interval and abs test for low precision clocks
If a clock doesn't have enough precision to check the sleep resolution
(quantum.tv_nsec > TEST_NSEC / 10) then record the quantum.tv_nsec,
but skip the interval_test and abs_test for that clock.

Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
Tested-by: Magnus Lindholm <linmag7@gmail.com>
2026-08-04 06:13:38 +02:00
Magnus Lindholm 4a07bb292f 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>
2026-08-03 15:53:19 -03:00
Xi Ruoyao 6758def717 io: fix ftw ABI on MIPS n64
On MIPS n64 off_t is same as off64_t, but struct stat is not same as
struct stat64 (very peculiar but see the "as tempting as it..." comment
in linux/mips/kernel_stat.h).  As the ftw/ftw64 callback accepts a
pointer to a function who accepts struct stat/stat64, for MIPS n64 we
must use different implementations for ftw and ftw64.

Thus for testing if ftw64 can be aliased to ftw, we should check
XSTAT_IS_XSTAT64 instead of __OFF_T_MATCHES_OFF64_T.

This resolves the io/tst-ftw-lnk failure observed on MIPS n64.

Link: https://sourceware.org/glibc/wiki/Testing/Tests/io/tst-ftw-lnk
Signed-off-by: Xi Ruoyao <xry111@xry111.site>
Reviewed-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org>
2026-08-03 15:53:12 -03:00
Ryota Saito 04eeb80847 sysdeps: Fix comment typos in sysdeps/unix/sysdep.h
Fix grammar in the comments describing __SYSCALL_CANCEL_CALL and
__INTERNAL_SYSCALL_CANCEL_CALL.

Signed-off-by: Ryota Saito <saito.ryota.23@shizuoka.ac.jp>
Reviewed-by: Collin Funk <collin.funk1@gmail.com>
2026-08-01 11:55:50 -07:00
Adhemerval Zanella b01abba04a math: Fix x86_64 tanh _FloatN aliases binding to the FMA variant [BZ 34465]
The generic implementation emits libm_alias_double unconditionally, so
tanhf32x and tanhf64 bind directly to __tanh_fma.

Guard the alias with '#ifndef __tanh' and emit it from the dispatcher,
as sin.  Also remove the stale __expm1 defines, unused since tanh moved
to CORE-MATH.

Checked on x86_64-linux-gnu, and with 'qemu-x86_64 -cpu Nehalem'.

Reported-by: Michael Brunnbauer <brunni@netestate.de>
2026-07-30 09:50:37 -03:00
Arjun Shankar 4535a6a52d dlfcn: Deprecate dlinfo request type RTLD_DI_ORIGIN (bug #24298)
Commit b52619f2e8 added a new dlinfo
request type, RTLD_DI_ORIGIN_PATH, to be used instead of RTLD_DI_ORIGIN
which is prone to buffer overflows.  With a replacement available,
RTLD_DI_ORIGIN can now be deprecated.

This commit deprecates RTLD_DI_ORIGIN by adding a compile-time warning
upon its use, and documents the deprecation in the manual.

The warning depends on "Enumerator Attributes" supported by gcc
since 6.1 and by clang.  A new macro __attribute_deprecated_enum__,
analogous to __attribute_deprecated_msg__, is defined in cdefs.h.
Because gnulib can override system-installed cdefs.h, thus hiding our
definition, the deprecation is conditional on the macro being defined.

Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
2026-07-30 12:48:36 +02:00
Adhemerval Zanella 26f0f2aa7d benchtests: Create objdir in the bench-%.c generation rule
The $(objpfx)bench-%.c rule writes its output into $(objpfx) without
ensuring that directory exists.  Serial builds happened to satisfy
that ordering, with parallel builds the generation recipe can
run before the directory is created, failing with:

  cannot create .../benchtests/bench-xxx.c-tmp: Directory nonexistent

Add the standard $(make-target-directory).

Reviewed-by: Florian Weimer <fweimer@redhat.com>
2026-07-28 13:27:49 -03:00
Yury Khrustalev 37a64a1618 misc: Makefile style fix 2026-07-28 11:34:30 +01:00
Xi Ruoyao 02ea17b5ad elf: test: handle different rootsbindir in tst-ldconfig-cache
When compiling a glibc for a merged-/usr distro people may set
rootsbindir=/usr/sbin.  But tst-ldconfig-cache has hard-coded
/sbin/ldconfig path and so it fails with a different rootsbindir.

Fix it by using support_install_rootsbindir like run_ldconfig in
test-container.c.

Signed-off-by: Xi Ruoyao <xry111@xry111.site>
Reviewed-by: Florian Weimer <fweimer@redhat.com>
2026-07-28 09:28:37 +02:00
Hammad Mengal 18b8719d1e localedata: Add brh_PK locale for Brahui language [BZ #33952]
Add locale data for Brahui (brh), a Dravidian language spoken by
approximately 2.8 million people (2023 Pakistan Census) primarily in
Balochistan, Pakistan.  Brahui is the only Dravidian language written
in the Perso-Arabic (Nastaliq) script.

The ISO 639-3 code brh is added to iso-639.def.  Brahui has no ISO
639-1 or ISO 639-2 code, so the three-letter code is used for both the
terminology and bibliographic fields, as is already done for other
639-3-only entries such as brx (Bodo).

Locale content follows CLDR locale brh, for which the submitter is the
contributing native speaker.

Changes since v3:
  - iso-639.def: place Brahui before Braj, restoring alphabetical
    order by English language name.
  - LC_TIME: add first_weekday 1 and first_workday 2.  The previous
    value of 7 selected Saturday, which does not match CLDR territory
    data for PK (firstDay = sun); ur_PK and sd_PK both use 1.
  - LC_TIME: reorder d_t_fmt and date_fmt so the date precedes the
    time, matching the CLDR brh date-time combination pattern and the
    shape used by sd_PK, and use U+060C ARABIC COMMA as the separator,
    which is the comma in the CLDR brh punctuation exemplar set.
  - LC_TIME: abday repeats the full day names, as Brahui has no
    distinct abbreviated forms; CLDR brh gives identical values at the
    abbreviated and wide widths, and ur_PK, pa_PK and fa_IR do the
    same.
  - LC_TIME: am_pm now matches the CLDR brh day-period values.
  - LC_MONETARY: n_sep_by_space 1, matching p_sep_by_space, so that
    positive and negative amounts are spaced alike.
  - LC_MESSAGES: yesexpr accepts U+062C and U+0647, and noexpr accepts
    U+0627, since these initials occur in attested spellings of the
    affirmative and negative words.
  - LC_CTYPE: add transliterations for U+06C1 and U+06B7.
  - LC_TELEPHONE: use the "+%c %a %l" form.
  - LC_IDENTIFICATION: record CLDR as the source; bump revision.

Signed-off-by: Hammad Mengal <hammadalo99@gmail.com>

Reviewed-by: Mike FABIAN <mfabian@redhat.com>
2026-07-28 09:00:36 +02:00
Adhemerval Zanella fdc90dbb52 math: Fix sinh worst-case results for |x| > 36.736801 [BZ 34441]
The CORE-MATH import mistranslated the accurate path result scaling
'th *= sp.f' as 'th *= asuint64 (sp)' (commit 106f8c2ed6), and two of
the 51 exceptional-case table entries were dropped when the table was
moved to e_sinh_data.c (commit f05c4907a2).

Checked on x86_64-linux-gnu and aarch64-linux-gnu.
2026-07-27 14:13:51 -03:00
Wilco Dijkstra 17a90edfe5 AArch64: Add ifunc masking tunable
Remove the glibc.cpu.name tunable since it's unused and out of date.
Add support for glibc.cpu.hwcaps to adjust ifunc selection for debugging
and benchmarking.  Only allow disabling of features that are (a) used by
ifuncs, (b) safe to disable to a more generic ifunc without any security
impact.

Reviewed-by: Yury Khrustalev <yury.khrustalev@arm.com>
2026-07-27 13:24:35 +00:00
Samuel Thibault 29dadb8eee hurd: fix fork's longjmp demangling on i386
i386's setjmp does not actually mangle ebp.
2026-07-27 00:59:36 +02:00
Samuel Thibault 0674869ee8 hurd: Make the readlink __fstatat64 references optional
They may show up or not depending on the toolchain in use.
2026-07-25 02:40:39 +02:00
Andreas K. Hüttel dc884378d7 NEWS: add 2.45 section
Signed-off-by: Andreas K. Hüttel <dilfridge@gentoo.org>
2026-07-25 09:12:28 +09:00
Andreas K. Hüttel 84df13f8eb version.h: bump to 2.44.9000 / development
Signed-off-by: Andreas K. Hüttel <dilfridge@gentoo.org>
2026-07-25 09:10:58 +09:00
Andreas K. Hüttel c3a3a9808a ChangeLog.old/ChangeLog.33: add
Signed-off-by: Andreas K. Hüttel <dilfridge@gentoo.org>
2026-07-24 22:16:45 +09:00
Andreas K. Hüttel 50245c56a6 version.h, include/features.h: Increase version number
Signed-off-by: Andreas K. Hüttel <dilfridge@gentoo.org>
2026-07-24 22:10:57 +09:00
Andreas K. Hüttel bc92b40b15 NEWS: drop empty section
Signed-off-by: Andreas K. Hüttel <dilfridge@gentoo.org>
2026-07-24 21:53:17 +09:00
Andreas K. Hüttel 5961de5588 po: update (only line number changes)
Signed-off-by: Andreas K. Hüttel <dilfridge@gentoo.org>
2026-07-24 21:48:02 +09:00
Andreas K. Hüttel 12726491af libc.pot: regenerate
Signed-off-by: Andreas K. Hüttel <dilfridge@gentoo.org>
2026-07-24 21:12:27 +09:00
Samuel Thibault ffaa52a30e hurd: Make setitimer clear interval on value being 0
posix says value being 0 means disabling a timer, regardless of the
interval, so we should clear the interval in that case, so a further
setitimer call does not see a non-zero interval.
2026-07-22 22:26:20 +02:00
Samuel Thibault 015e8ef482 hurd: xfail more tests waiting for barrier setpshared support 2026-07-22 22:26:20 +02:00
Andreas K. Hüttel 0f731d92cd manual/install.texi, INSTALL: update version numbers
Signed-off-by: Andreas K. Hüttel <dilfridge@gentoo.org>
2026-07-22 00:29:10 +09:00
Florian Weimer e9996c743d resolv: Disable TCP servers in tst-resolv-res_init-failure
This avoids spurious xaccept errors on slow systems.  With this
change, the test still reproduces the original bug.

Reviewed-by: Carlos O'Donell <carlos@redhat.com>
2026-07-21 15:54:27 +02:00
Andreas K. Hüttel b9bd146ad1 NEWS: mention more recent developments
Signed-off-by: Andreas K. Hüttel <dilfridge@gentoo.org>
2026-07-21 22:48:35 +09:00
Yury Khrustalev 3f3229739e math: test: Fix unsupported check in test-narrowing-trap
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
2026-07-21 13:39:42 +01:00
Samuel Thibault a5aa0df24a hurd: demangle pointers on fork's longjmp
The thread state structure requires plain pointers, while the jmpbuf has
mangled pointers.

Fixes 78f1f0e39c
("Consolidate the C pointer guard and align the assembly
implementations")
2026-07-21 09:16:35 +02:00
Samuel Thibault 623279d52a hurd: Add __readlink and readlink to dl-sysdep.c
Fixes fcea66cd46
("Add system-wide tunables: Filters")
which adds calling it from rtld.
2026-07-21 09:16:35 +02:00
Samuel Thibault 0d61a81612 hurd: Add __fstatat64 to dl-sysdep.c
Fixes b9957a70b8
("Add system-wide tunables: cache ld.so.cache")
which adds calling it from rtld.
2026-07-21 09:16:35 +02:00
Florian Weimer 7ace114369 manual: Add stability warning regarding system-wide tunables
And mention system-wide tunables in NEWS.
Reviewed-by: Andreas K. Hüttel <dilfridge@gentoo.org>
2026-07-21 12:21:08 +09:00
Andreas K. Hüttel a36971bebe contrib.texi: update
Signed-off-by: Andreas K. Hüttel <dilfridge@gentoo.org>
2026-07-20 23:12:23 +09:00
Andreas K. Hüttel b2d4136341 NEWS: insert list of fixed bugs
Signed-off-by: Andreas K. Hüttel <dilfridge@gentoo.org>
2026-07-20 17:32:04 +09:00
Andreas K. Hüttel a8e580f6a0 NEWS: editorial changes
Signed-off-by: Andreas K. Hüttel <dilfridge@gentoo.org>
2026-07-20 14:24:35 +09:00
Adhemerval Zanella 6b29e74c73 math: Update tanh from CORE-MATH (revision cf237fa0)
Sync the double-precision tanh implementation with CORE-MATH revision
cf237fa0.

Checked on aarch64-linux-gnu.
2026-07-18 09:36:58 -03:00
Peter Bergner 249639137e Revert "malloc: Remove dynamic mmap/trim threshold [BZ #30769]"
This change causes large degradations on multiple SPEC benchmarks,
so we have to revert this commit.

GLIBC BZ: https://sourceware.org/PR34394

This reverts commit 17a79a5120

Signed-off-by: Peter Bergner <bergner@tenstorrent.com>
Reviewed-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org>
2026-07-18 02:36:05 +08:00
Adhemerval Zanella a29c483d3c Add RWF_NOSIGNAL from Linux 6.18 to bits/uio-ext.h
It was added by commit db2ab24a341ce89351a1bede37a96a3e3ce1726a.

Reviewed-by: Carlos O'Donell <carlos@redaht.com>
2026-07-17 13:54:06 +00:00
Adhemerval Zanella 5c47592adb math: Fix inaccurate sin/cos/tan for large arguments (BZ 34376)
The Payne-Hanek range reducer __branred delivers the reduced argument
as a double-double with only about 93 significant bits.  For arguments
extremely close to a multiple of pi/2 the true reduced argument can be
as small as 2^-61, so most of those bits cancel and sin/cos/tan can be
wrong by up to ~143000 ulp.  This inaccuracy used to be handled by the
multiple-precision slow paths, which was removed by commit
649095838b ("sin/cos slow paths: remove slow paths from huge range
reduction") and commit 476d692e8a ("math: Remove slow paths in tan
[BZ #15267]").

Restore the e_rem_pio2.c (removed as unused by commit ca3aac57ef
"Remove unused math files") and use __ieee754_rem_pio2 for
the huge-argument reduction instead of __branred, which is removed.

It also does not depend on precise IEEE double rounding, so the nofma
and vector-width workarounds for branred.c are no longer needed.

The file is restored trimmed to its huge-argument path, the callers
reduce smaller arguments themselves and handle non-finite inputs, so
only 1e8 < |x| < 2^1024 reaches __ieee754_rem_pio2.

Checked on x86_64-linux-gnu, aarch64-linux-gnu, armv7a-linux-gnueabihf,
and i686-linux-gnu.

Reviewed-by: Carlos O'Donell <carlos@redhat.com>
2026-07-17 13:52:58 +00:00
Adhemerval Zanella 70685abb80 benchtests: Add path-oriented workloads to tan
The tan input list spans the full binary64 range, so a single number mixes
the kernel, and the i__branred reductions in one average.  Add two named
workloads that isolate the ends of that spread, so each can be measured
separately:

  - workload-fast.wrf: uniform random inputs in [-pi, pi].

  - workload-slow.wrf: |x| in [2^27, 2^1024), log-uniform over binades.

The existing full-range inputs are replaced as the default workload.

Reviewed-by: Carlos O'Donell <carlos@redhat.com>
2026-07-17 12:55:24 +00:00
Adhemerval Zanella 18f97e140d benchtests: Add path-oriented workloads to sin
The sin input list spans the full binary64 range, so a single number mixes
the kernel, the reduce_sincos reduction , and the __branred reduction in
one average.  Add three named workloads that isolate the paths __cos
actually dispatches to, so each can be measured separately:

  - workload-fast.wrf: uniform random inputs in [-pi, pi].

  - workload-moderate.wrf: |x| in [4, 6.7e7], log-uniform over binades.

  - workload-slow.wrf: |x| in [2^27, 2^1024), log-uniform over binades.

The existing full-range inputs are replaced as the default workload.

Reviewed-by: Carlos O'Donell <carlos@redaht.com>
2026-07-17 12:55:18 +00:00
Adhemerval Zanella 49d25edb76 benchtests: Add path-oriented workloads to cos
The cos input list spans the full binary64 range, so a single number mixes
the kernel, the reduce_sincos reduction , and the __branred reduction in one
average.  Add three named workloads that isolate the paths __cos actually
dispatches to, so each can be measured separately:

  - workload-fast.wrf: uniform random inputs in [0, 2*pi].

  - workload-moderate.wrf: |x| in [4, 6.7e7], log-uniform over binades.

  - workload-slow.wrf: |x| in [2^27, 2^1024), log-uniform over binades.

The existing full-range inputs are replaced as the default workload.

Reviewed-by: Carlos O'Donell <carlos@redhat.com>
2026-07-17 12:55:05 +00:00
Adhemerval Zanella 2678adc8eb sparc: Align THP tests to the 8MB huge-page size
The sparc64 uses an 8KB base page and 8MB PMD transparent huge page.
It fixes the following regression on sparc:

FAIL: elf/tst-thp-1
FAIL: elf/tst-thp-1-no-s-code
FAIL: elf/tst-thp-1-no-s-code-pde
FAIL: elf/tst-thp-1-no-s-code-static
FAIL: elf/tst-thp-1-pde
FAIL: elf/tst-thp-1-static
FAIL: elf/tst-thp-align

Checked with the elf tests on qemu sparc64.

Tested-by: Andreas K. Hüttel <dilfridge@gentoo.org>
2026-07-16 16:09:34 -03:00
Adhemerval Zanella 82a0bf8d33 elf: Defer arch PLT IFUNC relocations in the two-phase relocation split
The split introduced by commit 63b31c05a8 does not handle sparc
and (R_SPARC_JMP_IREL) powerpc64 (ELFv1, R_PPC64_JMP_IREL), which
are emited in some constructions.  Handle such cases on
elf_dynamic_is_Rel_irelative.

It fixes elf/tst-ifunc-fault-bindnow and elf/tst-ifunc-fault-lazy on
sparc64 (powerpc64 emits R_PPC64_IRELATIVE in both cases,
R_PPC64_JMP_IREL is emitted only when the ifunc is called, not just
referenced).

Checked with the elf tests on qemu sparc64 and powerpc64.

Tested-by: Andreas K. Hüttel <dilfridge@gentoo.org>
2026-07-16 16:09:31 -03:00
Adhemerval Zanella c82b609596 sparc: Fix static IFUNC startup crash by redirecting __mempcpy (BZ #34396)
After commit b75ad99d45, __libc_setup_tls -> _dl_allocate_tls_init copies
the TLS init image with the IFUNC __mempcpy before ARCH_SETUP_IREL resolves
it, so on a multi-arch sparcv9/sparc64 static build the call jumps through an
unrelocated PLT slot and the process dies with SIGILL.

The sparc dl-symbol-redir-ifunc.h only redirected memset.  Redirect
memcpy, memmove, mempcpy and __mempcpy to the ultra1 routines as well,
and merge the identical sparc64 and sparc32/sparcv9 copies into a single
sysdeps/sparc file.  The redirection is guarded by __sparc_v9__ &&
USE_MULTIARCH so that sparcv8 (leon) and --disable-multi-arch builds,
which have no __*_ultra1 routines, are left untouched.

Checked with elf tests for sparc32 and sparc64 on qemu system.

Tested-by: Andreas K. Hüttel <dilfridge@gentoo.org>
2026-07-16 16:09:27 -03:00
H.J. Lu af51ed63d0 Revert "strace-tst-thp.sh: Allow unsupported THP tests"
This reverts commit ea50bcc538.
2026-07-16 06:15:44 +08:00
H.J. Lu ea50bcc538 strace-tst-thp.sh: Allow unsupported THP tests
Change strace-tst-thp.sh to

output=${test_prog}.$$
...
/bin/sh -c \
  "timeout -k 4 $((3*$TIMEOUTFACTOR)) ${cmd} --direct 2>&1" > "${output}"
if grep -E "madvise\(0x[0-9a-f]+, [0-9]+, 0xe)" "${output}"; then
...

so that unsupported THP tests exit with status 77.

Signed-off-by: H.J. Lu <hjl.tools@gmail.com>
Reviewed-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org>
2026-07-15 19:27:16 +08:00
H.J. Lu e03cefb56b thp: Disable THP if THP isn't supported by kernel
Since DL_MAP_DEFAULT_THP_PAGESIZE is defined for x86-64, THP control
is to set to madvise by default.  If THP is disabled in x86-64 kernel,
madvise (..., MADV_HUGEPAGE) returns -EINVAL to indicate that THP isn't
supported.  Add _dl_thp_madvise to disable THP in this case.  This
fixes BZ #34348.

Signed-off-by: H.J. Lu <hjl.tools@gmail.com>
Reviewed-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org>
2026-07-15 19:25:18 +08:00
H.J. Lu 81ae821113 thp: Link THP PDE tests with $(LOAD-THP-ADDRESS-LDFLAGS)
LOAD-THP-ADDRESS-LDFLAGS was added to work around:

https://sourceware.org/bugzilla/show_bug.cgi?id=34184

which is needed for THP PDE tests.  Add $(LOAD-THP-ADDRESS-LDFLAGS) to
LDFLAGS-tst-thp-1 and LDFLAGS-tst-thp-1-no-s-code if PIE isn't built
by default so that they are linked with $(LOAD-THP-ADDRESS-LDFLAGS).
This fixes BZ #34314.

Signed-off-by: H.J. Lu <hjl.tools@gmail.com>
2026-07-15 19:20:22 +08:00
Adhemerval Zanella cdfa80fad3 Add advisory text for CVE-2026-6368 2026-07-14 15:36:00 -03:00
Adhemerval Zanella e2cefe16c3 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>
2026-07-14 15:36:00 -03:00
DJ DelorieandAdhemerval Zanella Netto 2324aa7aa8 ldconfig: add --install option
Add --install option, which copies a pre-built ld.so.cache into place,
honoring the cache and root options and defaults.  This gives the user
a canonical "correct" way to install a pre-built cache without risk
of a program trying to load a partially-written file.

Co-authored-by: Adhemerval Zanella Netto <adhemerval.zanella@linaro.org>
Reviewed-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org>
2026-07-14 14:20:55 -04:00
Andreas K. Hüttel 69b0bacd72 po: Integrate translations
Signed-off-by: Andreas K. Hüttel <dilfridge@gentoo.org>
2026-07-14 22:04:19 +09:00
Stefan Liebler a3d4ff18c5 s390: Use 64bit branch relative on count instruction in strncpy-z900.S [BZ #34398]
At the time the s390-32 strncpy implementation was adjusted for the
s390-64 port, the brct (branch relative on count) instruction was
not adjusted from 32bit to 64bit instruction.

If n contains a value >32bit, the number of 8 byte chunks is computed
with srlg (64bit shift right). The processing of 8 byte chunks is then
processed by looping with brct (32bit branch relative on count) instruction.

This patch just uses the brctg (64bit branch relative on count) instruciton.

Note 1: There is a second loop copying the remaining seven bytes.  The usage
of 32bit brct for looping is fine here.

Note 2: If glibc is build with architecture level set >=z13, the z900 variant
of strncpy is not build at all.

Note 3: If glibc is build for <z13, the z900 ifunc variant is only chosen if
not run on >=z13 or if called via __GI_strncpy.
2026-07-14 14:39:21 +02:00
Stefan Liebler 202b4f794a Use correct type for glibc.malloc.perturb in tst-tunconf1.c
On s390x the test elf/tunconf1 fails with:
tst-tunconf1.c:41: numeric comparison failure (widths 64 and 32)
   left: 180388626436 (0x2a00000004); from: (long)perturb
  right: 42 (0x2a); from: 42

According to elf/dl-tunables.list, glibc.malloc.perturb is of type int32_t (4byte)
and not size_t (8byte) which was used for TUNABLE_GET_FULL inside the testcase.
Therefore the correct 32bit value 0x2a=42 is written to the to the wrong place
and leads to the comparison failure.

The printf format specifiers for size_t were also adjusted.
Reviewed-by: DJ Delorie <dj@redhat.com>
2026-07-14 09:59:39 +02:00
Adhemerval Zanella aafc0024b3 benchtests: Build benchmarks in parallel
The unconditional '.NOTPARALLEL' in benchtests/Makefile forced the whole
subdirectory to build serially, even though its only purpose is to keep
the benchmark *runs* from perturbing each other's timing.

Replace it with ordering that serializes only the benchmark runs, and
only when more than one benchmark group will actually run.  The combined
'bench' goal builds every benchmark program in parallel (through
bench-build) and then runs the bench-set, bench-func and bench-malloc
groups strictly one after another.

Reviewed-by: Sam James <sam@gentoo.org>
2026-07-13 13:52:07 -03:00
Adhemerval Zanella b8985facc9 sparc: Fix static (non-PIE) executables when PIE is enabled by default
For the default --enable-default-pie, $(pic-default) adds -DPIC to
CPPFLAGS-.o so.  However, -fPIE ($(pie-default)) is only added to
CFLAGS-.o, which does not affect assembler (.S) sources

On SPARC the GOT register setup in SETUP_PIC_REG references
_GLOBAL_OFFSET_TABLE_ through %hi/%lo, and the assembler only rewrite
those into the required PC-relative relocations (R_SPARC_PC22 and
R_SPARC_PC10) when it is in *PIC* mode; otherwise it emits absolute
R_SPARC_HI22/R_SPARC_LO10.  With the absolute relocations the
__sparc_get_pc_thunk sequence adds the run-time PC to an already-absolute
GOT address, so the computed GOT register is wrong.  In _start this makes
the address of main come out bogus, and __libc_start_main jumps to an
unmapped address.

This removes the requirement of the --disable-default-pie for sparc
to build static binaries correctly.

Checked some tests (mainly the elf/ one) on a sparc64-linux-gnu
qemu system.

Reviewed-by: Sam James <sam@gentoo.org>
2026-07-13 13:52:07 -03:00
Adhemerval Zanella 1c0531af67 elf: Remove unused tunable_seclevel_t
The per-tunable security level is no longer part of struct _tunable and
no tunable in dl-tunables.list declares one.

Reviewed-by: DJ Delorie <dj@redhat.com>
2026-07-13 13:52:07 -03:00
Adhemerval Zanella 098e6c969c elf: Remove _dl_unload_cache
It is a no-op since b9957a70b8.

Reviewed-by: DJ Delorie <dj@redhat.com>
2026-07-13 13:52:07 -03:00
Adhemerval Zanella 3a9c4dbe30 manual: Document default AT_SECURE handling for system-wide tunables
A system-wide tunable without an onlysecure/nonsecure/anysecure prefix
defaults to "nonsecure", i.e. it is not applied to AT_SECURE processes.
This is a deliberate, conservative default but was not documented.

Reviewed-by: DJ Delorie <dj@redhat.com>
2026-07-13 13:52:07 -03:00
Adhemerval Zanella 93d68cfbeb elf: Let environment aliases override overridable system-wide tunables
The environment-variable alias loop in __tunables_init skipped every tunable
whose "initialized" flag was set, which was originally meant only to give
the canonical GLIBC_TUNABLES form precedence over the legacy MALLOC_*
aliases.

Now that the cache also sets "initialized", a legacy alias could no longer
override an *overridable* cache default, even though the canonical
GLIBC_TUNABLES form still could.

Track separately the tunables that were set from GLIBC_TUNABLES during this
call and skip only those in the alias loop

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

Reviewed-by: DJ Delorie <dj@redhat.com>
2026-07-13 13:51:57 -03:00
Adhemerval Zanella f1c94392d9 elf: Avoid redundant ld.so.cache reload after first load
_dl_check_ldsocache_needs_loading only stored the stat fields it
compares (mtime, ino, size, dev) on the path where a cache was already
loaded.  On the very first call CACHE is NULL and the function returned
"needs loading" without recording those fields, leaving
new_cache_file_time zero.  The next call then copied that zero value
into cache_file_time and compared it against the freshly stat'd values,
which always differed, forcing a second, unnecessary load (munmap +
mmap + re-parse) of an unchanged cache at every startup.

It can be shown with repro:

  $ cat << EOF > repro.c
  #include <dlfcn.h>
  int main (void) { dlopen ("does-not-exist-xyz.so.99", RTLD_NOW); return 0; }
  EOF
  $ gcc repro.c -o repro
  $ strace -f -e trace=openat elf/ld.so --library-path . ./repro 2>&1 | grep -c "/etc/ld.so.cache"

The result should be 1, instead of 2.

Record the stat fields as soon as the stat succeeds, before the
CACHE == NULL early return, so the following call has an accurate
baseline and does not spuriously reload.

Reviewed-by: DJ Delorie <dj@redhat.com>
2026-07-13 11:36:47 -03:00
Adhemerval Zanella 4e971f5558 elf: Verify the tunable cache header signature and version
The tunable header signature and version are written by ldconfig but
never checked them on read, so the version field was inert.  Reject
the section unless both match.

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

Reviewed-by: DJ Delorie <dj@redhat.com>
2026-07-13 11:36:24 -03:00
Adhemerval Zanella 3d3cd10c4e elf: Bound the tunable cache string table against the mapping size
_dl_load_cache_tunables bounds each entry's string offsets against
[s_start, start + cache_new->len_strings], but len_strings is an
unvalidated 32-bit field from ld.so.cache and s_start/s_end were int.  A
corrupt cache with an oversized len_strings could make s_end exceed the
mapping (or overflow), letting an offset point outside the mmap; the
following strcmp/__strdup would then read unmapped memory.

Compute the offsets as size_t and clamp s_end to cachesize, matching how
the regular library lookup bounds string offsets against the mapping size.

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

Reviewed-by: DJ Delorie <dj@redhat.com>
2026-07-13 11:26:31 -03:00
Siddhesh Poyarekar 5396eb7045 localedata: Use libc-alpha ML as the canonical contact
Replace instances of "bug-glibc@gnu.org", "libc-locales@sourceware.org"
and "bug-glibc-locales@gnu.org" with libc-alpha@sourceware.org as the
single touchpoint for the community.

Signed-off-by: Siddhesh Poyarekar <siddhesh@gotplt.org>
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
2026-07-10 16:30:45 -04:00
Florian Weimer 980089ebab posix: Use unique PID file in tst-spawn3 and tst-spawn3-pidfd
The test sources are built twice and the two tests may run in parallel.
They cannot use the same PID file.

Reviewed-by: Sam James <sam@gentoo.org>
2026-07-09 17:22:42 +02:00
Florian Weimer 20b13fa08b localedata: Avoid concurrently written locales in gen-locale.sh
There is no cross-directory exclusion of concurrent $(gen-locales)
usage.  Parallel localedef calls can clobber locale data as it is
being loaded by tests.

With the separate staging areas, there are no peer directories,
so hard-linking no longer happens.  The touch command is therefore
unnecessary.

Reviewed-by: Sam James <sam@gentoo.org>
2026-07-09 10:34:10 +02:00
DJ Delorie 617376a04b Add system-wide tunables: implement overridability
Implement the overridability/nonoverridability flags
for tunables.

Reviewed-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org>
2026-07-08 18:18:26 -04:00
Andreas K. Hüttel b5eecf35d9 libc.pot: regenerate
Signed-off-by: Andreas K. Hüttel <dilfridge@gentoo.org>
2026-07-07 10:39:18 +09:00
Yury Khrustalev d70dd7d722 Revert "malloc: aarch64: Add ifuncs for malloc functions"
Due to issue in GDB and Valgrind that incorrectly call malloc
ifunc resolver as the malloc function, we have to revert this
change.

GDB BZ: https://sourceware.org/bugzilla/show_bug.cgi?id=34330
Valgrind bug: https://bugs.kde.org/show_bug.cgi?id=522497

This reverts commit 9ed3576e61.

Reviewed-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org>
2026-07-06 16:33:43 +01:00
Adhemerval Zanella b416f91801 netinet/tcp.h: Sync with Linux 6.15 and fix struct tcp_info tail (BZ 34347)
Add the TCP_RTO_MAX_MS and TCP_RTO_MIN_US socket options (commit
54a378f43425085d0684679d99735696b69165bc, Linux 6.15) and TCP_DELACK_MAX_US
(commit 9552f90835ef3552d0af327e48dc360717777d62, Linux 6.15).

Commit 7e46c2aae4 synced the accurate ECN
additions but encoded the trailing bitfield word of struct tcp_info
incorrectly as two uint16_t fields (tcpi_accecn_fail_mode and
tcpi_accecn_opt_seen), omitting tcpi_ecn_mode and tcpi_options2.  Restore
the kernel layout:

  uint32_t tcpi_ecn_mode:2,
	   tcpi_accecn_opt_seen:2,
	   tcpi_accecn_fail_mode:4,
	   tcpi_options2:24;

The overall structure size is unchanged.  Also add the TCPI_ECN_MODE_*
and TCP_ACCECN_* value constants for these fields, introduced together
with them by Linux commit 4fa4ac5e5848 (Linux 7.0).

Reviewed-by: Florian Weimer <fweimer@redhat.com>
2026-07-06 10:50:50 -03:00
Adhemerval Zanella 3e3146fd86 Add OPEN_TREE_NAMESPACE and FSMOUNT_NAMESPACE to sys/mount.h
Add OPEN_TREE_NAMESPACE (commit 9b8a0ba68246a61d903ce62c35c303b1501df28b,
Linux 7.0) and FSMOUNT_NAMESPACE (commit
5e8969bd192712419aae511dd5ba26855c2c78db, Linux 7.1).
2026-07-06 10:47:38 -03:00
Adhemerval Zanella 28c3a25bc2 s390: Prevent hoisting the thread-pointer read in THREAD_SET_STACK_GUARD (BZ 34297)
THREAD_SET_STACK_GUARD reads the thread pointer via THREAD_SELF
(__builtin_thread_pointer), which the compiler treats as invariant.  In the
static startup path the thread pointer is installed by the __libc_setup_tls
call that immediately precedes the guard store, so the read must stay below
it.  The existing barrier only clobbered the access registers a0/a1, which
creates no dependency on the call, so the compiler could move the whole
barrier and read above __libc_setup_tls.

This is sensitive to instruction scheduling and recent TLS startup
changes exposed it on s390x.

Add a "memory" clobber to the barrier so it is tied to the call's memory
effects and cannot be hoisted above it.  The macro is shared with the
dynamic loader, so both startup paths are covered.

I checked on s390x-linux-gnu build for arch5, arch8, arch9, and arch11
by running the elf tests on qemu system (kernel 6.1.0).

Reviewed-by: Stefan Liebler <stli@linux.ibm.com>
2026-07-06 10:47:30 -03:00
Adhemerval Zanella 1d95a42ead Add new AArch64 HWCAP definitions from Linux 6.14, 6.18 and 7.0 to bits/hwcap.h
Add the 2024 dpISA HWCAP bits HWCAP_CMPBR, HWCAP_FPRCVT, HWCAP_F8MM8,
HWCAP_F8MM4, HWCAP_SVE_F16MM, HWCAP_SVE_ELTPERM, HWCAP_SVE_AES2,
HWCAP_SVE_BFSCALE, HWCAP_SVE2P2, HWCAP_SME2P2, HWCAP_SME_SBITPERM,
HWCAP_SME_AES, HWCAP_SME_SFEXPA, HWCAP_SME_STMOP and HWCAP_SME_SMOP4
(commit 819935464cb2f72fff8dfbbf95cf2726d4a66388, Linux 6.14), HWCAP3_LSFE
(commit 220928e52cb03d223b3acad3888baf0687486d21, Linux 6.18) and
HWCAP3_LS64 (commit 58ce78667a641f93afa0c152c700a1673383d323, Linux 7.0).

Reviewed-by: Wilco Dijkstra  <Wilco.Dijkstra@arm.com>
2026-07-06 10:47:06 -03:00
H.J. Lu 0f61d77aef Makefile: Depend on elf/subdir_lib only if $(subdirs) has elf
commit 7cac99621e
Author: Adhemerval Zanella <adhemerval.zanella@linaro.org>
Date:   Wed Jun 10 16:26:15 2026 -0300

    Makefile: Run the subdirectory recursion in parallel

added:

$(elf-objpfx)ld.so $(elf-objpfx)sofini.os $(elf-objpfx)interp.os: \
  | elf/subdir_lib ;

which doesn't work with

$ make check -jN subdirs=DIR

where DIR doesn't have elf.  Add such rule only if $(subdirs) has elf.
This fixes BZ #34355.

Signed-off-by: H.J. Lu <hjl.tools@gmail.com>
2026-07-06 16:28:12 +08:00
Andreas Schwab db59f39646 sysdeps/x86: don't spuriously mark tests as xfail
Properly set xfail marker, $(with-lld) is always non-empty.
2026-07-06 09:36:06 +02:00
59cb960a22 riscv: Add RVV strncpy for both multiarch and non-multiarch builds
This patch adds an RVV-optimized implementation of strncpy for RISC-V and
enables it for both multiarch (IFUNC) and non-multiarch builds.

The implementation integrates Hau Hsu's 2023 RVV work under a unified
ifunc-based framework. A vectorized version (__strncpy_vector) is added
alongside the generic fallback (__strncpy_generic). The runtime resolver
selects the RVV variant when RISCV_HWPROBE_KEY_IMA_EXT_0 reports vector
support (RVV).

Currently, the resolver still selects the RVV variant even when the RVV
extension is disabled via prctl(). As a consequence, any process that
has RVV disabled via prctl() will receive SIGILL when calling strncpy().

Co-authored-by: Hau Hsu <hau.hsu@sifive.com>
Co-authored-by: Jerry Shih <jerry.shih@sifive.com>
Signed-off-by: Yao Zihong <zihong.plct@isrc.iscas.ac.cn>
Reviewed-by: Peter Bergner <bergner@tenstorrent.com>
2026-07-05 13:36:37 +00:00
df0669d41d riscv: Add RVV stpncpy for both multiarch and non-multiarch builds
This patch adds an RVV-optimized implementation of stpncpy for RISC-V and
enables it for both multiarch (IFUNC) and non-multiarch builds.

The implementation integrates Hau Hsu's 2023 RVV work under a unified
ifunc-based framework. A vectorized version (__stpncpy_vector) is added
alongside the generic fallback (__stpncpy_generic). The runtime resolver
selects the RVV variant when RISCV_HWPROBE_KEY_IMA_EXT_0 reports vector
support (RVV).

Currently, the resolver still selects the RVV variant even when the RVV
extension is disabled via prctl(). As a consequence, any process that
has RVV disabled via prctl() will receive SIGILL when calling stpncpy().

Co-authored-by: Hau Hsu <hau.hsu@sifive.com>
Co-authored-by: Jerry Shih <jerry.shih@sifive.com>
Signed-off-by: Yao Zihong <zihong.plct@isrc.iscas.ac.cn>
Reviewed-by: Peter Bergner <bergner@tenstorrent.com>
2026-07-05 13:36:37 +00:00
H.J. Lu d692a3444e Add tst-thp-size-mod.so dependency to strace THP tests
After

7cac99621e Makefile: Run the subdirectory recursion in parallel

tests under elf may run in parallel. "make check -jN" reports

FAIL: elf/strace-tst-thp-align-default
FAIL: elf/strace-tst-thp-align-disabled
FAIL: elf/strace-tst-thp-align-enabled

at random since they use tst-thp-align which dlopens tst-thp-size-mod.so,
but tst-thp-size-mod.so dependency is missing.  Add the missing dependency
to fix BZ #34351.

Signed-off-by: H.J. Lu <hjl.tools@gmail.com>
2026-07-05 19:10:24 +08:00
Adhemerval Zanella d109f366ce build-many-glibcs.py: Update Linux kernel version to 7.1
Use the 7.1 release as the default Linux kernel version for building test
compilers and headers.

Reviewed-by: Florian Weimer <fweimer@redhat.com>
2026-07-03 16:32:00 -03:00
Adhemerval Zanella c6ce3bed6d Update kernel version to 7.1 in header constant tests
There are no new constants covered by tst-mman-consts.py or
tst-openat2-consts.py in Linux 6.18, 6.19, 7.0, or 7.1.

Reviewed-by: Florian Weimer <fweimer@redhat.com>
2026-07-03 16:31:58 -03:00
Adhemerval Zanella 800ab3e463 Update syscall lists for Linux 7.1
Linux 6.18 adds the uprobe syscall (x86_64 only), Linux 6.19 adds listns,
and Linux 7.0 adds rseq_slice_yield.  Linux 7.0 also wires up clone3 on
sparc and memfd_secret on loongarch.  Update syscall-names.list and
regenerate the arch-syscall.h headers with build-many-glibcs.py
update-syscalls.

Reviewed-by: Florian Weimer <fweimer@redhat.com>
2026-07-03 16:31:55 -03:00
Adhemerval Zanella 568e673fa9 Add NT_RISCV_USER_CFI from Linux 7.0 to elf.h
It was added by commit 2af7c9cf021c5dabe880b68e5cc22c618060d954.

Reviewed-by: Florian Weimer <fweimer@redhat.com>
2026-07-03 16:31:54 -03:00
Adhemerval Zanella 6f1d069804 Add IPPROTO_AGGFRAG from Linux 6.14 to netinet/in.h (BZ 34347)
It was added by commit 64e844505bc08cde3f346f193cbbbab0096fef54.

Reviewed-by: Florian Weimer <fweimer@redhat.com>
2026-07-03 16:31:52 -03:00
Adhemerval Zanella b4a0ea4a2c Add SCHED_GETATTR_FLAG_DL_DYNAMIC from Linux 7.1 to bits/sched.h
It was added by commit 2e7af192697ef2a71c76fd57860b0fcd02754e14, which
introduced the flags argument for sched_getattr.

Reviewed-by: Florian Weimer <fweimer@redhat.com>
2026-07-03 16:31:50 -03:00
Adhemerval Zanella b9476fa9aa Update PIDFD_* constants for Linux 7.1
The pidfd_info interface was extended to report coredump information:

  * PIDFD_INFO_SUPPORTED_MASK, along with the supported_mask field, so
    userspace can check which flags the running kernel supports (commit
    dfd78546c95330db2252e0d7e937a15ab5eddb4e, Linux 6.19).

  * PIDFD_INFO_COREDUMP_SIGNAL, along with the coredump_signal field
    (commit 036375522be8425874e9e0f907c7127e315c7a52, Linux 6.19).

  * PIDFD_INFO_COREDUMP_CODE, along with the coredump_code field (commit
    701f7f4fbabbf4989ba6fbf033b160dd943221d5, Linux 7.1).

The struct pidfd_info is extended accordingly and PIDFD_INFO_SIZE_VER1,
PIDFD_INFO_SIZE_VER2, and PIDFD_INFO_SIZE_VER3 are added to reflect the
new struct sizes.

Reviewed-by: Florian Weimer <fweimer@redhat.com>
2026-07-03 16:31:48 -03:00
Adhemerval Zanella 5bba5e06e0 Add new LoongArch HWCAP definitions from Linux 7.0 and 7.1 to bits/hwcap.h
Add HWCAP_LOONGARCH_SCQ (commit 48543c4283e76d561d11b9955222b1a3054abdb9,
Linux 7.0) and HWCAP_LOONGARCH_LAM_BH (commit
1dd3e8a8eeb4059fb34b07578362380cf35b7ed5, Linux 7.1).

Reviewed-by: Florian Weimer <fweimer@redhat.com>
2026-07-03 16:31:43 -03:00
Adhemerval Zanella f2e3dacbff Add new constants from Linux 6.12, 6.18 and 6.19 to bits/fcntl-linux.h
Add the FD_NSFS_ROOT (commit e83f0b5d10dcf62833008327cb661c7d118bca85,
Linux 6.18), and F_GETDELEG and F_SETDELEG (commit
1602bad16d7df82faca6d7c70821117684a66f49, Linux 6.19).

Reviewed-by: Florian Weimer <fweimer@redhat.com>
2026-07-03 16:31:41 -03:00
RyotaSaito 2077c0e385 x86: Remove unused VZEROUPPER_SHORT_RETURN macro from memset
The VZEROUPPER_SHORT_RETURN macro in memset-vec-unaligned-erms.S has had
no users since commit e59ced2384 ("x86: Optimize
memset-vec-unaligned-erms.S") removed its last invocation, leaving both
the VEC_SIZE > 16 definition and the "rep; ret" fallback definition in
place.  Remove the two now-dead definitions.

Signed-off-by: RyotaSaito <saito.ryota.23@shizuoka.ac.jp>
Reviewed-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org>
2026-07-03 14:55:54 -03:00
Samuel Balazi 70dd422b6f string: Fix memory leak in argz-addsep.c
Assign the realloc result to a temporary variable, so the original
memory block is not lost if the allocation fails.

Reviewed-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org>
2026-07-03 14:55:43 -03:00
Adhemerval Zanella 1ab0003872 Makerules: run test-container helper through the built loader
The tests-container rule launches support/test-container, which is always
dynamically linked, through $(test-via-rtld-prefix).  That prefix is empty
for tests listed in tests-static/xtests-static, so for a static container
test the helper ran under the system loader/libc instead of the newly
built one.

Reviewed-by: Florian Weimer <fweimer@redhat.com>
2026-07-03 14:07:58 -03:00
Adhemerval Zanella 2b13da5e0e Makerules: add 'make check-parallel' to run tests without serialization
The default 'make check' serializes the timing-sensitive test runs: the
threading (nptl, or htl on Hurd) and realtime (rt) subdirectories run
with .NOTPARALLEL and are ordered after the rest of the test run, so they
are not perturbed by competing machine load.

Add a check-parallel (and xcheck-parallel) variant for when that is not
wanted -- an idle machine, or a run where the extra throughput is worth
the risk of flakiness in the timing-sensitive tests (check the
libc-alpha discussion [1] for more context why this approach was proposed).

A new serialize-tests flag (default yes, defined in Makeconfig) gates both
the per-subdirectory .NOTPARALLEL and the top-level run-time ordering;
check-parallel just runs the suite with serialize-tests=no, so every test
program builds and runs at full concurrency in a single pass.

'make check' and its default behavior are unchanged.

[1] https://inbox.sourceware.org/libc-alpha/lhutsr3khz7.fsf@oldenburg.str.redhat.com/

Reviewed-by: Sam James <sam@gentoo.org>
2026-07-03 13:01:13 -03:00
Adhemerval Zanella 19e158b7f0 Run check-installed-headers concurrently for each header
The check-installed-headers-c/-cxx tests ran one script invocation per
subdirectory over all of its installed headers, performing about 80
compiler invocations per header serially.

Give each header its own intermediate target so the compiler
invocations parallelize under the make jobserver, recording the
per-header script exit status next to the output.  The .out target
concatenates the per-header outputs in the original $(headers) order
and fails if any recorded status is non-zero, so both the .out contents
(verified byte-identical for all 76 files) and the tests.sum results
are unchanged.

Results on a x86_64 machine [1] from a make check with run-built-tests=no
show neutral results, and on aarch64 machine [2] it improves from 241.574s
to 182.405.

[1] Ryzen 5900x, 12c/24t, gcc 16.1.1, binutils 2.26, and GNU make 4.3
[2] N1, 80c, gcc 15.1.1, binutils 2.25, GNU make 4.3

Reviewed-by: Sam James <sam@gentoo.org>
2026-07-03 13:00:07 -03:00
Adhemerval Zanella b6804fb36e Makefile: Do not install the container testroot if not running tests
Every subdirectory tests target depends on
$(objpfx)testroot.pristine/install.stamp, whose recipe performs a full
DESTDIR installation (about 12s and 154MB on x86_64).  The testroot is
only consumed by the container tests, which do not run when
run-built-tests is no, so skip it entirely in that case.

This saves about 10s on x86_64 [1] and 30s on aarch64 [2].

[1] Ryzen 5900x, 12c/24t, gcc 16.1.1, binutils 2.26, and GNU make 4.3
[2] N1, 80c, gcc 15.1.1, binutils 2.25, GNU make 4.3

Reviewed-by: Sam James <sam@gentoo.org>
2026-07-03 12:48:32 -03:00
Adhemerval Zanella ef1cb97f69 Makefile: Do not force elf last for the others and tests passes
The requirement that the elf subdirectory comes last in the
subdirectory ordering stems from its lib pass: the rtld link consumes
$(common-objpfx)libc_pic.a, which aggregates every other
subdirectory's objects.

The others, tests, and xtests classes have no such dependency: everything
they consume from other subdirectories is provided by the pass barriers
(others after lib, tests after others).  Keep elf last only for the
object-building classes and let its others and tests sub-makes run
concurrently with the other subdirectories.

With elf no longer forced last for those classes, the Depend edges
pointing to elf (e.g. support/Depend) no longer create a cycle there,
so honor them instead of dropping them.

This improves the make check with run-built-tests=no, specially on
machine with many cores.  Results on a x86_64 machine [1] it improves
from 190s to 181s, while on a aarch64 machine [2] it improves from
298.726s to 243.098s.

Build results remain bit-identical and the tests.sum failure sets are
unchanged.

[1] Ryzen 5900x, 12c/24t, gcc 16.1.1, binutils 2.26, and GNU make 4.3
[2] N1, 80c, gcc 15.1.1, binutils 2.25, GNU make 4.3

Reviewed-by: Sam James <sam@gentoo.org>
2026-07-03 12:46:57 -03:00
Adhemerval Zanella 7cac99621e Makefile: Run the subdirectory recursion in parallel
The top-level makefile was marked .NOTPARALLEL and ran the
per-subdirectory sub-makes strictly one at a time in the topological
order computed by scripts/gen-sorted.awk.  Only the compilations inside
a single subdirectory could run in parallel, so on wide machines every
subdirectory's compile tail and link steps left most cores idle, once
per subdirectory per pass.

Drop .NOTPARALLEL and encode the ordering the serial recursion relied
on as explicit dependencies between the per-subdirectory targets:

  * The subdirectories that generate shared files in $(common-objpfx)
    consumed by the rest of the build without explicit dependencies run
    serially, in their sorted order, before the rest fan out: csu
    provides the tree-wide gen-as-const headers, and on Hurd the mach
    and hurd directories generate the MiG RPC headers (every other
    subdirectory otherwise runs a nested make in hurd/ to create them,
    racing under parallel recursion; see sysdeps/mach/hurd/Makefile).
    The first of them also materializes the other shared generated files
    (abi-versions.h, sysd-syscalls, before-compile headers).

  * The edges requested by the Depend files (now emitted by
    gen-sorted.awk as subdir-deps-*) are preserved.  Edges pointing to
    elf are dropped, as the sorted list already overrides them by
    forcing elf last.

  * The tests and xtests classes only run the per-directory test
    programs, which are mutually independent once the others pass has
    built the tree.  They therefore carry only the others pass barrier
    below and none of the csu-first or Depend edges (+ordered_parallel_-
    subdir_targets excludes them); otherwise "make subdir/tests" would
    also run the tests of every subdirectory reachable through those
    edges, rather than just the requested one.

  * elf stays last: its rtld link consumes $(common-objpfx)libc_pic.a,
    which aggregates every other subdirectory's objects, and its
    rtld-Rules recursion compiles into the other subdirectories' object
    directories.

  * Pass barriers replace the implicit pass ordering: others after lib
    (a subdirectory others sub-make would otherwise race to link
    libc.so itself), tests/xtests after others, and the testroot
    install behind others.

  * The threading (nptl, or htl on Hurd) and realtime (rt) tests are
    timing-sensitive and were previously shielded from system load by
    the global .NOTPARALLEL.  With the recursion now parallel, a full
    test run ('make check'/'tests', run-built-tests=yes) orders them
    after the rest of the test run and one group at a time -- the
    threading subdirectory, then rt -- and each serializes its own run
    via a .NOTPARALLEL in its Makefile.  A targeted 'make subdir/tests'
    is not ordered.

    The serialization (the per-subdirectory .NOTPARALLEL and the ordering
    above) constrains only the test run, not the build of the test
    programs; but building and running a subdirectory's tests are fused
    in its sub-make, so under run-built-tests=yes the serialized
    subdirectories would also build their test programs serially.  To
    avoid that, the top-level 'make check' (in Makerules) now runs two
    passes: it builds every test program with run-built-tests=no, where
    the recursion is fully parallel and none of the serialization
    applies, and then runs the tests with run-built-tests=yes.  'make
    tests' and a subdirectory's own 'check' stay single pass.

  * The subdirectory-built files that the top-level libc.so and
    linkobj/libc_pic.a rules list as prerequisites (elf/ld.so,
    interp.os, sofini.os, sunrpc/librpc_compat_pic.a, and on Hurd
    mach/libmachuser_pic.a and hurd/libhurduser_pic.a, from which the
    lib*user-link.so inputs of libc.so are built) get order-only edges
    on the corresponding sub-make with an explicit empty recipe.  A
    prerequisite-only rule would trigger an implicit rule search and
    this level would compile them itself in the wrong context.

  * The install, clean, abi, and stubs target classes keep the
    previous total order via a serial dependency chain.

  * The elf DSO sorting test recipes, run when make remakes the
    included generated makefiles at parse time, create the elf object
    directory before writing into it; the serial recursion no longer
    guarantees another rule created it first.

  * catgets builds locale-specific message catalogs (and tst-catgets
    reads one) by running gencat under de_DE.ISO-8859-1, hr_HR.ISO-8859-2
    and ja_JP.SJIS, but never declared those locales as prerequisites: it
    relied on localedata running before it in the serial order.  Under
    the parallel recursion gencat could run before localedata generated
    the locale, fall back to C, and fail.  catgets/Makefile now pulls the
    locales in via gen-locales.mk, like the other subdirectories that use
    locales in their tests.

Results on a x86_64 machine [1] with default configuration [3]: a
from-scratch build improves from 78.728s to 61s, and check with
run-built-tests=no from 374s to 190s.

On a 80-core aarch64 machine [2] with default configuration [3]: a
from-scratch build improves from 105.251s to 56.703s, and check with
run-built-tests=no from 886.183s to 298.726s.

Build results are unchanged: all 8919 built objects, archives, and
shared objects are bit-identical to the serial build across 7 clean
parallel builds, the installed tree layout is identical, and the
tests.sum failure sets are identical.  i686-gnu was verified with
repeated from-scratch builds.

[1] Ryzen 5900x, 12c/24t, gcc 16.1.1, binutils 2.26, and GNU make 4.3
[2] N1, 80c, gcc 15.1.1, binutils 2.25, GNU make 4.3
[3] --enable-stack-protector=all --enable-bind-now=yes --enable-profile=yes
    --enable-fortify-source=2 --enable-hardcoded-path-in-tests

Reviewed-by: Sam James <sam@gentoo.org>
2026-07-03 12:46:47 -03:00
Adhemerval Zanella e80612e596 scripts/gen-sorted.awk: Also emit the subdirectory dependency edges
gen-sorted.awk collects the inter-subdirectory dependencies from the
Depend files and the sysdeps Subdirs 'first' directives, but only uses
them to compute the flattened sorted-subdirs list.

This change also emit the raw edges as subdir-deps-<dir> make variables
so the parent makefile can express the same ordering as explicit
dependencies between the per-subdirectory recursion targets and run
independent subdirectories in parallel.

For instance, on x86_64-linux-gnu build the 'sysd-sorted' now shows:

  [...]
  subdir-deps-assert += iconvdata
  subdir-deps-assert += localedata
  subdir-deps-catgets += intl
  subdir-deps-debug += localedata
  subdir-deps-iconvdata += iconv
  subdir-deps-iconvdata += localedata
  subdir-deps-intl += iconvdata
  subdir-deps-intl += localedata
  subdir-deps-libio += localedata
  subdir-deps-localedata += locale
  [...]

Reviewed-by: Sam James <sam@gentoo.org>
2026-07-03 12:24:05 -03:00
Sam James 3c779ab155 intl: create correct directory in tst-translit.sh
Depending on parallelism, it's possible for domaindir/existing-locale/LC_MESSAGES
to have not been created yet:
```
msgfmt: error while opening "build/intl/domaindir/existing-locale/LC_MESSAGES/translit.mo" for writing: No such file or directory
make[2]: Leaving directory 'src/intl'
FAIL: intl/tst-translit
original exit status 1
cat: build/intl/tst-translit.out: No such file or directory
make[1]: *** [Makefile:944: test] Error 1
```

If so, the following msgfmt call will fail. Fix the typo in the mkdir call.

Arguably we should split these test preparations to avoid producing binaries
we know won't PASS because their support data is missing.

Reviewed-by: Collin Funk <collin.funk1@gmail.com>
2026-07-03 12:10:24 +01:00
Andreas K. Hüttel 84c3993f1f po/*.po: integrate current state of translations
Signed-off-by: Andreas K. Hüttel <dilfridge@gentoo.org>
2026-07-01 11:14:06 +09:00
Andreas K. Hüttel 45267197ff po/libc.pot: regenerate
Signed-off-by: Andreas K. Hüttel <dilfridge@gentoo.org>
2026-07-01 10:53:46 +09:00
DJ Delorie fae194043a Add system-wide tunables: manual
Document the syntax and operation.

Reviewed-by: Arjun Shankar <arjun@redhat.com>
2026-06-30 16:49:44 -04:00
DJ Delorie fcea66cd46 Add system-wide tunables: Filters
Add support for [proc:*] syntax where * matches /proc/self/exe
(fallback: argv[0] unless AT_SECURE).  Tunables after such a
line are limited to matching processes.

Note that this filter is reset when including a file or at
end of file.

If the filename starts with a slash (example: [proc:/bin/foo]) the
full path must match.  If not (example: [proc:foo]) the basename is
matched.

Add support for filtering out AT_SECURE or non-AT_SECURE binaries:

  $glibc.only-for.nonsecure-binaries=1
  @glibc.only-for.secure-binaries=1

Reviewed-by: Arjun Shankar <arjun@redhat.com>
2026-06-30 16:49:44 -04:00
DJ Delorie 9a953f9a48 Add system-wide tunables: Apply tunables part
Load ld.so.cache and fetch the tunables extension.  Apply
those tunables to the current program.  We do not yet apply
security policies.

Reviewed-by: Arjun Shankar <arjun@redhat.com>
2026-06-30 16:49:44 -04:00
DJ Delorie b9957a70b8 Add system-wide tunables: cache ld.so.cache
The purpose of this change is twofold:

1. The ld.so.cache is cached in memory and only re-read if/when
   it changes on disk.  This allows us to have much more intensive
   security checks in the future, without impacting performance as
   much.  It also allows for cases where the cache is corrupted -
   we continue using the last valid one.

2. We break out the load/check logic so that the cache can be
   loaded independently of the library lookup, such as for
   code that only needs to look at the extensions.

Reviewed-by: Arjun Shankar <arjun@redhat.com>
2026-06-30 16:49:42 -04:00
DJ Delorie e24269f74b Add system-wide tunables: ldconfig part
Adds support for reading /etc/tunables.conf

The file contains one line per tunable, like this:

glibc.foo.bar=14
glibc.malloc.more=0

Additionally, each line can be prefixed with a single word or character
that controls overridability by the GLIBC_TUNABLES env var:

overridable glibc.foo=0
+glibc.foo=0
   ^ May be overridden (the default)
nonoverridable glibc.foo=0
-glibc.foo=0
   ^ May not be overridden

The tunable cache format allows for a filter to be assigned to
each tunable, to be used at program start to decide if a tunable
applies to that program.  No such filters have yet been specified.

The cache format also stores a pre-parsed value for the tunable, and
the ID of the tunable, to improve load-time performance.

Reviewed-by: Arjun Shankar <arjun@redhat.com>
2026-06-30 16:46:08 -04:00
715 changed files with 46974 additions and 29767 deletions
File diff suppressed because it is too large Load Diff
+8 -12
View File
@@ -480,7 +480,7 @@ build the GNU C Library:
GCC 12.1 or higher is required. In general it is recommended to
use the newest version of the compiler that is known to work for
building the GNU C Library, as newer compilers usually produce
better code. As of release time, GCC 15.2.1 is the newest compiler
better code. As of release time, GCC 16.1.1 is the newest compiler
verified to work to build the GNU C Library.
For multi-arch support it is recommended to use a GCC which has
@@ -502,7 +502,7 @@ build the GNU C Library:
You must use GNU 'binutils' (as and ld) to build the GNU C Library.
No other assembler or linker has the necessary functionality at the
moment. As of release time, GNU 'binutils' 2.45.1 is the newest
moment. As of release time, GNU 'binutils' 2.46.1 is the newest
verified to work to build the GNU C Library.
* GNU 'texinfo' 4.7 or later
@@ -511,7 +511,7 @@ build the GNU C Library:
need this version of the 'texinfo' package. Earlier versions do
not understand all the tags used in the document, and the
installation mechanism for the info files is not present or works
differently. As of release time, 'texinfo' 7.2 is the newest
differently. As of release time, 'texinfo' 7.3 is the newest
verified to work to build the GNU C Library.
* GNU 'awk' 3.1.2, or higher
@@ -519,13 +519,9 @@ build the GNU C Library:
'awk' is used in several places to generate files. Some 'gawk'
extensions are used, including the 'asorti' function, which was
introduced in version 3.1.2 of 'gawk'. As of release time, 'gawk'
version 5.3.2 is the newest verified to work to build the GNU C
version 5.4.1 is the newest verified to work to build the GNU C
Library.
Testing the GNU C Library requires 'gawk' to be compiled with
support for high precision arithmetic via the 'MPFR'
multiple-precision floating-point computation library.
* GNU 'bison' 2.7 or later
'bison' is used to generate the 'yacc' parser code in the 'intl'
@@ -536,19 +532,19 @@ build the GNU C Library:
Perl is not required, but if present it is used in some tests and
the 'mtrace' program, to build the GNU C Library manual. As of
release time 'perl' version 5.42.0 is the newest verified to work
release time 'perl' version 5.44.0 is the newest verified to work
to build the GNU C Library.
* GNU 'sed' 3.02 or newer
'Sed' is used in several places to generate files. Most scripts
work with any version of 'sed'. As of release time, 'sed' version
4.9 is the newest verified to work to build the GNU C Library.
4.10 is the newest verified to work to build the GNU C Library.
* Python 3.4 or later
Python is required to build the GNU C Library. As of release time,
Python 3.14.0 is the newest verified to work for building and
Python 3.14.6 is the newest verified to work for building and
testing the GNU C Library.
* PExpect 4.0
@@ -634,7 +630,7 @@ components of the GNU C Library installation to be in '/lib' and some in
Library with '--prefix=/usr'. If you set some other prefix or allow it
to default to '/usr/local', then all the components are installed there.
As of release time, Linux version 6.12 is the newest stable version
As of release time, Linux version 7.1 is the newest stable version
verified to work to build the GNU C Library.
Reporting Bugs
+28 -1
View File
@@ -165,6 +165,15 @@ rtlddir = $(slibdir)
endif
inst_rtlddir = $(install_root)$(rtlddir)
# Directory referenced by the libc.so linker script (AS_NEEDED entry) for
# the dynamic linker at build time. This points at the location where the
# loader is actually installed so the linker can resolve it while building
# against libc. It defaults to rtlddir (where it differs, the loader is
# installed in rtlddir-build but identified/loaded at runtime via rtlddir).
ifndef rtlddir-build
rtlddir-build = $(rtlddir)
endif
# Prefix to put on files installed in $(libdir). For libraries `libNAME.a',
# the prefix is spliced between `lib' and the name, so the linker switch
# `-l$(libprefix)NAME' finds the library; for other files the prefix is
@@ -782,6 +791,14 @@ run-built-tests = yes
endif
endif
# Whether the timing-sensitive test runs are serialized: each is run with
# .NOTPARALLEL and, at the top level, ordered after the rest of the test run.
# This is the default; 'make check-parallel' clears it to run every test
# concurrently.
ifndef serialize-tests
serialize-tests = yes
endif
# Whether to build the static math tests
ifndef build-math-static-tests
build-math-static-tests = no
@@ -815,8 +832,15 @@ $(subst $(empty) ,:,$(strip $(patsubst -Wl$(comma)-rpath-link=%, %,\
run-via-rtld-prefix = \
$(if $(strip $(filter $(notdir $(built-program-file)), \
$(tests-static) $(xtests-static))),, $(rtld-prefix))
# $(container-via-rtld-prefix) is like $(run-via-rtld-prefix), but for the
# support/test-container helper, which is always dynamically linked even
# when the test it launches is static. It must therefore always run
# through the newly built loader, unlike $(run-via-rtld-prefix) which is
# empty for tests listed in tests-static or xtests-static.
container-via-rtld-prefix = $(rtld-prefix)
else
run-via-rtld-prefix =
container-via-rtld-prefix =
endif
# $(run-program-env) is the default environment variable settings to
# use when running a program built with the newly built library.
@@ -883,6 +907,7 @@ endif
ifeq (yes,$(build-hardcoded-path-in-tests))
test-via-rtld-prefix =
test-container-via-rtld-prefix =
test-program-prefix-before-env = $(test-wrapper-env)
test-program-prefix-after-env =
test-program-prefix = $(test-program-prefix-before-env) $(run-program-env) \
@@ -894,6 +919,7 @@ test-program-cmd = $(test-program-cmd-before-env) $(run-program-env) \
host-test-program-cmd = $(built-program-file)
else
test-via-rtld-prefix = $(run-via-rtld-prefix)
test-container-via-rtld-prefix = $(container-via-rtld-prefix)
test-program-prefix-before-env = $(run-program-prefix-before-env)
test-program-prefix-after-env = $(run-program-prefix-after-env)
test-program-prefix = $(run-program-prefix)
@@ -933,8 +959,9 @@ endif
installed-modules = nonlib nscd ldconfig locale_programs \
iconvprogs libnss_files libnss_compat libnss_db libnss_hesiod \
libutil libpcprofile libnsl
+time64-flags = -D_TIME_BITS=64
+extra-time-flags = $(if $(filter $(installed-modules),\
$(in-module)),-D_TIME_BITS=64 -D_FILE_OFFSET_BITS=64)
$(in-module)),$(+time64-flags) -D_FILE_OFFSET_BITS=64)
# We might want to compile with some stack-protection flag.
ifneq ($(stack-protector),)
+198 -14
View File
@@ -54,9 +54,6 @@ configure: configure.ac aclocal.m4; $(autoconf-it)
endif # $(AUTOCONF) = no
# We don't want to run anything here in parallel.
.NOTPARALLEL:
# These are the targets that are made by making them in each subdirectory.
+subdir_targets := subdir_lib objects objs others subdir_mostlyclean \
subdir_clean subdir_distclean subdir_realclean \
@@ -129,6 +126,13 @@ lib-noranlib: subdir_lib
ifeq (yes,$(build-shared))
# Build the shared object from the PIC object library.
lib: $(common-objpfx)libc.so $(common-objpfx)linkobj/libc.so
ifdef libc.so-version
# Every program linked in the others pass lists the versioned name
# (through link-libc-between-gnulib) as a prerequisite, and the rule
# creating the symbolic link is visible in every sub-make. Build it
# here once so the concurrent sub-makes do not race to create it.
lib: $(common-objpfx)libc.so$(libc.so-version)
endif
endif # $(build-shared)
# Used to build testrun.sh.
@@ -490,6 +494,159 @@ subdir=$(@D)$(if $($(@D)-srcdir),\
endef
.PHONY: $(+subdir_targets) $(all-subdirs-targets)
# Encode the topological ordering computed by scripts/gen-sorted.awk as
# explicit dependencies between the per-subdirectory targets, so that
# independent subdirectories build concurrently. In summary:
#
# * Every subdirectory depends on the first sorted one (csu, or mach on
# Hurd): its sub-make also materializes the shared generated files in
# $(common-objpfx) (abi-versions.h, sysd-syscalls, before-compile
# headers, ...) that concurrent sub-makes would otherwise race to
# create.
#
# * The edges requested by the Depend files (emitted by gen-sorted.awk
# as subdir-deps-*) are preserved.
#
# * elf stays last for the object-building classes, as in the sorted
# list: its rtld link consumes $(common-objpfx)libc_pic.a, which
# aggregates every other subdirectory's objects, and its rtld-Rules
# recursion compiles into the other subdirectories' object
# directories. The others/tests/xtests classes have no such
# dependency (the pass barriers below provide everything they need),
# so elf is unordered there.
#
# * Only target classes without cross-directory file conflicts use this
# sparse ordering; everything else (install, clean, abi, stubs) keeps
# the previous total order via a serial chain.
+elf_last_subdir_targets := \
subdir_lib objects \
objs \
subdir_objs \
# +elf_last_subdir_targets
+parallel_subdir_targets := \
$(+elf_last_subdir_targets) \
others \
tests \
xtests \
# +parallel_subdir_targets
+serial_subdir_targets := $(filter-out $(+parallel_subdir_targets),\
$(+subdir_targets))
# The tests and xtests classes run, rather than build, the per-directory
# test programs; once the 'others' pass barrier below has built the tree
# they are mutually independent and carry no cross-directory ordering.
# Keeping them out of the generated-file and Depend edges below is what
# lets 'make subdir/tests' run only that subdirectory's tests.
+barrier_only_subdir_targets := tests xtests
+ordered_parallel_subdir_targets := \
$(filter-out $(+barrier_only_subdir_targets),$(+parallel_subdir_targets))
# The subdirectories that generate shared files in $(common-objpfx)
# consumed by the rest of the build without explicit dependencies: csu
# provides the gen-as-const headers, and on Hurd the mach and hurd
# directories generate the MiG RPC headers (every other subdirectory
# otherwise runs a nested make in hurd/ to create them, racing under
# parallel recursion; see sysdeps/mach/hurd/Makefile). Run them serially,
# in their sorted order (mach, hurd, csu).
+subdir-pregen := $(filter mach hurd csu,$(subdirs))
+subdir-rest := $(filter-out $(+subdir-pregen),$(subdirs))
$(foreach t,$(+ordered_parallel_subdir_targets),$(eval \
$(addsuffix /$(t),$(+subdir-rest)): $(addsuffix /$(t),$(+subdir-pregen))))
+subdir-pregen-prev :=
$(foreach d,$(+subdir-pregen),$(foreach t,$(+ordered_parallel_subdir_targets),$(eval \
$(d)/$(t): $(addsuffix /$(t),$(+subdir-pregen-prev))))\
$(eval +subdir-pregen-prev := $(d)))
# For the classes where elf is forced last, edges pointing to elf are
# dropped: the sorted list always overrides such Depend requests today
# (e.g. support/Depend), and the elf-last edges below would otherwise
# create a cycle. The remaining classes honor them.
$(foreach t,$(+elf_last_subdir_targets),$(foreach d,$(+subdir-rest),$(eval \
$(d)/$(t): $(addsuffix /$(t),\
$(filter-out elf,$(filter $(subdirs),$(subdir-deps-$(d))))))))
$(foreach t,$(filter-out $(+elf_last_subdir_targets),\
$(+ordered_parallel_subdir_targets)),\
$(foreach d,$(+subdir-rest),$(eval \
$(d)/$(t): $(addsuffix /$(t),$(filter $(subdirs),$(subdir-deps-$(d)))))))
ifneq (,$(filter elf,$(subdirs)))
$(foreach t,$(+elf_last_subdir_targets),$(eval \
elf/$(t): $(addsuffix /$(t),$(filter-out elf,$(subdirs)))))
endif
# The archive rules in Makerules list every stamp file as a
# prerequisite of libc_pic.a, which the elf sub-make evaluates for the
# librtld.map link, but a sub-make can only create its own directory's
# stamps. Create the top-level ones before the fan-out.
$(foreach t,$(+elf_last_subdir_targets),$(eval \
$(addsuffix /$(t),$(subdirs)): \
$(foreach o,$(object-suffixes-for-libc),$(common-objpfx)stamp$(o))))
# Pass barriers: a subdirectory 'others' build links programs against
# the libraries, so the 'lib' pass (including the top-level libc.so
# link) must have completed.
# 'tests' and 'xtests' additionally require the 'others' pass. The
# testroot used by the container tests performs a full installation in
# its recipe, which must not run concurrently with the build passes.
$(addsuffix /others,$(subdirs)): lib
$(addsuffix /tests,$(subdirs)) $(addsuffix /xtests,$(subdirs)): others
$(objpfx)testroot.pristine/install.stamp: | others
# Timing-sensitive test runs: the threading tests (nptl/htl) and the realtime
# tests (rt) are perturbed by the machine load, so run them after the rest of
# the test run has finished and one group at a time. Those subdirectories
# also serialize their own tests (.NOTPARALLEL in their Makefiles).
#
# This only orders a full-suite run ('make check'/'tests'); a targeted
# 'make subdir/tests' is left alone. And it only orders the test run
# (run-built-tests=yes); the "build the tests" pass (run-built-tests=no)
# is left fully parallel, so every test program still builds concurrently.
# serialize-tests=no ('make check-parallel') drops the ordering entirely.
ifeq ($(run-built-tests),yes)
ifeq (yes,$(serialize-tests))
ifneq (,$(filter tests xtests check xcheck,$(MAKECMDGOALS)))
+late-test-subdirs := $(filter nptl htl,$(subdirs)) $(filter rt,$(subdirs))
+test-run-prev := \
$(addsuffix /tests,$(filter-out $(+late-test-subdirs),$(subdirs)))
$(foreach d,$(+late-test-subdirs),\
$(eval $(d)/tests: $(+test-run-prev))\
$(eval +test-run-prev += $(d)/tests))
endif
endif
endif
ifeq (yes,$(build-shared))
# The top-level libc.so and linkobj/libc_pic.a rules list these
# subdirectory-built files as prerequisites, but no rule at this level
# builds them. The explicit empty recipe (';') is required, a
# prerequisite-only rule would send make on an implicitrule search and
# have this level compile them itself with the wrong context.
ifneq (,$(filter elf,$(subdirs)))
$(elf-objpfx)ld.so $(elf-objpfx)sofini.os $(elf-objpfx)interp.os: \
| elf/subdir_lib ;
endif
ifneq (,$(filter sunrpc,$(subdirs)))
# Makerules explicit adds librpc_compat_pic.a as a dependency of
# libc_pic.a.
$(common-objpfx)sunrpc/librpc_compat_pic.a: | sunrpc/subdir_lib ;
endif
# Hurd sysdedp Makeilfe links libc.so against the lib*user-link.so
# objects, built by the %-link.so: %_pic.a pattern rule from archives
# that only the mach and hurd sub-makes create.
ifneq (,$(filter mach,$(subdirs)))
$(common-objpfx)mach/libmachuser_pic.a: | mach/subdir_lib ;
endif
ifneq (,$(filter hurd,$(subdirs)))
$(common-objpfx)hurd/libhurduser_pic.a: | hurd/subdir_lib ;
endif
endif
# The remaining target classes keep the old total order.
+subdir-chain-prev :=
$(foreach d,$(subdirs),$(foreach t,$(+serial_subdir_targets),$(eval \
$(d)/$(t): $(addsuffix /$(t),$(+subdir-chain-prev))))\
$(eval +subdir-chain-prev := $(d)))
# Targets to clean things up to various degrees.
@@ -540,26 +697,41 @@ $(objpfx)check-local-headers.out: scripts/check-local-headers.sh
$(evaluate-test)
ifneq "$(headers)" ""
# Special test of all the installed headers in this directory.
# Special test of all the installed headers in this directory. See
# Rules for the per-header split rationale.
tests-special += $(objpfx)check-installed-headers-c.out
libof-check-installed-headers-c := testsuite
$(objpfx)check-installed-headers-c.out: \
+cih-c-iouts := $(patsubst %,$(objpfx)check-installed-headers-c/%.iout,\
$(headers))
$(+cih-c-iouts): $(objpfx)check-installed-headers-c/%.iout: \
scripts/check-installed-headers.sh $(headers)
$(SHELL) $(..)scripts/check-installed-headers.sh c $(supported-fortify) \
"$(CC) $(test-config-cflags-finput-charset-ascii) \
$(filter-out -std=%,$(CFLAGS)) -D_ISOMAC $(+includes)" \
$(headers) > $@; \
$(make-target-directory)
($(SHELL) $(..)scripts/check-installed-headers.sh c $(supported-fortify) \
"$(CC) $(test-config-cflags-finput-charset-ascii) \
$(filter-out -std=%,$(CFLAGS)) -D_ISOMAC $(+includes)" \
$*; echo $$? > $@-ret) > $@T; \
mv -f $@T $@
$(objpfx)check-installed-headers-c.out: $(+cih-c-iouts)
cat $^ > $@; \
! grep -qv '^0$$' $(+cih-c-iouts:%=%-ret); \
$(evaluate-test)
ifneq "$(CXX)" ""
tests-special += $(objpfx)check-installed-headers-cxx.out
libof-check-installed-headers-cxx := testsuite
$(objpfx)check-installed-headers-cxx.out: \
+cih-cxx-iouts := $(patsubst %,$(objpfx)check-installed-headers-cxx/%.iout,\
$(headers))
$(+cih-cxx-iouts): $(objpfx)check-installed-headers-cxx/%.iout: \
scripts/check-installed-headers.sh $(headers)
$(SHELL) $(..)scripts/check-installed-headers.sh c++ $(supported-fortify) \
"$(CXX) $(test-config-cxxflags-finput-charset-ascii) \
$(filter-out -std=%,$(CXXFLAGS)) -D_ISOMAC $(+includes)" \
$(headers) > $@; \
$(make-target-directory)
($(SHELL) $(..)scripts/check-installed-headers.sh c++ $(supported-fortify) \
"$(CXX) $(test-config-cxxflags-finput-charset-ascii) \
$(filter-out -std=%,$(CXXFLAGS)) -D_ISOMAC $(+includes)" \
$*; echo $$? > $@-ret) > $@T; \
mv -f $@T $@
$(objpfx)check-installed-headers-cxx.out: $(+cih-cxx-iouts)
cat $^ > $@; \
! grep -qv '^0$$' $(+cih-cxx-iouts:%=%-ret); \
$(evaluate-test)
endif # $(CXX)
@@ -648,8 +820,13 @@ else
LINKS_DSO_PROGRAM = links-dso-program
endif
# The testroot is only used by the container tests, which are not run
# when run-built-tests is no; skip the installation entirely in that
# case.
ifeq ($(run-built-tests),yes)
$(tests-container) $(addsuffix /tests,$(subdirs)) : \
$(objpfx)testroot.pristine/install.stamp
endif
$(objpfx)testroot.pristine/install.stamp :
test -d $(objpfx)testroot.pristine || \
mkdir $(objpfx)testroot.pristine
@@ -700,7 +877,11 @@ endif
touch $(objpfx)testroot.pristine/install.stamp
tests-special-notdir = $(patsubst $(objpfx)%, %, $(tests-special))
# The build-only first pass of the two-pass 'make check' (see Makerules)
# passes tests-summary=no: the merge and summary are left to the second
# pass, which folds in this pass's $(tests-special) results.
tests: $(tests-special)
ifneq ($(tests-summary),no)
$(..)scripts/merge-test-results.sh -s $(objpfx) "" \
$(sort $(tests-special-notdir:.out=)) \
> $(objpfx)subdir-tests.sum
@@ -708,11 +889,14 @@ tests: $(tests-special)
$(sort $(subdirs) .) \
> $(objpfx)tests.sum
$(call summarize-tests,tests.sum)
endif
xtests:
ifneq ($(tests-summary),no)
$(..)scripts/merge-test-results.sh -t $(objpfx) subdir-xtests.sum \
$(sort $(subdirs)) \
> $(objpfx)xtests.sum
$(call summarize-tests,xtests.sum, for extra tests)
endif
# The realclean target is just like distclean for the parent, but we want
# the subdirs to know the difference in case they care.
+79 -11
View File
@@ -259,7 +259,17 @@ endif # gen-py-const-headers
ifdef gen-as-const-headers
# Generating headers for assembly constants.
# We need this defined early to get into before-compile before
# it's used in sysd-rules, below.
# it's used in sysd-rules, below. The gen-as-const-headers is evaluated
# per subdirectory, so the before-compile dependency below only orders
# the generated header before the compiles of the subdirectory whose
# Makefile adds the .sym directive.
# The parallel subdirectory recursion does not order sibling subdirectories,
# so a .sym must be added in the subdirectory that compiles its consumers,
# or in csu (which runs before the parallel) when it has consumers in
# several subdirectories.
# It must not add the same .sym in several subdirectories though: their
# concurrent sub-makes would race generating the header through the fixed
# temporary files below.
# Define GEN_AS_CONST_HEADERS to avoid circular dependency [BZ #22792].
# NB: <tcb-offsets.h> is generated from tcb-offsets.sym to define
# offsets and sizes of types in <tls.h> and maybe <pthread.h> which
@@ -302,7 +312,12 @@ lib-names-h-abi = gnu/lib-names-$(default-abi).h
lib-names-stmp-abi = gnu/lib-names-$(default-abi).stmp
before-compile += $(common-objpfx)$(lib-names-h-abi)
common-generated += gnu/lib-names.h
# The $(inst_includedir)/%.h install rules are defined only where $(headers)
# is non-empty, and with parallel subdir recursion a subdir without headers
# (e.g. csu) may run before the top level has installed the header.
ifndef subdir
install-others-nosubdir: $(inst_includedir)/$(lib-names-h-abi)
endif
$(common-objpfx)gnu/lib-names.h:
$(make-target-directory)
{ \
@@ -743,10 +758,20 @@ all-dt-files := $(foreach o,$(object-suffixes-for-libc),$(+depfiles:.d=$o.dt))
$(wildcard $(all-dt-files:.dt=.d))
# This is a funny rule in that it removes its input file.
#
# More than one make can convert the .dt files of a single object
# directory: the elf rtld-Rules recursion runs a sub-make over every
# $(rtld-subdirs) directory, concurrently with that directory's own
# sub-make under the parallel subdir recursion. Add the PID of the
# shell to the temporary name and claim the input with a rename: only
# the run that wins converts and installs the target.
%.d: %.dt
@sed $(sed-remove-objpfx) $< > $(@:.d=.T) && \
mv -f $(@:.d=.T) $@ && \
rm -f $<
@dt=$(@:.d=.T)$$$$; \
if mv -f $< $$dt 2>/dev/null; then \
sed $(sed-remove-objpfx) $$dt > $$dt.new && \
mv -f $$dt.new $@ && \
rm -f $$dt; \
fi
# Avoid the .h.d files for any .sym files whose .h files don't exist yet.
# They will be generated when they're needed, and trying too early won't work.
@@ -1024,7 +1049,7 @@ $(inst_libdir)/libc.so: $(common-objpfx)format.lds \
cat $<; \
echo 'GROUP ( $(slibdir)/libc.so$(libc.so-version)' \
'$(libdir)/$(patsubst %,$(libtype.oS),$(libprefix)$(libc-name))'\
' AS_NEEDED (' $(rtlddir)/$(rtld-installed-name) ') )' \
' AS_NEEDED (' $(rtlddir-build)/$(rtld-installed-name) ') )' \
) > $@.new
mv -f $@.new $@
@@ -1184,12 +1209,55 @@ ALL_BUILD_CFLAGS = $(BUILD_CFLAGS) $(BUILD_CPPFLAGS) -D_GNU_SOURCE \
-DIS_IN_build -include $(common-objpfx)config.h
# Support the GNU standard name for this target.
.PHONY: check
# Special target xcheck runs tests which cannot be run unconditionally;
# maintainers should use this target.
.PHONY: check xcheck
# Building and running a subdirectory's tests are fused in its sub-make,
# and run-built-tests is fixed for a make instance, so the only way to
# build every test program with the recursion fully parallel while the
# run still honors the per-subdirectory .NOTPARALLEL (nptl/htl/rt) and the
# run-time ordering is to use two passes. At the top level, 'make check'
# therefore builds the test programs (run-built-tests=no, recursion fully
# parallel) and then runs them (run-built-tests=yes). 'make tests' and a
# subdirectory's own 'check' stay single-pass.
# The first pass still runs the static checks ($(tests-special): abi,
# conformtest, installed headers, ...), so tests-summary=no makes it skip
# the results merge and summary: an unexpected FAIL there would otherwise
# abort 'check' before the second pass runs any built test, and even a
# clean run would print a misleading partial summary. The .test-result
# files persist, so the second pass folds those results into the one
# complete summary at the end.
check-twopass :=
ifndef subdir
ifeq (yes,$(run-built-tests))
check-twopass := yes
endif
endif
ifeq (yes,$(check-twopass))
check:
$(MAKE) run-built-tests=no tests-summary=no tests
$(MAKE) run-built-tests=yes tests
xcheck:
$(MAKE) run-built-tests=no tests-summary=no xtests
$(MAKE) run-built-tests=yes xtests
else
check: tests
# Special target to run tests which cannot be run unconditionally.
# Maintainers should use this target.
.PHONY: xcheck
xcheck: xtests
endif
# 'make check-parallel' runs the whole suite with maximum concurrency:
# serialize-tests=no drops the per-subdirectory .NOTPARALLEL and the run-time
# ordering, so every test builds and runs in parallel. A single pass suffices
# (there is no .NOTPARALLEL to work around, so the test programs already build
# concurrently).
# This is faster on an idle machine, at the cost of possible flakiness in the
# timing-sensitive tests under the heavier load.
.PHONY: check-parallel xcheck-parallel
check-parallel:
$(MAKE) serialize-tests=no tests
xcheck-parallel:
$(MAKE) serialize-tests=no xtests
# Also handle test inputs in sysdeps.
vpath %.input $(sysdirs)
@@ -1199,7 +1267,7 @@ vpath %.input $(sysdirs)
include $(o-iterator)
define o-iterator-doit
$(foreach f,$(tests-time64) $(xtests-time64),\
$(objpfx)$(f)$(o)): CFLAGS += -D_TIME_BITS=64 -D_FILE_OFFSET_BITS=64
$(objpfx)$(f)$(o)): CFLAGS += $(+time64-flags) -D_FILE_OFFSET_BITS=64
endef
object-suffixes-left := $(all-object-suffixes)
include $(o-iterator)
@@ -1375,7 +1443,7 @@ endef
# Also remove the dependencies and generated source files.
common-clean: common-mostlyclean
-rm -f $(addprefix $(objpfx),$(generated))
-rm -f $(objpfx)*.d $(objpfx)*.dt
-rm -f $(objpfx)*.d $(objpfx)*.dt $(objpfx)*.T[0-9]*
-rm -fr $(addprefix $(objpfx),$(generated-dirs))
-rm -f $(addprefix $(common-objpfx),$(common-generated))
-rm -f $(gen-as-const-headers:%.sym=$(common-objpfx)%.h)
+172 -17
View File
@@ -5,48 +5,101 @@ 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.45
Major new features:
[Add new features here]
Deprecated and removed features, and other changes affecting compatibility:
[Add deprecations, removals and changes affecting compatibility here]
Changes to build and runtime requirements:
[Add changes to build and runtime requirements here]
Security related changes:
The following CVEs were fixed in this release, details of which can be
found in the advisories directory of the release tarball:
[The release manager will add the list generated by
scripts/process-advisories.sh just before the release.]
The following bugs were resolved with this release:
[The release manager will add the list generated by
scripts/list-fixed-bugs.py just before the release.]
Version 2.44
Major new features:
* System-wide tunables can be applied using /etc/tunables.conf and
running ldconfig. Specific tunable settings and the
/etc/tunables.conf file format and path are not part of the stable
library interfaces and may change between releases.
* A new tunable, glibc.elf.thp, is added to map read-only segments with
Transparent Huge Pages (THP) if THP isn't disable in kernel. When
Transparent Huge Pages (THP) if THP is not disabled in the kernel. When
glibc.elf.thp is set to 1, malloc uses the actual kernel THP mode
instead of defaulting to madvise mode and madvise_thp will stop issuing
MADV_HUGEPAGE if kernel THP mode is always.
* THP page size in malloc is capped to MAX_THP_PAGESIZE. If THP page
size is above MAX_THP_PAGESIZE, THP in malloc is disabled.
* The THP page size in malloc is capped to MAX_THP_PAGESIZE. If the THP
page size is above MAX_THP_PAGESIZE, THP in malloc is disabled.
* Additional optimized and correctly rounded mathematical functions have
been imported from the CORE-MATH project, in particular cosh, sinh, and
tanh.
* The SVID handling for cosh and sinh were moved to compat symbols, allowing
improvements in performance.
* Many additional improvements to existing functions have been synchronized
from the CORE-MATH project.
* New locale added: hrx_BR (Hunsrik language spoken in Brazil).
* For C++26, the assert macro is now variadic, allowing more complex
arguments containing commas (which however still must evaluate to a single
value).
* The SVID error handling for cosh and sinh was moved to compatibility
symbols, allowing improvements in performance.
* Static PIE is now supported for arm-*-linux-gnueabi. It requires toolchain
support to correctly set the expected linker options.
* On AArch64 targets that support Guarded Control Stack extension all GCS
* On AArch64 targets that support the Guarded Control Stack extension all GCS
operations (including status, write on shadow stack, and push to shadow
stack) are locked after enabling GCS with ENFORCED or OVERRIDE GCS policy.
When a GCS operation is locked, a program cannot change this operation
status via prctl syscall. This prevents disabling or corrupting GCS
shadow stack during runtime.
status via the prctl syscall. This prevents disabling or corrupting the
GCS shadow stack during runtime.
* On AArch64 targets, log, exp, sin, cas, sinh, cosh, asinh, acosh, atanh
single and double precision special cases have been vectorized for SVE and
AdvSIMD, and vector variants of powr have been added.
* On RISC-V targets, vector extension optimized variants of memcmp, memccpy,
memchr, memcpy, memmove, stpncpy, strcmp, strchr, strcpy, strncmp, strncpy,
strlen, and strrchr have been added.
* On PowerPC, memchr optimized for Power10 has been re-added.
* Support for LoongArch32 has been added.
* Pre-built ld.so.cache files can be installed with ldconfig.
* A new locale has been added: hrx_BR (Hunsrik language spoken in Brazil).
Deprecated and removed features, and other changes affecting compatibility:
* Although malloc and related functions currently return pointers
aligned to alignof (max_align_t), the documentation now says future
versions of glibc may relax alignment requirements for small allocations.
For example, a future malloc (1) might return a pointer with odd
For example, a future malloc(1) might return a pointer with odd
alignment, because no object of size 1 can have a fundamental
alignment greater than 1.
* The s390-linux-gnu (31bit) configuration is no longer supported.
* The s390-linux-gnu (31bit) configuration is no longer supported.
* The --enable-memory-tagging configure option has been removed.
The corresponding AArch64-specific functionality that was previously
@@ -57,10 +110,6 @@ Deprecated and removed features, and other changes affecting compatibility:
remaining behavior was to suppress the link-time warnings on the NSS
interface functions in libc.a, which are now emitted unconditionally.
Changes to build and runtime requirements:
[Add changes to build and runtime requirements here]
Security related changes:
The following CVEs were fixed in this release, details of which can be
@@ -80,8 +129,114 @@ found in the advisories directory of the release tarball:
The following bugs were resolved with this release:
[The release manager will add the list generated by
scripts/list-fixed-bugs.py just before the release.]
[2363] libc: EOPNOTSUPP and ENOTSUP in errno.h must be different,
according to SUSv3
[3794] manual: iconv: //TRANSLIT and //IGNORE feature not documented
[15792] dynamic-link: [arm] ARM dynamic linker should save/restore
coprocessor registers
[20331] libc: fts ignores errors from readdir()
[20680] dynamic-link: ifunc resolver cannot access the thread pointer
with static linking
[22944] libc: fts cannot traverse paths which have a length longer
than USHRT_MAX
[25257] libc: sotruss: fix error message for '--f' argument
[25770] locale: newlocale memory leak in LOCPATH parsing and on error
paths
[27582] libc: x86_64: IFUNC in static user programs may crash when
built with -fstack-protector-all
[28218] dynamic-link: ld.so: ifunc resolver calls a lazy PLT. When
does it work?
[28817] libc: static-pie ifunc resolver tls failure
[28940] nss: __nss_database_get doesn't check for allocation failure
[30136] manual: Please document behaviour of iconv(3) when input is
untranslatable
[30304] nptl: nptl/tst-pthread-gdb-attach test fails with new libc
shared library version
[30769] malloc: malloc_trim is not working correctly for arenas other
than arena 0
[30976] dynamic-link: rtld: resolve ifunc relocations after
JUMP_SLOT/GLOB_DAT/etc
[30992] libc: alpha: setrlimit() with negative values besides
RLIM_INFINITY returns EPERM
[31901] libc: elf/tst-glibc-hwcaps-prepend-cache fails on i686
[33226] math: math-vector-fortran.h vs not ffast-math
[33626] libc: execvpe should skip inaccessible $PATH components
[33650] build: abilist.awk doesn't handle unversioned defined symbols
[33785] stdio: New streams are linked into global list before they are
fully initialized
[33848] build: Build fails at openat2.h, redefinition of 'struct
open_how'
[33882] libc: Recursion in nftw() causes stack overflow(CWE-674)
[33904] build: error: '__vasprintf_chk' undeclared here
[33921] build: Building with Linux-7.0-rc1 errors on OPEN_TREE_CLONE
[33935] stdio: _IO_wfile_doallocate not linked correctly when linking
glibc statically
[33980] locale: iconv: ibm139x trigger assertion error when converting
to internal while lack enough room (CVE-2026-4046)
[33985] build: ld: cannot find -lgcc_s: No such file or directory
[33999] stdio: libio: potential dangling _IO_save_base or memory leak
in wgenops.c
[34006] stdio: libio: inconsistent fmemopen_write behavior on last \0
[34008] stdio: stdio-common: scanf %mc pattern will cause heap
overflow when width > 1024
[34014] nss: gethostbyaddr and gethostbyaddr_r may incorrectly handle
DNS response
[34015] nss: gethostbyaddr and gethostbyaddr_r return invalid DNS
hostnames
[34019] stdio: libio: undefined behavior when setbuf on open_memstream
[34033] network: resolv/ns_print.c: ns_sprintrrf TSIG path bypasses
buflen and can overflow caller buffer
[34064] dynamic-link: The unnecessary PT_NOTE check in when loading a
binary
[34069] network: Buffer overread in ns_sprintrrf with corrupted RDATA
field (CVE-2026-6238)
[34070] hurd: Calling open ("/dev/tty/", O_RDONLY) causes the program
to segfault
[34073] regex: regexec can mistakenly match with backrefs and the $
anchor
[34079] dynamic-link: THP segment load aligns all PT_LOAD segments to
THP page size
[34080] dynamic-link: Support THP segment load with THP enabled with
madvise
[34083] dynamic-link: __get_thp_mode and __get_thp_size are called
twice
[34090] libc: wordexp WRDE_APPEND rollback restores stale we_wordv,
leading to invalid free in wordfree
[34098] libc: Missing SUPPORT_STATIC_PIE in arm32
[34129] string: x86: Non-temporal memset unreachable on AMD Zen 3/4/5
[34144] libc: ld.so clobbers VFP registers during runtime linking
[34154] network: Segfault in sock_eq after res_init() returns -1, due
to stale _u._ext.nscount in __res_iclose
[34156] dynamic-link: dlsym(RTLD_DEFAULT, ...) from a constructor
SIGSEGVs when tail-called
[34164] dynamic-link: elf: IFUNC resolvers do not see static TLS
initialization
[34170] dynamic-link: elf: IFUNC resolver reading global-
dynamic/TLSDESC __thread variable crashes inside __tls_get_addr
[34183] math: fma produces wrong results
[34192] nptl: pthread_setname_np opens /proc/<tid>/comm with O_RDWR
instead of O_WRONLY|O_CLOEXEC
[34196] libc: elf: static dlopen: pointer guard of the loaded
ld.so/libc.so is left uninitialized
[34197] dynamic-link: elf: Stack canary and pointer guard are
recoverable from AT_RANDOM (getauxval)
[34205] libc: aarch64: SIGSEGV in tunable_strcmp in static-pie
binaries run with a string tunable
[34208] stdio: scanf not pushback after matching failure
[34210] libc: elf/tst-glibc-hwcaps-prepend-cache fails on
armv7a-unknown-linux-gnueabihf
[34236] locale: Non-representable transliteration still causes iconv
to exit with 1 if //TRANSLIT is specified
[34289] network: ns_sprintrrf uses p_class, p_type internally
[34311] build: THP tests failed to link
[34347] libc: Incorrect trailing bitfield word of struct tcp_info
[34348] dynamic-link: FAIL: elf/tst-thp-1 if THP is disabled in kernel
[34351] build: Random test failures
[34355] build: [2.44 Regression] "make check -j7 subdirs=stdio-common"
no longer works
[34396] libc: sparc64-unknown-linux-gnu , Gentoo: >200 test failures,
SIGILL in many binaries
[34398] string: Truncated strncpy on s390x z900 ifunc variant
Version 2.43
+31 -14
View File
@@ -80,15 +80,24 @@ common-generated += dummy.o dummy.c
ifneq "$(headers)" ""
# Test that all of the headers installed by this directory can be compiled
# in isolation.
# in isolation. Each header gets its own intermediate target so that the
# it can run concurrently under -j; the .out target concatenates the per-header
# results in the original $(headers) order.
tests-special += $(objpfx)check-installed-headers-c.out
libof-check-installed-headers-c := testsuite
$(objpfx)check-installed-headers-c.out: \
+cih-c-iouts := $(patsubst %,$(objpfx)check-installed-headers-c/%.iout,\
$(headers))
$(+cih-c-iouts): $(objpfx)check-installed-headers-c/%.iout: \
$(..)scripts/check-installed-headers.sh $(headers)
$(SHELL) $(..)scripts/check-installed-headers.sh c $(supported-fortify) \
"$(CC) $(test-config-cflags-finput-charset-ascii) \
$(filter-out -std=%,$(CFLAGS)) -D_ISOMAC $(+includes)" \
$(headers) > $@; \
$(make-target-directory)
($(SHELL) $(..)scripts/check-installed-headers.sh c $(supported-fortify) \
"$(CC) $(test-config-cflags-finput-charset-ascii) \
$(filter-out -std=%,$(CFLAGS)) -D_ISOMAC $(+includes)" \
$*; echo $$? > $@-ret) > $@T; \
mv -f $@T $@
$(objpfx)check-installed-headers-c.out: $(+cih-c-iouts)
cat $^ > $@; \
! grep -qv '^0$$' $(+cih-c-iouts:%=%-ret); \
$(evaluate-test)
ifneq "$(CXX)" ""
@@ -96,12 +105,19 @@ ifneq "$(CXX)" ""
# in isolation as C++.
tests-special += $(objpfx)check-installed-headers-cxx.out
libof-check-installed-headers-cxx := testsuite
$(objpfx)check-installed-headers-cxx.out: \
+cih-cxx-iouts := $(patsubst %,$(objpfx)check-installed-headers-cxx/%.iout,\
$(headers))
$(+cih-cxx-iouts): $(objpfx)check-installed-headers-cxx/%.iout: \
$(..)scripts/check-installed-headers.sh $(headers)
$(SHELL) $(..)scripts/check-installed-headers.sh c++ $(supported-fortify) \
"$(CXX) $(test-config-cxxflags-finput-charset-ascii) \
$(filter-out -std=%,$(CXXFLAGS)) -D_ISOMAC $(+includes)" \
$(headers) > $@; \
$(make-target-directory)
($(SHELL) $(..)scripts/check-installed-headers.sh c++ $(supported-fortify) \
"$(CXX) $(test-config-cxxflags-finput-charset-ascii) \
$(filter-out -std=%,$(CXXFLAGS)) -D_ISOMAC $(+includes)" \
$*; echo $$? > $@-ret) > $@T; \
mv -f $@T $@
$(objpfx)check-installed-headers-cxx.out: $(+cih-cxx-iouts)
cat $^ > $@; \
! grep -qv '^0$$' $(+cih-cxx-iouts:%=%-ret); \
$(evaluate-test)
endif # $(CXX)
@@ -413,7 +429,7 @@ $(objpfx)%.out: /dev/null $(objpfx)% # Make it 2nd arg for canned sequence.
# and pid namespaces) in which to run, should be added to
# tests-container.
$(tests-container:%=$(objpfx)%.out): $(objpfx)%.out : $(if $(wildcard $(objpfx)%.files),$(objpfx)%.files,/dev/null) $(objpfx)%
$(test-wrapper-env) $(run-program-env) $(test-via-rtld-prefix) \
$(test-wrapper-env) $(run-program-env) $(test-container-via-rtld-prefix) \
$(common-objpfx)support/test-container env $(run-program-env) $($*-ENV) $(test-tunables) \
$(host-test-program-cmd) $($*-ARGS) > $@; \
$(evaluate-test)
@@ -451,8 +467,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
+2 -1
View File
@@ -113,6 +113,7 @@ gnulib:
stdlib/setenv.c
stdlib/strtoll.c
stdlib/strtoul.c
# Merged from gnulib 2026-08-27, (gnulib commit ec224ee81b)
stdlib/tst-stdc_rotate_left.c
stdlib/tst-stdc_rotate_right.c
# Merged from gnulib 2014-6-26, needs merge back
@@ -280,7 +281,7 @@ core-math:
sysdeps/ieee754/dbl-64/s_erf.c
# src/binary64/erfc/erfc.c, revision 55e9869e
sysdeps/ieee754/dbl-64/s_erfc.c
# src/binary64/tanh/tanh.c, revision 8ea8ea35
# src/binary64/tanh/tanh.c, revision bb39e4fa
sysdeps/ieee754/dbl-64/s_tanh.c
# src/binary32/acos/acosf.c, revision 56dd347
sysdeps/ieee754/flt-32/e_acosf.c
+19
View File
@@ -0,0 +1,19 @@
wordexp with WRDE_APPEND may result in an invalid call to free()
Calling wordexp with WRDE_APPEND in conjunction with an invalid expansion
(where an error like WRDE_BADCHAR would be returned) can create a stale
address in the wordexp_t that can cause an invalid free from wordfree.
This affects the GNU C Library version 2.0 to version 2.43.
In WRDE_APPEND mode, wordexp saves the caller-visible wordexp_t state
before appending the processing input. If the word expansion grows
we_wordv via realloc, and realloc requires moving we_wordv to a new memory
location (instead of expanding in-place), and the expansion later fails,
the rollback fails to properly restore all previous we_wordv values and
may add stale pointers into the caller-visible state. A subsequent
wordfree may then issue an invalid call to free().
CVE-Id: CVE-2026-6368
Public-Date: 2026-07-14
Vulnerable-Commit: 8f2ece695d8822e9ecc63ecd157e90bf17a6fe65 (1.93-260)
Reported-by: shinobu
+18
View File
@@ -0,0 +1,18 @@
Buffer overflow in fopen mode argument processing
Passing an effectively empty string to the `,ccs=` syntax extension of
the mode argument in the `fopen` function in the GNU C Library version
2.45 or earlier may result in a heap buffer overflow when the mode
string input to the function is attacker controlled.
This usage pattern is not seen in applications in common GNU or Linux
distributions and applications that process user-supplied values for
`ccs` should not pass them through without validation.
CVE-Id: CVE-2026-18374
Public-Date: 2026-08-27
Vulnerable-Commit: 129d706d77587e4d6627cc1ebef9be0f7cbc65f0
Fix-Commit: 9765a538ebf8661a6e5578e01e35a3dd30db7eb4 (2.45)
Fix-Commit: cca93e5d88d3d4ed073c03100467696f652269e7 (2.45)
Reported-by: AISLE in partnership with Red Hat
CVSS: CVSS:3.1/AV:L/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:L - 4.9
+4 -1
View File
@@ -45,6 +45,9 @@ Reported-By:
The entity that reported this issue. There could be multiple entries, one for
each reporter.
CVSS:
CVSS score for the issue.
Adding an Advisory
------------------
@@ -57,7 +60,7 @@ An advisory for a CVE needs to be added on the master branch in two steps:
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
2. Finish all backports on release branches and then back on the master
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.
+5
View File
@@ -33,6 +33,11 @@ routines := \
assert-perr \
# routines
# Called during static library initialization, so turn stack-protection
# off for non-shared builds.
CFLAGS-__libc_assert_fail.o = $(no-stack-protector)
CFLAGS-__libc_assert_fail.op = $(no-stack-protector)
tests := \
test-assert \
test-assert-2 \
+25 -3
View File
@@ -409,9 +409,9 @@ $(addprefix $(objpfx)bench-,calloc-thread): $(libm-benchtests)
# Rules to build and execute the benchmarks. Do not put any benchmark
# parameters beyond this point.
# We don't want the benchmark programs to run in parallel since that could
# affect their performance.
.NOTPARALLEL:
# Benchmark programs must not run concurrently, however building them is
# safe in parallel. So '.NOTPARALLEL:' is used only when benchmarks run
# or when more than one group is going to run.
bench-extra-objs = json-lib.o
@@ -622,8 +622,30 @@ $(bench-link-targets): %: %.o $(objpfx)json-lib.o \
$(bench-link-targets): LDFLAGS += $(link-bench-bind-now)
$(objpfx)bench-%.c: %-inputs $(bench-deps)
$(make-target-directory)
{ if [ -n "$($*-INCLUDE)" ]; then \
cat $($*-INCLUDE); \
fi; \
$(PYTHON) scripts/bench.py $(patsubst %-inputs,%,$<); } > $@-tmp
mv -f $@-tmp $@
# Serialize the benchmark runs so their timing is not perturbed by a
# concurrent workload, while still building every benchmark program in parallel.
# Ordering is only needed when more than one benchmark group run: the combined
# 'bench' goal runs all three groups, and the bench* goals can also be combined
# on a single command line. A lone group needs no ordering -- make builds its
# programs in parallel and then runs its single recipe, which cannot overlap a
# compile.
ifneq (,$(filter bench,$(MAKECMDGOALS)))
bench-run-active := bench-set bench-func bench-malloc
else
bench-run-active := $(filter bench-set bench-func bench-malloc,$(MAKECMDGOALS))
endif
ifneq (,$(word 2,$(bench-run-active)))
# Hold every active run until all benchmark programs have been built.
$(bench-run-active): | bench-build
# And then run the active groups strictly one at a time.
bench-func: | $(filter bench-set,$(bench-run-active))
bench-malloc: | $(filter bench-set bench-func,$(bench-run-active))
endif
+1 -1
View File
@@ -48,7 +48,7 @@ do_one_test (json_ctx_t *json_ctx, impl_t *impl, const CHAR *s,
const CHAR *rej, RES_TYPE exp_res)
{
RES_TYPE res = CALL (impl, s, rej);
size_t i, iters = INNER_LOOP_ITERS8 / CHARBYTES;
size_t i, iters = CHARBYTES > 1 ? INNER_LOOP_ITERS : INNER_LOOP_ITERS_LARGE;
timing_t start, stop, cur;
if (res != exp_res)
+2 -1
View File
@@ -41,7 +41,8 @@ static void
do_one_test (json_ctx_t *json_ctx, impl_t *impl, const CHAR *s,
const CHAR *acc, size_t exp_res)
{
size_t res = CALL (impl, s, acc), i, iters = INNER_LOOP_ITERS8 / CHARBYTES;
size_t res = CALL (impl, s, acc), i;
size_t iters = CHARBYTES > 1 ? INNER_LOOP_ITERS : INNER_LOOP_ITERS_LARGE;
timing_t start, stop, cur;
if (res != exp_res)
+3006 -2405
View File
File diff suppressed because it is too large Load Diff
+3006 -4911
View File
File diff suppressed because it is too large Load Diff
+2004 -3446
View File
File diff suppressed because it is too large Load Diff
+11 -3
View File
@@ -60,6 +60,14 @@ vpath %.c ../locale/programs
include ../Rules
# The catalog-generation tests below run gencat under specific locales,
# and tst-catgets reads the resulting catalog, so the build must wait for
# those locales to be generated. Without this dependency a parallel build
# races catgets against localedata and gencat can run before the locale
# exists (it then falls back to C and the test fails).
LOCALES := de_DE.ISO-8859-1 hr_HR.ISO-8859-2 ja_JP.SJIS
include ../gen-locales.mk
$(objpfx)gencat: $(gencat-modules:%=$(objpfx)%.o)
catgets-CPPFLAGS := -DNLSPATH='"$(localedir)/%L/%N:$(localedir)/%L/LC_MESSAGES/%N:$(localedir)/%l/%N:$(localedir)/%l/LC_MESSAGES/%N:"'
@@ -95,7 +103,7 @@ tst-catgets-ENV = NLSPATH="$(objpfx)%l/%N.cat" LANG=de \
ifeq ($(run-built-tests),yes)
# This test just checks whether the program produces any error or not.
# The result is not tested.
$(objpfx)test1.cat: test1.msg $(objpfx)gencat
$(objpfx)test1.cat: test1.msg $(objpfx)gencat $(gen-locales)
$(built-program-cmd-before-env) \
$(run-program-env) LC_ALL=hr_HR.ISO-8859-2 \
$(built-program-cmd-after-env) -H $(objpfx)test1.h $@ $<; \
@@ -103,7 +111,7 @@ $(objpfx)test1.cat: test1.msg $(objpfx)gencat
$(objpfx)test2.cat: test2.msg $(objpfx)gencat
$(built-program-cmd) -H $(objpfx)test2.h $@ $<; \
$(evaluate-test)
$(objpfx)de/libc.cat: $(objpfx)de.msg $(objpfx)gencat
$(objpfx)de/libc.cat: $(objpfx)de.msg $(objpfx)gencat $(gen-locales)
$(make-target-directory)
$(built-program-cmd-before-env) \
$(run-program-env) LC_ALL=de_DE.ISO-8859-1 \
@@ -116,7 +124,7 @@ $(objpfx)de.msg: xopen-msg.awk $(..)po/de.po
LC_ALL=C $(AWK) -f $^ $< > $@
$(objpfx)test-gencat.out: test-gencat.sh $(objpfx)test-gencat \
$(objpfx)sample.SJIS.cat
$(objpfx)sample.SJIS.cat $(gen-locales)
$(SHELL) $< $(common-objpfx) '$(test-program-cmd-before-env)' \
'$(run-program-env)' '$(test-program-cmd-after-env)'; \
$(evaluate-test)
+5 -1
View File
@@ -264,10 +264,14 @@ LIBC_START_MAIN (int (*main) (int, char **, char ** MAIN_AUXVEC_DECL),
_dl_aux_init (auxvec);
# endif
__tunables_init (__environ);
__tunables_init (__environ, argv);
ARCH_INIT_CPU_FEATURES ();
/* Every string tunable has been consumed by ARCH_INIT_CPU_FEATURES, before
any code outside of libc startup runs. */
__tunable_seal_strings ();
/* Do static-pie self relocation for the non-IRELATIVE part after tunables
and cpu features are set up. IFUNC entries are deferred until after the
TCB and the stack-protector canary are usable, so that an instrumented
+24 -12
View File
@@ -36,10 +36,15 @@
trampoline, read, 3 * fn, and do_test. */
#define NUM_FUNCTIONS 7
/* Avoid the read wrapper frame truncation on targets that add extra frames
between it and handle_signal (the cancellable syscall wrappers
__syscall_cancel*, or the i686 __kernel_vsyscall entry). */
#define MAX_FUNCTIONS 64
void
handle_signal (int signum)
{
void *addresses[NUM_FUNCTIONS];
void *addresses[MAX_FUNCTIONS];
char **symbols;
int n;
int i;
@@ -70,23 +75,30 @@ handle_signal (int signum)
return;
}
/* Do not check name for signal trampoline or cancellable syscall
wrappers (__syscall_cancel*). */
for (; i < n - 1; i++)
if (match (symbols[i], "read"))
/* Skip the signal trampoline and any cancellable syscall wrapper frames
(__syscall_cancel*) and require the read syscall wrapper to be
present (but skip intermediates). */
for (i = 1; i < n; i++)
if (match (symbols[i], "read")
&& !match (symbols[i], "read_nocancel")
&& !match (symbols[i], "io_read"))
break;
if (i == n - 1)
if (i == n)
{
FAIL ();
return;
}
for (; i < n - 1; i++)
if (!match (symbols[i], "fn"))
{
FAIL ();
return;
}
/* The read wrapper must be followed by the three fn recursion frames. */
for (int j = 0; j < 3; j++)
{
i++;
if (i == n || !match (symbols[i], "fn"))
{
FAIL ();
return;
}
}
/* Symbol names are not available for static functions, so we do not
check do_test. */
+7 -2
View File
@@ -145,8 +145,13 @@ enum
RTLD_DI_SERINFOSIZE = 5,
/* Treat ARG as `char *', and store there the directory name used to
expand $ORIGIN in this shared object's dependency file names. */
RTLD_DI_ORIGIN = 6,
expand $ORIGIN in this shared object's dependency file names.
Deprecated due to potential for buffer overflows. */
RTLD_DI_ORIGIN
# ifdef __attribute_deprecated_enum__
__attribute_deprecated_enum__ ("Use RTLD_DI_ORIGIN_PATH instead")
# endif
= 6,
RTLD_DI_PROFILENAME = 7, /* Unsupported, defined by Solaris. */
RTLD_DI_PROFILEOUT = 8, /* Unsupported, defined by Solaris. */
+5
View File
@@ -22,6 +22,7 @@
#include <libintl.h>
#include <dl-tls.h>
#include <shlib-compat.h>
#include <libc-diag.h>
struct dlinfo_args
{
@@ -63,9 +64,13 @@ dlinfo_doit (void *argsblock)
_dl_rtld_di_serinfo (l, args->arg, true);
break;
DIAG_PUSH_NEEDS_COMMENT;
DIAG_IGNORE_NEEDS_COMMENT (6.1, "-Wdeprecated-declarations");
/* Deprecated via compile-time warning due to buffer overflow risk. */
case RTLD_DI_ORIGIN:
strcpy (args->arg, l->l_origin);
break;
DIAG_POP_NEEDS_COMMENT;
case RTLD_DI_ORIGIN_PATH:
if (l->l_origin != (char *) -1)
+5
View File
@@ -21,6 +21,7 @@
#include <stdlib.h>
#include <error.h>
#include <support/check.h>
#include <libc-diag.h>
#define TEST_FUNCTION do_test ()
@@ -51,11 +52,15 @@ do_test (void)
}
}
DIAG_PUSH_NEEDS_COMMENT;
/* Ignore deprecation to be able to test deprecated request type. */
DIAG_IGNORE_NEEDS_COMMENT (6.1, "-Wdeprecated-declarations");
char origin[8192]; /* >= PATH_MAX, in theory */
TRY (RTLD_DI_ORIGIN, origin)
{
printf ("origin: %s\n", origin);
}
DIAG_POP_NEEDS_COMMENT;
const char *origin_path;
TRY (RTLD_DI_ORIGIN_PATH, &origin_path)
+123 -5
View File
@@ -225,6 +225,7 @@ ldconfig-modules := \
readlib \
static-stubs \
stringtable \
tunconf \
xmalloc \
xstrdup \
# ldconfig-modules
@@ -279,6 +280,7 @@ tests-static-normal := \
# tests-static-normal
tests-static-internal := \
tst-assert-startup-static \
tst-atrandom-scrub-static \
tst-dl-printf-static \
tst-dl_find_object-static \
@@ -289,9 +291,10 @@ tests-static-internal := \
tst-tls1-static-non-pie \
tst-tunables \
tst-tunables-enable_secure \
tst-tunables-seal-static \
# tests-static-internal
ifeq (yes,$(have-gcc-ifunc))
ifeq (yesyes,$(have-gcc-ifunc)$(have-ssp))
tests-static-internal += \
tst-ifunc-resolver-protector-static \
tst-ifunc-resolver-protector-static-non-pie \
@@ -335,6 +338,7 @@ tests-internal := \
$(tests-static-internal) \
tst-tls1 \
tst-tls_tp_offset \
tst-tunconf1 \
# tests-internal
tests-static := $(tests-static-normal) $(tests-static-internal)
@@ -345,6 +349,17 @@ tests-static += \
tst-tls9-static \
# tests-static
tst-tunconf1-TUNABLES-only = \
glibc.malloc.tcache_count=5 \
glibc.malloc.perturb=41 \
glibc.malloc.mmap_threshold=10002 \
glibc.malloc.trim_threshold=10002 \
glibc.malloc.arena_max=300
tst-tunconf1-ENV = \
MALLOC_MMAP_MAX_=200 \
MALLOC_TOP_PAD_=200 \
MALLOC_ARENA_MAX=400
static-dlopen-environment = \
LD_LIBRARY_PATH=$(ld-library-path):$(common-objpfx)dlfcn
tst-tls9-static-ENV = $(static-dlopen-environment)
@@ -553,6 +568,7 @@ tests-internal += \
tst-audit19a \
tst-create_format1 \
tst-dl-hwcaps_split \
tst-dl-path-normalize \
tst-dl_find_object \
tst-dl_find_object-threads \
tst-dlmopen2 \
@@ -566,6 +582,7 @@ tests-internal += \
tst-tls6 \
tst-tls7 \
tst-tls8 \
tst-tunables-seal \
unload \
unload2 \
# tests-internal
@@ -577,13 +594,17 @@ endif
tests-container += \
tst-dlopen-self-container \
tst-dlopen-tlsmodid-container \
tst-ldconfig-cache \
tst-origin-secure \
tst-pldd \
tst-preload-pthread-libc \
tst-ptrguard-static-dlopen \
tst-rootdir \
tst-tunconf1 \
# tests-container
test-srcs = \
tst-origin-secure-victim \
tst-pathopt \
tst-sprof-basic \
# tests-srcs
@@ -712,6 +733,7 @@ tests-special += $(tests-execstack-special-$(have-z-execstack))
ifeq ($(run-built-tests),yes)
tests-special += \
$(objpfx)tst-ldconfig-X.out \
$(objpfx)tst-ldconfig-install.out \
$(objpfx)tst-ldconfig-p.out \
$(objpfx)tst-ldconfig-soname.out \
$(objpfx)tst-rtld-help.out \
@@ -734,6 +756,9 @@ one-hundred = $(foreach x,0 1 2 3 4 5 6 7 8 9, \
0$x 1$x 2$x 3$x 4$x 5$x 6$x 7$x 8$x 9$x)
tst-tls-many-dynamic-modules := \
$(foreach n,$(one-hundred),tst-tls-manydynamic$(n)mod)
tst-ldconfig-cache-modules := \
$(foreach n,01 02 03 04 05,tst-tls-manydynamic$(n)mod)
$(objpfx)tst-ldconfig-cache.out: $(tst-ldconfig-cache-modules:%=$(objpfx)%.so)
tst-tls-many-dynamic-modules-dep-suffixes = 0 1 2 3 4 5 6 7 8 9 10 11 12 13 \
14 15 16 17 18 19
tst-tls-many-dynamic-modules-dep = \
@@ -758,7 +783,7 @@ test-extras += \
tst-tlsmod18a \
# test-extras
ifeq (yes,$(have-gcc-ifunc))
ifeq (yesyes,$(have-gcc-ifunc)$(have-ssp))
# The resolver helper needs <tls.h> for the TCB-canary STACK_CHK_GUARD
# macro, so it must be compiled with MODULE_NAME=testsuite_internal.
extra-test-objs += \
@@ -820,6 +845,7 @@ modules-names += \
libtracemod3-1 \
libtracemod4-1 \
libtracemod5-1 \
libtst-origin-secure-mod \
ltglobmod1 \
ltglobmod2 \
neededobj1 \
@@ -1015,6 +1041,7 @@ modules-names += \
tst-nodeps2-mod \
tst-non-directory-mod \
tst-null-argv-lib \
tst-origin-secure-evilmod \
tst-p_alignmod-base \
tst-p_alignmod3 \
tst-ptrguard-static-dlopen-mod \
@@ -1243,6 +1270,17 @@ LDFLAGS-tst-pie-address-static += \
$(load-address-ldflag)=$(pde-load-address)
endif
endif
ifeq (yes,$(enable-static-pie))
tests-static += \
tst-pie-rpath-static \
# tests-static
tests-container += \
tst-pie-rpath-static \
# tests-container
modules-names += \
tst-pie-rpath-mod \
# modules-names
endif
ifeq (yes,$(have-protected-data))
tests += vismain
tests-pie += vismain
@@ -1299,7 +1337,6 @@ tests += \
tst-ifunc-plt-bindnow \
tst-ifunc-plt-dlopen \
tst-ifunc-plt-dlopen-bindnow \
tst-ifunc-resolver-protector \
tst-ifunc-tls-init \
tst-ifunc-tls-init-gd-ld \
tst-ifunc-tls-write \
@@ -1368,7 +1405,6 @@ modules-names += \
ifuncmod6 \
tst-ifunc-plt-dep \
tst-ifunc-plt-lib \
tst-ifunc-resolver-protector-mod \
tst-ifunc-tls-init-gd-global-lib \
tst-ifunc-tls-init-gd-lib \
tst-ifunc-tls-init-ld-lib \
@@ -1377,6 +1413,13 @@ modules-names += \
tst-ifunc-tls-write-lib \
tst-tls-tdata-reloc-lib \
# modules-names
ifeq (yes,$(have-gcc-ifunc))
tests += \
tst-ifunc-fault-dep-bindnow \
tst-ifunc-fault-dep-lazy \
# tests
modules-names += tst-ifunc-fault-mod
endif
ifneq (no,$(have-test-mtls-descriptor))
tests += tst-ifunc-tls-init-tlsdesc
modules-names += tst-ifunc-tls-init-tlsdesc-lib
@@ -1386,6 +1429,10 @@ endif
ifeq (no,$(with-lld))
modules-names += ifuncmod5
endif
ifeq ($(have-ssp),yes)
tests += tst-ifunc-resolver-protector
modules-names += tst-ifunc-resolver-protector-mod
endif
endif
endif
@@ -1406,6 +1453,7 @@ tests-special += \
$(objpfx)check-execstack.out \
$(objpfx)check-initfini.out \
$(objpfx)check-localplt.out \
$(objpfx)check-symbol-version.out \
$(objpfx)check-textrel.out \
$(objpfx)check-wx-segment.out \
# tests-special
@@ -1441,6 +1489,7 @@ ifndef avoid-generated
# Makefile fragment to be included.
define include_dsosort_tests
$(objpfx)$(1).generated-makefile: $(1)
$$(make-target-directory)
$(PYTHON) $(..)scripts/dso-ordering-test.py \
--description-file $$< --objpfx $(objpfx) --output-makefile $$@T
mv $$@T $$@
@@ -1449,6 +1498,7 @@ endef
# Likewise, where the .def file itself is generated.
define include_dsosort_tests_objpfx
$(objpfx)$(1).generated-makefile: $(objpfx)$(1)
$$(make-target-directory)
$(PYTHON) $(..)scripts/dso-ordering-test.py \
--description-file $$< --objpfx $(objpfx) --output-makefile $$@T
mv $$@T $$@
@@ -1467,12 +1517,15 @@ $(eval $(call include_dsosort_tests,dso-sort-tests-1.def))
$(eval $(call include_dsosort_tests,dso-sort-tests-2.def))
$(objpfx)dso-sort-tests-all2.def: dso-sort-tests-all.py
$(make-target-directory)
$(PYTHON) $< 2 > $@
$(objpfx)dso-sort-tests-all3.def: dso-sort-tests-all.py
$(make-target-directory)
$(PYTHON) $< 3 > $@
$(objpfx)dso-sort-tests-all4.def: dso-sort-tests-all.py
$(make-target-directory)
$(PYTHON) $< 4 > $@
$(eval $(call include_dsosort_tests_objpfx,dso-sort-tests-all2.def))
@@ -1550,7 +1603,9 @@ $(objpfx)dl-allobjs.os: $(all-rtld-routines:%=$(objpfx)%.os)
# when compiled for libc.
rtld-stubbed-symbols = \
__libc_assert_fail \
__syscall_cancel \
__libc_single_threaded_internal \
__syscall_cancel_arch \
__syscall_do_cancel \
calloc \
free \
malloc \
@@ -1567,6 +1622,7 @@ endif
# These symbols might be emitted by the compiler when fortify is enabled
# (through builtins).
rtld-stubbed-symbols += \
__GI___chk_fail \
__GI___vfprintf_chk \
__GI___vsprintf_chk \
__GI___vsyslog_chk \
@@ -2344,6 +2400,12 @@ $(objpfx)check-initfini.out: $(..)scripts/check-initfini.awk \
$(evaluate-test)
generated += check-initfini.out
$(objpfx)check-symbol-version.out: $(..)scripts/check-symbol-version.awk \
$(all-built-dso:=.dynsym)
LC_ALL=C $(AWK) -f $^ > $@; \
$(evaluate-test)
generated += check-symbol-version.out
$(objpfx)tst-dlopenrpath: $(objpfx)tst-dlopenrpathmod.so
CFLAGS-tst-dlopenrpath.c += -DPFX=\"$(objpfx)\"
LDFLAGS-tst-dlopenrpathmod.so += -Wl,-rpath,\$$ORIGIN/test-subdir
@@ -2521,6 +2583,27 @@ $(objpfx)tst-ifunc-fault-bindnow.out: $(objpfx)tst-ifunc-fault-bindnow \
$(objpfx)ld.so
$(tst-ifunc-fault-script)
LDFLAGS-tst-ifunc-fault-dep-lazy = -Wl,-z,lazy
LDFLAGS-tst-ifunc-fault-dep-bindnow = -Wl,-z,now
define tst-ifunc-fault-dep-script
( $(test-wrapper) $(rtld-prefix) --verify $< \
&& $(test-wrapper-env) LD_TRACE_LOADED_OBJECTS=1 $(rtld-prefix) $< \
&& $(test-wrapper-env) LD_TRACE_LOADED_OBJECTS=1 LD_DEBUG=unused \
$(rtld-prefix) $< \
&& $(test-wrapper-env) LD_TRACE_LOADED_OBJECTS=1 LD_WARN=yes LD_BIND_NOW=1 \
$(rtld-prefix) $< \
) > $@; $(evaluate-test)
endef
$(objpfx)tst-ifunc-fault-dep-lazy: $(objpfx)tst-ifunc-fault-mod.so
$(objpfx)tst-ifunc-fault-dep-bindnow: $(objpfx)tst-ifunc-fault-mod.so
$(objpfx)tst-ifunc-fault-dep-lazy.out: $(objpfx)tst-ifunc-fault-dep-lazy \
$(objpfx)tst-ifunc-fault-mod.so $(objpfx)ld.so
$(tst-ifunc-fault-dep-script)
$(objpfx)tst-ifunc-fault-dep-bindnow.out: \
$(objpfx)tst-ifunc-fault-dep-bindnow \
$(objpfx)tst-ifunc-fault-mod.so $(objpfx)ld.so
$(tst-ifunc-fault-dep-script)
LDFLAGS-tst-ifunc-plt-lib.so = -Wl,-z,lazy
tst-ifunc-plt-bindnow-ENV = LD_BIND_NOW=1
@@ -2824,6 +2907,11 @@ $(objpfx)tst-ldconfig-X.out : tst-ldconfig-X.sh $(objpfx)ldconfig
'$(run-program-env)' > $@; \
$(evaluate-test)
$(objpfx)tst-ldconfig-install.out : tst-ldconfig-install.sh $(objpfx)ldconfig
$(SHELL) $< '$(common-objpfx)' '$(test-wrapper-env)' \
'$(run-program-env)' > $@; \
$(evaluate-test)
$(objpfx)tst-ldconfig-p.out : tst-ldconfig-p.sh $(objpfx)ldconfig
$(SHELL) $< '$(common-objpfx)' '$(sysconfdir)' '$(test-wrapper-env)' \
'$(run-program-env)' > $@; \
@@ -3115,6 +3203,9 @@ $(objpfx)tst-glibc-hwcaps-cache.out: $(objpfx)tst-glibc-hwcaps
tst-tunables-ARGS = -- $(host-test-program-cmd)
tst-tunables-enable_secure-ARGS = -- $(host-test-program-cmd)
CFLAGS-tst-tunables-seal-static.c += $(CFLAGS-tst-tunables-seal.c)
tst-tunables-seal-static-TUNABLES += $(tst-tunables-seal-TUNABLES)
$(objpfx)list-tunables.out: tst-rtld-list-tunables.sh $(objpfx)ld.so
$(SHELL) $< $(objpfx)ld.so '$(test-wrapper-env)' \
'$(run_program_env)' > $(objpfx)/tst-rtld-list-tunables.out
@@ -3705,3 +3796,30 @@ $(objpfx)tst-dl-debug-exclude.out: tst-dl-debug-exclude.sh \
$(objpfx)tst-recursive-tls > $@; \
$(evaluate-test)
endif
CFLAGS-tst-assert-startup-static.c += $(no-stack-protector)
LDFLAGS-tst-assert-startup-static += -Wl,-z,muldefs
$(objpfx)tst-assert-startup-static.out: $(objpfx)tst-assert-startup-static
$(test-program-cmd-before-env) \
$(run-program-env) \
$< > $@ 2>&1; echo "status: $$?" >> $@; \
grep -q 'Fatal glibc error: tst-assert-startup-static' $@ \
&& grep -q '^status: 134$$' $@; \
$(evaluate-test)
LDFLAGS-tst-pie-rpath-static += -Wl,-rpath,\$$ORIGIN/tst-pie-rpath-static-subdir
$(objpfx)tst-pie-rpath-static.out: $(objpfx)tst-pie-rpath-mod.so
LDFLAGS-libtst-origin-secure-mod.so += -Wl,-soname,libtst-origin-secure-mod.so
LDFLAGS-tst-origin-secure-evilmod.so += -Wl,-soname,libtst-origin-secure-mod.so
$(objpfx)tst-origin-secure-victim: $(objpfx)libtst-origin-secure-mod.so
# The number of "../" here must match the layout invariants described in
# tst-origin-secure.c.
LDFLAGS-tst-origin-secure-victim += \
-Wl,--no-as-needed \
-Wl,-rpath,\$$ORIGIN/sub/../../../../..$(slibdir)/tst-origin-secure \
-Wl,--disable-new-dtags
$(objpfx)tst-origin-secure.out: $(objpfx)tst-origin-secure-victim \
$(objpfx)libtst-origin-secure-mod.so \
$(objpfx)tst-origin-secure-evilmod.so
+106 -2
View File
@@ -36,6 +36,7 @@
#include <dl-cache.h>
#include <version.h>
#include <stringtable.h>
#include <tunconf.h>
/* Used to store library names, paths, and other strings. */
static struct stringtable strings;
@@ -275,7 +276,8 @@ check_new_cache (struct cache_file_new *cache)
/* Print the extension information in *EXT. */
static void
print_extensions (struct cache_extension_all_loaded *ext)
print_extensions (struct cache_extension_all_loaded *ext,
const char *cache_data)
{
if (ext->sections[cache_extension_tag_generator].base != NULL)
{
@@ -284,6 +286,65 @@ print_extensions (struct cache_extension_all_loaded *ext)
ext->sections[cache_extension_tag_generator].size, stdout);
putchar ('\n');
}
if (ext->sections[cache_extension_tag_tunables].base != NULL)
{
struct tunable_header_cached *thc;
struct tunable_entry_cached *tec;
int i, count;
thc = (struct tunable_header_cached *)
ext->sections[cache_extension_tag_tunables].base;
tec = thc->tunables;
count = thc->num_tunables;
printf("tunables sig 0x%08x ver 0x%08x count %u\n",
thc->signature, thc->version, thc->num_tunables);
/* Check that COUNT won't overflow our data block. */
assert (ext->sections[cache_extension_tag_tunables].base
+ ext->sections[cache_extension_tag_tunables].size
== (void *) & tec[count]);
for (i = 0; i < count; ++ i)
{
printf (" [%d] %s = %s [flags 0x%08x (",
i,
cache_data + tec[i].name_offset,
cache_data + tec[i].value_offset,
tec[i].flags);
if (tec[i].flags & TUNCONF_FLAG_PARSED)
printf ("parsed,");
if (tec[i].flags & TUNCONF_FLAG_NEGATIVE)
printf ("negative,");
if ((tec[i].flags & TUNCONF_FLAG_OVERRIDABLE)
== TUNCONF_OVERRIDE_ALLOW)
printf ("overridable");
else
printf ("nonoverridable");
switch (tec[i].flags & (TUNCONF_EXCLUDE_SECURE
| TUNCONF_EXCLUDE_UNSECURE))
{
case TUNCONF_EXCLUDE_SECURE:
printf(",nonsecure");
break;
case TUNCONF_EXCLUDE_UNSECURE:
printf(",onlysecure");
break;
case TUNCONF_EXCLUDE_SECURE | TUNCONF_EXCLUDE_UNSECURE:
printf(",ignore");
break;
case 0:
printf(",anysecure");
break;
}
switch (tec[i].flags & TUNCONF_FLAG_FILTER)
{
case TUNCONF_FILTER_PERPROC:
printf(",[proc]");
break;
}
if (tec[i].flag_offset != 0)
printf (",'%s'", cache_data + tec[i].flag_offset);
printf (")]\n");
}
}
}
/* Print the whole cache file, if a file contains the new cache format
@@ -394,7 +455,7 @@ print_cache (const char *cache_name)
cache_new->libs[i].hwcap, hwcaps_string,
cache_data + cache_new->libs[i].value);
}
print_extensions (&ext);
print_extensions (&ext, cache_data);
}
/* Cleanup. */
munmap (cache, cache_size);
@@ -466,6 +527,18 @@ write_extensions (int fd, uint32_t str_offset,
if (p->used)
hwcaps_array[p->section_index] = str_offset + p->name->offset;
struct tunable_header_cached *tunable_data;
size_t tunable_size;
size_t tunable_aligner = 0;
tunable_data = get_tunconf_ext (str_offset);
if (tunable_data == NULL)
{
/* There is no section for tunables data. */
hwcaps_offset -= sizeof (struct cache_extension_section);
}
/* This is the offset of the generator string. */
uint32_t generator_offset = hwcaps_offset;
if (hwcaps_count == 0)
@@ -498,6 +571,23 @@ write_extensions (int fd, uint32_t str_offset,
ext->sections[xid].size = hwcaps_size;
}
if (tunable_data != NULL)
{
uint32_t tunable_offset_ua;
uint32_t tunable_offset;
tunable_size = TUNCONF_SIZE (tunable_data);
tunable_offset_ua = generator_offset + strlen (generator);
tunable_offset = ALIGN_UP (tunable_offset_ua, 8);
tunable_aligner = tunable_offset - tunable_offset_ua;
++xid;
ext->sections[xid].tag = cache_extension_tag_tunables;
ext->sections[xid].flags = 0;
ext->sections[xid].offset = tunable_offset;
ext->sections[xid].size = tunable_size;
}
++xid;
ext->count = xid;
assert (xid <= cache_extension_count);
@@ -509,6 +599,14 @@ write_extensions (int fd, uint32_t str_offset,
|| write (fd, generator, strlen (generator)) != strlen (generator))
error (EXIT_FAILURE, errno, _("Writing of cache extension data failed"));
if (tunable_data)
{
if (write (fd, " ", tunable_aligner) != tunable_aligner
|| write (fd, tunable_data, tunable_size) != tunable_size)
error (EXIT_FAILURE, errno, _("Writing of cache tunable data failed"));
free (tunable_data);
}
free (hwcaps_array);
free (ext);
}
@@ -1106,3 +1204,9 @@ out_fail:
free (temp_name);
free (file_entries);
}
struct stringtable_entry *
cache_store_string (const char *string)
{
return stringtable_add (&strings, string);
}
+243 -90
View File
@@ -17,6 +17,7 @@
<https://www.gnu.org/licenses/>. */
#include <assert.h>
#include <intprops.h>
#include <unistd.h>
#include <ldsodefs.h>
#include <sys/mman.h>
@@ -26,11 +27,24 @@
#include <_itoa.h>
#include <dl-hwcaps.h>
#include <dl-isa-level.h>
#include <fcntl.h>
#include <sys/stat.h>
#include "tunconf.h"
/* This is the starting address and the size of the mmap()ed file. */
static struct cache_file *cache;
static struct cache_file_new *cache_new;
static size_t cachesize;
#ifdef SHARED
static struct cache_extension_all_loaded ext;
#endif
static struct {
typeof ((*(struct __stat64_t64 *)0).st_mtime) mtime;
typeof ((*(struct __stat64_t64 *)0).st_ino) ino;
typeof ((*(struct __stat64_t64 *)0).st_size) size;
typeof ((*(struct __stat64_t64 *)0).st_dev) dev;
} cache_file_time, new_cache_file_time;
#ifdef SHARED
/* This is used to cache the priorities of glibc-hwcaps
@@ -53,6 +67,7 @@ glibc_hwcaps_priorities_free (void)
free (glibc_hwcaps_priorities);
glibc_hwcaps_priorities = NULL;
glibc_hwcaps_priorities_allocated = 0;
glibc_hwcaps_priorities_length = 0;
}
/* Ordered comparison of a hwcaps string from the cache on the left
@@ -84,10 +99,6 @@ glibc_hwcaps_compare (uint32_t left_index, struct dl_hwcaps_priority *right)
static void
glibc_hwcaps_priorities_init (void)
{
struct cache_extension_all_loaded ext;
if (!cache_extension_load (cache_new, cache, cachesize, &ext))
return;
uint32_t length = (ext.sections[cache_extension_tag_glibc_hwcaps].size
/ sizeof (uint32_t));
if (length > glibc_hwcaps_priorities_allocated)
@@ -374,6 +385,170 @@ _dl_cache_libcmp (const char *p1, const char *p2)
return *p1 - *p2;
}
/* Set the cache back to the "no cache" state, which may include
cleaning up a loaded cache. */
static void
_dl_maybe_unload_ldsocache (void)
{
if (cache != NULL)
__munmap (cache, cachesize);
cache = NULL;
cache_new = NULL;
cachesize = 0;
#ifdef SHARED
glibc_hwcaps_priorities_free ();
#endif
}
/* Returns TRUE if for any reason the cache needs to be reloaded
(including, the first time, loaded). */
static bool
_dl_check_ldsocache_needs_loading (void)
{
int rv;
static bool copy_old_time = 0;
struct __stat64_t64 new_cache_file_stat;
/* Save the previous stat every time. We only care when this
changes, and we only stat it here, so we can get away with doing
the copy now instead of at every single return statement in this
function. However, we only need to copy it if the previous stat
succeeded. The only way this could be subverted is if the admin
moves the file aside, then moves it back, but CACHE would be set
to NULL in the interim so that would be detected. */
if (copy_old_time)
cache_file_time = new_cache_file_time;
rv = __fstatat64_time64 (AT_FDCWD, LD_SO_CACHE, &new_cache_file_stat, 0);
copy_old_time = (rv >= 0);
/* No file to load, but there used to be. Assume user intentionally
deleted the cache and act accordingly. */
if (rv < 0 && cache != NULL)
{
_dl_maybe_unload_ldsocache ();
return false;
}
/* No file to load and no loaded cache, so nothing to do. */
if (rv < 0)
return false;
/* Store the fields we check, in order they're likely to differ. We
must do this even for the first load (CACHE == NULL below), so that
the next call copies an accurate NEW_CACHE_FILE_TIME into
CACHE_FILE_TIME and does not spuriously reload the unchanged cache. */
new_cache_file_time.mtime = new_cache_file_stat.st_mtime;
new_cache_file_time.ino = new_cache_file_stat.st_ino;
new_cache_file_time.size = new_cache_file_stat.st_size;
new_cache_file_time.dev = new_cache_file_stat.st_dev;
/* Any file is better than no file (likely the first time
through). */
if (cache == NULL)
return true;
/* At this point, NEW_CACHE_FILE_TIME is valid as well as
CACHE_FILE_TIME, so we compare them. */
return (memcmp (&new_cache_file_time, &cache_file_time,
sizeof(new_cache_file_time)));
}
/* Attempts to load and validate the cache. On return, CACHE is either
unchanged (still loaded or still not loaded) or valid. */
static void
_dl_maybe_load_ldsocache (void)
{
struct cache_file *tmp_cache = NULL;
struct cache_file_new *tmp_cache_new = NULL;
size_t tmp_cachesize = 0;
/* Read the contents of the file. */
void *file = _dl_sysdep_read_whole_file (LD_SO_CACHE, &tmp_cachesize,
PROT_READ);
/* We can handle three different cache file formats here:
- only the new format
- the old libc5/glibc2.0/2.1 format
- the old format with the new format in it
The following checks if the cache contains any of these formats. */
if (file != MAP_FAILED && tmp_cachesize > sizeof *cache_new
&& memcmp (file, CACHEMAGIC_VERSION_NEW,
sizeof CACHEMAGIC_VERSION_NEW - 1) == 0
/* Check for corruption, avoiding overflow. */
&& ((tmp_cachesize - sizeof *cache_new) / sizeof (struct file_entry_new)
>= ((struct cache_file_new *) file)->nlibs))
{
if (! cache_file_new_matches_endian (file))
{
__munmap (file, tmp_cachesize);
return;
}
tmp_cache_new = file;
tmp_cache = file;
}
else if (file != MAP_FAILED && tmp_cachesize > sizeof *cache
&& memcmp (file, CACHEMAGIC, sizeof CACHEMAGIC - 1) == 0
/* Check for corruption, avoiding overflow. */
&& ((tmp_cachesize - sizeof *cache) / sizeof (struct file_entry)
>= ((struct cache_file *) file)->nlibs))
{
size_t offset;
/* Looks ok. */
tmp_cache = file;
/* Check for new version. */
offset = ALIGN_CACHE (sizeof (struct cache_file)
+ tmp_cache->nlibs * sizeof (struct file_entry));
tmp_cache_new = (struct cache_file_new *) ((void *) tmp_cache + offset);
if (tmp_cachesize < (offset + sizeof (struct cache_file_new))
|| memcmp (tmp_cache_new->magic, CACHEMAGIC_VERSION_NEW,
sizeof CACHEMAGIC_VERSION_NEW - 1) != 0)
tmp_cache_new = NULL;
else
{
if (! cache_file_new_matches_endian (tmp_cache_new))
/* The old-format part of the cache is bogus as well
if the endianness does not match. (But it is
unclear how the new header can be located if the
endianness does not match.) */
{
__munmap (file, tmp_cachesize);
return;
}
}
}
else
{
if (file != MAP_FAILED)
__munmap (file, tmp_cachesize);
return;
}
struct cache_extension_all_loaded tmp_ext;
if (!cache_extension_load (tmp_cache_new, tmp_cache, tmp_cachesize, &tmp_ext))
{
/* The extension is corrupt, so the cache is corrupt. */
__munmap (file, tmp_cachesize);
return;
}
/* If we've gotten here, the loaded cache is good and we need to
save it. */
_dl_maybe_unload_ldsocache ();
cache = tmp_cache;
cache_new = tmp_cache_new;
cachesize = tmp_cachesize;
#ifdef SHARED
ext = tmp_ext;
#endif
assert (cache != NULL);
}
/* Look up NAME in ld.so.cache and return the file name stored there, or null
if none is found. The cache is loaded if it was not already. If loading
@@ -389,81 +564,14 @@ _dl_load_cache_lookup (const char *name)
if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_LIBS))
_dl_debug_printf (" search cache=%s\n", LD_SO_CACHE);
if (_dl_check_ldsocache_needs_loading ())
_dl_maybe_load_ldsocache ();
if (cache == NULL)
{
/* Read the contents of the file. */
void *file = _dl_sysdep_read_whole_file (LD_SO_CACHE, &cachesize,
PROT_READ);
/* We can handle three different cache file formats here:
- only the new format
- the old libc5/glibc2.0/2.1 format
- the old format with the new format in it
The following checks if the cache contains any of these formats. */
if (file != MAP_FAILED && cachesize > sizeof *cache_new
&& memcmp (file, CACHEMAGIC_VERSION_NEW,
sizeof CACHEMAGIC_VERSION_NEW - 1) == 0
/* Check for corruption, avoiding overflow. */
&& ((cachesize - sizeof *cache_new) / sizeof (struct file_entry_new)
>= ((struct cache_file_new *) file)->nlibs))
{
if (! cache_file_new_matches_endian (file))
{
__munmap (file, cachesize);
file = (void *) -1;
}
cache_new = file;
cache = file;
}
else if (file != MAP_FAILED && cachesize > sizeof *cache
&& memcmp (file, CACHEMAGIC, sizeof CACHEMAGIC - 1) == 0
/* Check for corruption, avoiding overflow. */
&& ((cachesize - sizeof *cache) / sizeof (struct file_entry)
>= ((struct cache_file *) file)->nlibs))
{
size_t offset;
/* Looks ok. */
cache = file;
/* Check for new version. */
offset = ALIGN_CACHE (sizeof (struct cache_file)
+ cache->nlibs * sizeof (struct file_entry));
cache_new = (struct cache_file_new *) ((void *) cache + offset);
if (cachesize < (offset + sizeof (struct cache_file_new))
|| memcmp (cache_new->magic, CACHEMAGIC_VERSION_NEW,
sizeof CACHEMAGIC_VERSION_NEW - 1) != 0)
cache_new = (void *) -1;
else
{
if (! cache_file_new_matches_endian (cache_new))
{
/* The old-format part of the cache is bogus as well
if the endianness does not match. (But it is
unclear how the new header can be located if the
endianness does not match.) */
cache = (void *) -1;
cache_new = (void *) -1;
__munmap (file, cachesize);
}
}
}
else
{
if (file != MAP_FAILED)
__munmap (file, cachesize);
cache = (void *) -1;
}
assert (cache != NULL);
}
if (cache == (void *) -1)
/* Previously looked for the cache file and didn't find it. */
return NULL;
const char *best;
if (cache_new != (void *) -1)
if (cache_new != NULL)
{
const char *string_table = (const char *) cache_new;
best = search_cache (string_table, cachesize,
@@ -502,22 +610,67 @@ _dl_load_cache_lookup (const char *name)
return result;
}
#ifndef MAP_COPY
/* If the system does not support MAP_COPY we cannot leave the file open
all the time since this would create problems when the file is replaced.
Therefore we provide this function to close the file and open it again
once needed. */
void
_dl_unload_cache (void)
const struct tunable_header_cached *
_dl_load_cache_tunables (const char **data)
{
if (cache != NULL && cache != (struct cache_file *) -1)
struct cache_extension_all_loaded ext;
struct tunable_header_cached *thc;
struct tunable_entry_cached *tec;
int i, count;
if (_dl_check_ldsocache_needs_loading ())
_dl_maybe_load_ldsocache ();
if (cache_new)
*data = (const char *) cache_new;
else
return NULL;
if (!cache_extension_load (cache_new, cache, cachesize, &ext))
return NULL;
/* Validate length/contents here. */
if (ext.sections[cache_extension_tag_tunables].size
< sizeof(struct tunable_header_cached))
return NULL;
thc = (struct tunable_header_cached *)
ext.sections[cache_extension_tag_tunables].base;
/* Reject data produced by a different tunable cache format. */
if (thc->signature != TUNCONF_SIGNATURE || thc->version != TUNCONF_VERSION)
return NULL;
tec = thc->tunables;
count = thc->num_tunables;
if (ext.sections[cache_extension_tag_tunables].base
+ ext.sections[cache_extension_tag_tunables].size
!= (void *) & tec[count])
return NULL;
/* Validate each entry. The string table lies between the file entries
and the end of the mapping; clamp its end to CACHESIZE so that a bogus
len_strings cannot make an offset point outside the mapped file. */
size_t s_start = (const char *) (&cache_new->libs[cache_new->nlibs]) - *data;
size_t s_end;
if (s_start >= cachesize
|| INT_ADD_WRAPV (s_start, cache_new->len_strings, &s_end))
return NULL;
if (s_end > cachesize)
s_end = cachesize;
for (i = 0; i < count; i ++)
{
__munmap (cache, cachesize);
cache = NULL;
if (thc->tunables[i].name_offset < s_start
|| thc->tunables[i].name_offset >= s_end
|| thc->tunables[i].value_offset < s_start
|| thc->tunables[i].value_offset >= s_end)
return NULL;
if (thc->tunables[i].flag_offset != 0
&& (thc->tunables[i].flag_offset < s_start
|| thc->tunables[i].flag_offset >= s_end))
return NULL;
}
#ifdef SHARED
/* This marks the glibc_hwcaps_priorities array as out-of-date. */
glibc_hwcaps_priorities_length = 0;
#endif
return thc;
}
#endif
+28 -59
View File
@@ -34,6 +34,7 @@
#include <gnu/lib-names.h>
#include <dl-tunables.h>
#include <dl-scratch-buffer.h>
#include <dl-path-normalize.h>
#include "dynamic-link.h"
#include "get-dynamic-info.h"
@@ -91,67 +92,30 @@ static const size_t system_dirs_len[] =
};
#define nsystem_dirs_len array_length (system_dirs_len)
/* Return true if the normalized path NPATH of length NLEN is rooted in one of
the trusted system directories. The system_dirs entries carry a trailing
'/'; NPATH matches an entry when it shares the entry's leading component
sequence and then either ends or continues with '/'. For instance,
"/lib64" and "/lib64/x" match "/lib64/" but "/lib64x" does not. */
static bool
is_trusted_path_normalize (const char *path, size_t len)
path_is_trusted (const char *npath, size_t nlen)
{
if (len == 0)
return false;
struct dl_scratch_buffer scratch = dl_scratch_buffer_init ();
dl_scratch_buffer_allocate (&scratch, len + 2, 0);
char *npath = scratch.data;
char *wnp = npath;
while (*path != '\0')
{
if (path[0] == '/')
{
if (path[1] == '.')
{
if (path[2] == '.' && (path[3] == '/' || path[3] == '\0'))
{
while (wnp > npath && *--wnp != '/')
;
path += 3;
continue;
}
else if (path[2] == '/' || path[2] == '\0')
{
path += 2;
continue;
}
}
if (wnp > npath && wnp[-1] == '/')
{
++path;
continue;
}
}
*wnp++ = *path++;
}
if (wnp == npath || wnp[-1] != '/')
*wnp++ = '/';
bool result = false;
const char *trun = system_dirs;
for (size_t idx = 0; idx < nsystem_dirs_len; ++idx)
{
if (wnp - npath >= system_dirs_len[idx]
&& memcmp (trun, npath, system_dirs_len[idx]) == 0)
{
/* Found it. */
result = true;
break;
}
/* Compare against the entry without its trailing '/'. */
size_t dirlen = system_dirs_len[idx] - 1;
if (nlen >= dirlen
&& memcmp (trun, npath, dirlen) == 0
&& (npath[dirlen] == '/' || npath[dirlen] == '\0'))
return true;
trun += system_dirs_len[idx] + 1;
}
dl_scratch_buffer_free (&scratch);
return result;
return false;
}
/* Given a substring starting at INPUT, just after the DST '$' start
@@ -335,16 +299,21 @@ _dl_dst_substitute (struct link_map *l, const char *input, char *result)
checked for trust, the authors of the binaries themselves are
trusted to have designed this correctly. Only $ORIGIN is tested in
this way because it may be manipulated in some ways with hard
links. */
if (__glibc_unlikely (check_for_trusted)
&& !is_trusted_path_normalize (result, wp - result))
{
*result = '\0';
return result;
}
links.
_dl_normalize_path replaces the expansion with its normalized form
in place, so that the path that is opened is exactly the path that
was validated. */
*wp = '\0';
if (__glibc_unlikely (check_for_trusted))
{
size_t nlen = _dl_normalize_path (result);
if (!path_is_trusted (result, nlen))
*result = '\0';
}
return result;
}
@@ -1319,7 +1288,7 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd,
if (l->l_ld != NULL)
l->l_ld = (ElfW(Dyn) *) ((ElfW(Addr)) l->l_ld + l->l_addr);
elf_get_dynamic_info (l, false, false);
elf_get_dynamic_info (l, false);
/* Make sure we are not dlopen'ing an object that has the
DF_1_NOOPEN flag set, or a PIE object. */
-8
View File
@@ -163,14 +163,6 @@ __libc_fatal (const char *message)
}
rtld_hidden_def (__libc_fatal)
void
__attribute__ ((noreturn))
__chk_fail (void)
{
_exit (127);
}
rtld_hidden_def (__chk_fail)
#ifndef NDEBUG
/* Define (weakly) our own assert failure function which doesn't use stdio.
If we are linked into the user program (-ldl), the normal __assert_fail
+19 -62
View File
@@ -367,53 +367,6 @@ resize_tls_slotinfo (struct link_map *new)
return any_tls;
}
/* Second stage of TLS update, after resize_tls_slotinfo. This
function does not raise any exception. It should only be called if
resize_tls_slotinfo returned true. */
static void
update_tls_slotinfo (struct link_map *new)
{
for (unsigned int i = 0; i < new->l_searchlist.r_nlist; ++i)
_dl_add_to_slotinfo (new->l_searchlist.r_list[i], true);
size_t newgen = GL(dl_tls_generation) + 1;
if (__glibc_unlikely (newgen == 0))
_dl_fatal_printf (N_("\
TLS generation counter wrapped! Please report this."));
/* Can be read concurrently. */
atomic_store_release (&GL(dl_tls_generation), newgen);
/* We need a second pass for static tls data, because
_dl_update_slotinfo must not be run while calls to
_dl_add_to_slotinfo are still pending. */
for (unsigned int i = 0; i < new->l_searchlist.r_nlist; ++i)
{
struct link_map *imap = new->l_searchlist.r_list[i];
if (imap->l_need_tls_init && imap->l_tls_blocksize > 0)
{
/* For static TLS we have to allocate the memory here and
now, but we can delay updating the DTV. */
imap->l_need_tls_init = 0;
#ifdef SHARED
/* Update the slot information data for the current
generation. */
/* FIXME: This can terminate the process on memory
allocation failure. It is not possible to raise
exceptions from this context; to fix this bug,
_dl_update_slotinfo would have to be split into two
operations, similar to resize_scopes and update_scopes
above. This is related to bug 16134. */
_dl_update_slotinfo (imap->l_tls_modid, newgen);
#endif
_dl_init_static_tls (imap);
assert (imap->l_need_tls_init == 0);
}
}
}
/* Mark the objects as NODELETE if required. This is delayed until
after dlopen failure is not possible, so that _dl_close can clean
up objects if necessary. */
@@ -671,17 +624,26 @@ dl_open_worker_begin (void *a)
if (mode & RTLD_GLOBAL)
add_to_global_resize (new);
/* Install the new modules in the DTV slotinfo and initialise their
static TLS *before* relocation, so an IFUNC resolver firing during
the relocation loop below can reach its DSO's __thread storage via
__tls_get_addr / TLSDESC. Without this, the resolver's TLS access
for a just-loaded module would index into an unallocated DTV slot
and crash. If relocation later fails, the subsequent _dl_close_worker
cleans up these slotinfo entries via remove_slotinfo. */
/* Register the new modules in the DTV slotinfo and bump the TLS
generation counter *before* relocation, so an IFUNC resolver firing
during the relocation loop below can reach its DSO's __thread storage
via __tls_get_addr / TLSDESC. Without this, the new module is not yet
in GL(dl_tls_dtv_slotinfo_list), so the resolver's dynamic-TLS lookup
fails to find it and faults. The static-TLS image itself is copied
lazily on first access, and if relocation later fails, the subsequent
_dl_close_worker cleans up these slotinfo entries via remove_slotinfo. */
if (any_tls)
/* FIXME: This calls _dl_update_slotinfo, which aborts the process
on memory allocation failure. See bug 16134. */
update_tls_slotinfo (new);
{
for (unsigned int i = 0; i < new->l_searchlist.r_nlist; ++i)
_dl_add_to_slotinfo (new->l_searchlist.r_list[i], true);
size_t newgen = GL(dl_tls_generation) + 1;
if (__glibc_unlikely (newgen == 0))
_dl_fatal_printf (N_("\
TLS generation counter wrapped! Please report this."));
/* Can be read concurrently. */
atomic_store_release (&GL(dl_tls_generation), newgen);
}
/* Perform relocation. This can trigger lazy binding in IFUNC
resolvers. For NODELETE mappings, these dependencies are not
@@ -898,11 +860,6 @@ no more namespaces available for dlmopen()"));
struct dl_exception exception;
int errcode = _dl_catch_exception (&exception, dl_open_worker, &args);
#if defined USE_LDCONFIG && !defined MAP_COPY
/* We must unmap the cache file. */
_dl_unload_cache ();
#endif
/* Do this for both the error and success cases. The old value has
only been determined if the namespace ID was assigned (i.e., it
is not __LM_ID_CALLER). In the success case, we actually may
+118
View File
@@ -0,0 +1,118 @@
/* In-place lexical path normalization for the dynamic loader.
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/>. */
#ifndef _DL_PATH_NORMALIZE_H
#define _DL_PATH_NORMALIZE_H
#include <stddef.h>
#include <string.h>
/* Lexically normalize the null-terminated PATH in place and return the
length of the result (excluding the terminating NUL byte):
- Runs of '/' are collapsed to a single '/'.
- "." components are removed.
- A ".." component removes the preceding component if there is one and it
is not itself a preserved "..". In an absolute path a surplus ".." at
the root is dropped ("/../a" normalizes to "/a"), in a relative path
leading ".." components are preserved ("../a" stays "../a", "a/../../b"
normalizes to "../b").
- The result has no trailing '/' except for the root path "/" itself
("/a/" normalizes to "/a").
- The result is empty if and only if every component cancels or is removed
("", ".", "a/.." all normalize to "").
The PATH is written in place, and the internal write cursor never runs
ahead of the read cursor. Only bytes within the strlen (PATH) + 1 storage
are accessed. */
static inline size_t
_dl_normalize_path (char *path)
{
/* The root '/' of an absolute path is not removed. */
char *pstart = path + (path[0] == '/');
const char *rnp = pstart;
char *wnp = pstart;
/* End of the prefix a ".." may not remove. Either the root '/', or, for
relative paths, the original start of the string extended by any
preserved leading ".." components. */
char *limit = pstart;
while (*rnp != '\0')
{
/* Collapse consecutive separators. */
if (*rnp == '/')
{
++rnp;
continue;
}
/* [RNP, REND) is the next input component. */
const char *rend = rnp;
while (*rend != '\0' && *rend != '/')
++rend;
size_t clen = rend - rnp;
/* Drop '.' component. */
if (clen == 1 && rnp[0] == '.')
;
else if (clen == 2 && rnp[0] == '.' && rnp[1] == '.')
{
if (wnp > limit)
{
/* Remove the last component along with the '/' separating it
from its predecessor (the root '/' of an absolute path is
retained). */
while (wnp > limit && wnp[-1] != '/')
--wnp;
if (wnp > pstart)
--wnp;
}
else if (pstart == path)
{
/* No component is left and the original path is relative:
keep the unresolvable ".." (it becomes part of the
preserved prefix). */
if (wnp > pstart)
*wnp++ = '/';
*wnp++ = '.';
*wnp++ = '.';
limit = wnp;
}
/* Otherwise the path is absolute and the surplus ".." at the
root is dropped ("/../a" normalizes to "/a"). */
}
else
{
if (wnp > pstart)
*wnp++ = '/';
memmove (wnp, rnp, clen);
wnp += clen;
}
rnp = rend;
}
*wnp = '\0';
return wnp - path;
}
#endif /* _DL_PATH_NORMALIZE_H */
+10 -4
View File
@@ -72,15 +72,19 @@ _dl_relocate_static_pie (void)
/* Read our own dynamic section and fill in the info array. */
main_map->l_ld = ((void *) l_addr + elf_machine_dynamic ());
elf_get_dynamic_info (main_map, false, true);
elf_get_dynamic_info (main_map, false);
# ifdef ELF_MACHINE_BEFORE_RTLD_RELOC
ELF_MACHINE_BEFORE_RTLD_RELOC (main_map, main_map->l_info);
# endif
/* Relocate ourselves so we can do normal function calls and data access
using the global offset table. IRELATIVE entries are deferred. */
ELF_DYNAMIC_RELOCATE_NOIFUNC (main_map, NULL, 0, 0);
using the global offset table. IRELATIVE entries are deferred.
Lazy binding is never used here, so edr_lazy comes back as 0 and the
deferred pass can hardcode the same value. */
int edr_lazy = 0;
ELF_DYNAMIC_RELOCATE_PASS (DL_RELOC_NORMAL, main_map, NULL, edr_lazy,
0, 0);
/* Initialize _r_debug_extended. */
struct r_debug *r = _dl_debug_initialize (0, LM_ID_BASE);
@@ -98,7 +102,9 @@ void
_dl_relocate_static_pie_ifunc (void)
{
struct link_map *main_map = _dl_get_dl_main_map ();
ELF_DYNAMIC_RELOCATE_IFUNC (main_map, NULL, 0, 0);
int edr_lazy = 0;
ELF_DYNAMIC_RELOCATE_PASS (DL_RELOC_IRELATIVE, main_map, NULL, edr_lazy,
0, 0);
main_map->l_relocated = 1;
}
#endif
+103 -42
View File
@@ -37,6 +37,47 @@
#endif
/* Return the number of bytes that would be allocated in the static
TLS block for MAP. If the available space is insufficient, return a
value greater than the available space to indicate failure. OFFSET_OUT
is updated with the TLS offset of the map. */
static inline size_t
__attribute__ ((always_inline))
_dl_static_tls_allocation (struct link_map *map, size_t *offset_out)
{
#if TLS_TCB_AT_TP
size_t freebytes = GLRO(dl_tls_static_size) - GL(dl_tls_static_used);
if (freebytes < TLS_TCB_SIZE)
return TLS_TCB_SIZE + map->l_tls_blocksize;
freebytes -= TLS_TCB_SIZE;
size_t blsize = map->l_tls_blocksize + map->l_tls_firstbyte_offset;
if (freebytes < blsize)
return TLS_TCB_SIZE + blsize;
size_t n = (freebytes - blsize) / map->l_tls_align;
/* Account optional static TLS surplus usage. */
size_t use = freebytes - n * map->l_tls_align - map->l_tls_firstbyte_offset;
*offset_out = GL(dl_tls_static_used) + use;
return use;
#elif TLS_DTV_AT_TP
/* dl_tls_static_used includes the TCB at the beginning. */
size_t offset = (ALIGN_UP(GL(dl_tls_static_used)
- map->l_tls_firstbyte_offset,
map->l_tls_align)
+ map->l_tls_firstbyte_offset);
size_t used = offset + map->l_tls_blocksize;
/* Account optional static TLS surplus usage. */
size_t use = used - GL(dl_tls_static_used);
*offset_out = offset;
return use;
#else
# error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined"
#endif
}
/* We are trying to perform a static TLS relocation in MAP, but it was
dynamically loaded. This can only work if there is enough surplus in
the static TLS area already allocated for each running thread. If this
@@ -54,57 +95,30 @@ _dl_try_allocate_static_tls (struct link_map *map, bool optional)
/* If we've already used the variable with dynamic access, or if the
alignment requirements are too high, fail. */
if (map->l_tls_offset == FORCED_DYNAMIC_TLS_OFFSET
|| map->l_tls_align > GLRO (dl_tls_static_align))
|| map->l_tls_align > GLRO(dl_tls_static_align))
{
fail:
return -1;
}
#if TLS_TCB_AT_TP
size_t freebytes = GLRO (dl_tls_static_size) - GL(dl_tls_static_used);
if (freebytes < TLS_TCB_SIZE)
goto fail;
freebytes -= TLS_TCB_SIZE;
size_t offset = 0;
size_t use = _dl_static_tls_allocation (map, &offset);
size_t blsize = map->l_tls_blocksize + map->l_tls_firstbyte_offset;
if (freebytes < blsize)
goto fail;
size_t n = (freebytes - blsize) / map->l_tls_align;
/* Account optional static TLS surplus usage. */
size_t use = freebytes - n * map->l_tls_align - map->l_tls_firstbyte_offset;
if (optional && use > GL(dl_tls_static_optional))
goto fail;
else if (optional)
GL(dl_tls_static_optional) -= use;
size_t offset = GL(dl_tls_static_used) + use;
map->l_tls_offset = GL(dl_tls_static_used) = offset;
#elif TLS_DTV_AT_TP
/* dl_tls_static_used includes the TCB at the beginning. */
size_t offset = (ALIGN_UP(GL(dl_tls_static_used)
- map->l_tls_firstbyte_offset,
map->l_tls_align)
+ map->l_tls_firstbyte_offset);
size_t used = offset + map->l_tls_blocksize;
if (used > GLRO (dl_tls_static_size))
if (use > GLRO(dl_tls_static_size) - GL(dl_tls_static_used))
goto fail;
/* Account optional static TLS surplus usage. */
size_t use = used - GL(dl_tls_static_used);
if (optional && use > GL(dl_tls_static_optional))
goto fail;
else if (optional)
GL(dl_tls_static_optional) -= use;
map->l_tls_offset = offset;
#if TLS_TCB_AT_TP
GL(dl_tls_static_used) = offset;
#elif TLS_DTV_AT_TP
map->l_tls_firstbyte_offset = GL(dl_tls_static_used);
GL(dl_tls_static_used) = used;
#else
# error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined"
GL(dl_tls_static_used) = offset + map->l_tls_blocksize;
#endif
/* Initialise the static TLS region, the map may not yet be l_relocated (a
@@ -131,13 +145,57 @@ _dl_try_allocate_static_tls (struct link_map *map, bool optional)
not be inlined as much as possible. */
void
__attribute_noinline__
_dl_allocate_static_tls (struct link_map *map)
_dl_allocate_static_tls (struct link_map *map, struct link_map *sym_map,
const ElfW(Sym) *sym)
{
if (map->l_tls_offset == FORCED_DYNAMIC_TLS_OFFSET
|| _dl_try_allocate_static_tls (map, false))
if (sym_map->l_tls_offset == FORCED_DYNAMIC_TLS_OFFSET
|| _dl_try_allocate_static_tls (sym_map, false))
{
_dl_signal_error (0, map->l_name, NULL, N_("\
cannot allocate memory in static TLS block"));
const char *symname = "unknown";
const char *def_map_info = "";
const char *def_map_name = "";
struct dl_exception exception;
if (sym != NULL)
{
const char *strtab
= (const char *) D_PTR (sym_map, l_info[DT_STRTAB]);
symname = strtab + sym->st_name;
if (symname[0] == '\0')
symname = "unknown";
}
if (sym_map != map)
{
def_map_info = " defined in ";
def_map_name = DSO_FILENAME (sym_map->l_name);
}
if (sym_map->l_tls_offset == FORCED_DYNAMIC_TLS_OFFSET)
{
/* XXX We cannot translate the message. */
_dl_exception_create_format (
&exception, DSO_FILENAME (map->l_name),
"cannot allocate memory in static TLS block: "
"%s%s%s: previously used as global-dynamic",
symname, def_map_info, def_map_name);
}
else
{
size_t offset = 0;
size_t requested = _dl_static_tls_allocation (sym_map, &offset);
size_t available
= (GLRO(dl_tls_static_size) - GL(dl_tls_static_used));
/* XXX We cannot translate the message. */
_dl_exception_create_format (
&exception, DSO_FILENAME (map->l_name),
"cannot allocate memory in static TLS block: "
"%s%s%s: requested %zx, available %zx",
symname, def_map_info, def_map_name, requested, available);
}
_dl_signal_exception (0, &exception, N_("TLS allocation error"));
}
}
@@ -278,7 +336,9 @@ _dl_relocate_object_no_relro (struct link_map *l, struct r_scope_elem *scope[],
IFUNC resolvers. Without this, a resolver would see the unrelocated
initialiser bytes that were placed into the slot by the early
_dl_allocate_tls_init. */
ELF_DYNAMIC_RELOCATE_NOIFUNC (l, scope, lazy, consider_profiling);
int edr_lazy = lazy;
ELF_DYNAMIC_RELOCATE_PASS (DL_RELOC_NORMAL, l, scope, edr_lazy,
consider_profiling, skip_ifunc);
#ifdef SHARED
/* Re-initialise the static TLS slot with the .tdata so the IRELATIVE
@@ -291,7 +351,8 @@ _dl_relocate_object_no_relro (struct link_map *l, struct r_scope_elem *scope[],
_dl_init_static_tls (l);
#endif
ELF_DYNAMIC_RELOCATE_IFUNC (l, scope, lazy, skip_ifunc);
ELF_DYNAMIC_RELOCATE_PASS (DL_RELOC_IRELATIVE, l, scope, edr_lazy,
0, skip_ifunc);
if ((consider_profiling || consider_symbind)
&& l->l_info[DT_PLTRELSZ] != NULL)
+1 -1
View File
@@ -303,7 +303,7 @@ _dl_sort_maps (struct link_map **maps, unsigned int nmaps,
PTR_MANGLE/DEMANGLE, further impairing performance of small, common
input cases. A simple if-case with direct function calls appears to
be the fastest. */
if (__glibc_likely (GLRO(dl_dso_sort_algo) == dso_sort_algorithm_original))
if (GLRO(dl_dso_sort_algo) == dso_sort_algorithm_original)
_dl_sort_maps_original (maps, nmaps, force_first, for_fini);
else
_dl_sort_maps_dfs (maps, nmaps, force_first, for_fini);
+2 -2
View File
@@ -33,10 +33,10 @@
&& ((sym_map)->l_tls_offset \
!= FORCED_DYNAMIC_TLS_OFFSET), 1))
#define CHECK_STATIC_TLS(map, sym_map) \
#define CHECK_STATIC_TLS(map, sym_map, sym) \
do { \
if (!HAVE_STATIC_TLS (map, sym_map)) \
_dl_allocate_static_tls (sym_map); \
_dl_allocate_static_tls (map, sym_map, sym); \
} while (0)
#define TRY_STATIC_TLS(map, sym_map) \
+3 -6
View File
@@ -697,17 +697,14 @@ _dl_allocate_tls_init (void *result, bool main_thread)
For audit modules or dependencies with initial-exec TLS,
we can not set the initial TLS image on default loader
initialization because it would already be set by the
audit setup, which uses the dlopen code and already
clears l_need_tls_init. Calls with !main_thread from
pthread_create need to initialize TLS for the current
thread regardless of namespace. */
audit setup, which uses the dlopen code. Calls with
!main_thread from pthread_create need to initialize TLS
for the current thread regardless of namespace. */
if (map->l_ns != LM_ID_BASE && main_thread)
continue;
memset (__mempcpy (dest, map->l_tls_initimage,
map->l_tls_initimage_size), '\0',
map->l_tls_blocksize - map->l_tls_initimage_size);
if (main_thread)
map->l_need_tls_init = 0;
}
total += cnt;
+2 -14
View File
@@ -42,20 +42,6 @@ typedef struct
tunable_num_t max;
} tunable_type_t;
/* Security level for tunables. This decides what to do with individual
tunables for AT_SECURE binaries. */
typedef enum
{
/* Erase the tunable for AT_SECURE binaries so that child processes don't
read it. */
TUNABLE_SECLEVEL_SXID_ERASE = 0,
/* Ignore the tunable for AT_SECURE binaries, but don't erase it, so that
child processes can read it. */
TUNABLE_SECLEVEL_SXID_IGNORE = 1,
/* Read the tunable. */
TUNABLE_SECLEVEL_NONE = 2,
} tunable_seclevel_t;
/* A tunable. */
struct _tunable
{
@@ -65,6 +51,8 @@ struct _tunable
tunable_val_t val; /* The value. */
bool initialized; /* Flag to indicate that the tunable is
initialized. */
bool locked; /* If set, modifications are not
allowed. */
/* Compatibility elements. */
const char env_alias[TUNABLE_ALIAS_MAX]; /* The compatibility environment
variable name. */
+215 -3
View File
@@ -37,6 +37,7 @@
#define TUNABLES_INTERNAL 1
#include "dl-tunables.h"
#include "tunconf.h"
static char **
get_next_env (char **envp, char **name, char **val, char ***prev_envp)
@@ -64,6 +65,17 @@ get_next_env (char **envp, char **name, char **val, char ***prev_envp)
return NULL;
}
/* Set by __tunable_seal_strings once the values of the string tunables are
no longer valid. */
static bool tunables_strings_sealed attribute_relro;
static void __attribute__ ((noreturn))
tunable_sealed_error (const tunable_t *cur, const char *action)
{
_dl_fatal_printf ("Fatal glibc error: %s: string tunable %s after "
"process initialization\n", cur->name, action);
}
static void
do_tunable_update_val (tunable_t *cur, const tunable_val_t *valp,
const tunable_num_t *minp,
@@ -71,9 +83,14 @@ do_tunable_update_val (tunable_t *cur, const tunable_val_t *valp,
{
tunable_num_t val, min, max;
if (cur->locked)
return;
switch (cur->type.type_code)
{
case TUNABLE_TYPE_STRING:
if (__glibc_unlikely (tunables_strings_sealed))
tunable_sealed_error (cur, "set");
cur->val.strval = valp->strval;
cur->initialized = true;
return;
@@ -175,6 +192,14 @@ struct tunable_toset_t
enum { tunables_list_size = array_length (tunable_list) };
/* Records tunables that were set from GLIBC_TUNABLES during this call, so
that a legacy environment-variable alias does not override them (the
canonical GLIBC_TUNABLES form takes precedence over the aliases).
A tunable that was set only from the system-wide cache is deliberately not
recorded here, so an alias may still override an overridable cache default;
a nonoverridable one remains protected by tunable_t::locked. */
static bool tunable_set_by_env[tunables_list_size];
/* Parse the tunable string VALSTRING and set TUNABLES with the found tunables
and their respective values. The VALSTRING is parsed in place, with the
tunable start and size recorded in TUNABLES.
@@ -284,6 +309,10 @@ parse_tunables (const char *valstring)
if (!tunable_initialize (tunables[i].t, tunables[i].value,
tunables[i].len))
parse_tunable_print_error (&tunables[i]);
else
/* GLIBC_TUNABLES set this tunable; a legacy alias must not
override it. */
tunable_set_by_env[i] = true;
}
}
@@ -291,7 +320,7 @@ parse_tunables (const char *valstring)
ENV_ALIAS to find values. Later we will also use the tunable names to find
values. */
void
__tunables_init (char **envp)
__tunables_init (char **envp, char **argv)
{
char *envname = NULL;
char *envval = NULL;
@@ -302,6 +331,155 @@ __tunables_init (char **envp)
if (MALLOC_DEFAULT_THP_PAGESIZE > 0)
TUNABLE_SET (glibc, malloc, hugetlb, 1);
#if defined(SHARED) && defined (USE_LDCONFIG)
const char *prog_name = (argv && argv[0]) ? argv[0] : "";
int prog_name_len = -1;
const char *base_name = NULL;
#ifdef PATH_MAX
char exebuf[PATH_MAX];
#else
char exebuf[256];
#endif
const struct tunable_header_cached *thc;
const char *td;
thc = _dl_load_cache_tunables (&td);
if (thc != NULL)
{
for (int t = 0; t < thc->num_tunables; ++ t)
{
const struct tunable_entry_cached *tec = &( thc->tunables[t] );
int tid = tec->tunable_id;
const char *name = td + tec->name_offset;
const char *value = td + tec->value_offset;
/* Check that we have the correct tunable, and search by
name if needed. We rely on order of operations here to
avoid mis-indexing tunables[]. */
if (tid < 0 || tid >= tunables_list_size
|| strcmp (name, tunable_list[tid].name) != 0)
{
/* It does not, search by name instead. */
tid = -1;
for (int i = 0; i < tunables_list_size; i++)
{
if (strcmp (name, tunable_list[i].name) == 0)
{
tid = i;
break;
}
}
if (tid == -1)
continue;
}
/* At this point, TID is valid for the tunable we want. */
if (tec->flags & TUNCONF_EXCLUDE_SECURE && __libc_enable_secure)
goto skip_due_to_filter;
if (tec->flags & TUNCONF_EXCLUDE_UNSECURE && !__libc_enable_secure)
goto skip_due_to_filter;
/* Apply selected filter, if any. */
switch (tec->flags & TUNCONF_FLAG_FILTER) {
case TUNCONF_FILTER_NONE:
break;
case TUNCONF_FILTER_PERPROC:
/* Perform one-time calculations that aren't needed if we
don't use this filter. */
if (prog_name_len == -1)
{
ssize_t n = readlink ("/proc/self/exe",
exebuf, sizeof (exebuf) - 1);
if (n > 0 && n < sizeof(exebuf)-1)
{
/* If /proc/self/exe exists and we can read it,
it's more reliable than argv[] so use it. */
exebuf[n] = '\0';
prog_name = exebuf;
}
else if (__libc_enable_secure)
prog_name = NULL;
if (prog_name != NULL)
{
const char *slash = NULL, *cp;
for (cp = prog_name; *cp; ++ cp)
if (*cp == '/')
slash = cp;
if (slash)
base_name = slash + 1;
else
base_name = prog_name;
prog_name_len = strlen (prog_name);
}
}
/* prog_name and the cached string are both NUL terminated. */
if (prog_name)
{
if (((const char *)(td + tec->flag_offset))[0] == '/')
{
if (strcmp (prog_name, td + tec->flag_offset) != 0)
goto skip_due_to_filter;
}
else
{
if (strcmp (base_name, td + tec->flag_offset) != 0)
goto skip_due_to_filter;
}
}
else
/* Program is AT_SECURE but the only source of program
name is argv[0], which is not secure, so we do not
match any name-based filter. */
goto skip_due_to_filter;
break;
default:
/* Unknown filter. */
goto skip_due_to_filter;
}
/* If the tunable is set here, any previously set
overridability flag is discarded. We need to reset the
overridability flag here so we can change the tunable,
and may set it later if this tunable also locks it. */
tunable_list[tid].locked = false;
/* See if the parsed type matches the desired type. */
if (tunable_list[tid].type.type_code == TUNABLE_TYPE_STRING)
{
/* This is a memory leak but there's no easy way around
it, as the mapping will go away if the disk file is
updated and the cache is reloaded. */
tunable_list[tid].val.strval.str = __strdup (value);
tunable_list[tid].val.strval.len = strlen (value);
tunable_list[tid].initialized = true;
}
else
{
tunable_val_t tval;
if (tec->flags & TUNCONF_FLAG_PARSED)
{
tval.numval = tec->parsed_value;
do_tunable_update_val (& tunable_list[tid],
&tval, NULL, NULL);
}
else
{
tunable_initialize (& tunable_list[tid],
value, strlen (value));
}
}
/* The overriability flag only applies to tunables
which aren't filtered out. */
if ((tec->flags & TUNCONF_FLAG_OVERRIDABLE)
== TUNCONF_OVERRIDE_DENY)
tunable_list[tid].locked = true;
skip_due_to_filter:;
}
}
#endif /* defined(SHARED) && defined (USE_LDCONFIG) */
/* Ignore tunables for AT_SECURE programs. */
if (__libc_enable_secure)
return;
@@ -345,9 +523,13 @@ __tunables_init (char **envp)
for (int i = 0; i < tunable_num_env_alias; i++)
{
/* Skip over tunables that have either been set or already initialized. */
/* Skip aliases whose tunable was already set through GLIBC_TUNABLES,
which takes precedence over the alias. A value coming only from the
system-wide cache does not block the alias here: an overridable cache
default may still be overridden, while a nonoverridable one is
protected by tunable_t::locked. */
if (tunables_env_alias[i].t == NULL
|| tunables_env_alias[i].t->initialized)
|| tunable_set_by_env[tunable_env_alias_list[i]])
continue;
if (!tunable_initialize (tunables_env_alias[i].t,
@@ -460,6 +642,10 @@ __tunable_get_val (tunable_id_t id, void *valp, tunable_callback_t callback)
}
case TUNABLE_TYPE_STRING:
{
/* String tunable values are only valid during early startup; once
sealed they must not be read. */
if (__glibc_unlikely (tunables_strings_sealed))
tunable_sealed_error (cur, "read");
*((const struct tunable_str_t **) valp) = &cur->val.strval;
break;
}
@@ -472,3 +658,29 @@ __tunable_get_val (tunable_id_t id, void *valp, tunable_callback_t callback)
}
rtld_hidden_def (__tunable_get_val)
/* A string tunable value usually references the GLIBC_TUNABLES (or alias)
environment string, which lives in the environment block the kernel places
on the initial stack. That memory is owned by the application, which may
overwrite it (e.g. setproctitle), so the reference is only safe while no
application code has run.
A value coming from the system-wide cache is a private copy instead, but
it is sealed as well so that the lifetime rule does not depend on where
the value came from.
Drop the references so that a later access triggers a fatal error. */
void
__tunable_seal_strings (void)
{
for (int i = 0; i < tunables_list_size; i++)
{
tunable_t *cur = &tunable_list[i];
if (cur->type.type_code != TUNABLE_TYPE_STRING)
continue;
cur->val.strval = (struct tunable_str_t) { NULL, 0 };
}
tunables_strings_sealed = true;
}
rtld_hidden_def (__tunable_seal_strings)
+3 -1
View File
@@ -47,19 +47,21 @@ typedef void (*tunable_callback_t) (tunable_val_t *);
#include "dl-tunable-list.h"
extern void __tunables_init (char **);
extern void __tunables_init (char **, char **);
extern void __tunables_print (void);
extern bool __tunable_is_initialized (tunable_id_t);
extern void __tunable_get_val (tunable_id_t, void *, tunable_callback_t);
extern void __tunable_set_val (tunable_id_t, tunable_val_t *, tunable_num_t *,
tunable_num_t *);
extern void __tunable_get_default (tunable_id_t id, void *valp);
extern void __tunable_seal_strings (void);
rtld_hidden_proto (__tunables_init)
rtld_hidden_proto (__tunables_print)
rtld_hidden_proto (__tunable_is_initialized)
rtld_hidden_proto (__tunable_get_val)
rtld_hidden_proto (__tunable_set_val)
rtld_hidden_proto (__tunable_get_default)
rtld_hidden_proto (__tunable_seal_strings)
/* Define TUNABLE_GET and TUNABLE_SET in short form if TOP_NAMESPACE and
TUNABLE_NAMESPACE are defined. This is useful shorthand to get and set
+23 -9
View File
@@ -45,7 +45,13 @@ elf_dynamic_is_Rel_irelative (const ElfW(Rel) *reloc, const ElfW(Sym) *sym)
return ((sym != NULL
&& ELFW(ST_TYPE) (sym->st_info) == STT_GNU_IFUNC
&& sym->st_shndx != SHN_UNDEF)
|| r_type == ELF_MACHINE_IRELATIVE);
|| r_type == ELF_MACHINE_IRELATIVE
# ifdef ELF_MACHINE_IRELATIVE_PLT
/* Some ports resolve an IFUNC PLT slot for a local resolver with a
dedicated reloc that carries no symboli. */
|| r_type == ELF_MACHINE_IRELATIVE_PLT
# endif
);
#else
return false;
#endif
@@ -73,17 +79,23 @@ elf_dynamic_Rel_audit_symbind (struct link_map *map,
/* Perform the relocations in MAP on the running program image as specified
by RELTAG, SZTAG. If LAZY is nonzero, this is the first pass on PLT
relocations; they should be set up to call _dl_runtime_resolve, rather
than fully resolved now.
than fully resolved now. If SKIP_IFUNC is nonzero no IFUNC resolver is
called; this is required for the trace modes (ldd -u / ldd -r), which
relocate objects.
IRELATIVE entries are always skipped (non-bootstrap); they are handled
IRELATIVE entries and relocations against an STT_GNU_IFUNC symbol defined
in MAP itself are always skipped (non-bootstrap); they are handled
separately by elf_dynamic_do_Rel_irelative after all other relocations
for both .rel.dyn and .rel.plt have been processed. */
for both .rel.dyn and .rel.plt have been processed. Relocations against
an IFUNC symbol defined in *another* object are not deferred, since the
IFUNC symbol is only known after symbol resolution, and the defining object
has already been relocated at this point. */
static inline void __attribute__ ((always_inline))
elf_dynamic_do_Rel (struct link_map *map, struct r_scope_elem *scope[],
ElfW(Addr) reladdr, ElfW(Addr) relsize,
__typeof (((ElfW(Dyn) *) 0)->d_un.d_val) nrelative,
int lazy)
int lazy, int skip_ifunc)
{
const ElfW(Rel) *relative = (const void *) reladdr;
const ElfW(Rel) *r = relative + nrelative;
@@ -105,7 +117,7 @@ elf_dynamic_do_Rel (struct link_map *map, struct r_scope_elem *scope[],
void *const r_addr_arg = (void *) (l_addr + r->r_offset);
const struct r_found_version *rversion = &map->l_versions[ndx];
elf_machine_rel (map, scope, r, sym, rversion, r_addr_arg, 0);
elf_machine_rel (map, scope, r, sym, rversion, r_addr_arg, skip_ifunc);
}
#else /* !RTLD_BOOTSTRAP */
#if !defined DO_RELA || !defined ELF_MACHINE_PLT_REL
@@ -120,7 +132,7 @@ elf_dynamic_do_Rel (struct link_map *map, struct r_scope_elem *scope[],
const ElfW (Sym) *sym = &symtab[ELFW (R_SYM) (r->r_info)];
if (elf_dynamic_is_Rel_irelative (r, sym))
continue;
elf_machine_lazy_rel (map, scope, l_addr, r, 0);
elf_machine_lazy_rel (map, scope, l_addr, r, skip_ifunc);
}
}
else
@@ -152,7 +164,8 @@ elf_dynamic_do_Rel (struct link_map *map, struct r_scope_elem *scope[],
if (elf_dynamic_is_Rel_irelative (r, sym))
continue;
elf_machine_rel (map, scope, r, sym, rversion, r_addr_arg, 0);
elf_machine_rel (map, scope, r, sym, rversion, r_addr_arg,
skip_ifunc);
elf_dynamic_Rel_audit_symbind (map, scope, r, sym, rversion,
r_addr_arg);
}
@@ -166,7 +179,8 @@ elf_dynamic_do_Rel (struct link_map *map, struct r_scope_elem *scope[],
if (elf_dynamic_is_Rel_irelative (r, sym))
continue;
elf_machine_rel (map, scope, r, sym, NULL, r_addr_arg, 0);
elf_machine_rel (map, scope, r, sym, NULL, r_addr_arg,
skip_ifunc);
elf_dynamic_Rel_audit_symbind (map, scope, r, sym, NULL,
r_addr_arg);
}
+60 -63
View File
@@ -78,18 +78,23 @@ elf_machine_lazy_rel (struct link_map *map, struct r_scope_elem *scope[],
consumes precisely the very end of the DT_REL*, or DT_JMPREL and DT_REL*
are completely separate and there is a gap between them. */
/* This controls which sub-passes _ELF_DYNAMIC_DO_RELOC runs. Used to
interleave TLS / stack-protector setup between the two passes so IFUNC
resolvers see a fully-initialised TCB. */
enum elf_dynamic_reloc_phase
/* Selects which relocations a pass processes. Splitting them allows the
caller to interleave TLS / stack-protector setup between the two passes,
so IFUNC resolvers see a fully-initialised TCB.
This is orthogonal to the skip_ifunc argument, which says whether an IFUNC
resolver may be run at all and is honoured by every pass. In particular
DL_RELOC_NORMAL also runs IFUNC resolvers, for relocations against an
IFUNC symbol defined in another object. */
enum elf_dynamic_reloc_pass
{
DL_RELOC_BOTH = 0, /* Non-IRELATIVE pass then IRELATIVE pass. */
DL_RELOC_NOIFUNC = 1, /* Non-IRELATIVE pass only. */
DL_RELOC_IFUNC = 2, /* IRELATIVE pass only. */
DL_RELOC_ALL = 0, /* Non-IRELATIVE relocations, then IRELATIVE. */
DL_RELOC_NORMAL = 1, /* Non-IRELATIVE relocations only. */
DL_RELOC_IRELATIVE = 2, /* IRELATIVE relocations only. */
};
# define _ELF_DYNAMIC_DO_RELOC(RELOC, reloc, map, scope, do_lazy, skip_ifunc, \
test_rel, phase) \
test_rel, pass) \
do { \
struct { ElfW(Addr) start, size; \
__typeof (((ElfW(Dyn) *) 0)->d_un.d_val) nrelative; int lazy; } \
@@ -136,14 +141,15 @@ enum elf_dynamic_reloc_phase
by the linker. */ \
if (!DO_RTLD_BOOTSTRAP) \
{ \
if ((phase) != DL_RELOC_IFUNC) \
if ((pass) != DL_RELOC_IRELATIVE) \
for (int ranges_index = 0; ranges_index < 2; ++ranges_index) \
elf_dynamic_do_##reloc ((map), scope, \
ranges[ranges_index].start, \
ranges[ranges_index].size, \
ranges[ranges_index].nrelative, \
ranges[ranges_index].lazy); \
if ((phase) != DL_RELOC_NOIFUNC) \
ranges[ranges_index].lazy, \
skip_ifunc); \
if ((pass) != DL_RELOC_NORMAL) \
for (int ranges_index = 0; ranges_index < 2; ++ranges_index) \
elf_dynamic_do_##reloc##_irelative ((map), scope, \
ranges[ranges_index].start, \
@@ -158,7 +164,8 @@ enum elf_dynamic_reloc_phase
ranges[ranges_index].start, \
ranges[ranges_index].size, \
ranges[ranges_index].nrelative, \
ranges[ranges_index].lazy); \
ranges[ranges_index].lazy, \
skip_ifunc); \
} while (0)
# if ELF_MACHINE_NO_REL || ELF_MACHINE_NO_RELA
@@ -169,37 +176,21 @@ enum elf_dynamic_reloc_phase
# if ! ELF_MACHINE_NO_REL
# include "do-rel.h"
# define ELF_DYNAMIC_DO_REL(map, scope, lazy, skip_ifunc) \
# define ELF_DYNAMIC_DO_REL(map, scope, lazy, skip_ifunc, pass) \
_ELF_DYNAMIC_DO_RELOC (REL, Rel, map, scope, lazy, skip_ifunc, \
_ELF_CHECK_REL, DL_RELOC_BOTH)
# define ELF_DYNAMIC_DO_REL_NOIFUNC(map, scope, lazy) \
_ELF_DYNAMIC_DO_RELOC (REL, Rel, map, scope, lazy, 0, \
_ELF_CHECK_REL, DL_RELOC_NOIFUNC)
# define ELF_DYNAMIC_DO_REL_IFUNCONLY(map, scope, lazy, skip_ifunc) \
_ELF_DYNAMIC_DO_RELOC (REL, Rel, map, scope, lazy, skip_ifunc, \
_ELF_CHECK_REL, DL_RELOC_IFUNC)
_ELF_CHECK_REL, pass)
# else
# define ELF_DYNAMIC_DO_REL(map, scope, lazy, skip_ifunc) /* Nothing to do. */
# define ELF_DYNAMIC_DO_REL_NOIFUNC(map, scope, lazy) /* Nothing to do. */
# define ELF_DYNAMIC_DO_REL_IFUNCONLY(map, scope, lazy, skip_ifunc) /* Nothing. */
# define ELF_DYNAMIC_DO_REL(map, scope, lazy, skip_ifunc, pass) /* Nothing. */
# endif
# if ! ELF_MACHINE_NO_RELA
# define DO_RELA
# include "do-rel.h"
# define ELF_DYNAMIC_DO_RELA(map, scope, lazy, skip_ifunc) \
# define ELF_DYNAMIC_DO_RELA(map, scope, lazy, skip_ifunc, pass) \
_ELF_DYNAMIC_DO_RELOC (RELA, Rela, map, scope, lazy, skip_ifunc, \
_ELF_CHECK_REL, DL_RELOC_BOTH)
# define ELF_DYNAMIC_DO_RELA_NOIFUNC(map, scope, lazy) \
_ELF_DYNAMIC_DO_RELOC (RELA, Rela, map, scope, lazy, 0, \
_ELF_CHECK_REL, DL_RELOC_NOIFUNC)
# define ELF_DYNAMIC_DO_RELA_IFUNCONLY(map, scope, lazy, skip_ifunc) \
_ELF_DYNAMIC_DO_RELOC (RELA, Rela, map, scope, lazy, skip_ifunc, \
_ELF_CHECK_REL, DL_RELOC_IFUNC)
_ELF_CHECK_REL, pass)
# else
# define ELF_DYNAMIC_DO_RELA(map, scope, lazy, skip_ifunc) /* Nothing to do. */
# define ELF_DYNAMIC_DO_RELA_NOIFUNC(map, scope, lazy) /* Nothing to do. */
# define ELF_DYNAMIC_DO_RELA_IFUNCONLY(map, scope, lazy, skip_ifunc) /* Nothing. */
# define ELF_DYNAMIC_DO_RELA(map, scope, lazy, skip_ifunc, pass) /* Nothing. */
# endif
# define ELF_DYNAMIC_DO_RELR(map) \
@@ -240,37 +231,43 @@ enum elf_dynamic_reloc_phase
# else
# define DO_RTLD_BOOTSTRAP 0
# endif
/* Perform one relocation pass over MAP. PASS selects which relocations are
processed. It is orthogonal to SKIP_IFUNC, which suppresses running IFUNC
resolvers in whichever pass is selected.
Unless PASS is DL_RELOC_IRELATIVE, this also performs the
machine-specific PLT/GOT setup, the DT_RELR relocations, and the
ELF_DYNAMIC_AFTER_RELOC hook.
LAZY must be an int lvalue. elf_machine_runtime_setup may downgrade the
requested mode (currently only hppa, when it cannot install the lazy
trampoline) and it has side effects, so it must run exactly once (the
effective mode is stored back into LAZY). A later DL_RELOC_IRELATIVE
call must be handed that same lvalue, so that both passes partition the
relocation ranges identically. */
# define ELF_DYNAMIC_RELOCATE_PASS(pass, map, scope, lazy, consider_profile, \
skip_ifunc) \
do { \
if ((pass) != DL_RELOC_IRELATIVE) \
{ \
(lazy) = elf_machine_runtime_setup ((map), (scope), (lazy), \
(consider_profile)); \
if (!is_rtld_link_map (map) || DO_RTLD_BOOTSTRAP) \
ELF_DYNAMIC_DO_RELR (map); \
} \
ELF_DYNAMIC_DO_REL ((map), (scope), (lazy), skip_ifunc, (pass)); \
ELF_DYNAMIC_DO_RELA ((map), (scope), (lazy), skip_ifunc, (pass)); \
if ((pass) != DL_RELOC_IRELATIVE) \
ELF_DYNAMIC_AFTER_RELOC ((map), (lazy)); \
} while (0)
/* Run both passes back to back, for callers with nothing to interleave.
Unlike ELF_DYNAMIC_RELOCATE_PASS, LAZY need not be an lvalue. */
# define ELF_DYNAMIC_RELOCATE(map, scope, lazy, consider_profile, skip_ifunc) \
do { \
int edr_lazy = elf_machine_runtime_setup ((map), (scope), (lazy), \
(consider_profile)); \
if (!is_rtld_link_map (map) || DO_RTLD_BOOTSTRAP) \
ELF_DYNAMIC_DO_RELR (map); \
ELF_DYNAMIC_DO_REL ((map), (scope), edr_lazy, skip_ifunc); \
ELF_DYNAMIC_DO_RELA ((map), (scope), edr_lazy, skip_ifunc); \
ELF_DYNAMIC_AFTER_RELOC ((map), (edr_lazy)); \
} while (0)
/* Like ELF_DYNAMIC_RELOCATE but only processes the non-IRELATIVE pass.
The IRELATIVE pass must be completed later via ELF_DYNAMIC_RELOCATE_IFUNC.
Used by the static-pie startup so the TCB and stack-protector canary can
be initialised between the two passes. */
# define ELF_DYNAMIC_RELOCATE_NOIFUNC(map, scope, lazy, consider_profile) \
do { \
int edr_lazy = elf_machine_runtime_setup ((map), (scope), (lazy), \
(consider_profile)); \
if (!is_rtld_link_map (map) || DO_RTLD_BOOTSTRAP) \
ELF_DYNAMIC_DO_RELR (map); \
ELF_DYNAMIC_DO_REL_NOIFUNC ((map), (scope), edr_lazy); \
ELF_DYNAMIC_DO_RELA_NOIFUNC ((map), (scope), edr_lazy); \
ELF_DYNAMIC_AFTER_RELOC ((map), (edr_lazy)); \
} while (0)
/* IRELATIVE-only companion to ELF_DYNAMIC_RELOCATE_NOIFUNC. */
# define ELF_DYNAMIC_RELOCATE_IFUNC(map, scope, lazy, skip_ifunc) \
do { \
ELF_DYNAMIC_DO_REL_IFUNCONLY ((map), (scope), (lazy), skip_ifunc); \
ELF_DYNAMIC_DO_RELA_IFUNCONLY ((map), (scope), (lazy), skip_ifunc); \
int edr_lazy = (lazy); \
ELF_DYNAMIC_RELOCATE_PASS (DL_RELOC_ALL, (map), (scope), edr_lazy, \
(consider_profile), skip_ifunc); \
} while (0)
#endif
+1
View File
@@ -847,6 +847,7 @@ typedef struct
#define NT_RISCV_VECTOR 0x901 /* RISC-V vector registers */
#define NT_RISCV_TAGGED_ADDR_CTRL 0x902 /* RISC-V tagged
address control */
#define NT_RISCV_USER_CFI 0x903 /* RISC-V shadow stack state */
#define NT_LOONGARCH_CPUCFG 0xa00 /* LoongArch CPU config registers. */
#define NT_LOONGARCH_CSR 0xa01 /* LoongArch control and
status registers. */
+2 -5
View File
@@ -26,8 +26,7 @@
#include <libc-diag.h>
static inline void __attribute__ ((unused, always_inline))
elf_get_dynamic_info (struct link_map *l, bool bootstrap,
bool static_pie_bootstrap)
elf_get_dynamic_info (struct link_map *l, bool bootstrap)
{
#if __ELF_NATIVE_CLASS == 32
typedef Elf32_Word d_tag_utype;
@@ -35,10 +34,8 @@ elf_get_dynamic_info (struct link_map *l, bool bootstrap,
typedef Elf64_Xword d_tag_utype;
#endif
#ifndef STATIC_PIE_BOOTSTRAP
if (!bootstrap && l->l_ld == NULL)
return;
#endif
ElfW(Dyn) **info = l->l_info;
@@ -128,7 +125,7 @@ elf_get_dynamic_info (struct link_map *l, bool bootstrap,
#endif
if (info[DT_RELR] != NULL)
assert (info[DT_RELRENT]->d_un.d_val == sizeof (ElfW(Relr)));
if (bootstrap || static_pie_bootstrap)
if (bootstrap)
{
assert (info[DT_RUNPATH] == NULL);
assert (info[DT_RPATH] == NULL);
+4 -2
View File
@@ -47,8 +47,10 @@ ldconfig_parse_config_1 (const char *filename, bool do_chroot,
opt_chroot - If non-NULL, all paths are relative to this.
callback - for each non-blank line in the file, this function is called
with the line and it's location.
callback - for each non-blank line in the file, this function is
called with the line and it's location. Will also be called
with a NULL line at the start and end of each file, for
file-scoped config items.
*/
void
+183 -5
View File
@@ -44,12 +44,17 @@
#include <dl-cache.h>
#include <dl-hwcaps.h>
#include <dl-is_dso.h>
#include "tunconf.h"
#ifndef LD_SO_CONF
# define LD_SO_CONF SYSCONFDIR "/ld.so.conf"
#endif
#ifndef TUNABLES_CONF
# define TUNABLES_CONF SYSCONFDIR "/tunables.conf"
#endif
/* Get libc version number. */
#include <version.h>
@@ -104,12 +109,18 @@ static int opt_manual_link;
/* Should we ignore an old auxiliary cache file? */
static int opt_ignore_aux_cache;
/* Install a pre-existing cache file instead of generating a new one. */
static int opt_install;
/* Cache file to use. */
static char *cache_file;
/* Configuration file. */
/* Configuration file for libraries. */
static const char *config_file;
/* Configuration file for tunables. */
static const char *tunconfig_file;
/* Name and version of program. */
static void print_version (FILE *stream, struct argp_state *state);
void (*argp_program_version_hook) (FILE *, struct argp_state *)
@@ -127,11 +138,13 @@ static const struct argp_option options[] =
{ NULL, 'X', NULL, 0, N_("Don't update symbolic links"), 0},
{ NULL, 'r', N_("ROOT"), 0, N_("Change to and use ROOT as root directory"), 0},
{ NULL, 'C', N_("CACHE"), 0, N_("Use CACHE as cache file"), 0},
{ NULL, 'f', N_("CONF"), 0, N_("Use CONF as configuration file"), 0},
{ NULL, 'f', N_("CONF"), 0, N_("Use CONF as configuration file for libraries"), 0},
{ NULL, 't', N_("TUNCONF"), 0, N_("Use TUNCONF as configuration file for tunables"), 0},
{ NULL, 'n', NULL, 0, N_("Only process directories specified on the command line. Don't build cache."), 0},
{ NULL, 'l', NULL, 0, N_("Manually link individual libraries."), 0},
{ "format", 'c', N_("FORMAT"), 0, N_("Format to use: new (default), old, or compat"), 0},
{ "ignore-aux-cache", 'i', NULL, 0, N_("Ignore auxiliary cache file"), 0},
{ "install", 'I', NULL, 0, N_("Install pre-existing cache file"), 0},
{ NULL, 0, NULL, 0, NULL, 0 }
};
@@ -164,6 +177,9 @@ parse_opt (int key, char *arg, struct argp_state *state)
case 'f':
config_file = arg;
break;
case 't':
tunconfig_file = arg;
break;
case 'i':
opt_ignore_aux_cache = 1;
break;
@@ -197,6 +213,9 @@ parse_opt (int key, char *arg, struct argp_state *state)
else if (strcmp (arg, "new") == 0)
opt_format = opt_format_new;
break;
case 'I':
opt_install = 1;
break;
default:
return ARGP_ERR_UNKNOWN;
}
@@ -421,8 +440,11 @@ add_dir_1 (const char *line, const char *from_file, int from_line)
}
static void
add_dir_callback (const char *line, const char *from_file, int from_line)
add_dir_callback (char *line, const char *from_file, int from_line)
{
/* Denotes file boundaries. Not needed here. */
if (line == NULL)
return;
if (!strncasecmp (line, "hwcap", 5) && isblank (line[5]))
error (0, 0, _("%s:%u: hwcap directive ignored"), from_file, from_line);
else
@@ -1026,6 +1048,155 @@ search_dirs (void)
}
}
static void
install_cache_file (const char *source_arg)
{
int e;
if (source_arg == NULL)
error (EXIT_FAILURE, 0, _("Missing source file name"));
const char *source = (opt_chroot
? chroot_canon (opt_chroot, source_arg)
: source_arg);
if (source == NULL)
error (EXIT_FAILURE, errno, _("Can't find %s"), source_arg);
int src_fd = open (source, O_RDONLY);
if (src_fd < 0)
error (EXIT_FAILURE, errno, _("Can't open %s"), source);
char *dest = xmalloc (strlen (cache_file) + 1 + 1);
/* This matches the temp file created by cache.c, and should be
on the same filesystem as the cache file. */
sprintf (dest, "%s~", cache_file);
int dest_fd;
struct stat st;
if (fstat (src_fd, &st) < 0)
error (EXIT_FAILURE, errno, _("Can't stat %s"), source);
char buf[512];
ssize_t r, w = 0, sz = 0;
char *bp = buf;
/* Read the first part of the file and verify it looks
reasonable. */
while (sz < sizeof (buf)
&& (r = read (src_fd, bp, sizeof (buf) - sz)) > 0)
{
sz += r;
bp += r;
}
if (r < 0)
error (EXIT_FAILURE, errno, _("Error reading file %s"), source);
if (! ((sz >= sizeof (CACHEMAGIC)
&& memcmp (buf, CACHEMAGIC,
sizeof (CACHEMAGIC) - 1) == 0)
|| (sz >= sizeof (CACHEMAGIC_NEW)
&& memcmp (buf, CACHEMAGIC_NEW,
sizeof (CACHEMAGIC_NEW) - 1) == 0)))
{
error (EXIT_FAILURE, 0,
_("File %s does not look like an ld.so.cache file"),
source);
}
/* Now write that first part out. */
dest_fd = open (dest, O_CREAT|O_WRONLY|O_TRUNC|O_NOFOLLOW,
S_IRUSR|S_IWUSR);
if (dest_fd < 0)
error (EXIT_FAILURE, errno, _("Can't create %s"), dest);
r = sz;
bp = buf;
while (r > 0 && (w = write (dest_fd, bp, r)) > 0)
{
r -= w;
bp += w;
}
if (w < 0)
{
e = errno;
unlink (dest);
close (dest_fd);
error (EXIT_FAILURE, e, _("Error writing file %s"), dest);
}
/* At this point, sz contains the number of bytes copied so far.
Copy the rest of the file. */
while ((r = read (src_fd, buf, sizeof(buf))) > 0)
{
bp = buf;
while (r > 0 && (w = write (dest_fd, bp, r)) > 0)
{
bp += w;
r -= w;
sz += w;
}
if (w <= 0)
break;
}
if (r < 0)
{
e = errno;
unlink (dest);
close (dest_fd);
error (EXIT_FAILURE, e, _("Error reading file %s"), source);
}
if (w < 0)
{
e = errno;
unlink (dest);
close (dest_fd);
error (EXIT_FAILURE, e, _("Error writing file %s"), dest);
}
close (src_fd);
/* Make sure we copied it all. */
if (sz < st.st_size)
{
unlink (dest);
close (dest_fd);
error (EXIT_FAILURE, 0, _("Unable to copy file %s to %s"),
source, dest);
}
/* Make sure user can always read the cache file */
if (fchmod (dest_fd, S_IROTH|S_IRGRP|S_IRUSR|S_IWUSR))
{
e = errno;
unlink (dest);
close (dest_fd);
error (EXIT_FAILURE, e,
_("Changing access rights of %s to %#o failed"), dest,
S_IROTH|S_IRGRP|S_IRUSR|S_IWUSR);
}
if (fsync (dest_fd) != 0)
{
e = errno;
unlink (dest);
close (dest_fd);
error (EXIT_FAILURE, e, _("Writing to %s failed"), dest);
}
if (rename (dest, cache_file) < 0)
{
e = errno;
unlink (dest);
close (dest_fd);
error (EXIT_FAILURE, e, _("Can't rename %s to %s"),
dest, cache_file);
}
if (close (dest_fd) != 0)
error (EXIT_FAILURE, errno, _("Writing to %s failed"), dest);
exit (0);
}
int
main (int argc, char **argv)
@@ -1045,8 +1216,8 @@ main (int argc, char **argv)
argp_parse (&argp, argc, argv, 0, &remaining, NULL);
/* Remaining arguments are additional directories if opt_manual_link
is not set. */
if (remaining != argc && !opt_manual_link)
and opt_install are not set. */
if (remaining != argc && !opt_manual_link && !opt_install)
{
int i;
for (i = remaining; i < argc; ++i)
@@ -1089,6 +1260,9 @@ main (int argc, char **argv)
if (config_file == NULL)
config_file = LD_SO_CONF;
if (tunconfig_file == NULL)
tunconfig_file = TUNABLES_CONF;
if (opt_print_cache)
{
if (opt_chroot != NULL)
@@ -1139,6 +1313,8 @@ main (int argc, char **argv)
exit (0);
}
if (opt_install)
install_cache_file (argv[remaining]);
if (opt_build_cache)
init_cache ();
@@ -1164,6 +1340,8 @@ main (int argc, char **argv)
search_dirs ();
parse_tunconf (tunconfig_file, opt_chroot);
if (opt_build_cache)
{
save_cache (cache_file);
@@ -1,5 +1,5 @@
/* Symbol rediretion for loader/static initialization code.
Copyright (C) 2022-2026 Free Software Foundation, Inc.
/* Module for tst-origin-secure (the "good" copy).
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
@@ -16,9 +16,10 @@
License along with the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */
#ifndef _DL_IFUNC_GENERIC_H
#define _DL_IFUNC_GENERIC_H
#include "tst-origin-secure.h"
asm ("memset = __memset_ultra1");
#endif
int
origin_secure_id (void)
{
return ORIGIN_SECURE_ID_TRUSTED;
}
+8 -7
View File
@@ -545,7 +545,7 @@ _dl_start (void *arg)
/* Read our own dynamic section and fill in the info array. */
bootstrap_map.l_ld = (void *) bootstrap_map.l_addr + elf_machine_dynamic ();
bootstrap_map.l_ld_readonly = DL_RO_DYN_SECTION;
elf_get_dynamic_info (&bootstrap_map, true, false);
elf_get_dynamic_info (&bootstrap_map, true);
#if NO_TLS_OFFSET != 0
bootstrap_map.l_tls_offset = NO_TLS_OFFSET;
@@ -1671,6 +1671,12 @@ dl_main (const ElfW(Phdr) *phdr,
_dl_handle_execstack_tunable ();
/* Every string tunable has been consumed by now (init_cpu_features runs
from DL_PLATFORM_INIT, before dl_main). It precedes any code outside
the dynamic loader (the audit modules and IFUNC resolvers), and
RELRO. */
__tunable_seal_strings ();
/* If the current libname is different from the SONAME, add the
latter as well. */
{
@@ -1694,7 +1700,7 @@ dl_main (const ElfW(Phdr) *phdr,
if (! rtld_is_main)
{
/* Extract the contents of the dynamic section for easy access. */
elf_get_dynamic_info (main_map, false, false);
elf_get_dynamic_info (main_map, false);
/* If the main map is libc.so, update the base namespace to
refer to this map. If libc.so is loaded later, this happens
@@ -2371,11 +2377,6 @@ dl_main (const ElfW(Phdr) *phdr,
/* Auditing checkpoint: we have added all objects. */
_dl_audit_activity_nsid (LM_ID_BASE, LA_ACT_CONSISTENT);
#if defined USE_LDCONFIG && !defined MAP_COPY
/* We must munmap() the cache file. */
_dl_unload_cache ();
#endif
/* Once we return, _dl_sysdep_start will invoke
the DT_INIT functions and then *USER_ENTRY. */
}
+1 -1
View File
@@ -64,7 +64,7 @@ setup_vdso (struct link_map *main_map __attribute__ ((unused)),
l->l_addr = l->l_map_start - l->l_addr;
l->l_map_end += l->l_addr;
l->l_ld = (void *) ((ElfW(Addr)) l->l_ld + l->l_addr);
elf_get_dynamic_info (l, false, false);
elf_get_dynamic_info (l, false);
_dl_setup_hash (l);
l->l_relocated = 1;
+43
View File
@@ -0,0 +1,43 @@
/* Check if assert works during program startup.
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 <assert.h>
#include <stdlib.h>
/* The __libc_assert_fail is used internally for assert() calls. */
extern _Noreturn __typeof (__assert_fail) __libc_assert_fail;
/* The __tunables_init is called just before self-relocation and TLS setup,
so overriding it is a way to reach the assert code at that point. */
void
__tunables_init (char **env, char **argv)
{
/* Inside libc, assert() is redirected to __libc_assert_fail. This test is
not built as part of libc, so a plain assert() here would call the public
__assert_fail instead, which uses __progname and the translation routines
and thus is not what the startup code issues. Call the internal routine
directly. */
__libc_assert_fail ("error", __FILE__, __LINE__, __func__);
}
int
main (void)
{
/* Fail with a different error code than abort. */
exit (EXIT_FAILURE);
}
+1 -1
View File
@@ -79,7 +79,7 @@ if [ $fail -ne 0 ]; then
echo "Test FAILED"
cat "${debug_output}".*
rm -f "${debug_output}".*
exit 1
exit $fail
fi
echo "Test PASSED"
+1 -1
View File
@@ -43,7 +43,7 @@ rc=$?
if test $rc -eq 77; then
echo "Test is not supported"
rm -f "${output}".*
exit 77
exit $rc
fi
output=$(ls "${output}".*)
+142
View File
@@ -0,0 +1,142 @@
/* Unit tests for dl-path-normalize.h.
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 <dl-path-normalize.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <support/check.h>
#include <support/next_to_fault.h>
static void
check_one_guarded (const char *input, const char *expected, bool before)
{
size_t size = strlen (input) + 1;
struct support_next_to_fault ntf
= before ? support_next_to_fault_allocate_before (size)
: support_next_to_fault_allocate (size);
memcpy (ntf.buffer, input, size);
size_t len = _dl_normalize_path (ntf.buffer);
TEST_COMPARE (len, strlen (ntf.buffer));
TEST_COMPARE_STRING (ntf.buffer, expected);
support_next_to_fault_free (&ntf);
}
static void
check_one (const char *input, const char *expected)
{
/* Check that _dl_normalize_path does not access the string outside the
input argument. It checks for both over-runs and under-runs (the
latter for the case of '..' expansions). */
check_one_guarded (input, expected, false);
check_one_guarded (input, expected, true);
}
static int
do_test (void)
{
/* Absolute paths. */
check_one ("/", "/");
check_one ("//", "/");
check_one ("///", "/");
check_one ("////", "/");
check_one ("/a", "/a");
check_one ("/a/", "/a");
check_one ("/a//", "/a");
check_one ("//a//b//", "/a/b");
check_one ("/.", "/");
check_one ("/./", "/");
check_one ("/./a", "/a");
check_one ("/a/./b", "/a/b");
check_one ("/a/.", "/a");
check_one ("/..", "/");
check_one ("/../", "/");
check_one ("/../a", "/a");
check_one ("/a/..", "/");
check_one ("/a/../", "/");
check_one ("/a/../..", "/");
check_one ("/a/../b", "/b");
check_one ("/a/../../b", "/b");
check_one ("/a/b/../../c", "/c");
check_one ("/a/b/../c", "/a/c");
check_one ("/a/b/c/../..", "/a");
check_one ("/usr/lib/../lib64", "/usr/lib64");
check_one ("/usr/lib/../lib64/", "/usr/lib64");
check_one ("/usr/lib/..//lib64/", "/usr/lib64");
check_one ("/usr/lib/../../lib64/", "/lib64");
/* "." and ".." are special only as complete components. */
check_one ("/a..", "/a..");
check_one ("/..a", "/..a");
check_one ("/a/...", "/a/...");
check_one ("/.../a", "/.../a");
check_one ("/a./b", "/a./b");
check_one (".a", ".a");
check_one ("a.", "a.");
check_one ("..a", "..a");
check_one ("...", "...");
/* Relative paths. */
check_one ("", "");
check_one (".", "");
check_one ("./", "");
check_one ("..", "..");
check_one ("../", "..");
check_one ("a", "a");
check_one ("a/", "a");
check_one ("a//b", "a/b");
check_one ("a..", "a..");
check_one ("./a", "a");
check_one ("./.", "");
check_one ("./..", "..");
check_one ("a/..", "");
check_one ("a/../", "");
check_one ("ab/..", "");
check_one (".a/..", "");
check_one ("a./..", "");
check_one (".../..", "");
check_one ("a/./..", "");
check_one ("a/b/..", "a");
check_one ("abc/def/..", "abc");
/* Appending a component to an emptied relative output must not produce a
leading '/' (the path must stay relative). */
check_one ("a/../b", "b");
check_one ("a/.././b", "b");
check_one ("a/../lib64/b", "lib64/b");
/* Leading ".." components of a relative path are preserved and stack
instead of cancelling each other; ordinary components may follow and be
removed again afterwards. */
check_one ("../a", "../a");
check_one ("../..", "../..");
check_one ("../../..", "../../..");
check_one ("../../a", "../../a");
check_one ("../a/..", "..");
check_one ("../../a/..", "../..");
check_one ("a/../../b", "../b");
check_one ("a/b/../../..", "..");
return 0;
}
#include <support/test-driver.c>
@@ -1,5 +1,5 @@
/* Types for the NSCD implementation. Generic version.
Copyright (c) 2000-2026 Free Software Foundation, Inc.
/* Program calling an IFUNC defined in a dependency. BIND_NOW variant.
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
@@ -16,6 +16,4 @@
License along with the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */
#include <stdint.h>
typedef int32_t nscd_ssize_t;
#include "tst-ifunc-fault-dep-lazy.c"
+27
View File
@@ -0,0 +1,27 @@
/* Program calling an IFUNC defined in a dependency (BZ 34428).
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/>. */
extern void magic (void);
int
main (void)
{
/* JMP_SLOT relocation against an undefined symbol. */
magic ();
return 1;
}
+40
View File
@@ -0,0 +1,40 @@
/* Shared object exporting an IFUNC symbol with a resolver which crashes.
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 <stddef.h>
#include <sys/cdefs.h>
static void
implementation (void)
{
/* Produce a crash, without depending on any relocations. */
volatile char *volatile p = NULL;
*p = 0;
}
static __typeof__ (implementation) *
__attribute_used__
resolver (void)
{
/* Produce a crash, without depending on any relocations. */
volatile char *volatile p = NULL;
*p = 0;
return implementation;
}
void magic (void) __attribute__ ((ifunc ("resolver")));
+137
View File
@@ -0,0 +1,137 @@
/* Test ldconfig cache is correctly used when changed.
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; see the file COPYING.LIB. If
not, see <https://www.gnu.org/licenses/>. */
/* What we're testing for: We initially load ld.so.cache at startup
and remember it. If we detect that ld.so.cache has changed, and we
can load it successfully, we replace our remember it. If it
doesn't change, or if the new version is corrupted, we continue
using the old remembered copy. */
#include <fcntl.h>
#include <support/support.h>
#include <support/check.h>
#include <support/xstdio.h>
#include <support/xstdlib.h>
#include <support/xdlfcn.h>
#include <support/xunistd.h>
/* Verify that we can (or can't) load one of our test objects. */
static void
try (int i, int invert)
{
char dlname[100];
char symname[100];
int (*proc)(int);
void *dl;
/* These match the objects copied by tst-ldconfig-cache.script,
copied from tst-tls-manydynamic*.so. */
sprintf (dlname, "libcache%d.so", i);
sprintf (symname, "set_value_%02d", i);
dl = dlopen (dlname, RTLD_NOW);
if (invert)
{
/* This is a negative test; if the object doesn't load the test
passes. */
TEST_VERIFY (dl == NULL);
return;
}
else
{
/* This is a positive test; if the object doesn't load the test
fails. */
if (dl == NULL)
FAIL_EXIT1 ("error: dlopen: %s\n", dlerror ());
}
proc = xdlsym (dl, symname);
/* We don't need to call the symbol, just make sure it exists. */
TEST_VERIFY (proc != NULL);
xdlclose (dl);
}
/* Cause corruption in the cache that should prevent loading it. */
static void
corrupt (void)
{
int fd = xopen ("/etc/ld.so.cache", O_RDWR, 0);
char bytes[] = { 15, 32, 184, 4 };
xwrite (fd, bytes, sizeof(bytes));
xclose (fd);
}
/* Regenerate the cache from ld.so.conf. */
static void
ldconfig (void)
{
char *cmd = xasprintf("%s/ldconfig -X", support_install_rootsbindir);
xsystem (cmd);
free(cmd);
}
/* Change ld.so.conf to refer to the new directory, and generate a new
cache. */
static void
newpath (const char *p)
{
FILE *f = xfopen ("/etc/ld.so.conf", "w");
fprintf (f, "%s\n", p);
xfclose (f);
ldconfig ();
}
static int
do_test (void)
{
/* Test that the cache we started with can still load objects in
/a. */
try (1, 0);
/* Create a new cache that doesn't include /a but corrupt it. Test
that we still use the cache with /a in it. */
newpath ("/c");
corrupt ();
try (2, 0);
/* Regenerate a clean cache with /a in it and verify we can load
objects in /a. */
newpath ("/a");
try (3, 0);
/* Generate a new cache with /b but not /a and make sure objects
in /a can't be loaded. */
newpath ("/b");
try (3, 1);
/* But objects in /b can be loaded. */
try (4, 0);
/* Even multiple times. */
try (5, 0);
return 0;
}
#include <support/test-driver.c>
@@ -0,0 +1,3 @@
/lib
/lib64
/a
@@ -0,0 +1,7 @@
mkdirp 0755 /a
cp $B/elf/tst-tls-manydynamic01mod.so /a/libcache1.so
cp $B/elf/tst-tls-manydynamic02mod.so /a/libcache2.so
cp $B/elf/tst-tls-manydynamic03mod.so /a/libcache3.so
mkdirp 0755 /b
cp $B/elf/tst-tls-manydynamic04mod.so /b/libcache4.so
cp $B/elf/tst-tls-manydynamic05mod.so /b/libcache5.so
+125
View File
@@ -0,0 +1,125 @@
#!/bin/sh
# Test that ldconfig --install installs a pre-built cache file.
# 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/>.
set -e
common_objpfx=$1
test_wrapper_env=$2
run_program_env=$3
testroot="${common_objpfx}elf/tst-ldconfig-install-directory"
cleanup () {
rm -rf "$testroot"
}
trap cleanup 0
rm -rf "$testroot"
mkdir -p "$testroot/etc"
ldconfig="${common_objpfx}elf/ldconfig"
run_ldconfig () {
${test_wrapper_env} ${run_program_env} "$ldconfig" "$@"
}
errors=0
fail () {
echo "error: $1"
errors=1
}
# Build a pre-built cache to install.
source="$testroot/prebuilt-ld.so.cache"
mkdir -p "$testroot/lib"
run_ldconfig -X -f /dev/null -C "$source" "$testroot/lib"
test -r "$source" || fail "ldconfig did not create the pre-built cache"
# Pad the source past the 512-byte internal copy buffer so that the multi-block
# copy path is exercised, while leaving the cache magic at the start intact.
dd if=/dev/zero bs=1024 count=4 >> "$source" 2>/dev/null
dest="$testroot/etc/ld.so.cache"
temp="$dest~"
run_ldconfig --install -f /dev/null -C "$dest" "$source"
# The destination must exist and be byte-identical to the source.
if test -r "$dest"; then
if cmp -s "$source" "$dest"; then
echo "info: installed cache matches the source"
else
fail "installed cache differs from the source"
fi
else
fail "destination cache file was not created"
fi
# The temporary file used during the atomic rename must not be left behind.
if test -e "$temp"; then
fail "temporary file $temp was left behind"
fi
# The installed cache must be world-readable (0644).
if test -r "$dest"; then
mode=$(ls -l "$dest" | cut -c1-10)
case "$mode" in
(-rw-r--r--) echo "info: installed cache has expected permissions" ;;
(*) fail "installed cache has unexpected permissions: $mode" ;;
esac
fi
# A second install over an existing cache must also succeed.
run_ldconfig --install -f /dev/null -C "$dest" "$source"
if cmp -s "$source" "$dest"; then
echo "info: re-install over an existing cache works"
else
fail "re-install produced a different cache"
fi
# Error case: a source file that is not a cache must be rejected, and no
# destination must be produced.
rm -f "$dest"
notcache="$testroot/not-a-cache"
echo "this is not an ld.so.cache file" > "$notcache"
if run_ldconfig --install -f /dev/null -C "$dest" "$notcache" 2>"$testroot/err"; then
fail "ldconfig accepted a file that is not a cache"
else
if grep -q "does not look like an ld.so.cache file" "$testroot/err"; then
echo "info: non-cache source correctly rejected"
else
fail "unexpected error message for non-cache source"
cat "$testroot/err"
fi
fi
test -e "$dest" && fail "destination created from an invalid source"
# Error case: a missing source argument must be diagnosed.
if run_ldconfig --install -f /dev/null -C "$dest" 2>"$testroot/err"; then
fail "ldconfig accepted --install without a source file"
else
grep -q "Missing source file name" "$testroot/err" \
|| fail "unexpected error message for missing source"
fi
# Error case: a nonexistent source must be diagnosed.
if run_ldconfig --install -f /dev/null -C "$dest" \
"$testroot/does-not-exist" 2>"$testroot/err"; then
fail "ldconfig accepted a nonexistent source file"
fi
exit $errors
+1 -3
View File
@@ -29,8 +29,6 @@
/* Plugin to load. */
static void *plugin_lib = NULL;
/* Plugin function. */
static void (*plugin_func) (void);
#define LIB_PLUGIN "tst-nodelete-dlclose-plugin.so"
/* This function is never called but the plugin references it.
@@ -55,7 +53,7 @@ primary (void)
}
dlerror ();
plugin_func = (void (*) (void)) dlsym (plugin_lib, "plugin_func");
dlsym (plugin_lib, "plugin_func");
error = dlerror ();
if (error != NULL)
{
+28
View File
@@ -0,0 +1,28 @@
/* Module for tst-origin-secure (the attacker-controlled copy).
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 "tst-origin-secure.h"
/* If the victim reports this copy, the loader opened the un-normalized rpath
and resolved it through the attacker's symlink -- i.e. the trusted-path
check was bypassed (bug 34360). */
int
origin_secure_id (void)
{
return ORIGIN_SECURE_ID_ATTACKER;
}
+43
View File
@@ -0,0 +1,43 @@
/* Victim program for tst-origin-secure.
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 "tst-origin-secure.h"
extern int __libc_enable_secure;
/* Report both which module was loaded and whether the loader ran in secure
mode, so the driver can tell a genuine trusted-path bypass apart from a run
that simply was not secure.
The exit status is the combination of the ORIGIN_SECURE_STATUS_* bits:
_NONE trusted copy, not secure
_ATTACKER attacker copy, not secure (the control run)
_SECURE trusted copy, secure (a fixed loader)
_SECURE | _ATTACKER attacker copy, secure (the bug: the raw
rpath was opened) */
int
main (void)
{
int status = ORIGIN_SECURE_STATUS_NONE;
if (origin_secure_id () == ORIGIN_SECURE_ID_ATTACKER)
status |= ORIGIN_SECURE_STATUS_ATTACKER;
if (__libc_enable_secure != 0)
status |= ORIGIN_SECURE_STATUS_SECURE;
return status;
}
+203
View File
@@ -0,0 +1,203 @@
/* Test that AT_SECURE $ORIGIN rpath entries are looked up using the
normalized (trusted) path, not the raw expansion (bug 34360).
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/>. */
/* For a SUID/SGID program the loader only honors $ORIGIN in DT_RPATH when
the normalized expansion is rooted in a trusted directory. If the loader
opens the un-normalized string (that contains "../"), it might disagree
as soon as a path component is a symbolic link.
This test builds the executable with the rpath:
$ORIGIN/sub/../../../../..SLIBDIR/tst-origin-secure
and runs it as BASE/a/b/victim, so $ORIGIN is BASE/a/b. Lexically the
five "../" pop $ORIGIN/sub back to "/" (BASE is /tmp/tst-origin-secure,
so $ORIGIN/sub is the five components tmp, tst-origin-secure, a, b, sub),
and the entry normalizes to the trusted SLIBDIR/tst-origin-secure. But
"sub" is a symlink pointing six levels deep under BASE, so opening the raw
string makes the kernel resolve the "../" through the symlink and land in
BASE/x1 SLIBDIR/tst-origin-secure instead.
The "../" count in the rpath (see the Makefile) is therefore
depth(BASE) + 2 (for the "a/b" of $ORIGIN) + 1 (for "sub"); it is
independent of SLIBDIR, which is appended whole on both the raw and the
normalized side.
A trusted copy of the module (ORIGIN_SECURE_ID_TRUSTED) is installed in
SLIBDIR/tst-origin-secure; an attacker copy (ORIGIN_SECURE_ID_ATTACKER) is
placed at the symlink-diverted location. The trusted subdirectory is
rooted under SLIBDIR (so it passes the trusted-path check) but is not
itself a default loader search directory.
The victim reports, in its exit status, both which module it loaded and
whether it ran in secure mode.
Secure mode is forced with glibc.rtld.enable_secure=1 so that no real
SUID/SGID binary is required. */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <support/capture_subprocess.h>
#include <support/check.h>
#include <support/support.h>
#include <support/xunistd.h>
#include "tst-origin-secure.h"
#define BASE "/tmp/tst-origin-secure"
#define SONAME "libtst-origin-secure-mod.so"
/* Subdirectory of the trusted SLIBDIR that the rpath normalizes to. It is
trusted (rooted under SLIBDIR) but not a default search directory. */
#define SUBDIR "tst-origin-secure"
static int
run_victim (char *const *envp)
{
const char *victim = BASE "/a/b/victim";
char *const argv[] = { (char *) victim, NULL };
struct support_capture_subprocess res
= support_capture_subprogram (victim, argv, envp);
/* The victim itself prints nothing; forward any loader diagnostics to
the test log. */
if (res.err.length > 0)
printf ("info: victim stderr: %s\n", res.err.buffer);
int status = res.status;
support_capture_subprocess_free (&res);
return WIFEXITED (status) ? WEXITSTATUS (status) : -1;
}
/* With SLIBDIR "/lib64" the container layout is:
/lib64/tst-origin-secure/libtst-origin-secure-mod.so trusted copy (id 1)
BASE/a/b/victim the executable
BASE/a/b/sub -> BASE/x1/x2/x3/x4/x5/x6 six levels deep
BASE/x1/lib64/tst-origin-secure/libtst-origin-secure-mod.so
attacker copy (id 2)
BASE/x1/x2/x3/x4/x5/x6/ the symlink target
The victim's rpath is $ORIGIN/sub + five "../" + /lib64/tst-origin-secure. */
static void
do_prepare (int argc, char **argv)
{
const char *slibdir = support_slibdir_prefix;
const char *objelf = support_objdir_root;
char *good_src = xasprintf ("%s/elf/libtst-origin-secure-mod.so", objelf);
char *evil_src = xasprintf ("%s/elf/tst-origin-secure-evilmod.so", objelf);
char *victim_src = xasprintf ("%s/elf/tst-origin-secure-victim", objelf);
xmkdirp (BASE "/a/b", 0755);
xmkdirp (BASE "/x1/x2/x3/x4/x5/x6", 0755);
/* Where the trusted copy lives (reached only via the normalized rpath,
SLIBDIR/SUBDIR) ... */
char *good_dir = xasprintf ("%s/%s", slibdir, SUBDIR);
char *good_dst = xasprintf ("%s/%s", good_dir, SONAME);
xmkdirp (good_dir, 0755);
/* ... and where the raw, symlink-diverted lookup lands. */
char *evil_dir = xasprintf ("%s/x1%s/%s", BASE, slibdir, SUBDIR);
char *evil_dst = xasprintf ("%s/%s", evil_dir, SONAME);
xmkdirp (evil_dir, 0755);
/* support_copy_file preserves the source mode, so the victim stays
executable and the modules readable; no chmod is needed. */
support_copy_file (good_src, good_dst);
support_copy_file (evil_src, evil_dst);
support_copy_file (victim_src, BASE "/a/b/victim");
unlink (BASE "/a/b/sub");
xsymlink (BASE "/x1/x2/x3/x4/x5/x6", BASE "/a/b/sub");
free (good_src);
free (evil_src);
free (victim_src);
free (good_dir);
free (good_dst);
free (evil_dir);
free (evil_dst);
}
#define PREPARE do_prepare
static int
do_test (void)
{
/* Control run: in normal mode $ORIGIN is honored without the trusted check,
so the raw rpath resolves through "sub" and the attacker copy is
loaded. */
{
char *const env[] = { NULL };
int rc = run_victim (env);
if (rc != ORIGIN_SECURE_STATUS_ATTACKER)
FAIL_EXIT1 ("control run returned status %d, expected %d (attacker "
"copy, not secure): the $ORIGIN layout does not reproduce "
"the divergence between the raw and the normalized rpath",
rc, ORIGIN_SECURE_STATUS_ATTACKER);
}
/* Secure run: force AT_SECURE. A fixed loader normalizes the rpath to the
trusted SLIBDIR/SUBDIR and loads the trusted copy; a loader with the bug
opens the raw path, resolves "sub", and loads the attacker copy. */
{
char *const env[] = { (char *) "GLIBC_TUNABLES=glibc.rtld.enable_secure=1",
NULL };
int rc = run_victim (env);
switch (rc)
{
/* Secure, trusted copy loaded via the normalized rpath: fixed. */
case ORIGIN_SECURE_STATUS_SECURE:
break;
/* Secure, attacker copy loaded: the raw rpath was opened. */
case ORIGIN_SECURE_STATUS_SECURE | ORIGIN_SECURE_STATUS_ATTACKER:
FAIL_EXIT1 ("secure-mode loader resolved the un-normalized rpath "
"through the attacker symlink (bug 34360)");
/* Not secure, attacker copy: exactly what the control run produced, so
the tunable did not engage and this run says nothing about the
trusted-path handling. */
case ORIGIN_SECURE_STATUS_ATTACKER:
FAIL_UNSUPPORTED ("glibc.rtld.enable_secure=1 did not enable "
"secure mode (victim status %d)", rc);
/* Not secure, yet the trusted copy was loaded, which is reachable only
through the normalized rpath, and only a secure loader normalizes it.
Fail rather than report UNSUPPORTED. */
case ORIGIN_SECURE_STATUS_NONE:
FAIL_EXIT1 ("secure run loaded the trusted copy but the victim "
"reports not being secure: __libc_enable_secure is no "
"longer a valid proxy for secure mode");
/* Neither copy loaded: since the trusted copy is reachable only through
the normalized rpath, this means the rpath entry was not honored at
all. */
default:
FAIL_EXIT1 ("secure run did not load the module via the normalized "
"rpath (victim status %d)", rc);
}
}
return 0;
}
#include <support/test-driver.c>
+41
View File
@@ -0,0 +1,41 @@
/* Definitions shared by the tst-origin-secure test, its victim and modules.
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/>. */
#ifndef _TST_ORIGIN_SECURE_H
#define _TST_ORIGIN_SECURE_H 1
enum
{
ORIGIN_SECURE_ID_TRUSTED = 1, /* The copy installed in the trusted
SLIBDIR. */
ORIGIN_SECURE_ID_ATTACKER = 2, /* The copy reachable only by resolving the
"sub" symlink. */
};
extern int origin_secure_id (void);
enum
{
ORIGIN_SECURE_STATUS_NONE = 0,
ORIGIN_SECURE_STATUS_ATTACKER = 1 << 0, /* The victim loaded attacker
rather than the trusted. */
ORIGIN_SECURE_STATUS_SECURE = 1 << 1, /* The loader ran the victim in
secure mode. */
};
#endif
@@ -1,5 +1,5 @@
/* Types for the NSCD implementation. Alpha version.
Copyright (c) 2000-2026 Free Software Foundation, Inc.
/* Check if RPATH/RUNPATH is allowed for static-pie.
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
@@ -13,9 +13,7 @@
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
License along with the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */
#include <stdint.h>
typedef int64_t nscd_ssize_t;
int foo (void) { return 42; }
+38
View File
@@ -0,0 +1,38 @@
/* Check if RPATH/RUNPATH is allowed for static-pie.
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 <support/check.h>
#include <support/xdlfcn.h>
/* The module is placed in the directory named by the RUNPATH of this
program (tst-pie-rpath-static.root/tst-pie-rpath-static.script), so
dlopen can only find it if the RUNPATH is honoured. */
#define LIBNAME "tst-pie-rpath-mod.so"
static int
do_test (void)
{
void *h = xdlopen (LIBNAME, RTLD_NOW);
int (*foo)(void) = xdlsym (h, "foo");
TEST_COMPARE (foo (), 42);
xdlclose (h);
return 0;
}
#include <support/test-driver.c>
@@ -0,0 +1,2 @@
mkdirp 0755 $B/elf/tst-pie-rpath-static-subdir
cp $B/elf/tst-pie-rpath-mod.so $B/elf/tst-pie-rpath-static-subdir/tst-pie-rpath-mod.so
+1 -1
View File
@@ -74,7 +74,7 @@ if [ $fail -ne 0 ]; then
echo "Test FAILED"
cat "${debug_output}"
rm -f "${debug_output}"
exit 1
exit $fail
fi
echo "Test PASSED"
+1
View File
@@ -0,0 +1 @@
#include "tst-tunables-seal.c"
+75
View File
@@ -0,0 +1,75 @@
/* Verify that string tunables are sealed after early startup.
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/>. */
/* This generic test is parameterized by TST_SEAL_TUNABLE_NAME, the name of
a glibc.cpu string tunable for the target ABI. */
#include <stdlib.h>
#include <support/check.h>
#ifdef TST_SEAL_TUNABLE_NAME
# include <string.h>
# include <unistd.h>
# include <support/capture_subprocess.h>
# define TUNABLE_NAMESPACE cpu
# include <elf/dl-tunables.h>
# define STRINGIFY(x) STRINGIFY1 (x)
# define STRINGIFY1(x) #x
/* The full internal name of the tunable, e.g. "glibc.cpu.hwcaps", as
embedded in the fatal error message. */
# define TST_SEAL_TUNABLE_FULLNAME \
STRINGIFY (TOP_NAMESPACE) "." STRINGIFY (TUNABLE_NAMESPACE) "." \
STRINGIFY (TST_SEAL_TUNABLE_NAME)
static void
read_sealed_tunable (void *closure)
{
TUNABLE_GET (TST_SEAL_TUNABLE_NAME, struct tunable_str_t *, NULL);
/* Not reached: the read above is a fatal error. Exit successfully so
that a missing diagnostic is caught as an unexpected exit status. */
_exit (EXIT_SUCCESS);
}
#endif /* TST_SEAL_TUNABLE_NAME */
static int
do_test (void)
{
#ifndef TST_SEAL_TUNABLE_NAME
FAIL_UNSUPPORTED ("the target ABI has no glibc.cpu string tunable");
#else
struct support_capture_subprocess result
= support_capture_subprocess (read_sealed_tunable, NULL);
support_capture_subprocess_check (&result, "tst-tunables-seal", 127,
sc_allow_stderr);
TEST_VERIFY (strstr (result.err.buffer,
"Fatal glibc error: " TST_SEAL_TUNABLE_FULLNAME
": string tunable read after process initialization")
!= NULL);
support_capture_subprocess_free (&result);
return 0;
#endif
}
#include <support/test-driver.c>
+81
View File
@@ -0,0 +1,81 @@
/* Test that the tunables cache can override env vars.
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 <inttypes.h>
#include <stdint.h>
#include <stdio.h>
#include <support/check.h>
#include "dl-tunables.h"
static int
do_test (void)
{
size_t tcache_count = TUNABLE_GET_FULL (glibc, malloc, tcache_count, size_t, NULL);
size_t tcache_max = TUNABLE_GET_FULL (glibc, malloc, tcache_max, size_t, NULL);
int32_t perturb = TUNABLE_GET_FULL (glibc, malloc, perturb, int32_t, NULL);
size_t mmap_threshold = TUNABLE_GET_FULL (glibc, malloc, mmap_threshold, size_t, NULL);
size_t trim_threshold = TUNABLE_GET_FULL (glibc, malloc, trim_threshold, size_t, NULL);
printf("tcache count is %zu (should be 5, from env)\n", tcache_count);
TEST_COMPARE ((long)tcache_count, 5);
printf("tcache max is %zu (should be 4, from /etc)\n", tcache_max);
TEST_COMPARE ((long)tcache_max, 4);
/* This is set by the environment but blocked by the config. */
printf("perturb is %" PRId32 " (should be 42, from /etc)\n",
perturb);
TEST_COMPARE (perturb, 42);
/* This is blocked by the general config, enabled by filter, set in env. */
printf("mmap_threshold is %zu (should be 10002, from env)\n",
mmap_threshold);
TEST_COMPARE ((long)mmap_threshold, 10002);
/* This is allowed by the general config, blocked by filter, set in env. */
printf("trim_threshold is %zu (should be 10001, from filter)\n",
trim_threshold);
TEST_COMPARE ((long)trim_threshold, 10001);
/* Interaction with legacy environment-variable aliases (MALLOC_*). */
int32_t mmap_max = TUNABLE_GET_FULL (glibc, malloc, mmap_max, int32_t, NULL);
size_t top_pad = TUNABLE_GET_FULL (glibc, malloc, top_pad, size_t, NULL);
size_t arena_max = TUNABLE_GET_FULL (glibc, malloc, arena_max, size_t, NULL);
/* Overridable cache default (100); the MALLOC_MMAP_MAX_ alias overrides
it, just like GLIBC_TUNABLES would. */
printf("mmap_max is %" PRId32 " (should be 200, from MALLOC_MMAP_MAX_ alias)"
"\n",
mmap_max);
TEST_COMPARE (mmap_max, 200);
/* Nonoverridable cache default (100); the MALLOC_TOP_PAD_ alias must not
override it. */
printf("top_pad is %zu (should be 100, from /etc nonoverridable)\n",
top_pad);
TEST_COMPARE ((long)top_pad, 100);
/* Set both by GLIBC_TUNABLES (300) and by the MALLOC_ARENA_MAX alias
(400); the canonical GLIBC_TUNABLES form wins. */
printf("arena_max is %zu (should be 300, from GLIBC_TUNABLES)\n", arena_max);
TEST_COMPARE ((long)arena_max, 300);
return 0;
}
#include <support/test-driver.c>
+31
View File
@@ -0,0 +1,31 @@
# These test the parser for both the overridability characters as well as
# tunables that either never exist, or only exist on some platforms.
-glibc.cpu.cached_memopt=1
+glibc.cpu.hwcaps=some,random,string
@glibc.test_secure=1
$glibc.test_unsecure=1
# These are checked inside the test case
glibc.malloc.tcache_max=6
$glibc.malloc.tcache_count=3
-glibc.malloc.perturb=42
-glibc.malloc.mmap_threshold=10000
overridable glibc.malloc.trim_threshold=10000
# Interaction with legacy environment-variable aliases (MALLOC_*), checked
# in the test case:
# - mmap_max: overridable cache default, must be overridable by the
# MALLOC_MMAP_MAX_ alias just like by GLIBC_TUNABLES.
# - top_pad: nonoverridable cache default, must NOT be overridable by the
# MALLOC_TOP_PAD_ alias.
glibc.malloc.mmap_max=100
-glibc.malloc.top_pad=100
[proc:/bin/ls]
glibc.malloc.tcache_max=7
[proc:tst-tunconf1]
glibc.malloc.tcache_max=4
+glibc.malloc.mmap_threshold=10001
nonoverridable glibc.malloc.trim_threshold=10001
View File
View File
+440
View File
@@ -0,0 +1,440 @@
/* Manage /etc/tunables.*
Copyright (C) 1999-2023 Free Software Foundation, Inc.
This file is part of the GNU C Library.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published
by the Free Software Foundation; version 2 of the License, or
(at your option) any later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, see <https://www.gnu.org/licenses/>. */
#include <alloca.h>
#include <argp.h>
#include <assert.h>
#include <error.h>
#include <inttypes.h>
#include <glob.h>
#include <libgen.h>
#include <libintl.h>
#include <locale.h>
#include <programs/xmalloc.h>
#include <stdint.h>
#include <stdio.h>
#include <stdio_ext.h>
#include <stdlib.h>
#include <string.h>
#define TUNABLES_INTERNAL
#include <elf/dl-tunables.h>
#include <unistd.h>
#include <ldconfig.h>
#include <dl-cache.h>
#include <version.h>
#include <stringtable.h>
#include <array_length.h>
#include "tunconf.h"
/*----------------------------------------------------------------------*/
#ifndef TUNABLES_CONF
# define TUNABLES_CONF SYSCONFDIR "/tunables.conf"
#endif
#ifndef TUNABLES_CACHE
# define TUNABLES_CACHE SYSCONFDIR "/tunables.cache"
#endif
/* Tunable Override Policies. */
typedef enum {
TOP_ALLOW = 0, /* let the environment variable override */
TOP_DENY /* no override allowed */
} TOP;
struct tunable_entry_int {
struct stringtable_entry *name;
struct stringtable_entry *value;
struct stringtable_entry *filter;
TOP top;
bool exclude_secure:1;
bool exclude_nonsecure:1;
int tunable_id;
unsigned int value_is_negative:1;
unsigned int value_was_parsed:1;
unsigned long long value_ull;
signed long long value_sll;
long filter_flags;
struct tunable_entry_int *next;
};
struct tunable_entry_int *entry_list;
static int filter_flags = 0;
static char *filter_string = NULL;
/*----------------------------------------------------------------------*/
static void
clear_filter (void)
{
free (filter_string);
filter_string = NULL;
filter_flags = 0;
}
/* Filters are lines the are bracketed, like
[prog:foo]
*/
static void
parse_filter (char *line, const char *filename, int lineno)
{
const char *colon = NULL;
const char *right_bracket = NULL;
const char *cp;
for (cp = line; *cp != 0; ++cp)
{
if (*cp == ':')
colon = cp;
if (*cp == ']')
{
right_bracket = cp;
break;
}
}
/* Special case: [] means "no filter" */
if (right_bracket != NULL && right_bracket == line + 1)
{
clear_filter ();
return;
}
if (colon == NULL)
{
error_at_line (0, 0, filename, lineno,
"syntax error, filter line ignored: `%s' (missing ':')\n",
line);
return;
}
if (right_bracket == NULL)
{
error_at_line (0, 0, filename, lineno,
"syntax error, filter line ignored: `%s' (missing ']')\n",
line);
return;
}
if (filter_string != NULL)
{
clear_filter ();
}
if (colon - line - 1 == 4 && memcmp ("proc", line + 1, 4) == 0)
{
/* Consider this example: [proc:foo] ..." */
/* We allocate 4 bytes, [0] through [3]. */
filter_string = (char *) xmalloc (right_bracket - colon);
/* We copy "foo" for 3 bytes, [0] through [2]. */
memcpy (filter_string, colon + 1, right_bracket - colon - 1);
/* [3] = 0 so now "foo\0". */
filter_string [right_bracket - colon - 1] = 0;
filter_flags = TUNCONF_FILTER_PERPROC;
}
else
error_at_line (0, 0, filename, lineno,
"unrecognized filter `%.*s', ignored\n",
(int)(colon - line - 1), line + 1);
}
static void
add_tunable (char *line, const char *filename, int lineno)
{
TOP top = TOP_ALLOW;
char *name;
char *value;
char *eq;
char *orig_line;
struct tunable_entry_int *entry;
int i, id;
static struct tunable_entry_int **entry_list_next = &entry_list;
bool exclude_secure = 1, exclude_nonsecure = 0;
/* Denotes file boundaries. */
if (line == NULL)
{
clear_filter();
return;
}
orig_line = line;
/* Leading whitespace has already been stripped. */
/* Canonicalize the line. */
for (i=0; line[i]; i++)
{
if (line[i] == '\t')
line[i] = ' ';
if (line[i] == '\n' || line[i] == '\r')
{
line[i] = '\0';
break;
}
}
/* Parse modifiers. */
while (*line)
{
int prefix_len;
#define TUN_PREFIX(s) \
prefix_len = sizeof(s) - 1, \
strncmp (line, s " ", prefix_len + 1) == 0
if (TUN_PREFIX("overridable"))
{
top = TOP_ALLOW;
/* The line++ below skips the space. */
line += prefix_len;
}
else if (TUN_PREFIX ("nonoverridable"))
{
top = TOP_DENY;
line += prefix_len;
}
else if (TUN_PREFIX ("onlysecure"))
{
exclude_nonsecure = 1;
exclude_secure = 0;
line += prefix_len;
}
else if (TUN_PREFIX ("nonsecure"))
{
exclude_secure = 1;
exclude_nonsecure = 0;
line += prefix_len;
}
else if (TUN_PREFIX ("anysecure"))
{
exclude_secure = 0;
exclude_nonsecure = 0;
line += prefix_len;
}
else switch (*line)
{
case '+':
top = TOP_ALLOW;
break;
case '-':
top = TOP_DENY;
break;
case '@':
exclude_nonsecure = 1;
exclude_secure = 0;
break;
case '$':
exclude_nonsecure = 0;
exclude_secure = 1;
break;
case '*':
exclude_nonsecure = 0;
exclude_secure = 0;
break;
case '[':
parse_filter (line, filename, lineno);
return;
case ' ':
break;
default:
goto done;
}
line ++;
}
done:
/* NAME now points to the start of the tunable name. */
name = line;
/* Look for the '=' separator. */
eq = strchr (line, '=');
if (eq == NULL)
{
error_at_line (0, 0, filename, lineno,
"syntax error, line ignored: `%s' (missing '=')",
orig_line);
return;
}
if (eq == name)
{
error_at_line (0, 0, filename, lineno,
"syntax error, line ignored: `%s' (missing tunable name)",
orig_line);
return;
}
/* At this point, EQ actually points to '='. */
value = eq + 1;
while (*value && isspace(*value))
value ++;
if (*value == 0)
{
error_at_line (0, 0, filename, lineno,
"syntax error, line ignored: `%s' (missing value)",
orig_line);
return;
}
/* VALUE now points to the start of the value. */
/* Split the string into name and value c-strings. */
*eq = 0;
/* Trim trailing whitespace off NAME. */
while (*name && isspace (name[strlen(name)-1]))
name[strlen(name)-1] = 0;
/* Trim trailing whitespace off VALUE. */
while (*value && isspace (value[strlen(value)-1]))
value[strlen(value)-1] = 0;
id = -1;
for (i = 0; i < array_length (tunable_list); i ++)
if (strcmp (tunable_list[i].name, name) == 0)
{
id = i;
break;
}
if (id == -1)
printf ("%s:%d: Warning: tunable %s not recognized.\n",
filename, lineno, name);
entry = (struct tunable_entry_int *) xcalloc (sizeof (struct tunable_entry_int), 1);
entry->name = cache_store_string (name);
entry->value = cache_store_string (value);
entry->tunable_id = id;
entry->top = top;
entry->exclude_secure = exclude_secure;
entry->exclude_nonsecure = exclude_nonsecure;
if (filter_flags)
{
entry->filter_flags = filter_flags;
entry->filter = cache_store_string (filter_string);
}
if (value[0] == '-')
{
entry->value_is_negative = 1;
if (sscanf (value, "%lld", &entry->value_sll) == 1)
entry->value_was_parsed = 1;
}
else
{
entry->value_is_negative = 0;
if (sscanf (value, "%llu", &entry->value_ull) == 1)
entry->value_was_parsed = 1;
}
*entry_list_next = entry;
entry_list_next = & (entry->next);
}
void
parse_tunconf (const char *filename, char *opt_chroot)
{
ldconfig_parse_config (filename, opt_chroot, add_tunable);
}
struct tunable_header_cached *
get_tunconf_ext (uint32_t string_table_offset)
{
struct tunable_entry_int *tei;
struct tunable_header_cached *thc;
size_t count;
size_t size;
/* First, count the number of entries we have. */
tei = entry_list;
count = 0;
while (tei != NULL)
{
++ count;
tei = tei->next;
}
if (count == 0)
return NULL;
/* Allocate enough space for the whole cached block. */
size = sizeof (struct tunable_header_cached)
+ sizeof (struct tunable_entry_cached) * count;
thc = (struct tunable_header_cached *) xmalloc (size);
/* Now, fill in the structures. */
thc->signature = TUNCONF_SIGNATURE;
thc->version = TUNCONF_VERSION;
thc->num_tunables = count;
thc->unused_1 = 0;
tei = entry_list;
count = 0;
while (tei != NULL)
{
struct tunable_entry_cached *tec;
tec = & ( thc->tunables[count] );
tec->flags = 0;
if (tei->value_was_parsed)
tec->flags |= TUNCONF_FLAG_PARSED;
if (tei->value_is_negative)
tec->flags |= TUNCONF_FLAG_NEGATIVE;
switch (tei->top)
{
case TOP_ALLOW:
tec->flags |= TUNCONF_OVERRIDE_ALLOW;
break;
case TOP_DENY:
tec->flags |= TUNCONF_OVERRIDE_DENY;
break;
}
if (tei->exclude_secure)
tec->flags |= TUNCONF_EXCLUDE_SECURE;
if (tei->exclude_nonsecure)
tec->flags |= TUNCONF_EXCLUDE_UNSECURE;
tec->tunable_id = tei->tunable_id;
tec->name_offset = tei->name->offset + string_table_offset;
tec->value_offset = tei->value->offset + string_table_offset;
if (tei->filter_flags != 0)
{
tec->flag_offset = tei->filter->offset + string_table_offset;
tec->flags |= tei->filter_flags;
}
else
tec->flag_offset = 0;
tec->unused_1 = 0;
if (tei->value_is_negative)
tec->parsed_value = (uint64_t) tei->value_sll;
else
tec->parsed_value = (uint64_t) tei->value_ull;
++ count;
tei = tei->next;
}
return thc;
}
+45
View File
@@ -0,0 +1,45 @@
#define TUNCONF_SIGNATURE 0x7c3ba94f
#define TUNCONF_VERSION 0x01000000
#define TUNCONF_FLAG_PARSED 0x00000001
#define TUNCONF_FLAG_NEGATIVE 0x00000002
#define TUNCONF_FLAG_OVERRIDABLE 0x0000000C
#define TUNCONF_OVERRIDE_DENY 0x00000004
#define TUNCONF_OVERRIDE_ALLOW 0x00000000
#define TUNCONF_EXCLUDE_SECURE 0x00000010
#define TUNCONF_EXCLUDE_UNSECURE 0x00000020
#define TUNCONF_FLAG_FILTER 0x0000ff00
#define TUNCONF_FILTER_NONE 0x00000000
#define TUNCONF_FILTER_PERPROC 0x00000100
/* An array of [num_tunables] of these follows the below. */
struct tunable_entry_cached {
uint32_t flags;
uint32_t tunable_id;
uint32_t name_offset;
uint32_t value_offset;
uint32_t flag_offset;
uint32_t unused_1; /* for alignment */
uint64_t parsed_value;
};
/* One of these is at the beginning of the tunable data block. */
struct tunable_header_cached {
uint32_t signature;
uint32_t version;
uint32_t num_tunables;
uint32_t unused_1; /* for alignment */
struct tunable_entry_cached tunables[0 /* num_tunables */];
};
void parse_tunconf (const char *filename, char *opt_chroot);
struct tunable_header_cached * get_tunconf_ext (uint32_t str_offset);
#define TUNCONF_SIZE(thc_p) (sizeof(struct tunable_header_cached) \
+ thc_p->num_tunables * sizeof (struct tunable_entry_cached))
extern const struct tunable_header_cached *
_dl_load_cache_tunables (const char **data);
+6
View File
@@ -17,6 +17,7 @@
<https://www.gnu.org/licenses/>. */
#include <stdio.h>
#include <libc-diag.h>
#define __no_type_class -1
#define __void_type_class 0
@@ -61,12 +62,17 @@ do_test (void)
struct { int a; } __record_type;
union { int a; int b; } __union_type;
/* clang warns that the variables are uninitializedd, but the builtin
only inspects the type of its operand and never evaluates it. */
DIAG_PUSH_NEEDS_COMMENT_CLANG;
DIAG_IGNORE_NEEDS_COMMENT_CLANG (23, "-Wuninitialized");
result |= TEST (integer);
result |= TEST (pointer);
result |= TEST (real);
result |= TEST (complex);
result |= TEST (record);
result |= TEST (union);
DIAG_POP_NEEDS_COMMENT_CLANG;
return result;
}
+7
View File
@@ -257,3 +257,10 @@ $(addprefix $(objpfx),$(tests-static) $(xtests-static)): $(srcdir)/libpthread_sy
else
$(addprefix $(objpfx),$(tests) $(test-srcs)): $(srcdir)/libpthread_syms.a $(objpfx)libpthread.a
endif
# Like rt, these tests prefer to be run serially.
ifeq (yes-yes,$(run-built-tests)-$(serialize-tests))
ifneq ($(filter %tests,$(MAKECMDGOALS)),)
.NOTPARALLEL:
endif
endif
+1 -1
View File
@@ -102,7 +102,7 @@ __file_name_lookup_at (int fd, int at_flags,
file_t dir = result;
err = __dir_mkfile (dir, orig_flags & ~(O_TMPFILE | O_DIRECTORY),
mode, &result);
mode & ~_hurd_umask, &result);
__mach_port_deallocate (__mach_task_self (), dir);
if (err)
{
+4 -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-bug33980
tst-iconv-iso-2022-cn-ext tst-bug33980 \
tst-jisx0213-progress
ifeq ($(have-thread-library),yes)
tests += bug-iconv3
endif
@@ -335,6 +336,8 @@ $(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; \
+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; \
+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 -4
View File
@@ -20,11 +20,9 @@ extern int __fcntl (int __fd, int __cmd, ...);
libc_hidden_proto (__fcntl)
extern int __fcntl64 (int __fd, int __cmd, ...) attribute_hidden;
libc_hidden_proto (__fcntl64)
extern int __openat (int __fd, const char *__file, int __oflag, ...)
__nonnull ((2));
extern int __openat (int __fd, const char *__file, int __oflag, ...);
libc_hidden_proto (__openat)
extern int __openat64 (int __fd, const char *__file, int __oflag, ...)
__nonnull ((2));
extern int __openat64 (int __fd, const char *__file, int __oflag, ...);
libc_hidden_proto (__openat64)
extern int __open_2 (const char *__path, int __oflag);
+1 -1
View File
@@ -529,7 +529,7 @@
/* Major and minor version number of the GNU C library package. Use
these macros to test for features in specific releases. */
#define __GLIBC__ 2
#define __GLIBC_MINOR__ 43
#define __GLIBC_MINOR__ 44
#define __GLIBC_PREREQ(maj, min) \
((__GLIBC__ << 16) + __GLIBC_MINOR__ >= ((maj) << 16) + (min))
-3
View File
@@ -194,9 +194,6 @@ struct link_map
the l_libname list. */
unsigned int l_faked:1; /* Nonzero if this is a faked descriptor
without associated file. */
unsigned int l_need_tls_init:1; /* Nonzero if GL(dl_init_static_tls)
should be called on this link map
when relocation finishes. */
unsigned int l_auditing:1; /* Nonzero if the DSO is used in auditing. */
unsigned int l_audit_any_plt:1; /* Nonzero if at least one audit module
is interested in the PLT interception.*/
+3
View File
@@ -65,6 +65,9 @@ extern int __xpg_sigpause (int sig);
/* Allocate real-time signal with highest/lowest available priority. */
extern int __libc_allocate_rtsig (int __high);
/* Similar to raise, but does not set errno. */
extern int __raise_direct (int signo) attribute_hidden;
# if IS_IN (rtld)
extern __typeof (__sigaction) __sigaction attribute_hidden;
extern __typeof (__libc_sigaction) __libc_sigaction attribute_hidden;
-1
View File
@@ -18,7 +18,6 @@
extern void __chk_fail (void) __attribute__ ((__noreturn__));
libc_hidden_proto (__chk_fail)
rtld_hidden_proto (__chk_fail)
/* If we are using redirects internally to support long double,
we need to tweak some macros to ensure the PLT bypass tricks
+1 -1
View File
@@ -60,7 +60,7 @@ extern int inet_pton (int __af, const char *__restrict __cp,
/* Convert a Internet address in binary network format for interface
type AF in buffer starting at CP to presentation form and place
result in buffer of length LEN astarting at BUF. */
result in buffer of length LEN starting at BUF. */
extern const char *inet_ntop (int __af, const void *__restrict __cp,
char *__restrict __buf, socklen_t __len)
__THROW;
+2
View File
@@ -91,6 +91,8 @@ enum
#define IPPROTO_MPLS IPPROTO_MPLS
IPPROTO_ETHERNET = 143, /* Ethernet-within-IPv6 Encapsulation. */
#define IPPROTO_ETHERNET IPPROTO_ETHERNET
IPPROTO_AGGFRAG = 144, /* AGGFRAG in ESP (RFC 9347). */
#define IPPROTO_AGGFRAG IPPROTO_AGGFRAG
IPPROTO_RAW = 255, /* Raw IP packets. */
#define IPPROTO_RAW IPPROTO_RAW
IPPROTO_SMC = 256, /* Shared Memory Communications. */
+1 -1
View File
@@ -24,7 +24,7 @@ test_program_prefix=$2
objpfx=$3
# Create the locale directories.
mkdir -p ${objpfx}localedir/existing-locale/LC_MESSAGES
mkdir -p ${objpfx}domaindir/existing-locale/LC_MESSAGES
msgfmt -o ${objpfx}domaindir/existing-locale/LC_MESSAGES/translit.mo \
translit.po
+1 -1
View File
@@ -309,7 +309,7 @@ tst-statvfs-ARGS = $(objpfx)tst-statvfs tst-statvfs.c /tmp
tst-open-tmpfile-ARGS = --test-dir=$(objpfx)
CFLAGS-ftwtest-time64.c += -D_TIME_BITS=64 -D_FILE_OFFSET_BITS=64
CFLAGS-ftwtest-time64.c += $(+time64-flags) -D_FILE_OFFSET_BITS=64
ifeq ($(run-built-tests),yes)
$(objpfx)ftwtest.out: ftwtest-sh $(objpfx)ftwtest
+4 -8
View File
@@ -135,18 +135,14 @@ open64 (__fortify_clang_overload_arg (const char *, ,__path), int __oflag,
#ifdef __USE_ATFILE
# ifndef __USE_FILE_OFFSET64
extern int __openat_2 (int __fd, const char *__path, int __oflag)
__nonnull ((2));
extern int __openat_2 (int __fd, const char *__path, int __oflag);
extern int __REDIRECT (__openat_alias, (int __fd, const char *__path,
int __oflag, ...), openat)
__nonnull ((2));
int __oflag, ...), openat);
# else
extern int __REDIRECT (__openat_2, (int __fd, const char *__path,
int __oflag), __openat64_2)
__nonnull ((2));
int __oflag), __openat64_2);
extern int __REDIRECT (__openat_alias, (int __fd, const char *__path,
int __oflag, ...), openat64)
__nonnull ((2));
int __oflag, ...), openat64);
# endif
# ifdef __va_arg_pack_len
+3 -5
View File
@@ -230,19 +230,17 @@ extern int open64 (const char *__file, int __oflag, ...) __nonnull ((1));
This function is a cancellation point and therefore not marked with
__THROW. */
# ifndef __USE_FILE_OFFSET64
extern int openat (int __fd, const char *__file, int __oflag, ...)
__nonnull ((2));
extern int openat (int __fd, const char *__file, int __oflag, ...);
# else
# ifdef __REDIRECT
extern int __REDIRECT (openat, (int __fd, const char *__file, int __oflag,
...), openat64) __nonnull ((2));
...), openat64);
# else
# define openat openat64
# endif
# endif
# ifdef __USE_LARGEFILE64
extern int openat64 (int __fd, const char *__file, int __oflag, ...)
__nonnull ((2));
extern int openat64 (int __fd, const char *__file, int __oflag, ...);
# endif
#endif
+2 -1
View File
@@ -18,6 +18,7 @@
#include <sys/types.h>
#ifndef __OFF_T_MATCHES_OFF64_T
#if !defined __OFF_T_MATCHES_OFF64_T \
|| !defined __INO_T_MATCHES_INO64_T
# include "io/fts-common.c"
#endif
+2 -1
View File
@@ -50,7 +50,8 @@ weak_alias (__fts64_read, fts64_read)
weak_alias (__fts64_set, fts64_set)
weak_alias (__fts64_children, fts64_children)
#ifdef __OFF_T_MATCHES_OFF64_T
#if defined __OFF_T_MATCHES_OFF64_T \
&& defined __INO_T_MATCHES_INO64_T
weak_alias (__fts64_open, fts_open)
weak_alias (__fts64_close, fts_close)
weak_alias (__fts64_read, fts_read)
+3 -1
View File
@@ -18,7 +18,9 @@
#include <sys/types.h>
#ifndef __OFF_T_MATCHES_OFF64_T
#include <kernel_stat.h>
#if !XSTAT_IS_XSTAT64
# include "ftw-common.c"
versioned_symbol (libc, __new_nftw, nftw, GLIBC_2_3_3);
+4 -1
View File
@@ -31,6 +31,9 @@
#define ftw __rename_ftw
#define nftw __rename_nftw
#include <sys/types.h>
#include <kernel_stat.h>
#include <shlib-compat.h>
#include "ftw-common.c"
@@ -44,7 +47,7 @@ versioned_symbol (libc, __new_nftw64, nftw64, GLIBC_2_3_3);
compat_symbol (libc, __old_nftw64, nftw64, GLIBC_2_1);
#endif
#ifdef __OFF_T_MATCHES_OFF64_T
#if XSTAT_IS_XSTAT64
weak_alias (__ftw64, ftw)
versioned_symbol (libc, __new_nftw64, nftw, GLIBC_2_3_3);
# if SHLIB_COMPAT(libc, GLIBC_2_1, GLIBC_2_3_3)

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