[glibc] elf: Propagate the pointer guard to ld.so loaded via static dlopen (BZ 34196)
Adhemerval Zanella via Glibc-cvs <[email protected]> Tue, 16 Jun 2026 18:15:35 +0000 (GMT)
| Newsgroups | gmane.comp.lib.glibc.cvs |
|---|---|
| Message-ID | <[email protected]> |
https://sourceware.org/git/gitweb.cgi?p=glibc.git;h=3785d4c0d0f2d1b08c4f1b744afa05951985e94d commit 3785d4c0d0f2d1b08c4f1b744afa05951985e94d Author: Adhemerval Zanella <[email protected]> Date: Fri Jun 12 13:10:09 2026 -0300 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 <[email protected]> Diff: --- elf/Makefile | 6 +++ elf/rtld_static_init.c | 12 +++++ elf/tst-ptrguard-static-dlopen-mod.c | 29 ++++++++++++ elf/tst-ptrguard-static-dlopen.c | 51 ++++++++++++++++++++++ .../tst-ptrguard-static-dlopen.script | 1 + 5 files changed, 99 insertions(+) diff --git a/elf/Makefile b/elf/Makefile index 5ede78c590..8a89ed3c60 100644 --- a/elf/Makefile +++ b/elf/Makefile @@ -270,6 +270,7 @@ tests-static-normal := \ tst-env-setuid-static \ tst-getauxval-static \ tst-linkall-static \ + tst-ptrguard-static-dlopen \ tst-single_threaded-pthread-static \ tst-single_threaded-static \ tst-tls-allocation-failure-static \ @@ -576,6 +577,7 @@ tests-container += \ tst-dlopen-tlsmodid-container \ tst-pldd \ tst-preload-pthread-libc \ + tst-ptrguard-static-dlopen \ tst-rootdir \ # tests-container @@ -1013,6 +1015,7 @@ modules-names += \ tst-null-argv-lib \ tst-p_alignmod-base \ tst-p_alignmod3 \ + tst-ptrguard-static-dlopen-mod \ tst-recursive-tlsmallocmod \ tst-recursive-tlsmod0 \ tst-recursive-tlsmod1 \ @@ -3201,6 +3204,9 @@ $(objpfx)tst-tls21mod.so: $(tst-tls-many-dynamic-modules:%=$(objpfx)%.so) $(objpfx)tst-getauxval-static.out: $(objpfx)tst-auxvalmod.so tst-getauxval-static-ENV = LD_LIBRARY_PATH=$(objpfx):$(common-objpfx) +$(objpfx)tst-ptrguard-static-dlopen.out: \ + $(objpfx)tst-ptrguard-static-dlopen-mod.so + $(objpfx)tst-dlmopen-gethostbyname.out: $(objpfx)tst-dlmopen-gethostbyname-mod.so $(objpfx)tst-ro-dynamic: $(objpfx)tst-ro-dynamic-mod.so diff --git a/elf/rtld_static_init.c b/elf/rtld_static_init.c index 04eb1c6fcc..fecde95440 100644 --- a/elf/rtld_static_init.c +++ b/elf/rtld_static_init.c @@ -81,5 +81,17 @@ __rtld_static_init (struct link_map *map) dl->_dl_find_object = _dl_find_object; dl->_dl_readonly_area = _dl_readonly_area; +#ifndef THREAD_SET_POINTER_GUARD + extern uintptr_t __pointer_chk_guard_local attribute_hidden; + const ElfW(Sym) *guard_sym + = _dl_lookup_direct (map, "__pointer_chk_guard", + 0x69f99cab, /* _dl_new_hash output. */ + "GLIBC_PRIVATE", + 0x0963cf85); /* _dl_elf_hash output. */ + assert (guard_sym != NULL); + *(uintptr_t *) DL_SYMBOL_ADDRESS (map, guard_sym) + = __pointer_chk_guard_local; +#endif + __rtld_static_init_arch (map, dl); } diff --git a/elf/tst-ptrguard-static-dlopen-mod.c b/elf/tst-ptrguard-static-dlopen-mod.c new file mode 100644 index 0000000000..1b98e24d03 --- /dev/null +++ b/elf/tst-ptrguard-static-dlopen-mod.c @@ -0,0 +1,29 @@ +/* Shared object for the static-dlopen pointer guard test. + 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 <setjmp.h> + +static jmp_buf jb; +void (*do_longjmp) (jmp_buf); + +void +foo (void) +{ + if (setjmp (jb) == 0) + do_longjmp (jb); +} diff --git a/elf/tst-ptrguard-static-dlopen.c b/elf/tst-ptrguard-static-dlopen.c new file mode 100644 index 0000000000..5e4337b11c --- /dev/null +++ b/elf/tst-ptrguard-static-dlopen.c @@ -0,0 +1,51 @@ +/* Test that the pointer guard is propagated to ld.so via static dlopen. + 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/>. */ + +/* A statically linked program dlopens a shared object; the object's setjmp + uses the just-mapped libc.so's pointer guard while the longjmp below uses + the program's guard. Unless __rtld_static_init propagates the guard to + the loaded loader the two differ, and the setjmp/longjmp round-trip jumps + to a corrupt address and crashes. */ + +#include <setjmp.h> +#include <support/check.h> +#include <support/xdlfcn.h> + +static void +call_longjmp (jmp_buf jb) +{ + longjmp (jb, 1); +} + +static int +do_test (void) +{ + void *h = xdlopen ("tst-ptrguard-static-dlopen-mod.so", RTLD_NOW); + void (*foo) (void) = xdlsym (h, "foo"); + void (**do_longjmp) (jmp_buf) = xdlsym (h, "do_longjmp"); + *do_longjmp = call_longjmp; + + /* foo () sets the jump buffer and calls back into call_longjmp; a + mismatched guard makes the return jump fault. */ + foo (); + + xdlclose (h); + return 0; +} + +#include <support/test-driver.c> diff --git a/elf/tst-ptrguard-static-dlopen.root/tst-ptrguard-static-dlopen.script b/elf/tst-ptrguard-static-dlopen.root/tst-ptrguard-static-dlopen.script new file mode 100644 index 0000000000..e4f49b3475 --- /dev/null +++ b/elf/tst-ptrguard-static-dlopen.root/tst-ptrguard-static-dlopen.script @@ -0,0 +1 @@ +cp $B/elf/tst-ptrguard-static-dlopen-mod.so $L/tst-ptrguard-static-dlopen-mod.so