summaryrefslogtreecommitdiffstats
path: root/libexec
diff options
context:
space:
mode:
authorjdp <jdp@FreeBSD.org>2000-07-17 17:18:13 +0000
committerjdp <jdp@FreeBSD.org>2000-07-17 17:18:13 +0000
commitd8dcadaeb6502770e772e80b4e14b0afb3fcb9d5 (patch)
treeff66dc70ea8da8bce0cc93925af492df17fd5c32 /libexec
parent5b9b8deed9b95d05509ec5d0c088b0190029e6bc (diff)
downloadFreeBSD-src-d8dcadaeb6502770e772e80b4e14b0afb3fcb9d5.zip
FreeBSD-src-d8dcadaeb6502770e772e80b4e14b0afb3fcb9d5.tar.gz
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>
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 65900a6..5847abb 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 b2ca9a5..c1c23c1 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 b2ca9a5..c1c23c1 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);
}
OpenPOWER on IntegriCloud