Author: kib
Date: Sat Jun  7 02:45:24 2014
New Revision: 267200
URL: http://svnweb.freebsd.org/changeset/base/267200

Log:
  MFC r266609:
  Change the _rtld_atfork() to lock the bind lock in write mode.

Modified:
  stable/10/lib/libthr/thread/thr_fork.c
  stable/10/lib/libthr/thread/thr_rtld.c
  stable/10/libexec/rtld-elf/rtld_lock.c
Directory Properties:
  stable/10/   (props changed)

Modified: stable/10/lib/libthr/thread/thr_fork.c
==============================================================================
--- stable/10/lib/libthr/thread/thr_fork.c      Sat Jun  7 02:38:13 2014        
(r267199)
+++ stable/10/lib/libthr/thread/thr_fork.c      Sat Jun  7 02:45:24 2014        
(r267200)
@@ -57,6 +57,7 @@
  *
  */
 
+#include <sys/syscall.h>
 #include "namespace.h"
 #include <errno.h>
 #include <link.h>
@@ -174,8 +175,15 @@ _fork(void)
                was_threaded = 0;
        }
 
-       /* Fork a new process: */
-       if ((ret = __sys_fork()) == 0) {
+       /*
+        * Fork a new process.
+        * There is no easy way to pre-resolve the __sys_fork symbol
+        * without performing the fork.  Use the syscall(2)
+        * indirection, the syscall symbol is resolved in
+        * _thr_rtld_init() with side-effect free call.
+        */
+       ret = syscall(SYS_fork);
+       if (ret == 0) {
                /* Child process */
                errsave = errno;
                curthread->cancel_pending = 0;
@@ -250,6 +258,5 @@ _fork(void)
        }
        errno = errsave;
 
-       /* Return the process ID: */
        return (ret);
 }

Modified: stable/10/lib/libthr/thread/thr_rtld.c
==============================================================================
--- stable/10/lib/libthr/thread/thr_rtld.c      Sat Jun  7 02:38:13 2014        
(r267199)
+++ stable/10/lib/libthr/thread/thr_rtld.c      Sat Jun  7 02:45:24 2014        
(r267200)
@@ -32,10 +32,12 @@
   */
 #include <sys/cdefs.h>
 #include <sys/mman.h>
+#include <sys/syscall.h>
 #include <link.h>
 #include <stdlib.h>
 #include <string.h>
 
+#include "libc_private.h"
 #include "rtld_lock.h"
 #include "thr_private.h"
 
@@ -207,7 +209,24 @@ _thr_rtld_init(void)
        li.thread_set_flag = _thr_rtld_set_flag;
        li.thread_clr_flag = _thr_rtld_clr_flag;
        li.at_fork = NULL;
-       
+
+       /*
+        * Preresolve the symbols needed for the fork interposer.  We
+        * call _rtld_atfork_pre() and _rtld_atfork_post() with NULL
+        * argument to indicate that no actual locking inside the
+        * functions should happen.  Neither rtld compat locks nor
+        * libthr rtld locks cannot work there:
+        * - compat locks do not handle the case of two locks taken
+        *   in write mode (the signal mask for the thread is corrupted);
+        * - libthr locks would work, but locked rtld_bind_lock prevents
+        *   symbol resolution for _rtld_atfork_post.
+        */
+       _rtld_atfork_pre(NULL);
+       _rtld_atfork_post(NULL);
+       _malloc_prefork();
+       _malloc_postfork();
+       syscall(SYS_getpid);
+
        /* mask signals, also force to resolve __sys_sigprocmask PLT */
        _thr_signal_block(curthread);
        _rtld_thread_init(&li);

Modified: stable/10/libexec/rtld-elf/rtld_lock.c
==============================================================================
--- stable/10/libexec/rtld-elf/rtld_lock.c      Sat Jun  7 02:38:13 2014        
(r267199)
+++ stable/10/libexec/rtld-elf/rtld_lock.c      Sat Jun  7 02:45:24 2014        
(r267200)
@@ -365,8 +365,19 @@ _rtld_atfork_pre(int *locks)
 {
        RtldLockState ls[2];
 
+       if (locks == NULL)
+               return;
+
+       /*
+        * Warning: this does not work with the rtld compat locks
+        * above, since the thread signal mask is corrupted (set to
+        * all signals blocked) if two locks are taken in write mode.
+        * The caller of the _rtld_atfork_pre() must provide the
+        * working implementation of the locks, and libthr locks are
+        * fine.
+        */
        wlock_acquire(rtld_phdr_lock, &ls[0]);
-       rlock_acquire(rtld_bind_lock, &ls[1]);
+       wlock_acquire(rtld_bind_lock, &ls[1]);
 
        /* XXXKIB: I am really sorry for this. */
        locks[0] = ls[1].lockstate;
@@ -378,6 +389,9 @@ _rtld_atfork_post(int *locks)
 {
        RtldLockState ls[2];
 
+       if (locks == NULL)
+               return;
+
        bzero(ls, sizeof(ls));
        ls[0].lockstate = locks[2];
        ls[1].lockstate = locks[0];
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to