git: 860c4d94ac46 - main - rtld: add LD_NO_DL_ITERATE_PHDR_AFTER_FORK env var
Date: Mon, 29 Jul 2024 23:58:59 UTC
The branch main has been updated by kib:
URL: https://cgit.FreeBSD.org/src/commit/?id=860c4d94ac46cee35a678cf3c9cdbd437dfed75e
commit 860c4d94ac46cee35a678cf3c9cdbd437dfed75e
Author: Konstantin Belousov <kib@FreeBSD.org>
AuthorDate: 2024-07-17 04:05:33 +0000
Commit: Konstantin Belousov <kib@FreeBSD.org>
CommitDate: 2024-07-29 23:57:33 +0000
rtld: add LD_NO_DL_ITERATE_PHDR_AFTER_FORK env var
which makes threaded fork ignore the phdr rtld lock, in particular
allowing the dl_iterate_phdr() to block in callback. The cost is that
the image started in this mode cannot use dl_iterate_phdr() after fork.
PR: 280318
Sponsored by: The FreeBSD Foundation
MFC after: 1 week
---
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 f49c429d0061..1f0c59722ac6 100644
--- a/libexec/rtld-elf/rtld.c
+++ b/libexec/rtld-elf/rtld.c
@@ -375,6 +375,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 fcd42f3841b3..656e980c6261 100644
--- a/libexec/rtld-elf/rtld.h
+++ b/libexec/rtld-elf/rtld.h
@@ -376,6 +376,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]);
}