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