[PATCH v4] elf: Add back support for programs that do not load libc.so
Florian Weimer
fweimer@redhat.com
Tue Nov 12 21:14:09 GMT 2024
Commit 8f8dd904c4a2207699bb666f30acceb5209c8d3f (“elf:
rtld_multiple_ref is always true”) removed some code that happened
to enable compatibility with programs that do not link against
libc.so. Such programs cannot call dlopen or any dynamic linker
functions (except __tls_get_addr), so this is not really useful.
Still ld.so should not crash with a null-pointer dereference
or undefined symbol reference in these cases.
---
v4: Add the missing --as-needed and revert the __stack_chk_guard kludge.
elf/Makefile | 10 ++++++++++
elf/dl-minimal.c | 5 +++++
sysdeps/nptl/dl-mutex.c | 4 ++++
sysdeps/unix/sysv/linux/Makefile | 5 +++++
sysdeps/unix/sysv/linux/arm/Makefile | 3 +++
sysdeps/unix/sysv/linux/tst-nolink-libc.c | 25 +++++++++++++++++++++++++
6 files changed, 52 insertions(+)
diff --git a/elf/Makefile b/elf/Makefile
index 3a1cb72955..869bb621b6 100644
--- a/elf/Makefile
+++ b/elf/Makefile
@@ -3169,3 +3169,13 @@ tst-rtld-no-malloc-audit-ENV = LD_AUDIT=$(objpfx)tst-auditmod1.so
# Any shared object should do.
tst-rtld-no-malloc-preload-ENV = LD_PRELOAD=$(objpfx)tst-auditmod1.so
+
+# These rules link (without libc.so) and run the special
+# elf/tst-nolink-libc test if a port adds it to the tests variables.
+# The test is always run directly, not under the dynamic linker.
+$(objpfx)tst-nolink-libc: $(objpfx)tst-nolink-libc.o $(objpfx)ld.so
+ $(LINK.o) -nostdlib -nostartfiles -o $@ $< \
+ -Wl,--dynamic-link=$(objpfx)ld.so,--as-needed $(objpfx)ld.so
+CFLAGS-tst-nolink-libc.c += $(no-stack-protector)
+$(objpfx)tst-nolink-libc.out: $(objpfx)tst-nolink-libc $(objpfx)ld.so
+ $< > $@ 2>&1; $(evaluate-test)
diff --git a/elf/dl-minimal.c b/elf/dl-minimal.c
index dfa0764f58..d22a428964 100644
--- a/elf/dl-minimal.c
+++ b/elf/dl-minimal.c
@@ -82,6 +82,11 @@ __rtld_malloc_init_real (struct link_map *main_map)
rtld relocation (which enables RELRO, after which the pointer
variables cannot be written to). */
+ if (GL (dl_ns)[LM_ID_BASE].libc_map == NULL)
+ /* Nothing is linked against libc.so, which means that there is no
+ malloc implementation available. */
+ return;
+
struct r_found_version version;
version.name = symbol_version_string (libc, GLIBC_2_0);
version.hidden = 0;
diff --git a/sysdeps/nptl/dl-mutex.c b/sysdeps/nptl/dl-mutex.c
index 8d123cbb2f..85c71c1f81 100644
--- a/sysdeps/nptl/dl-mutex.c
+++ b/sysdeps/nptl/dl-mutex.c
@@ -35,6 +35,10 @@ __rtld_mutex_init (void)
constructor while holding loader locks. */
struct link_map *libc_map = GL (dl_ns)[LM_ID_BASE].libc_map;
+ if (libc_map == NULL)
+ /* Special case: the program links against ld.so, but not libc.so,
+ so the full locking implementation is not available. */
+ return;
const ElfW(Sym) *sym
= _dl_lookup_direct (libc_map, "pthread_mutex_lock",
diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile
index 527c7a5ae8..c87daaba90 100644
--- a/sysdeps/unix/sysv/linux/Makefile
+++ b/sysdeps/unix/sysv/linux/Makefile
@@ -652,7 +652,12 @@ install-bin += \
# install-bin
$(objpfx)pldd: $(objpfx)xmalloc.o
+
+test-internal-extras += tst-nolink-libc
+ifeq ($(run-built-tests),yes)
+tests-special += $(objpfx)tst-nolink-libc.out
endif
+endif # $(subdir) == elf
ifeq ($(subdir),rt)
CFLAGS-mq_send.c += -fexceptions
diff --git a/sysdeps/unix/sysv/linux/arm/Makefile b/sysdeps/unix/sysv/linux/arm/Makefile
index a73c897f43..e73ce4f811 100644
--- a/sysdeps/unix/sysv/linux/arm/Makefile
+++ b/sysdeps/unix/sysv/linux/arm/Makefile
@@ -1,5 +1,8 @@
ifeq ($(subdir),elf)
sysdep-rtld-routines += aeabi_read_tp libc-do-syscall
+# The test uses INTERNAL_SYSCALL_CALL. In thumb mode, this uses
+# an undefined reference to __libc_do_syscall.
+CFLAGS-tst-nolink-libc.c += -marm
endif
ifeq ($(subdir),misc)
diff --git a/sysdeps/unix/sysv/linux/tst-nolink-libc.c b/sysdeps/unix/sysv/linux/tst-nolink-libc.c
new file mode 100644
index 0000000000..817f37784b
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/tst-nolink-libc.c
@@ -0,0 +1,25 @@
+/* Test program not linked against libc.so and not using any glibc functions.
+ Copyright (C) 2024 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 <sysdep.h>
+
+void
+_start (void)
+{
+ INTERNAL_SYSCALL_CALL (exit_group, 0);
+}
base-commit: 461cab1de747f3842f27a5d24977d78d561d45f9
More information about the Libc-alpha
mailing list