From 285d65221eacad3e6ca1cf8e6aac96f18ff3c522 Mon Sep 17 00:00:00 2001 From: Jed Davis Date: Wed, 16 Jul 2014 13:37:00 +0200 Subject: [PATCH] Bug 1038900 - Dynamically allocate signal number for sandbox startup. r=kang --- security/sandbox/linux/Sandbox.cpp | 47 +++++++++++++++++++++++++----- 1 file changed, 40 insertions(+), 7 deletions(-) diff --git a/security/sandbox/linux/Sandbox.cpp b/security/sandbox/linux/Sandbox.cpp index 4aafa9acbd1..56a425afac1 100644 --- a/security/sandbox/linux/Sandbox.cpp +++ b/security/sandbox/linux/Sandbox.cpp @@ -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 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();