Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "sandbox/linux/seccomp-bpf/trap.h" | 5 #include "sandbox/linux/seccomp-bpf/trap.h" |
| 6 | 6 |
| 7 #include <errno.h> | 7 #include <errno.h> |
| 8 #include <signal.h> | 8 #include <signal.h> |
| 9 #include <string.h> | 9 #include <string.h> |
| 10 #include <sys/syscall.h> | 10 #include <sys/syscall.h> |
| 11 | 11 |
| 12 #include <algorithm> | 12 #include <algorithm> |
| 13 #include <limits> | 13 #include <limits> |
| 14 | 14 |
| 15 #include "base/compiler_specific.h" | |
| 15 #include "base/logging.h" | 16 #include "base/logging.h" |
| 16 #include "build/build_config.h" | 17 #include "build/build_config.h" |
| 17 #include "sandbox/linux/bpf_dsl/seccomp_macros.h" | 18 #include "sandbox/linux/bpf_dsl/seccomp_macros.h" |
| 18 #include "sandbox/linux/seccomp-bpf/die.h" | 19 #include "sandbox/linux/seccomp-bpf/die.h" |
| 19 #include "sandbox/linux/seccomp-bpf/syscall.h" | 20 #include "sandbox/linux/seccomp-bpf/syscall.h" |
| 21 #include "sandbox/linux/services/syscall_wrappers.h" | |
| 20 #include "sandbox/linux/system_headers/linux_seccomp.h" | 22 #include "sandbox/linux/system_headers/linux_seccomp.h" |
| 21 | 23 #include "sandbox/linux/system_headers/linux_signal.h" |
| 22 // Android's signal.h doesn't define ucontext etc. | |
| 23 #if defined(OS_ANDROID) | |
| 24 #include "sandbox/linux/system_headers/android_ucontext.h" | |
| 25 #endif | |
| 26 | 24 |
| 27 namespace { | 25 namespace { |
| 28 | 26 |
| 29 struct arch_sigsys { | 27 struct arch_sigsys { |
| 30 void* ip; | 28 void* ip; |
| 31 int nr; | 29 int nr; |
| 32 unsigned int arch; | 30 unsigned int arch; |
| 33 }; | 31 }; |
| 34 | 32 |
| 35 const int kCapacityIncrement = 20; | 33 const int kCapacityIncrement = 20; |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 46 // a lot of complexity. Instead, we co-opt one bit in the signal mask. | 44 // a lot of complexity. Instead, we co-opt one bit in the signal mask. |
| 47 // If BUS is blocked, we assume that we have been called recursively. | 45 // If BUS is blocked, we assume that we have been called recursively. |
| 48 // There is a possibility for collision with other code that needs to do | 46 // There is a possibility for collision with other code that needs to do |
| 49 // this, but in practice the risks are low. | 47 // this, but in practice the risks are low. |
| 50 // If SIGBUS turns out to be a problem, we could instead co-opt one of the | 48 // If SIGBUS turns out to be a problem, we could instead co-opt one of the |
| 51 // realtime signals. There are plenty of them. Unfortunately, there is no | 49 // realtime signals. There are plenty of them. Unfortunately, there is no |
| 52 // way to mark a signal as allocated. So, the potential for collision is | 50 // way to mark a signal as allocated. So, the potential for collision is |
| 53 // possibly even worse. | 51 // possibly even worse. |
| 54 bool GetIsInSigHandler(const ucontext_t* ctx) { | 52 bool GetIsInSigHandler(const ucontext_t* ctx) { |
| 55 // Note: on Android, sigismember does not take a pointer to const. | 53 // Note: on Android, sigismember does not take a pointer to const. |
| 56 return sigismember(const_cast<sigset_t*>(&ctx->uc_sigmask), SIGBUS); | 54 return sigismember(const_cast<sigset_t*>(&ctx->uc_sigmask), LINUX_SIGBUS); |
| 57 } | 55 } |
| 58 | 56 |
| 59 void SetIsInSigHandler() { | 57 void SetIsInSigHandler() { |
| 60 sigset_t mask; | 58 sigset_t mask; |
| 61 if (sigemptyset(&mask) || sigaddset(&mask, SIGBUS) || | 59 if (sigemptyset(&mask) || sigaddset(&mask, LINUX_SIGBUS) || |
| 62 sigprocmask(SIG_BLOCK, &mask, NULL)) { | 60 sandbox::sys_sigprocmask(LINUX_SIG_BLOCK, &mask, NULL)) { |
| 63 SANDBOX_DIE("Failed to block SIGBUS"); | 61 SANDBOX_DIE("Failed to block SIGBUS"); |
| 64 } | 62 } |
| 65 } | 63 } |
| 66 | 64 |
| 67 bool IsDefaultSignalAction(const struct sigaction& sa) { | 65 bool IsDefaultSignalAction(const struct sigaction& sa) { |
| 68 if (sa.sa_flags & SA_SIGINFO || sa.sa_handler != SIG_DFL) { | 66 if (sa.sa_flags & SA_SIGINFO || sa.sa_handler != SIG_DFL) { |
| 69 return false; | 67 return false; |
| 70 } | 68 } |
| 71 return true; | 69 return true; |
| 72 } | 70 } |
| 73 | 71 |
| 74 } // namespace | 72 } // namespace |
| 75 | 73 |
| 76 namespace sandbox { | 74 namespace sandbox { |
| 77 | 75 |
| 78 Trap::Trap() | 76 Trap::Trap() |
| 79 : trap_array_(NULL), | 77 : trap_array_(NULL), |
| 80 trap_array_size_(0), | 78 trap_array_size_(0), |
| 81 trap_array_capacity_(0), | 79 trap_array_capacity_(0), |
| 82 has_unsafe_traps_(false) { | 80 has_unsafe_traps_(false) { |
| 83 // Set new SIGSYS handler | 81 // Set new SIGSYS handler |
| 84 struct sigaction sa = {}; | 82 struct sigaction sa = {}; |
| 85 sa.sa_sigaction = SigSysAction; | 83 // In some toolchain, sa_sigaction is not declared in struct sigaction. |
| 86 sa.sa_flags = SA_SIGINFO | SA_NODEFER; | 84 // So, here cast the pointer to the sa_handler's type. This works because |
| 87 struct sigaction old_sa; | 85 // |sa_handler| and |sa_sigaction| shares the same memory. |
| 88 if (sigaction(SIGSYS, &sa, &old_sa) < 0) { | 86 sa.sa_handler = reinterpret_cast<void (*)(int)>(SigSysAction); |
| 87 sa.sa_flags = LINUX_SA_SIGINFO | LINUX_SA_NODEFER; | |
| 88 struct sigaction old_sa = {}; | |
| 89 if (sys_sigaction(LINUX_SIGSYS, &sa, &old_sa) < 0) { | |
| 89 SANDBOX_DIE("Failed to configure SIGSYS handler"); | 90 SANDBOX_DIE("Failed to configure SIGSYS handler"); |
| 90 } | 91 } |
| 91 | 92 |
| 92 if (!IsDefaultSignalAction(old_sa)) { | 93 if (!IsDefaultSignalAction(old_sa)) { |
| 93 static const char kExistingSIGSYSMsg[] = | 94 static const char kExistingSIGSYSMsg[] = |
| 94 "Existing signal handler when trying to install SIGSYS. SIGSYS needs " | 95 "Existing signal handler when trying to install SIGSYS. SIGSYS needs " |
| 95 "to be reserved for seccomp-bpf."; | 96 "to be reserved for seccomp-bpf."; |
| 96 DLOG(FATAL) << kExistingSIGSYSMsg; | 97 DLOG(FATAL) << kExistingSIGSYSMsg; |
| 97 LOG(ERROR) << kExistingSIGSYSMsg; | 98 LOG(ERROR) << kExistingSIGSYSMsg; |
| 98 } | 99 } |
| 99 | 100 |
| 100 // Unmask SIGSYS | 101 // Unmask SIGSYS |
| 101 sigset_t mask; | 102 sigset_t mask; |
| 102 if (sigemptyset(&mask) || sigaddset(&mask, SIGSYS) || | 103 if (sigemptyset(&mask) || sigaddset(&mask, LINUX_SIGSYS) || |
| 103 sigprocmask(SIG_UNBLOCK, &mask, NULL)) { | 104 sys_sigprocmask(LINUX_SIG_UNBLOCK, &mask, NULL)) { |
| 104 SANDBOX_DIE("Failed to configure SIGSYS handler"); | 105 SANDBOX_DIE("Failed to configure SIGSYS handler"); |
| 105 } | 106 } |
| 106 } | 107 } |
| 107 | 108 |
| 108 bpf_dsl::TrapRegistry* Trap::Registry() { | 109 bpf_dsl::TrapRegistry* Trap::Registry() { |
| 109 // Note: This class is not thread safe. It is the caller's responsibility | 110 // Note: This class is not thread safe. It is the caller's responsibility |
| 110 // to avoid race conditions. Normally, this is a non-issue as the sandbox | 111 // to avoid race conditions. Normally, this is a non-issue as the sandbox |
| 111 // can only be initialized if there are no other threads present. | 112 // can only be initialized if there are no other threads present. |
| 112 // Also, this is not a normal singleton. Once created, the global trap | 113 // Also, this is not a normal singleton. Once created, the global trap |
| 113 // object must never be destroyed again. | 114 // object must never be destroyed again. |
| 114 if (!global_trap_) { | 115 if (!global_trap_) { |
| 115 global_trap_ = new Trap(); | 116 global_trap_ = new Trap(); |
| 116 if (!global_trap_) { | 117 if (!global_trap_) { |
| 117 SANDBOX_DIE("Failed to allocate global trap handler"); | 118 SANDBOX_DIE("Failed to allocate global trap handler"); |
| 118 } | 119 } |
| 119 } | 120 } |
| 120 return global_trap_; | 121 return global_trap_; |
| 121 } | 122 } |
| 122 | 123 |
| 123 void Trap::SigSysAction(int nr, siginfo_t* info, void* void_context) { | 124 void Trap::SigSysAction(int nr, LinuxSigInfo* info, void* void_context) { |
| 125 if (info) { | |
|
hidehiko
2015/04/23 15:59:56
Note: I temporarily reverted this part, because we
| |
| 126 MSAN_UNPOISON(info, sizeof(*info)); | |
| 127 } | |
| 128 if (void_context) { | |
| 129 MSAN_UNPOISON(void_context, sizeof(ucontext_t)); | |
| 130 } | |
| 131 | |
| 124 if (!global_trap_) { | 132 if (!global_trap_) { |
| 125 RAW_SANDBOX_DIE( | 133 RAW_SANDBOX_DIE( |
| 126 "This can't happen. Found no global singleton instance " | 134 "This can't happen. Found no global singleton instance " |
| 127 "for Trap() handling."); | 135 "for Trap() handling."); |
| 128 } | 136 } |
| 129 global_trap_->SigSys(nr, info, void_context); | 137 global_trap_->SigSys(nr, info, void_context); |
| 130 } | 138 } |
| 131 | 139 |
| 132 void Trap::SigSys(int nr, siginfo_t* info, void* void_context) { | 140 void Trap::SigSys(int nr, LinuxSigInfo* info, void* void_context) { |
| 133 // Signal handlers should always preserve "errno". Otherwise, we could | 141 // Signal handlers should always preserve "errno". Otherwise, we could |
| 134 // trigger really subtle bugs. | 142 // trigger really subtle bugs. |
| 135 const int old_errno = errno; | 143 const int old_errno = errno; |
| 136 | 144 |
| 137 // Various sanity checks to make sure we actually received a signal | 145 // Various sanity checks to make sure we actually received a signal |
| 138 // triggered by a BPF filter. If something else triggered SIGSYS | 146 // triggered by a BPF filter. If something else triggered SIGSYS |
| 139 // (e.g. kill()), there is really nothing we can do with this signal. | 147 // (e.g. kill()), there is really nothing we can do with this signal. |
| 140 if (nr != SIGSYS || info->si_code != SYS_SECCOMP || !void_context || | 148 if (nr != LINUX_SIGSYS || info->si_code != SYS_SECCOMP || !void_context || |
| 141 info->si_errno <= 0 || | 149 info->si_errno <= 0 || |
| 142 static_cast<size_t>(info->si_errno) > trap_array_size_) { | 150 static_cast<size_t>(info->si_errno) > trap_array_size_) { |
| 143 // ATI drivers seem to send SIGSYS, so this cannot be FATAL. | 151 // ATI drivers seem to send SIGSYS, so this cannot be FATAL. |
| 144 // See crbug.com/178166. | 152 // See crbug.com/178166. |
| 145 // TODO(jln): add a DCHECK or move back to FATAL. | 153 // TODO(jln): add a DCHECK or move back to FATAL. |
| 146 RAW_LOG(ERROR, "Unexpected SIGSYS received."); | 154 RAW_LOG(ERROR, "Unexpected SIGSYS received."); |
| 147 errno = old_errno; | 155 errno = old_errno; |
| 148 return; | 156 return; |
| 149 } | 157 } |
| 150 | 158 |
| (...skipping 221 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 372 "CHROME_SANDBOX_DEBUGGING is turned on first"); | 380 "CHROME_SANDBOX_DEBUGGING is turned on first"); |
| 373 } | 381 } |
| 374 } | 382 } |
| 375 // Returns the, possibly updated, value of has_unsafe_traps_. | 383 // Returns the, possibly updated, value of has_unsafe_traps_. |
| 376 return has_unsafe_traps_; | 384 return has_unsafe_traps_; |
| 377 } | 385 } |
| 378 | 386 |
| 379 Trap* Trap::global_trap_; | 387 Trap* Trap::global_trap_; |
| 380 | 388 |
| 381 } // namespace sandbox | 389 } // namespace sandbox |
| OLD | NEW |