git: 279e543dc707 - stable/14 - rtld: add LD_NO_DL_ITERATE_PHDR_AFTER_FORK env var

From: Konstantin Belousov <kib_at_FreeBSD.org>
Date: Mon, 05 Aug 2024 00:32:42 UTC
The branch stable/14 has been updated by kib:

URL: https://cgit.FreeBSD.org/src/commit/?id=279e543dc707ee19b28cee8a00deafea1f8b8d8e

commit 279e543dc707ee19b28cee8a00deafea1f8b8d8e
Author:     Konstantin Belousov <kib@FreeBSD.org>
AuthorDate: 2024-07-17 04:05:33 +0000
Commit:     Konstantin Belousov <kib@FreeBSD.org>
CommitDate: 2024-08-05 00:32:11 +0000

    rtld: add LD_NO_DL_ITERATE_PHDR_AFTER_FORK env var
    
    PR:     280318
    
    (cherry picked from commit 860c4d94ac46cee35a678cf3c9cdbd437dfed75e)
---
 libexec/rtld-elf/rtld.1      | 10 +++++++++-
 libexec/rtld-elf/rtld.c      |  1 +
 libexec/rtld-elf/rtld.h      |  1 +
 libexec/rtld-elf/rtld_lock.c |  7 +++++--
 4 files changed, 16 insertions(+), 3 deletions(-)

diff --git a/libexec/rtld-elf/rtld.1 b/libexec/rtld-elf/rtld.1
index 992138b1ffc0..31e046a5cdc4 100644
--- a/libexec/rtld-elf/rtld.1
+++ b/libexec/rtld-elf/rtld.1
@@ -26,7 +26,7 @@
 .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 .\"
-.Dd April 28, 2024
+.Dd July 24, 2025
 .Dt RTLD 1
 .Os
 .Sh NAME
@@ -329,6 +329,14 @@ The static TLS extra space is used when loading objects compiled for
 initial-exec TLS code model with
 .Xr dlopen 3 .
 The minimum value that can be specified is \'128\'.
+.It Ev LD_NO_DL_ITERATE_PHDR_AFTER_FORK
+Allow
+.Xr dl_iterate_phdr 3
+to block in callback, without causing deadlock with the
+.Xr fork 2 .
+The drawback is that the image started in this mode cannot use
+.Xr dl_iterate_phdr 3
+after fork.
 .El
 .Sh DIRECT EXECUTION MODE
 .Nm
diff --git a/libexec/rtld-elf/rtld.c b/libexec/rtld-elf/rtld.c
index 411fe7956873..e7fcfde8f474 100644
--- a/libexec/rtld-elf/rtld.c
+++ b/libexec/rtld-elf/rtld.c
@@ -376,6 +376,7 @@ static struct ld_env_var_desc ld_env_vars[] = {
 	LD_ENV_DESC(TRACE_LOADED_OBJECTS_ALL, false),
 	LD_ENV_DESC(SHOW_AUXV, false),
 	LD_ENV_DESC(STATIC_TLS_EXTRA, false),
+	LD_ENV_DESC(NO_DL_ITERATE_PHDR_AFTER_FORK, false),
 };
 
 const char *
diff --git a/libexec/rtld-elf/rtld.h b/libexec/rtld-elf/rtld.h
index 96a9da3c4ea3..97187b24ce84 100644
--- a/libexec/rtld-elf/rtld.h
+++ b/libexec/rtld-elf/rtld.h
@@ -383,6 +383,7 @@ enum {
 	LD_TRACE_LOADED_OBJECTS_ALL,
 	LD_SHOW_AUXV,
 	LD_STATIC_TLS_EXTRA,
+	LD_NO_DL_ITERATE_PHDR_AFTER_FORK,
 };
 
 void _rtld_error(const char *, ...) __printflike(1, 2) __exported;
diff --git a/libexec/rtld-elf/rtld_lock.c b/libexec/rtld-elf/rtld_lock.c
index 0c790450dcec..323bb7494c32 100644
--- a/libexec/rtld-elf/rtld_lock.c
+++ b/libexec/rtld-elf/rtld_lock.c
@@ -463,6 +463,7 @@ _rtld_atfork_pre(int *locks)
 
 	if (locks == NULL)
 		return;
+	bzero(ls, sizeof(ls));
 
 	/*
 	 * Warning: this did not worked well with the rtld compat
@@ -472,7 +473,8 @@ _rtld_atfork_pre(int *locks)
 	 * _rtld_atfork_pre() must provide the working implementation
 	 * of the locks anyway, and libthr locks are fine.
 	 */
-	wlock_acquire(rtld_phdr_lock, &ls[0]);
+	if (ld_get_env_var(LD_NO_DL_ITERATE_PHDR_AFTER_FORK) == NULL)
+		wlock_acquire(rtld_phdr_lock, &ls[0]);
 	wlock_acquire(rtld_bind_lock, &ls[1]);
 
 	/* XXXKIB: I am really sorry for this. */
@@ -492,5 +494,6 @@ _rtld_atfork_post(int *locks)
 	ls[0].lockstate = locks[2];
 	ls[1].lockstate = locks[0];
 	lock_release(rtld_bind_lock, &ls[1]);
-	lock_release(rtld_phdr_lock, &ls[0]);
+	if (ld_get_env_var(LD_NO_DL_ITERATE_PHDR_AFTER_FORK) == NULL)
+		lock_release(rtld_phdr_lock, &ls[0]);
 }