diff options
Diffstat (limited to 'sandbox/linux/seccomp/sigprocmask.cc')
-rw-r--r-- | sandbox/linux/seccomp/sigprocmask.cc | 120 |
1 files changed, 120 insertions, 0 deletions
diff --git a/sandbox/linux/seccomp/sigprocmask.cc b/sandbox/linux/seccomp/sigprocmask.cc new file mode 100644 index 0000000..9ff2922 --- /dev/null +++ b/sandbox/linux/seccomp/sigprocmask.cc @@ -0,0 +1,120 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "debug.h" +#include "sandbox_impl.h" + +namespace playground { + +// If the sandboxed process tries to mask SIGSEGV, there is a good chance +// the process will eventually get terminated. If this is really ever a +// problem, we can hide the fact that SIGSEGV is unmasked. But I don't think +// we really need this. Masking of synchronous signals is rarely necessary. + +#if defined(__NR_sigprocmask) +long Sandbox::sandbox_sigprocmask(int how, const void* set, void* old_set) { + long long tm; + Debug::syscall(&tm, __NR_sigprocmask, "Executing handler"); + + // Access the signal mask by triggering a SEGV and modifying the signal state + // prior to calling rt_sigreturn(). + long res = -ENOSYS; + #if defined(__x86_64__) + #error x86-64 does not support sigprocmask(); use rt_sigprocmask() instead + #elif defined(__i386__) + asm volatile( + "push %%ebx\n" + "movl %2, %%ebx\n" + "int $0\n" + "pop %%ebx\n" + : "=a"(res) + : "0"(__NR_sigprocmask), "ri"((long)how), + "c"((long)set), "d"((long)old_set) + : "esp", "memory"); + #else + #error Unsupported target platform + #endif + + // Update our shadow signal mask, so that we can copy it upon creation of + // new threads. + if (res == 0 && set != NULL) { + SecureMem::Args* args = getSecureMem(); + switch (how) { + case SIG_BLOCK: + *(unsigned long long *)&args->signalMask |= *(unsigned long long *)set; + break; + case SIG_UNBLOCK: + *(unsigned long long *)&args->signalMask &= ~*(unsigned long long *)set; + break; + case SIG_SETMASK: + *(unsigned long long *)&args->signalMask = *(unsigned long long *)set; + break; + default: + break; + } + } + + Debug::elapsed(tm, __NR_sigprocmask); + + return res; +} +#endif + +#if defined(__NR_rt_sigprocmask) +long Sandbox::sandbox_rt_sigprocmask(int how, const void* set, void* old_set, + size_t bytes) { + long long tm; + Debug::syscall(&tm, __NR_rt_sigprocmask, "Executing handler"); + + // Access the signal mask by triggering a SEGV and modifying the signal state + // prior to calling rt_sigreturn(). + long res = -ENOSYS; + #if defined(__x86_64__) + asm volatile( + "movq %5, %%r10\n" + "int $0\n" + : "=a"(res) + : "0"(__NR_rt_sigprocmask), "D"((long)how), + "S"((long)set), "d"((long)old_set), "r"((long)bytes) + : "r10", "r11", "rcx", "memory"); + #elif defined(__i386__) + asm volatile( + "push %%ebx\n" + "movl %2, %%ebx\n" + "int $0\n" + "pop %%ebx\n" + : "=a"(res) + : "0"(__NR_rt_sigprocmask), "ri"((long)how), + "c"((long)set), "d"((long)old_set), "S"((long)bytes) + : "esp", "memory"); + #else + #error Unsupported target platform + #endif + + // Update our shadow signal mask, so that we can copy it upon creation of + // new threads. + if (res == 0 && set != NULL && bytes >= 8) { + SecureMem::Args* args = getSecureMem(); + switch (how) { + case SIG_BLOCK: + *(unsigned long long *)&args->signalMask |= *(unsigned long long *)set; + break; + case SIG_UNBLOCK: + *(unsigned long long *)&args->signalMask &= ~*(unsigned long long *)set; + break; + case SIG_SETMASK: + *(unsigned long long *)&args->signalMask = *(unsigned long long *)set; + break; + default: + break; + } + } + + Debug::elapsed(tm, __NR_rt_sigprocmask); + + return res; +} +#endif + +} // namespace |