]> git.ipfire.org Git - thirdparty/glibc.git/commit
elf: Initialize TCB and stack-protector before static IFUNC resolvers (BZ 20680,...
authorAdhemerval Zanella <adhemerval.zanella@linaro.org>
Fri, 22 May 2026 17:08:13 +0000 (14:08 -0300)
committerAdhemerval Zanella <adhemerval.zanella@linaro.org>
Mon, 25 May 2026 12:49:21 +0000 (12:49 +0000)
commitb75ad99d45b7475eca46353e68f4009f3837c751
tree0fb82cce2a83e74cc52c538e012c6c6b29009423
parentaf34b1376a37fa27e1de9d869ed9493fc569bfa6
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>
20 files changed:
csu/libc-start.c
csu/static-reloc.c
elf/Makefile
elf/dl-reloc-static-pie.c
elf/dynamic-link.h
elf/tst-ifunc-bz28817.c [new file with mode: 0644]
elf/tst-ifunc-resolver-protector-mod.c [new file with mode: 0644]
elf/tst-ifunc-resolver-protector-static-mod.c [new file with mode: 0644]
elf/tst-ifunc-resolver-protector-static-non-pie-mod.c [new file with mode: 0644]
elf/tst-ifunc-resolver-protector-static-non-pie.c [new file with mode: 0644]
elf/tst-ifunc-resolver-protector-static.c [new file with mode: 0644]
elf/tst-ifunc-resolver-protector.c [new file with mode: 0644]
sysdeps/aarch64/multiarch/dl-symbol-redir-ifunc.h
sysdeps/generic/ldsodefs.h
sysdeps/generic/libc-start.h
sysdeps/loongarch/lp64/multiarch/dl-symbol-redir-ifunc.h
sysdeps/unix/sysv/linux/aarch64/libc-start.h
sysdeps/unix/sysv/linux/powerpc/libc-start.h [deleted file]
sysdeps/x86_64/libc-start.h
sysdeps/x86_64/multiarch/dl-symbol-redir-ifunc.h