[v8,4/6] elf: Allow RPATH/RUNPATH for static-pie (BZ 33326)

Message ID 20260318193454.2466865-5-adhemerval.zanella@linaro.org (mailing list archive)
State New
Headers
Series elf: Allow RPATH/RUNPATH for static-pie |

Checks

Context Check Description
redhat-pt-bot/TryBot-apply_patch success Patch applied to master at the time it was sent
linaro-tcwg-bot/tcwg_glibc_build--master-aarch64 success Build passed
linaro-tcwg-bot/tcwg_glibc_build--master-arm success Build passed
linaro-tcwg-bot/tcwg_glibc_check--master-aarch64 success Test passed
linaro-tcwg-bot/tcwg_glibc_check--master-arm success Test passed

Commit Message

Adhemerval Zanella Netto March 18, 2026, 7:34 p.m. UTC
  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
  

Patch

diff --git a/elf/Makefile b/elf/Makefile
index 29d771ef7a..986ef6b388 100644
--- a/elf/Makefile
+++ b/elf/Makefile
@@ -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
diff --git a/elf/dl-load.c b/elf/dl-load.c
index 7355eef8e7..c5ea40fa4a 100644
--- a/elf/dl-load.c
+++ b/elf/dl-load.c
@@ -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.  */
diff --git a/elf/dl-reloc-static-pie.c b/elf/dl-reloc-static-pie.c
index bdff2b5ee2..22acd9bb4f 100644
--- a/elf/dl-reloc-static-pie.c
+++ b/elf/dl-reloc-static-pie.c
@@ -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);
diff --git a/elf/get-dynamic-info.h b/elf/get-dynamic-info.h
index 46faa34acf..9591d00d59 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;
@@ -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);
diff --git a/elf/rtld.c b/elf/rtld.c
index e1c2105ba6..783db6eb5c 100644
--- a/elf/rtld.c
+++ b/elf/rtld.c
@@ -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
diff --git a/elf/setup-vdso.h b/elf/setup-vdso.h
index 0dba7072d5..58b7712046 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 0000000000..719eb41e09
--- /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 0000000000..02fb05d2e6
--- /dev/null
+++ b/elf/tst-pie-rpath-static.c
@@ -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>