| File: | root/firefox-clang/security/sandbox/chromium/sandbox/linux/seccomp-bpf/trap.cc |
| Warning: | line 154, column 29 Access to field 'si_code' results in a dereference of a null pointer (loaded from variable 'info') |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | // Copyright 2012 The Chromium Authors | |||
| 2 | // Use of this source code is governed by a BSD-style license that can be | |||
| 3 | // found in the LICENSE file. | |||
| 4 | ||||
| 5 | #include "sandbox/linux/seccomp-bpf/trap.h" | |||
| 6 | ||||
| 7 | #include <errno(*__errno_location ()).h> | |||
| 8 | #include <signal.h> | |||
| 9 | #include <stddef.h> | |||
| 10 | #include <stdint.h> | |||
| 11 | #include <string.h> | |||
| 12 | #include <sys/syscall.h> | |||
| 13 | ||||
| 14 | #include <algorithm> | |||
| 15 | #include <atomic> | |||
| 16 | #include <limits> | |||
| 17 | #include <tuple> | |||
| 18 | ||||
| 19 | #include "base/compiler_specific.h" | |||
| 20 | #include "base/logging.h" | |||
| 21 | #include "base/memory/raw_ptr_exclusion.h" | |||
| 22 | #include "build/build_config.h" | |||
| 23 | #include "sandbox/linux/bpf_dsl/seccomp_macros.h" | |||
| 24 | #include "sandbox/linux/seccomp-bpf/die.h" | |||
| 25 | #include "sandbox/linux/seccomp-bpf/syscall.h" | |||
| 26 | #include "sandbox/linux/services/syscall_wrappers.h" | |||
| 27 | #include "sandbox/linux/system_headers/linux_seccomp.h" | |||
| 28 | #include "sandbox/linux/system_headers/linux_signal.h" | |||
| 29 | ||||
| 30 | namespace { | |||
| 31 | ||||
| 32 | struct arch_sigsys { | |||
| 33 | // RAW_PTR_EXCLUSION: Points to a code address given to us by the kernel. | |||
| 34 | RAW_PTR_EXCLUSION__attribute__((annotate("raw_ptr_exclusion"))) void* ip; | |||
| 35 | int nr; | |||
| 36 | unsigned int arch; | |||
| 37 | }; | |||
| 38 | ||||
| 39 | const int kCapacityIncrement = 20; | |||
| 40 | ||||
| 41 | // Unsafe traps can only be turned on, if the user explicitly allowed them | |||
| 42 | // by setting the CHROME_SANDBOX_DEBUGGING environment variable. | |||
| 43 | const char kSandboxDebuggingEnv[] = "CHROME_SANDBOX_DEBUGGING"; | |||
| 44 | ||||
| 45 | // We need to tell whether we are performing a "normal" callback, or | |||
| 46 | // whether we were called recursively from within a UnsafeTrap() callback. | |||
| 47 | // This is a little tricky to do, because we need to somehow get access to | |||
| 48 | // per-thread data from within a signal context. Normal TLS storage is not | |||
| 49 | // safely accessible at this time. We could roll our own, but that involves | |||
| 50 | // a lot of complexity. Instead, we co-opt one bit in the signal mask. | |||
| 51 | // If BUS is blocked, we assume that we have been called recursively. | |||
| 52 | // There is a possibility for collision with other code that needs to do | |||
| 53 | // this, but in practice the risks are low. | |||
| 54 | // If SIGBUS turns out to be a problem, we could instead co-opt one of the | |||
| 55 | // realtime signals. There are plenty of them. Unfortunately, there is no | |||
| 56 | // way to mark a signal as allocated. So, the potential for collision is | |||
| 57 | // possibly even worse. | |||
| 58 | bool GetIsInSigHandler(const ucontext_t* ctx) { | |||
| 59 | // Note: on Android, sigismember does not take a pointer to const. | |||
| 60 | return sigismember(const_cast<sigset_t*>(&ctx->uc_sigmask), LINUX_SIGBUS7); | |||
| 61 | } | |||
| 62 | ||||
| 63 | void SetIsInSigHandler() { | |||
| 64 | sigset_t mask; | |||
| 65 | if (sigemptyset(&mask) || sigaddset(&mask, LINUX_SIGBUS7) || | |||
| 66 | sandbox::sys_sigprocmask(LINUX_SIG_BLOCK0, &mask, nullptr)) { | |||
| 67 | SANDBOX_DIE("Failed to block SIGBUS")sandbox::Die::SandboxDie("Failed to block SIGBUS", "/root/firefox-clang/security/sandbox/chromium/sandbox/linux/seccomp-bpf/trap.cc" , 67); | |||
| 68 | } | |||
| 69 | } | |||
| 70 | ||||
| 71 | bool IsDefaultSignalAction(const struct sigaction& sa) { | |||
| 72 | if (sa.sa_flags & SA_SIGINFO4 || sa.sa_handler__sigaction_handler.sa_handler != SIG_DFL((__sighandler_t) 0)) { | |||
| 73 | return false; | |||
| 74 | } | |||
| 75 | return true; | |||
| 76 | } | |||
| 77 | ||||
| 78 | } // namespace | |||
| 79 | ||||
| 80 | namespace sandbox { | |||
| 81 | ||||
| 82 | Trap::Trap() { | |||
| 83 | // Set new SIGSYS handler | |||
| 84 | struct sigaction sa = {}; | |||
| 85 | // In some toolchain, sa_sigaction is not declared in struct sigaction. | |||
| 86 | // So, here cast the pointer to the sa_handler's type. This works because | |||
| 87 | // |sa_handler| and |sa_sigaction| shares the same memory. | |||
| 88 | sa.sa_handler__sigaction_handler.sa_handler = reinterpret_cast<void (*)(int)>(SigSysAction); | |||
| 89 | sa.sa_flags = LINUX_SA_SIGINFO4 | LINUX_SA_NODEFER0x40000000; | |||
| 90 | struct sigaction old_sa = {}; | |||
| 91 | if (sys_sigaction(LINUX_SIGSYS31, &sa, &old_sa) < 0) { | |||
| 92 | SANDBOX_DIE("Failed to configure SIGSYS handler")sandbox::Die::SandboxDie("Failed to configure SIGSYS handler" , "/root/firefox-clang/security/sandbox/chromium/sandbox/linux/seccomp-bpf/trap.cc" , 92); | |||
| 93 | } | |||
| 94 | ||||
| 95 | if (!IsDefaultSignalAction(old_sa)) { | |||
| 96 | static const char kExistingSIGSYSMsg[] = | |||
| 97 | "Existing signal handler when trying to install SIGSYS. SIGSYS needs " | |||
| 98 | "to be reserved for seccomp-bpf."; | |||
| 99 | DLOG(FATAL)!((::logging::ShouldCreateLogMessage(::logging::LOGGING_FATAL ))) ? (void)0 : ::logging::LogMessageVoidify() & (::logging ::LogMessageFatal("/root/firefox-clang/security/sandbox/chromium/sandbox/linux/seccomp-bpf/trap.cc" , 99, ::logging::LOGGING_FATAL).stream()) << kExistingSIGSYSMsg; | |||
| 100 | LOG(ERROR)!((::logging::LOGGING_ERROR == ::logging::LOGGING_FATAL || :: logging::ShouldCreateLogMessage(::logging::LOGGING_ERROR))) ? (void)0 : ::logging::LogMessageVoidify() & (::logging::LogMessage ("/root/firefox-clang/security/sandbox/chromium/sandbox/linux/seccomp-bpf/trap.cc" , 100, ::logging::LOGGING_ERROR).stream()) << kExistingSIGSYSMsg; | |||
| 101 | } | |||
| 102 | ||||
| 103 | // Unmask SIGSYS | |||
| 104 | sigset_t mask; | |||
| 105 | if (sigemptyset(&mask) || sigaddset(&mask, LINUX_SIGSYS31) || | |||
| 106 | sys_sigprocmask(LINUX_SIG_UNBLOCK1, &mask, nullptr)) { | |||
| 107 | SANDBOX_DIE("Failed to configure SIGSYS handler")sandbox::Die::SandboxDie("Failed to configure SIGSYS handler" , "/root/firefox-clang/security/sandbox/chromium/sandbox/linux/seccomp-bpf/trap.cc" , 107); | |||
| 108 | } | |||
| 109 | } | |||
| 110 | ||||
| 111 | bpf_dsl::TrapRegistry* Trap::Registry() { | |||
| 112 | // Note: This class is not thread safe. It is the caller's responsibility | |||
| 113 | // to avoid race conditions. Normally, this is a non-issue as the sandbox | |||
| 114 | // can only be initialized if there are no other threads present. | |||
| 115 | // Also, this is not a normal singleton. Once created, the global trap | |||
| 116 | // object must never be destroyed again. | |||
| 117 | if (!global_trap_) { | |||
| 118 | global_trap_ = new Trap(); | |||
| 119 | if (!global_trap_) { | |||
| 120 | SANDBOX_DIE("Failed to allocate global trap handler")sandbox::Die::SandboxDie("Failed to allocate global trap handler" , "/root/firefox-clang/security/sandbox/chromium/sandbox/linux/seccomp-bpf/trap.cc" , 120); | |||
| 121 | } | |||
| 122 | } | |||
| 123 | return global_trap_; | |||
| 124 | } | |||
| 125 | ||||
| 126 | void Trap::SigSysAction(int nr, LinuxSigInfo* info, void* void_context) { | |||
| 127 | if (info) { | |||
| ||||
| 128 | MSAN_UNPOISON(info, sizeof(*info)); | |||
| 129 | } | |||
| 130 | ||||
| 131 | // Obtain the signal context. This, most notably, gives us access to | |||
| 132 | // all CPU registers at the time of the signal. | |||
| 133 | ucontext_t* ctx = reinterpret_cast<ucontext_t*>(void_context); | |||
| 134 | if (ctx) { | |||
| 135 | MSAN_UNPOISON(ctx, sizeof(*ctx)); | |||
| 136 | } | |||
| 137 | ||||
| 138 | if (!global_trap_) { | |||
| 139 | RAW_SANDBOX_DIE(sandbox::Die::RawSandboxDie("This can't happen. Found no global singleton instance " "for Trap() handling.") | |||
| 140 | "This can't happen. Found no global singleton instance "sandbox::Die::RawSandboxDie("This can't happen. Found no global singleton instance " "for Trap() handling.") | |||
| 141 | "for Trap() handling.")sandbox::Die::RawSandboxDie("This can't happen. Found no global singleton instance " "for Trap() handling."); | |||
| 142 | } | |||
| 143 | global_trap_->SigSys(nr, info, ctx); | |||
| 144 | } | |||
| 145 | ||||
| 146 | void Trap::SigSys(int nr, LinuxSigInfo* info, ucontext_t* ctx) { | |||
| 147 | // Signal handlers should always preserve "errno". Otherwise, we could | |||
| 148 | // trigger really subtle bugs. | |||
| 149 | const int old_errno = errno(*__errno_location ()); | |||
| 150 | ||||
| 151 | // Various sanity checks to make sure we actually received a signal | |||
| 152 | // triggered by a BPF filter. If something else triggered SIGSYS | |||
| 153 | // (e.g. kill()), there is really nothing we can do with this signal. | |||
| 154 | if (nr != LINUX_SIGSYS31 || info->si_code != SYS_SECCOMPSYS_SECCOMP || !ctx || | |||
| ||||
| 155 | info->si_errno <= 0 || | |||
| 156 | static_cast<size_t>(info->si_errno) > trap_array_size_) { | |||
| 157 | // ATI drivers seem to send SIGSYS, so this cannot be FATAL. | |||
| 158 | // See crbug.com/178166. | |||
| 159 | // TODO(jln): add a DCHECK or move back to FATAL. | |||
| 160 | RAW_LOG(ERROR, "Unexpected SIGSYS received.")::logging::RawLog(::logging::LOGGING_ERROR, "Unexpected SIGSYS received." ); | |||
| 161 | errno(*__errno_location ()) = old_errno; | |||
| 162 | return; | |||
| 163 | } | |||
| 164 | ||||
| 165 | ||||
| 166 | // Obtain the siginfo information that is specific to SIGSYS. | |||
| 167 | struct arch_sigsys sigsys; | |||
| 168 | #if defined(si_call_addr_sifields._sigsys._call_addr) | |||
| 169 | sigsys.ip = info->si_call_addr_sifields._sigsys._call_addr; | |||
| 170 | sigsys.nr = info->si_syscall_sifields._sigsys._syscall; | |||
| 171 | sigsys.arch = info->si_arch_sifields._sigsys._arch; | |||
| 172 | #else | |||
| 173 | // If the version of glibc doesn't include this information in | |||
| 174 | // siginfo_t (older than 2.17), we need to explicitly copy it | |||
| 175 | // into an arch_sigsys structure. | |||
| 176 | memcpy(&sigsys, &info->_sifields, sizeof(sigsys)); | |||
| 177 | #endif | |||
| 178 | ||||
| 179 | #if defined(__mips__) | |||
| 180 | // When indirect syscall (syscall(__NR_foo, ...)) is made on Mips, the | |||
| 181 | // number in register SECCOMP_SYSCALL(ctx) is always __NR_syscall and the | |||
| 182 | // real number of a syscall (__NR_foo) is in SECCOMP_PARM1(ctx) | |||
| 183 | bool sigsys_nr_is_bad = sigsys.nr != static_cast<int>(SECCOMP_SYSCALL(ctx)((ctx)->uc_mcontext.gregs[(REG_RAX)])) && | |||
| 184 | sigsys.nr != static_cast<int>(SECCOMP_PARM1(ctx)((ctx)->uc_mcontext.gregs[(REG_RDI)])); | |||
| 185 | #else | |||
| 186 | bool sigsys_nr_is_bad = sigsys.nr != static_cast<int>(SECCOMP_SYSCALL(ctx)((ctx)->uc_mcontext.gregs[(REG_RAX)])); | |||
| 187 | #endif | |||
| 188 | ||||
| 189 | // Some more sanity checks. | |||
| 190 | if (sigsys.ip != reinterpret_cast<void*>(SECCOMP_IP(ctx)((ctx)->uc_mcontext.gregs[(REG_RIP)])) || | |||
| 191 | sigsys_nr_is_bad || sigsys.arch != SECCOMP_ARCH(62|0x80000000|0x40000000)) { | |||
| 192 | // TODO(markus): | |||
| 193 | // SANDBOX_DIE() can call LOG(FATAL). This is not normally async-signal | |||
| 194 | // safe and can lead to bugs. We should eventually implement a different | |||
| 195 | // logging and reporting mechanism that is safe to be called from | |||
| 196 | // the sigSys() handler. | |||
| 197 | RAW_SANDBOX_DIE("Sanity checks are failing after receiving SIGSYS.")sandbox::Die::RawSandboxDie("Sanity checks are failing after receiving SIGSYS." ); | |||
| 198 | } | |||
| 199 | ||||
| 200 | intptr_t rc; | |||
| 201 | if (has_unsafe_traps_ && GetIsInSigHandler(ctx)) { | |||
| 202 | errno(*__errno_location ()) = old_errno; | |||
| 203 | if (sigsys.nr == __NR_clone56) { | |||
| 204 | RAW_SANDBOX_DIE("Cannot call clone() from an UnsafeTrap() handler.")sandbox::Die::RawSandboxDie("Cannot call clone() from an UnsafeTrap() handler." ); | |||
| 205 | } | |||
| 206 | #if defined(__mips__) | |||
| 207 | // Mips supports up to eight arguments for syscall. | |||
| 208 | // However, seccomp bpf can filter only up to six arguments, so using eight | |||
| 209 | // arguments has sense only when using UnsafeTrap() handler. | |||
| 210 | rc = Syscall::Call(SECCOMP_SYSCALL(ctx)((ctx)->uc_mcontext.gregs[(REG_RAX)]), | |||
| 211 | SECCOMP_PARM1(ctx)((ctx)->uc_mcontext.gregs[(REG_RDI)]), | |||
| 212 | SECCOMP_PARM2(ctx)((ctx)->uc_mcontext.gregs[(REG_RSI)]), | |||
| 213 | SECCOMP_PARM3(ctx)((ctx)->uc_mcontext.gregs[(REG_RDX)]), | |||
| 214 | SECCOMP_PARM4(ctx)((ctx)->uc_mcontext.gregs[(REG_R10)]), | |||
| 215 | SECCOMP_PARM5(ctx)((ctx)->uc_mcontext.gregs[(REG_R8)]), | |||
| 216 | SECCOMP_PARM6(ctx)((ctx)->uc_mcontext.gregs[(REG_R9)]), | |||
| 217 | SECCOMP_PARM7(ctx), | |||
| 218 | SECCOMP_PARM8(ctx)); | |||
| 219 | #else | |||
| 220 | rc = Syscall::Call(SECCOMP_SYSCALL(ctx)((ctx)->uc_mcontext.gregs[(REG_RAX)]), | |||
| 221 | SECCOMP_PARM1(ctx)((ctx)->uc_mcontext.gregs[(REG_RDI)]), | |||
| 222 | SECCOMP_PARM2(ctx)((ctx)->uc_mcontext.gregs[(REG_RSI)]), | |||
| 223 | SECCOMP_PARM3(ctx)((ctx)->uc_mcontext.gregs[(REG_RDX)]), | |||
| 224 | SECCOMP_PARM4(ctx)((ctx)->uc_mcontext.gregs[(REG_R10)]), | |||
| 225 | SECCOMP_PARM5(ctx)((ctx)->uc_mcontext.gregs[(REG_R8)]), | |||
| 226 | SECCOMP_PARM6(ctx)((ctx)->uc_mcontext.gregs[(REG_R9)])); | |||
| 227 | #endif // defined(__mips__) | |||
| 228 | } else { | |||
| 229 | const auto& trap = UNSAFE_TODO(trap_array_[info->si_errno - 1])clang unsafe_buffer_usage begin
trap_array_[info->si_errno - 1] clang unsafe_buffer_usage end ; | |||
| 230 | if (!trap.safe) { | |||
| 231 | SetIsInSigHandler(); | |||
| 232 | } | |||
| 233 | ||||
| 234 | // Copy the seccomp-specific data into a arch_seccomp_data structure. This | |||
| 235 | // is what we are showing to TrapFnc callbacks that the system call | |||
| 236 | // evaluator registered with the sandbox. | |||
| 237 | struct arch_seccomp_data data = { | |||
| 238 | static_cast<int>(SECCOMP_SYSCALL(ctx)((ctx)->uc_mcontext.gregs[(REG_RAX)])), | |||
| 239 | SECCOMP_ARCH(62|0x80000000|0x40000000), | |||
| 240 | reinterpret_cast<uint64_t>(sigsys.ip), | |||
| 241 | {static_cast<uint64_t>(SECCOMP_PARM1(ctx)((ctx)->uc_mcontext.gregs[(REG_RDI)])), | |||
| 242 | static_cast<uint64_t>(SECCOMP_PARM2(ctx)((ctx)->uc_mcontext.gregs[(REG_RSI)])), | |||
| 243 | static_cast<uint64_t>(SECCOMP_PARM3(ctx)((ctx)->uc_mcontext.gregs[(REG_RDX)])), | |||
| 244 | static_cast<uint64_t>(SECCOMP_PARM4(ctx)((ctx)->uc_mcontext.gregs[(REG_R10)])), | |||
| 245 | static_cast<uint64_t>(SECCOMP_PARM5(ctx)((ctx)->uc_mcontext.gregs[(REG_R8)])), | |||
| 246 | static_cast<uint64_t>(SECCOMP_PARM6(ctx)((ctx)->uc_mcontext.gregs[(REG_R9)]))}}; | |||
| 247 | ||||
| 248 | // Now call the TrapFnc callback associated with this particular instance | |||
| 249 | // of SECCOMP_RET_TRAP. | |||
| 250 | rc = trap.fnc(data, reinterpret_cast<void*>(trap.aux)); | |||
| 251 | } | |||
| 252 | ||||
| 253 | // Update the CPU register that stores the return code of the system call | |||
| 254 | // that we just handled, and restore "errno" to the value that it had | |||
| 255 | // before entering the signal handler. | |||
| 256 | Syscall::PutValueInUcontext(rc, ctx); | |||
| 257 | errno(*__errno_location ()) = old_errno; | |||
| 258 | ||||
| 259 | return; | |||
| 260 | } | |||
| 261 | ||||
| 262 | uint16_t Trap::Add(const Handler& handler) { | |||
| 263 | if (!handler.safe && !SandboxDebuggingAllowedByUser()) { | |||
| 264 | // Unless the user set the CHROME_SANDBOX_DEBUGGING environment variable, | |||
| 265 | // we never return an ErrorCode that is marked as "unsafe". This also | |||
| 266 | // means, the BPF compiler will never emit code that allow unsafe system | |||
| 267 | // calls to by-pass the filter (because they use the magic return address | |||
| 268 | // from Syscall::Call(-1)). | |||
| 269 | ||||
| 270 | // This SANDBOX_DIE() can optionally be removed. It won't break security, | |||
| 271 | // but it might make error messages from the BPF compiler a little harder | |||
| 272 | // to understand. Removing the SANDBOX_DIE() allows callers to easily check | |||
| 273 | // whether unsafe traps are supported (by checking whether the returned | |||
| 274 | // ErrorCode is ET_INVALID). | |||
| 275 | SANDBOX_DIE(sandbox::Die::SandboxDie("Cannot use unsafe traps unless CHROME_SANDBOX_DEBUGGING " "is enabled", "/root/firefox-clang/security/sandbox/chromium/sandbox/linux/seccomp-bpf/trap.cc" , 277) | |||
| 276 | "Cannot use unsafe traps unless CHROME_SANDBOX_DEBUGGING "sandbox::Die::SandboxDie("Cannot use unsafe traps unless CHROME_SANDBOX_DEBUGGING " "is enabled", "/root/firefox-clang/security/sandbox/chromium/sandbox/linux/seccomp-bpf/trap.cc" , 277) | |||
| 277 | "is enabled")sandbox::Die::SandboxDie("Cannot use unsafe traps unless CHROME_SANDBOX_DEBUGGING " "is enabled", "/root/firefox-clang/security/sandbox/chromium/sandbox/linux/seccomp-bpf/trap.cc" , 277); | |||
| 278 | } | |||
| 279 | ||||
| 280 | // We return unique identifiers together with SECCOMP_RET_TRAP. This allows | |||
| 281 | // us to associate trap with the appropriate handler. The kernel allows us | |||
| 282 | // identifiers in the range from 0 to SECCOMP_RET_DATA (0xFFFF). We want to | |||
| 283 | // avoid 0, as it could be confused for a trap without any specific id. | |||
| 284 | // The nice thing about sequentially numbered identifiers is that we can also | |||
| 285 | // trivially look them up from our signal handler without making any system | |||
| 286 | // calls that might be async-signal-unsafe. | |||
| 287 | // In order to do so, we store all of our traps in a C-style trap_array_. | |||
| 288 | ||||
| 289 | auto iter = trap_ids_.find(handler); | |||
| 290 | if (iter != trap_ids_.end()) { | |||
| 291 | // We have seen this pair before. Return the same id that we assigned | |||
| 292 | // earlier. | |||
| 293 | return iter->second; | |||
| 294 | } | |||
| 295 | ||||
| 296 | // This is a new pair. Remember it and assign a new id. | |||
| 297 | if (trap_array_size_ >= SECCOMP_RET_DATA0x0000ffffU /* 0xFFFF */ || | |||
| 298 | trap_array_size_ >= std::numeric_limits<uint16_t>::max()) { | |||
| 299 | // In practice, this is pretty much impossible to trigger, as there | |||
| 300 | // are other kernel limitations that restrict overall BPF program sizes. | |||
| 301 | SANDBOX_DIE("Too many SECCOMP_RET_TRAP callback instances")sandbox::Die::SandboxDie("Too many SECCOMP_RET_TRAP callback instances" , "/root/firefox-clang/security/sandbox/chromium/sandbox/linux/seccomp-bpf/trap.cc" , 301); | |||
| 302 | } | |||
| 303 | ||||
| 304 | // Our callers ensure that there are no other threads accessing trap_array_ | |||
| 305 | // concurrently (typically this is done by ensuring that we are single- | |||
| 306 | // threaded while the sandbox is being set up). But we nonetheless are | |||
| 307 | // modifying a live data structure that could be accessed any time a | |||
| 308 | // system call is made; as system calls could be triggering SIGSYS. | |||
| 309 | // So, we have to be extra careful that we update trap_array_ atomically. | |||
| 310 | // In particular, this means we shouldn't be using realloc() to resize it. | |||
| 311 | // Instead, we allocate a new array, copy the values, and then switch the | |||
| 312 | // pointer. We only really care about the pointer being updated atomically | |||
| 313 | // and the data that is pointed to being valid, as these are the only | |||
| 314 | // values accessed from the signal handler. It is OK if trap_array_size_ | |||
| 315 | // is inconsistent with the pointer, as it is monotonously increasing. | |||
| 316 | // Also, we only care about compiler barriers, as the signal handler is | |||
| 317 | // triggered synchronously from a system call. We don't have to protect | |||
| 318 | // against issues with the memory model or with completely asynchronous | |||
| 319 | // events. | |||
| 320 | if (trap_array_size_ >= trap_array_capacity_) { | |||
| 321 | trap_array_capacity_ += kCapacityIncrement; | |||
| 322 | auto* old_trap_array = trap_array_; | |||
| 323 | auto* new_trap_array = new TrapRegistry::Handler[trap_array_capacity_]; | |||
| 324 | std::copy_n(old_trap_array, trap_array_size_, new_trap_array); | |||
| 325 | ||||
| 326 | trap_array_ = new_trap_array; | |||
| 327 | // Prevent the compiler from moving delete[] before the store of the | |||
| 328 | // |new_trap_array|, otherwise a concurrent SIGSYS may see a |trap_array_| | |||
| 329 | // that still points to |old_trap_array| after it has been deleted. | |||
| 330 | std::atomic_signal_fence(std::memory_order_release); | |||
| 331 | delete[] old_trap_array; | |||
| 332 | } | |||
| 333 | ||||
| 334 | uint16_t id = trap_array_size_ + 1; | |||
| 335 | trap_ids_[handler] = id; | |||
| 336 | UNSAFE_TODO(trap_array_[trap_array_size_])clang unsafe_buffer_usage begin
trap_array_[trap_array_size_ ] clang unsafe_buffer_usage end = handler; | |||
| 337 | trap_array_size_++; | |||
| 338 | return id; | |||
| 339 | } | |||
| 340 | ||||
| 341 | bool Trap::SandboxDebuggingAllowedByUser() { | |||
| 342 | const char* debug_flag = getenv(kSandboxDebuggingEnv); | |||
| 343 | return debug_flag && *debug_flag; | |||
| 344 | } | |||
| 345 | ||||
| 346 | bool Trap::EnableUnsafeTraps() { | |||
| 347 | if (!has_unsafe_traps_) { | |||
| 348 | // Unsafe traps are a one-way fuse. Once enabled, they can never be turned | |||
| 349 | // off again. | |||
| 350 | // We only allow enabling unsafe traps, if the user explicitly set an | |||
| 351 | // appropriate environment variable. This prevents bugs that accidentally | |||
| 352 | // disable all sandboxing for all users. | |||
| 353 | if (SandboxDebuggingAllowedByUser()) { | |||
| 354 | // We only ever print this message once, when we enable unsafe traps the | |||
| 355 | // first time. | |||
| 356 | SANDBOX_INFO("WARNING! Disabling sandbox for debugging purposes")sandbox::Die::SandboxInfo("WARNING! Disabling sandbox for debugging purposes" , "/root/firefox-clang/security/sandbox/chromium/sandbox/linux/seccomp-bpf/trap.cc" , 356); | |||
| 357 | has_unsafe_traps_ = true; | |||
| 358 | } else { | |||
| 359 | SANDBOX_INFO(sandbox::Die::SandboxInfo("Cannot disable sandbox and use unsafe traps unless " "CHROME_SANDBOX_DEBUGGING is turned on first", "/root/firefox-clang/security/sandbox/chromium/sandbox/linux/seccomp-bpf/trap.cc" , 361) | |||
| 360 | "Cannot disable sandbox and use unsafe traps unless "sandbox::Die::SandboxInfo("Cannot disable sandbox and use unsafe traps unless " "CHROME_SANDBOX_DEBUGGING is turned on first", "/root/firefox-clang/security/sandbox/chromium/sandbox/linux/seccomp-bpf/trap.cc" , 361) | |||
| 361 | "CHROME_SANDBOX_DEBUGGING is turned on first")sandbox::Die::SandboxInfo("Cannot disable sandbox and use unsafe traps unless " "CHROME_SANDBOX_DEBUGGING is turned on first", "/root/firefox-clang/security/sandbox/chromium/sandbox/linux/seccomp-bpf/trap.cc" , 361); | |||
| 362 | } | |||
| 363 | } | |||
| 364 | // Returns the, possibly updated, value of has_unsafe_traps_. | |||
| 365 | return has_unsafe_traps_; | |||
| 366 | } | |||
| 367 | ||||
| 368 | Trap* Trap::global_trap_; | |||
| 369 | ||||
| 370 | } // namespace sandbox |