aboutsummaryrefslogtreecommitdiff
path: root/libexec
diff options
context:
space:
mode:
authorJohn Polstra <jdp@FreeBSD.org>2000-07-17 17:18:13 +0000
committerJohn Polstra <jdp@FreeBSD.org>2000-07-17 17:18:13 +0000
commitcf98e664033a885a34fc059b01d990153b322f82 (patch)
tree5934a076b31790410e34aa844018d67295f4a1c7 /libexec
parent15602c8dd8cbd2da4d7ec322b097b00620a00251 (diff)
downloadsrc-cf98e664033a885a34fc059b01d990153b322f82.tar.gz
src-cf98e664033a885a34fc059b01d990153b322f82.zip
Fix a bug which could cause programs with user threads packages to
lock against themselves, causing infinite spinning. Brian Feldman found this problem when testing with Mozilla and supplied the fix, which I have revised slightly. Here is the failure scenario. A thread calls dlopen() and acquires the writer lock. While the thread still holds the lock, a signal is delivered and caught. The signal handler tries to call a function which hasn't been bound yet. It thus enters the dynamic linker and tries to acquire the reader lock. Since the writer lock is already held, it will spin forever in the signal handler. The thread holding the lock won't be able to progress and release the lock. The solution is to block almost all signals while holding the exclusive lock. A similar problem could conceivably occur in the opposite order. Namely, a thread is holding the reader lock and then a signal handler calls dlopen() or dlclose() and spins waiting for the writer lock. We deal with this administratively by proclaiming that signal handlers aren't allowed to call dlopen() or dlclose(). Actually we don't have to proclaim a thing, since signal handlers aren't allowed to call any system functions except those which are explicitly permitted. Submitted by: Brian Fundakowski Feldman <green>
Notes
Notes: svn path=/head/; revision=63316
Diffstat (limited to 'libexec')
-rw-r--r--libexec/rtld-elf/alpha/lockdflt.c25
-rw-r--r--libexec/rtld-elf/amd64/lockdflt.c34
-rw-r--r--libexec/rtld-elf/i386/lockdflt.c34
3 files changed, 88 insertions, 5 deletions
diff --git a/libexec/rtld-elf/alpha/lockdflt.c b/libexec/rtld-elf/alpha/lockdflt.c
index 65900a63dc25..5847abbb1117 100644
--- a/libexec/rtld-elf/alpha/lockdflt.c
+++ b/libexec/rtld-elf/alpha/lockdflt.c
@@ -46,6 +46,7 @@
* them to make some progress.
*/
+#include <signal.h>
#include <stdlib.h>
#include <time.h>
@@ -70,6 +71,7 @@ typedef struct Struct_Lock {
} Lock;
static const struct timespec usec = { 0, 1000 }; /* 1 usec. */
+static sigset_t fullsigmask, oldsigmask;
static void *
lock_create(void *context)
@@ -123,9 +125,16 @@ static void
wlock_acquire(void *lock)
{
Lock *l = (Lock *)lock;
+ sigset_t tmp_oldsigmask;
- while (cmp0_and_store_int(&l->lock, WAFLAG) != 0)
+ for ( ; ; ) {
+ sigprocmask(SIG_BLOCK, &fullsigmask, &tmp_oldsigmask);
+ if (cmp0_and_store_int(&l->lock, WAFLAG) == 0)
+ break;
+ sigprocmask(SIG_SETMASK, &tmp_oldsigmask, NULL);
nanosleep(&usec, NULL);
+ }
+ oldsigmask = tmp_oldsigmask;
}
static void
@@ -142,6 +151,7 @@ wlock_release(void *lock)
Lock *l = (Lock *)lock;
atomic_add_int(&l->lock, -WAFLAG);
+ sigprocmask(SIG_SETMASK, &oldsigmask, NULL);
}
void
@@ -155,4 +165,17 @@ lockdflt_init(LockInfo *li)
li->wlock_release = wlock_release;
li->lock_destroy = lock_destroy;
li->context_destroy = NULL;
+ /*
+ * Construct a mask to block all signals except traps which might
+ * conceivably be generated within the dynamic linker itself.
+ */
+ sigfillset(&fullsigmask);
+ sigdelset(&fullsigmask, SIGILL);
+ sigdelset(&fullsigmask, SIGTRAP);
+ sigdelset(&fullsigmask, SIGABRT);
+ sigdelset(&fullsigmask, SIGEMT);
+ sigdelset(&fullsigmask, SIGFPE);
+ sigdelset(&fullsigmask, SIGBUS);
+ sigdelset(&fullsigmask, SIGSEGV);
+ sigdelset(&fullsigmask, SIGSYS);
}
diff --git a/libexec/rtld-elf/amd64/lockdflt.c b/libexec/rtld-elf/amd64/lockdflt.c
index b2ca9a5005eb..c1c23c16aa6d 100644
--- a/libexec/rtld-elf/amd64/lockdflt.c
+++ b/libexec/rtld-elf/amd64/lockdflt.c
@@ -72,6 +72,7 @@ typedef struct Struct_Lock {
} Lock;
static const struct timespec usec = { 0, 1000 }; /* 1 usec. */
+static sigset_t fullsigmask, oldsigmask;
static inline int
cmpxchgl(int old, int new, volatile int *m)
@@ -144,10 +145,17 @@ static void
lock80386_acquire(void *lock)
{
Lock *l = (Lock *)lock;
+ sigset_t tmp_oldsigmask;
- while (xchgl(1, &l->lock) != 0)
+ for ( ; ; ) {
+ sigprocmask(SIG_BLOCK, &fullsigmask, &tmp_oldsigmask);
+ if (xchgl(1, &l->lock) == 0)
+ break;
+ sigprocmask(SIG_SETMASK, &tmp_oldsigmask, NULL);
while (l->lock != 0)
nanosleep(&usec, NULL);
+ }
+ oldsigmask = tmp_oldsigmask;
}
static void
@@ -156,6 +164,7 @@ lock80386_release(void *lock)
Lock *l = (Lock *)lock;
l->lock = 0;
+ sigprocmask(SIG_SETMASK, &oldsigmask, NULL);
}
/*
@@ -175,9 +184,16 @@ static void
wlock_acquire(void *lock)
{
Lock *l = (Lock *)lock;
+ sigset_t tmp_oldsigmask;
- while (cmpxchgl(0, WAFLAG, &l->lock) != 0)
+ for ( ; ; ) {
+ sigprocmask(SIG_BLOCK, &fullsigmask, &tmp_oldsigmask);
+ if (cmpxchgl(0, WAFLAG, &l->lock) == 0)
+ break;
+ sigprocmask(SIG_SETMASK, &tmp_oldsigmask, NULL);
nanosleep(&usec, NULL);
+ }
+ oldsigmask = tmp_oldsigmask;
}
static void
@@ -194,6 +210,7 @@ wlock_release(void *lock)
Lock *l = (Lock *)lock;
atomic_add_int(&l->lock, -WAFLAG);
+ sigprocmask(SIG_SETMASK, &oldsigmask, NULL);
}
/*
@@ -250,4 +267,17 @@ lockdflt_init(LockInfo *li)
li->rlock_acquire = li->wlock_acquire = lock80386_acquire;
li->rlock_release = li->wlock_release = lock80386_release;
}
+ /*
+ * Construct a mask to block all signals except traps which might
+ * conceivably be generated within the dynamic linker itself.
+ */
+ sigfillset(&fullsigmask);
+ sigdelset(&fullsigmask, SIGILL);
+ sigdelset(&fullsigmask, SIGTRAP);
+ sigdelset(&fullsigmask, SIGABRT);
+ sigdelset(&fullsigmask, SIGEMT);
+ sigdelset(&fullsigmask, SIGFPE);
+ sigdelset(&fullsigmask, SIGBUS);
+ sigdelset(&fullsigmask, SIGSEGV);
+ sigdelset(&fullsigmask, SIGSYS);
}
diff --git a/libexec/rtld-elf/i386/lockdflt.c b/libexec/rtld-elf/i386/lockdflt.c
index b2ca9a5005eb..c1c23c16aa6d 100644
--- a/libexec/rtld-elf/i386/lockdflt.c
+++ b/libexec/rtld-elf/i386/lockdflt.c
@@ -72,6 +72,7 @@ typedef struct Struct_Lock {
} Lock;
static const struct timespec usec = { 0, 1000 }; /* 1 usec. */
+static sigset_t fullsigmask, oldsigmask;
static inline int
cmpxchgl(int old, int new, volatile int *m)
@@ -144,10 +145,17 @@ static void
lock80386_acquire(void *lock)
{
Lock *l = (Lock *)lock;
+ sigset_t tmp_oldsigmask;
- while (xchgl(1, &l->lock) != 0)
+ for ( ; ; ) {
+ sigprocmask(SIG_BLOCK, &fullsigmask, &tmp_oldsigmask);
+ if (xchgl(1, &l->lock) == 0)
+ break;
+ sigprocmask(SIG_SETMASK, &tmp_oldsigmask, NULL);
while (l->lock != 0)
nanosleep(&usec, NULL);
+ }
+ oldsigmask = tmp_oldsigmask;
}
static void
@@ -156,6 +164,7 @@ lock80386_release(void *lock)
Lock *l = (Lock *)lock;
l->lock = 0;
+ sigprocmask(SIG_SETMASK, &oldsigmask, NULL);
}
/*
@@ -175,9 +184,16 @@ static void
wlock_acquire(void *lock)
{
Lock *l = (Lock *)lock;
+ sigset_t tmp_oldsigmask;
- while (cmpxchgl(0, WAFLAG, &l->lock) != 0)
+ for ( ; ; ) {
+ sigprocmask(SIG_BLOCK, &fullsigmask, &tmp_oldsigmask);
+ if (cmpxchgl(0, WAFLAG, &l->lock) == 0)
+ break;
+ sigprocmask(SIG_SETMASK, &tmp_oldsigmask, NULL);
nanosleep(&usec, NULL);
+ }
+ oldsigmask = tmp_oldsigmask;
}
static void
@@ -194,6 +210,7 @@ wlock_release(void *lock)
Lock *l = (Lock *)lock;
atomic_add_int(&l->lock, -WAFLAG);
+ sigprocmask(SIG_SETMASK, &oldsigmask, NULL);
}
/*
@@ -250,4 +267,17 @@ lockdflt_init(LockInfo *li)
li->rlock_acquire = li->wlock_acquire = lock80386_acquire;
li->rlock_release = li->wlock_release = lock80386_release;
}
+ /*
+ * Construct a mask to block all signals except traps which might
+ * conceivably be generated within the dynamic linker itself.
+ */
+ sigfillset(&fullsigmask);
+ sigdelset(&fullsigmask, SIGILL);
+ sigdelset(&fullsigmask, SIGTRAP);
+ sigdelset(&fullsigmask, SIGABRT);
+ sigdelset(&fullsigmask, SIGEMT);
+ sigdelset(&fullsigmask, SIGFPE);
+ sigdelset(&fullsigmask, SIGBUS);
+ sigdelset(&fullsigmask, SIGSEGV);
+ sigdelset(&fullsigmask, SIGSYS);
}