3270 Commits
Author SHA1 Message Date
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
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
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
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
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
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
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 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
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
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 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
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
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
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
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
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 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 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
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
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 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
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
Adhemerval Zanella 16c74b94b9 elf: Fix clang-18 build of ifunc resolver tests
clang-18 errors on the static ifunc resolvers seen as unused.
2026-06-24 13:41:26 -03:00
H.J. Lu 53d909a283 elf: Support THP segment load with madvise enabled THP
The current THP segment load approach works only when THP is enabled
with always in the kernel.  If THP is enabled with madvise in the
kernel, to enable THP segment load in an application, madvise should
be called with MADV_HUGEPAGE on all THP eligible PT_LOAD segments:

1. Define DL_MAP_DEFAULT_THP_PAGESIZE in hugepages.h and default it to 0.
If DL_MAP_DEFAULT_THP_PAGESIZE is defined, assume kernel THP madvise mode.
If kernel THP mode is always or never, there is an extra madvise call
which has no impact.  DL_MAP_DEFAULT_THP_PAGESIZE is defined for x86-64
and 64-bit loongarch.
2. Update _dl_map_segment_align to support madvise THP mode.  This fixes
BZ #34079.
3. Call _dl_executable_postprocess in rtld_setup_main_map for dynamic
executables and in LIBC_START_MAIN for static executables, which calls
madvise with MADV_HUGEPAGE on all THP eligible PT_LOAD segments in
executable.  This fixes BZ #34080 for both dynamic and static executables.
4. Call _dl_postprocess_loadcmd_extra in _dl_postprocess_loadcmd, which
calls madvise with MADV_HUGEPAGE on all THP eligible PT_LOAD segments
when loading an object after they have been mapped in.  This fixes
BZ #34080 for shared objects.
5. Set the maximum page alignment on THP tests to THP page size as the
default maximum page alignment may be smaller than THP page size.
6. Add tests to verify that large executable PT_LOAD segments in
executables are mapped at addresses aligned to THP page size when the
kernel is configured to use THP in "always" mode or "madvise" mode by
inspecting /proc/self/maps to check that the mapping address is aligned
to THP page size reported by the kernel.  Also verify that madvise is
called with MADV_HUGEPAGE when the glibc tunable glibc.elf.thp=1 is used
and madvise isn't called with MADV_HUGEPAGE when the glibc tunable
glibc.elf.thp=0 is used.

Skip these tests if THP page size cannot be determined or if THP is not
enabled in "always" mode nor "madvise" mode.

Quote WANG Rui <wangrui@loongson.cn>:

From benchmarking a clang build of the Linux kernel on x86_64 with
your patch in THP madvise mode, I observed that iTLB misses were
reduced, similar to what we see in THP always mode.

NB: Some THP tests fail on arm due to limitations of arm32 kABI:

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

