[PATCH v11 4/5] elf: Allow RPATH/RUNPATH for static-pie (BZ 33326)
Adhemerval Zanella <[email protected]> Tue, 28 Jul 2026 18:13:22 -0300
| Newsgroups | gmane.comp.lib.glibc.alpha |
|---|---|
| Message-ID | <[email protected]> |
The initial static-pie support (commit 9d7a3741c9e59eba87fb) 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 <[email protected]> --- elf/Makefile | 14 +++++++ elf/dl-load.c | 2 +- elf/dl-reloc-static-pie.c | 2 +- elf/get-dynamic-info.h | 7 +--- elf/rtld.c | 4 +- elf/setup-vdso.h | 2 +- elf/tst-pie-rpath-mod.c | 19 ++++++++++ elf/tst-pie-rpath-static.c | 38 +++++++++++++++++++ .../tst-pie-rpath-static.script | 2 + 9 files changed, 80 insertions(+), 10 deletions(-) create mode 100644 elf/tst-pie-rpath-mod.c create mode 100644 elf/tst-pie-rpath-static.c create mode 100644 elf/tst-pie-rpath-static.root/tst-pie-rpath-static.script diff --git a/elf/Makefile b/elf/Makefile index 9482bcbfca3..b27191a09e3 100644 --- a/elf/Makefile +++ b/elf/Makefile @@ -1263,6 +1263,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 @@ -3746,3 +3757,6 @@ $(objpfx)tst-assert-startup-static.out: $(objpfx)tst-assert-startup-static 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 diff --git a/elf/dl-load.c b/elf/dl-load.c index 95404adae94..586af946112 100644 --- a/elf/dl-load.c +++ b/elf/dl-load.c @@ -1319,7 +1319,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. */ diff --git a/elf/dl-reloc-static-pie.c b/elf/dl-reloc-static-pie.c index 8463e46147d..ad47b9aef61 100644 --- a/elf/dl-reloc-static-pie.c +++ b/elf/dl-reloc-static-pie.c @@ -72,7 +72,7 @@ _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); diff --git a/elf/get-dynamic-info.h b/elf/get-dynamic-info.h index 46faa34acf4..7368cf454b7 100644 --- a/elf/get-dynamic-info.h +++ b/elf/get-dynamic-info.h @@ -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); diff --git a/elf/rtld.c b/elf/rtld.c index fc053df8586..9f668c9f6ed 100644 --- a/elf/rtld.c +++ b/elf/rtld.c @@ -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; @@ -1694,7 +1694,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 diff --git a/elf/setup-vdso.h b/elf/setup-vdso.h index 0dba7072d53..58b77120468 100644 --- a/elf/setup-vdso.h +++ b/elf/setup-vdso.h @@ -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; diff --git a/elf/tst-pie-rpath-mod.c b/elf/tst-pie-rpath-mod.c new file mode 100644 index 00000000000..719eb41e091 --- /dev/null +++ b/elf/tst-pie-rpath-mod.c @@ -0,0 +1,19 @@ +/* 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/>. */ + +int foo (void) { return 42; } diff --git a/elf/tst-pie-rpath-static.c b/elf/tst-pie-rpath-static.c new file mode 100644 index 00000000000..bd445c1e035 --- /dev/null +++ b/elf/tst-pie-rpath-static.c @@ -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> diff --git a/elf/tst-pie-rpath-static.root/tst-pie-rpath-static.script b/elf/tst-pie-rpath-static.root/tst-pie-rpath-static.script new file mode 100644 index 00000000000..943045a20f4 --- /dev/null +++ b/elf/tst-pie-rpath-static.root/tst-pie-rpath-static.script @@ -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 -- 2.53.0