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.
Static binaries do not support rpath because they lack dynamic
sections, and adding static-pie support affects only the dlopen
function. If static dlopen support is removed, this change has no effect.
This change also simplifies elf_get_dynamic_info and removes a
difference between dynamic and static binaries.
Tested on aarch64-linux-gnu and x86_64-linux-gnu.
Reviewed-by: Florian Weimer <fweimer@redhat.com>
---
elf/Makefile | 11 ++++++++
elf/dl-load.c | 2 +-
elf/dl-reloc-static-pie.c | 2 +-
elf/get-dynamic-info.h | 5 ++--
elf/rtld.c | 4 +--
elf/setup-vdso.h | 2 +-
elf/tst-pie-rpath-mod.c | 19 ++++++++++++++
elf/tst-pie-rpath-static.c | 52 ++++++++++++++++++++++++++++++++++++++
8 files changed, 89 insertions(+), 8 deletions(-)
create mode 100644 elf/tst-pie-rpath-mod.c
create mode 100644 elf/tst-pie-rpath-static.c
@@ -1201,7 +1201,11 @@ tests += \
# tests
tests-static += \
tst-pie-address-static \
+ tst-pie-rpath-static \
# tests-static
+modules-names += \
+ tst-pie-rpath-mod \
+ # modules-names
ifeq (yes,$(aligned-65536))
tests += tst-pie-bss-static
tests-static += tst-pie-bss-static
@@ -3569,3 +3573,10 @@ $(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
+CFLAGS-tst-pie-rpath-static.c += -DPFX=\"$(objpfx)\"
+ifeq (no,$(build-hardcoded-path-in-tests))
+LDFLAGS-tst-pie-rpath-mod.so += -Wl,-rpath,$(rpath-link)
+endif
+$(objpfx)tst-pie-rpath-static.out: $(objpfx)tst-pie-rpath-mod.so
@@ -1269,7 +1269,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. */
@@ -69,7 +69,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);
@@ -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;
@@ -128,7 +127,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);
@@ -547,7 +547,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;
@@ -1706,7 +1706,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
@@ -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;
new file mode 100644
@@ -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; }
new file mode 100644
@@ -0,0 +1,52 @@
+/* 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 <stdlib.h>
+#include <support/xunistd.h>
+#include <support/support.h>
+#include <support/xdlfcn.h>
+#include <support/check.h>
+#include <support/temp_file.h>
+
+#define LIBNAME "tst-pie-rpath-mod.so"
+#define TESTSUBDIR PFX "tst-pie-rpath-static-subdir"
+#define LIBPATH TESTSUBDIR "/" LIBNAME
+
+static void
+do_prepare (int argc, char **argv)
+{
+ xmkdir (TESTSUBDIR, 0777);
+ add_temp_file (TESTSUBDIR);
+
+ support_copy_file (PFX "/" LIBNAME, LIBPATH);
+ add_temp_file (LIBPATH);
+}
+#define PREPARE do_prepare
+
+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>