Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 7 Jun 2014 02:45:24 +0000 (UTC)
From:      Konstantin Belousov <kib@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-10@freebsd.org
Subject:   svn commit: r267200 - in stable/10: lib/libthr/thread libexec/rtld-elf
Message-ID:  <201406070245.s572jONL020842@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
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];



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201406070245.s572jONL020842>