The branch main has been updated by kib:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=860c4d94ac46cee35a678cf3c9cdbd437dfed75e

commit 860c4d94ac46cee35a678cf3c9cdbd437dfed75e
Author:     Konstantin Belousov <[email protected]>
AuthorDate: 2024-07-17 04:05:33 +0000
Commit:     Konstantin Belousov <[email protected]>
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]);
 }

Reply via email to