Signed-off-by: H.J. Lu <hjl.tools@gmail.com>
Reviewed-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org>
2026-06-20 05:35:24 +08:00
Adhemerval Zanella da11a7d92c Remove unused THREAD_SET_POINTER_GUARD and THREAD_COPY_POINTER_GUARD
Commit a5ec880f80 ("Consolidate pointer
guard to use a relro variable instead of the TCB") moved the pointer
guard to the module-local relro variable __pointer_chk_guard_local and
dropped the THREAD_{SET,COPY}_POINTER_GUARD macros, which are no longer
defined by any target.

Checked on a build for all afftected targets.
2026-06-19 14:23:05 -03:00
Adhemerval Zanella 337e18d661 elf: Scrub and reseed the AT_RANDOM bytes after deriving the guards (BZ 34197)
Once the pointer and stack guards have been derived from AT_RANDOM, scrub
the bytes and refill them with new random data unrelated to the guards.
On Linux, it uses getrandom syscall (as for tcache_key_initialize), and
fallback to zero the memory if the syscall is not avaiable.

This keeps AT_RANDOM useful to applications while ensuring those bytes no
longer reveal the guards.

The work is done by _dl_reseed_random, called once the guards are in place
and before any ELF constructor can observe AT_RANDOM: in security_init for
the dynamic loader and in __libc_start_main for statically linked programs.

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

Reviewed-by: DJ Delorie <dj@redhat.com>
2026-06-16 14:53:48 -03:00
Adhemerval Zanella 3785d4c0d0 elf: Propagate the pointer guard to ld.so loaded via static dlopen (BZ 34196)
The static-dlopen does not initialize the pointer guard for ABIs that
define THREAD_SET_POINTER_GUARD.  Besides not properly guard the
pointer if a libc.so symbol is called, this can lead to setjmp
failures (a jmp_buf set up by the loaded libc.so.6 cannot be restored
by the static program's __longjmp, and vice versa).

Seed the just-mapped loader's __pointer_chk_guard from the program's
__pointer_chk_guard_local in __rtld_static_init, next to the other
runtime values copied there.

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

Reviewed-by: DJ Delorie <dj@redhat.com>
2026-06-16 08:29:57 -03:00
Sam James d0cc9bf859 elf: don't clobber ld.so.conf in tst-glibc-hwcaps-prepend-cache [BZ #34210]
dbe5065f21 and ae589cb84d
cater for setups where ld.so.conf{,.d} is required to find runtime support
libraries, but tst-glibc-hwcaps-prepend-cache clobbers the created ld.so.conf
with its own entry.

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

Bug: https://bugs.gentoo.org/976773
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=31901
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=34210
Tested-by: Andreas K. Hüttel <dilfridge@gentoo.org>
Reported-by: Eli Schwartz <eschwartz@gentoo.org>
Reviewed-by: Andreas K. Hüttel <dilfridge@gentoo.org>
2026-06-06 21:22:46 +01:00
Adhemerval Zanella f9a11a380d elf: Set up TLS slotinfo for dlopen'd modules before relocation (BZ 34170)
An IFUNC resolver in a DSO that is being loaded by dlopen is allowed
to read its own TLS storage during the resolver call.  After
af34b1376a ("elf: Initialize static TLS before relocation processing
(BZ 34164)") that works for the initial-exec model on every supported
architecture.

However, it does not work for the dynamic-TLS path (on both -mtls-dialect mode,
if the ABI supports both).  Both lookup paths index the calling thread's
DTV by the new module's l_tls_modid and, on miss, walk
GL(dl_tls_dtv_slotinfo_list) to discover the module and lazily allocate
its TLS block.  The just-loaded DSO is however not yet in that list when
its resolver fires, so the lookup faults inside dlopen.  This is the
direct dlopen analog of BZ 34164.

The solution is to reorder dl_open_worker_begin so the slotinfo install
happens before the relocation pass.  The new order is:

  1. resize_scopes, resize_tls_slotinfo, add_to_global_resize
     (unchanged, still recoverable).
  2. update_tls_slotinfo: register the new modules in slotinfo, bump
     dl_tls_generation, initialise their static TLS images.
  3. Relocate the new objects.  IFUNC resolvers can now read their
     own DSO's __thread storage via any TLS model.
  4. Demarcation point.
  5. update_scopes, _dl_find_object_update.

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

Reviewed-by: H.J. Lu <hjl.tools@gmail.com>
2026-06-05 16:20:20 -03:00
Adhemerval Zanella 5879990337 elf: Fix tst-ifunc-tls-init with --disable-default-pie
The test failed with --disable-default-pie because its primary check read
the resolver's diagnostic side effect before the resolver had run.

In a non-PIE executable the references to the IFUNC (fptr and ifunc_tls)
are satisfied through a canonical IPLT entry in the executable itself.
Under the default lazy binding that IPLT is resolved on first use, not
during startup relocation, so the resolver had not yet run when
'check_sentinel' inspected that value.  With a PIE executable
(or LD_BIND_NOW=1) the resolver runs eagerly at startup and the check
passed.  The dlopen path was unaffected because dlopen resolves the
data relocation eagerly.

This is a test ordering issue: the resolver always reads the initial-exec
TLS correctly whenever it runs, so the BZ 34164 fix is not involved.
Reorder test_tls_ifunc so that fptr/ifunc_tls force the IFUNC to be
resolved before the last_seen_sentinel value is inspected.

Checked on x86_64-linux-gnu and i686-linux-gnu with --disable-default-pie.

Reported-by: Yury Khrustalev <yury.khrustalev@arm.com>
Reviewed-by: Yury Khrustalev <yury.khrustalev@arm.com>
2026-06-02 15:10:02 -03:00
Yury Khrustalev 0458560b5d misc: Fix typos in comments 2026-06-01 13:29:53 +01:00
Yury Khrustalev 70be9819b5 malloc: aarch64: Remove broken memory tagging
Remove the --enable-memory-tagging configure option along with
all associated variables and macros.

Removing the glibc.mem.tagging tunable.

Remove the memory-tagging makefile variable.

Remove the USE_MTAG macro definition and code that is conditionally
compiled when this macro is defined.

As a result, we change 'mtag_mmap_flags' to 'extra_mmap_prot' that
is now always defined. Change of the name due to this being used
as part of PROT options in mmap syscalls rather than part of flags.

Remove 'mtag_enabled' that would become compile-time false. Also
remove any code that would never be compiled when 'mtag_enabled'
is false.

Remove AArch64-specific code pertinent to memory tagging, that is
currently broken, from the core malloc implementation. We keep
the assembly code, since we are going to need it in the future. to
preserve Git history.

Reviewed-by: Wilco Dijkstra <Wilco.Dijkstra@arm.com>
2026-05-31 16:11:23 +01:00
Muhammad Kamran b9e893b60e aarch64: Use build attributes for asm feature marking
When the compiler defines __ARM_BUILDATTR64_FV, emit AArch64
feature-and-bits build attributes for BTI, PAC, and GCS from sysdep.h
instead of a GNU property note.  Keep the GNU property note as the
fallback for older toolchains.

Mirror the same marking logic in elf/tst-asm-helper.h so custom test
DSOs and assembly tests that cannot include sysdep.h get consistent
feature marking.

Reviewed-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org>
2026-05-29 13:58:58 -03:00
Adhemerval Zanella eceaece54b elf: Re-initialise static TLS after .tdata relocation (BZ 34164)
The af34b1376a (BZ 34164) changed the
TLS setup from:

  relocation loop (applies relocations to .tdata in DSO memory)
  _dl_allocate_tls_init copies relocated .tdata -> main thread TLS

to a new order:

  _dl_allocate_tls_init copies unrelocated .tdata -> main thread TLS
  relocation loop (relocates .tdata in DSO memory, but the TLS block
  has stale copies)

This broke file-scope thread-local initialised with the address of a
function (for instance the cache structs in libmpfr).

Fix it by splitting ELF_DYNAMIC_RELOCATE inside
_dl_relocate_object_no_relro into the non-IRELATIVE and IRELATIVE
sub-passes (similar as done on static-pie startup by b75ad99d45)
and call _dl_init_static_tls between them.  By the time the IFUNC
pass fires, .tdata is fully relocated.

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

Reviewed-by: H.J. Lu <hjl.tools@gmail.com>
2026-05-27 10:43:30 -03:00
Adhemerval Zanella b75ad99d45 elf: Initialize TCB and stack-protector before static IFUNC resolvers (BZ 20680, BZ 27582, BZ 28817)
In static linking the IFUNC IPLT (apply_irel for non-PIE, the IRELATIVE
phase inside _dl_relocate_static_pie for static-pie) ran before
__libc_setup_tls and before _dl_setup_stack_chk_guard.  When a resolver
is compiled with -fstack-protector(-all) its prologue loads the canary
from the TCB (TCB-canary ABIs: x86_64, i386, powerpc, s390) or from
__stack_chk_guard (global-var ABIs).  On the former the resolver
crashed reading an unmapped TCB; on the latter it loaded a zero canary
(no crash, but the check is ineffective).  The same applies to a
resolver that reads any thread-local: it crashes on TCB-canary ABIs and
observes a zero-filled slot on the others (BZ 20680).  The pointer
guard has the same problem (e.g. resolvers that register an atexit
handler).

Reorder csu/libc-start.c so that ARCH_SETUP_TLS, the stack-protector
canary and the pointer guard are set up before any IFUNC resolver
runs.  For static-pie this requires splitting the existing
_dl_relocate_static_pie into two phases so the TCB/canary setup can be
interleaved between the non-IRELATIVE and IRELATIVE passes.

The historical ARCH_SETUP_IREL / ARCH_APPLY_IREL split (introduced for
powerpc so its IFUNC resolvers could read TCB fields like hwcap and
at_platform) is no longer required: TLS is now set up before either
macro runs.  ARCH_APPLY_IREL is removed, ARCH_SETUP_IREL does the work
uniformly on every arch, and the powerpc-specific libc-start.h becomes
redundant.

__libc_setup_tls reaches memcpy / mempcpy via _dl_allocate_tls_init in
elf/dl-tls.c, so it requires update ABI specific dl-symbol-redir-ifunc.h
with memcpy/memmove.

Tests added (each fails pre-fix on TCB-canary ABIs with SIGSEGV; the
static-protector variants additionally fail on global-var ABIs with a
"resolver_canary != main_canary" diagnostic):

  elf/tst-ifunc-bz28817                            static-pie + TLS in
                                                   resolver (BZ 28817)
  elf/tst-ifunc-resolver-protector                 dynamic
  elf/tst-ifunc-resolver-protector-static          static-pie
  elf/tst-ifunc-resolver-protector-static-non-pie  non-PIE static

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

I also ran the ELF tests on qemu system for loongarch64-linux-gnuf64,
powerpc-linux-gnu, powerpc-linux-gnu-power4, powerpc-linux-gnu-soft,
powerpc64-linux-gnu, powerpc64le-linux-gnu, riscv64-linux-gnu, and
s390x-linux-gnu.
Reviewed-by: H.J. Lu <hjl.tools@gmail.com>
2026-05-25 12:49:21 +00:00
Adhemerval Zanella af34b1376a elf: Initialize static TLS before relocation processing (BZ 34164)
An IFUNC resolver firing during dynamic linker relocation reads its
DSO's __thread storage from a zero-filled slot: init_tls() allocates
the static TLS block zero-filled, but .tdata is not copied in until
the trailing _dl_allocate_tls_init at the end of dl_main, long after
the per-object phase 2 resolvers from commit 63b31c05a8 have run.
A resolver that *writes* TLS is even worse off -- the write is
clobbered by that same trailing copy.

dl_main (elf/rtld.c): populate the DTV slotinfo, bump
dl_tls_generation, and call _dl_allocate_tls_init right after
init_tls(), before the relocation loop.

_dl_try_allocate_static_tls (elf/dl-reloc.c): drop the
"defer-if-not-relocated" branch and always run _dl_init_static_tls
inline, so a CHECK_STATIC_TLS allocation triggered mid-relocation
initialises the slot before the same object's phase 2 fires.

The new tests cheks some scenarios:

  elf/tst-ifunc-tls-init         resolver reads its DSO's IE TLS.
  elf/tst-ifunc-tls-init-dlopen  same, via dlopen.
  elf/tst-ifunc-tls-write        resolver write to TLS must survive
                                 to main.

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

Reviewed-by: H.J. Lu <hjl.tools@gmail.com>
2026-05-25 12:49:14 +00:00