Bug 1038900 - Dynamically allocate signal number for sandbox startup. r=kang

This commit is contained in:
Jed Davis 2014-07-16 13:37:00 +02:00
parent d61ca8ca45
commit 285d65221e

View File

@ -224,12 +224,31 @@ InstallSyscallFilter(const sock_fprog *prog)
// Use signals for permissions that need to be set per-thread.
// The communication channel from the signal handler back to the main thread.
static mozilla::Atomic<int> sSetSandboxDone;
// about:memory has the first 3 RT signals. (We should allocate
// signals centrally instead of hard-coding them like this.)
static const int sSetSandboxSignum = SIGRTMIN + 3;
// Pass the filter itself through a global.
static const sock_fprog *sSetSandboxFilter;
// We have to dynamically allocate the signal number; see bug 1038900.
// This function returns the first realtime signal currently set to
// default handling (i.e., not in use), or 0 if none could be found.
//
// WARNING: if this function or anything similar to it (including in
// external libraries) is used on multiple threads concurrently, there
// will be a race condition.
static int
FindFreeSignalNumber()
{
for (int signum = SIGRTMIN; signum <= SIGRTMAX; ++signum) {
struct sigaction sa;
if (sigaction(signum, nullptr, &sa) == 0 &&
(sa.sa_flags & SA_SIGINFO) == 0 &&
sa.sa_handler == SIG_DFL) {
return signum;
}
}
return 0;
}
static bool
SetThreadSandbox()
{
@ -268,6 +287,7 @@ SetThreadSandboxHandler(int signum)
static void
BroadcastSetThreadSandbox()
{
int signum;
pid_t pid, tid;
DIR *taskdp;
struct dirent *de;
@ -283,8 +303,16 @@ BroadcastSetThreadSandbox()
LOG_ERROR("opendir /proc/self/task: %s\n", strerror(errno));
MOZ_CRASH();
}
if (signal(sSetSandboxSignum, SetThreadSandboxHandler) != SIG_DFL) {
LOG_ERROR("signal %d in use!\n", sSetSandboxSignum);
signum = FindFreeSignalNumber();
if (signum == 0) {
LOG_ERROR("No available signal numbers!");
MOZ_CRASH();
}
void (*oldHandler)(int);
oldHandler = signal(signum, SetThreadSandboxHandler);
if (oldHandler != SIG_DFL) {
// See the comment on FindFreeSignalNumber about race conditions.
LOG_ERROR("signal %d in use by handler %p!\n", signum, oldHandler);
MOZ_CRASH();
}
@ -309,7 +337,7 @@ BroadcastSetThreadSandbox()
}
// Reset the futex cell and signal.
sSetSandboxDone = 0;
if (syscall(__NR_tgkill, pid, tid, sSetSandboxSignum) != 0) {
if (syscall(__NR_tgkill, pid, tid, signum) != 0) {
if (errno == ESRCH) {
LOG_ERROR("Thread %d unexpectedly exited.", tid);
// Rescan threads, in case it forked before exiting.
@ -378,7 +406,12 @@ BroadcastSetThreadSandbox()
}
rewinddir(taskdp);
} while (sandboxProgress);
unused << signal(sSetSandboxSignum, SIG_DFL);
oldHandler = signal(signum, SIG_DFL);
if (oldHandler != SetThreadSandboxHandler) {
// See the comment on FindFreeSignalNumber about race conditions.
LOG_ERROR("handler for signal %d was changed to %p!", signum, oldHandler);
MOZ_CRASH();
}
unused << closedir(taskdp);
// And now, deprivilege the main thread:
SetThreadSandbox();