summaryrefslogtreecommitdiffstats
path: root/base/process_util_posix.cc
diff options
context:
space:
mode:
authorjln@chromium.org <jln@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-03-12 21:53:31 +0000
committerjln@chromium.org <jln@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-03-12 21:53:31 +0000
commita34eb9db2898d9cca06b9db802170f78bceec96d (patch)
tree244ee1b048048294594e2c0dfa1ea5fd79928d07 /base/process_util_posix.cc
parenta590764b77a53e1a0e83642012a93a50f633112e (diff)
downloadchromium_src-a34eb9db2898d9cca06b9db802170f78bceec96d.zip
chromium_src-a34eb9db2898d9cca06b9db802170f78bceec96d.tar.gz
chromium_src-a34eb9db2898d9cca06b9db802170f78bceec96d.tar.bz2
Linux: for all signals, reset the sa_restorer field before execve().
The kernel can leak addresses in sa_restorer. Before execve, we reset all sa_restorer to NULL. BUG=177956 NOTRY=true Review URL: https://chromiumcodereview.appspot.com/12314117 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@187659 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'base/process_util_posix.cc')
-rw-r--r--base/process_util_posix.cc69
1 files changed, 69 insertions, 0 deletions
diff --git a/base/process_util_posix.cc b/base/process_util_posix.cc
index 3d208a8..52e964b 100644
--- a/base/process_util_posix.cc
+++ b/base/process_util_posix.cc
@@ -135,6 +135,8 @@ int WaitpidWithTimeout(ProcessHandle handle, int64 wait_milliseconds,
return status;
}
+#if !defined(OS_LINUX) || \
+ (!defined(__i386__) && !defined(__x86_64__) && !defined(__arm__))
void ResetChildSignalHandlersToDefaults() {
// The previous signal handlers are likely to be meaningless in the child's
// context so we reset them to the defaults for now. http://crbug.com/44953
@@ -152,6 +154,73 @@ void ResetChildSignalHandlersToDefaults() {
signal(SIGTERM, SIG_DFL);
}
+#else
+
+// TODO(jln): remove the Linux special case once kernels are fixed.
+
+// Internally the kernel makes sigset_t an array of long large enough to have
+// one bit per signal.
+typedef uint64_t kernel_sigset_t;
+
+// This is what struct sigaction looks like to the kernel at least on X86 and
+// ARM. MIPS, for instance, is very different.
+struct kernel_sigaction {
+ void* k_sa_handler; // For this usage it only needs to be a generic pointer.
+ unsigned long k_sa_flags;
+ void* k_sa_restorer; // For this usage it only needs to be a generic pointer.
+ kernel_sigset_t k_sa_mask;
+};
+
+// glibc's sigaction() will prevent access to sa_restorer, so we need to roll
+// our own.
+int sys_rt_sigaction(int sig, const struct kernel_sigaction* act,
+ struct kernel_sigaction* oact) {
+ return syscall(SYS_rt_sigaction, sig, act, oact, sizeof(kernel_sigset_t));
+}
+
+// This function is intended to be used in between fork() and execve() and will
+// reset all signal handlers to the default.
+// The motivation for going through all of them is that sa_restorer can leak
+// from parents and help defeat ASLR on buggy kernels. We reset it to NULL.
+// See crbug.com/177956.
+void ResetChildSignalHandlersToDefaults(void) {
+ for (int signum = 1; ; ++signum) {
+ struct kernel_sigaction act = {0};
+ int sigaction_get_ret = sys_rt_sigaction(signum, NULL, &act);
+ if (sigaction_get_ret && errno == EINVAL) {
+#if !defined(NDEBUG)
+ // Linux supports 32 real-time signals from 33 to 64.
+ // If the number of signals in the Linux kernel changes, someone should
+ // look at this code.
+ const int kNumberOfSignals = 64;
+ RAW_CHECK(signum == kNumberOfSignals + 1);
+#endif // !defined(NDEBUG)
+ break;
+ }
+ // All other failures are fatal.
+ if (sigaction_get_ret) {
+ RAW_LOG(FATAL, "sigaction (get) failed.");
+ }
+
+ // The kernel won't allow to re-set SIGKILL or SIGSTOP.
+ if (signum != SIGSTOP && signum != SIGKILL) {
+ act.k_sa_handler = reinterpret_cast<void*>(SIG_DFL);
+ act.k_sa_restorer = NULL;
+ if (sys_rt_sigaction(signum, &act, NULL)) {
+ RAW_LOG(FATAL, "sigaction (set) failed.");
+ }
+ }
+#if !defined(NDEBUG)
+ // Now ask the kernel again and check that no restorer will leak.
+ if (sys_rt_sigaction(signum, NULL, &act) || act.k_sa_restorer) {
+ RAW_LOG(FATAL, "Cound not fix sa_restorer.");
+ }
+#endif // !defined(NDEBUG)
+ }
+}
+#endif // !defined(OS_LINUX) ||
+ // (!defined(__i386__) && !defined(__x86_64__) && !defined(__arm__))
+
TerminationStatus GetTerminationStatusImpl(ProcessHandle handle,
bool can_block,
int* exit_code) {