diff options
author | kib <kib@FreeBSD.org> | 2014-05-24 10:23:06 +0000 |
---|---|---|
committer | kib <kib@FreeBSD.org> | 2014-05-24 10:23:06 +0000 |
commit | 1b73f3761fc6bb166b9011b59b584f5273f9c0ed (patch) | |
tree | 013989eded475e9be57868fa60cc2a1b7133ff82 /libexec | |
parent | 7d2507a09db7441bf0ec5a2b33729f964a99d074 (diff) | |
download | FreeBSD-src-1b73f3761fc6bb166b9011b59b584f5273f9c0ed.zip FreeBSD-src-1b73f3761fc6bb166b9011b59b584f5273f9c0ed.tar.gz |
Right now, the rtld prefork hook locks the rtld bind lock in the read
mode. This allows the binder to be functional in the child after the
fork (assuming no lazy loading of a filter is needed), but other rtld
services which require write lock on rtld_bind_lock cause deadlock, if
called by child.
Change the _rtld_atfork() to lock the bind lock in write mode, making
the rtld fully functional after the fork.
Pre-resolve the symbols which are called by the libthr' fork()
interposer, since dynamic resolution causes deadlock due to the
rtld_bind_lock already owned in the write mode.
Reported and tested by: pho
Sponsored by: The FreeBSD Foundation
MFC after: 2 weeks
Diffstat (limited to 'libexec')
-rw-r--r-- | libexec/rtld-elf/rtld_lock.c | 16 |
1 files changed, 15 insertions, 1 deletions
diff --git a/libexec/rtld-elf/rtld_lock.c b/libexec/rtld-elf/rtld_lock.c index d1563e5..ea16c4d 100644 --- a/libexec/rtld-elf/rtld_lock.c +++ b/libexec/rtld-elf/rtld_lock.c @@ -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]; |