diff options
author | jln@chromium.org <jln@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-03-12 21:53:31 +0000 |
---|---|---|
committer | jln@chromium.org <jln@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-03-12 21:53:31 +0000 |
commit | a34eb9db2898d9cca06b9db802170f78bceec96d (patch) | |
tree | 244ee1b048048294594e2c0dfa1ea5fd79928d07 /base/process_util_posix.cc | |
parent | a590764b77a53e1a0e83642012a93a50f633112e (diff) | |
download | chromium_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.cc | 69 |
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) { |