NetBSD-Bugs archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: lib/57792: SIGSEGV in ld.elf_so / _rtld_call_ifunc



The attached patch should resolve the underlying issue -- both fixing
the t_ifunc_now test, and fixing the gtk4 issue.  Details in the
commit message.
# HG changeset patch
# User Taylor R Campbell <riastradh%NetBSD.org@localhost>
# Date 1744941415 0
#      Fri Apr 18 01:56:55 2025 +0000
# Branch trunk
# Node ID f0c0c2d90c130d5e6e06ac9f5a230a3902d23412
# Parent  438b14ea036dd2bd2e1109f5e08f7d74109e6fae
# EXP-Topic riastradh-pr57792-relrorounding
ld.elf_so(1): Defer RELRO a bit for eagerly-bound (-z now) programs.

GNU binutils links programs a little differently if they're eagerly
bound with -Wl,-z,now.  In particular, the part of the .got relocated
for ifuncs is covered by the RELRO region in eagerly-bound programs
(-z now), but not in lazily-bound programs (default).

Presumably this is done under the premise that eagerly-bound programs
will resolve all ifuncs at startup _before_ mprotecting the main
object's RELRO region.  But ld.elf_so was mprotecting it first, in
_rtld_do_copy_relocations, and then resolving ifuncs -- at which the
memory locations where it tries to write the resolutions will be
mapped read-only.

(In contrast, for lazily bound programs, ifuncs may also be resolved
lazily, so the locations they relocate are _not_ covered by the RELRO
region and we don't run into any trouble)

To avoid this trouble, for eagerly-bound programs, we defer the RELRO
mprotect of the main object by a little bit -- we move it from
_rtld_do_copy_relocations to just after _rtld_call_init_functions.

PR lib/57792: SIGSEGV in ld.elf_so / _rtld_call_ifunc

diff -r 438b14ea036d -r f0c0c2d90c13 libexec/ld.elf_so/reloc.c
--- a/libexec/ld.elf_so/reloc.c	Thu Apr 17 13:43:59 2025 +0000
+++ b/libexec/ld.elf_so/reloc.c	Fri Apr 18 01:56:55 2025 +0000
@@ -154,7 +154,22 @@ int
 		}
 	}
 #ifdef GNU_RELRO
-	if (_rtld_relro(dstobj, true) == -1)
+	/*
+	 * If the main program is lazily bound (default -- whether or
+	 * not LD_BINDNOW is set in the calling environment), we are
+	 * now done writing to anything covered by RELRO and we can
+	 * safely make it read-only.  There may still be ifunc
+	 * resolution to do later; it will happen in a read/write
+	 * segment and will not be made read-only.
+	 *
+	 * But if the main program is eagerly bound (i.e., the object
+	 * has DF_1_NOW set in DT_FLAGS_1, whether or not LD_BIND_NOW
+	 * is set in the calling environment), we delay protecting the
+	 * RELRO region as read-only until we have resolved ifuncs --
+	 * at which point we will make the ifunc resolution read-only
+	 * too.
+	 */
+	if (!dstobj->z_now && _rtld_relro(dstobj, true) == -1)
 		return -1;
 #endif
 #endif /* RTLD_INHIBIT_COPY_RELOCS */
diff -r 438b14ea036d -r f0c0c2d90c13 libexec/ld.elf_so/rtld.c
--- a/libexec/ld.elf_so/rtld.c	Thu Apr 17 13:43:59 2025 +0000
+++ b/libexec/ld.elf_so/rtld.c	Fri Apr 18 01:56:55 2025 +0000
@@ -806,6 +806,27 @@ Elf_Addr
 
 	_rtld_exclusive_exit(&mask);
 
+#ifdef GNU_RELRO
+	/*
+	 * If the main program is lazily bound (default -- whether or
+	 * not LD_BINDNOW is set in the calling environment), its RELRO
+	 * region has already been mapped read-only in
+	 * _rtld_do_copy_relocations.  The ifunc resolutions lie
+	 * outside this region, so future lazy ifunc resolution is
+	 * unaffected by the RELRO region's being read-only.
+	 *
+	 * If the main program is eagerly bound (i.e., the object has
+	 * DF_1_NOW set in DT_FLAGS_1, whether or not LD_BIND_NOW is
+	 * set in the calling environment), we deferred that from
+	 * _rtld_do_copy_relocations so that the ifunc resolution, we
+	 * have now resolved all ifuncs in it, so we can commit the
+	 * RELRO region to be read-only -- and that means ifunc
+	 * resolutions are read-only too.
+	 */
+	if (_rtld_objmain->z_now && _rtld_relro(_rtld_objmain, true) == -1)
+		return -1;
+#endif
+
 	/*
 	 * Return with the entry point and the exit procedure in at the top
 	 * of stack.


Home | Main Index | Thread Index | Old Index