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