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