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/prctl.h> | |
| 11 #include <sys/syscall.h> | 10 #include <sys/syscall.h> |
| 12 | 11 |
| 12 #include <algorithm> | |
| 13 #include <limits> | 13 #include <limits> |
| 14 | 14 |
| 15 #include "base/logging.h" | 15 #include "base/logging.h" |
| 16 #include "sandbox/linux/seccomp-bpf/codegen.h" | 16 #include "build/build_config.h" |
| 17 #include "sandbox/linux/seccomp-bpf/die.h" | 17 #include "sandbox/linux/seccomp-bpf/die.h" |
| 18 #include "sandbox/linux/seccomp-bpf/linux_seccomp.h" | |
| 18 #include "sandbox/linux/seccomp-bpf/syscall.h" | 19 #include "sandbox/linux/seccomp-bpf/syscall.h" |
| 19 | 20 |
| 20 // Android's signal.h doesn't define ucontext etc. | 21 // Android's signal.h doesn't define ucontext etc. |
| 21 #if defined(OS_ANDROID) | 22 #if defined(OS_ANDROID) |
| 22 #include "sandbox/linux/services/android_ucontext.h" | 23 #include "sandbox/linux/services/android_ucontext.h" |
| 23 #endif | 24 #endif |
| 24 | 25 |
| 25 namespace { | 26 namespace { |
| 26 | 27 |
| 28 struct arch_sigsys { | |
| 29 void* ip; | |
| 30 int nr; | |
| 31 unsigned int arch; | |
| 32 }; | |
| 33 | |
| 27 const int kCapacityIncrement = 20; | 34 const int kCapacityIncrement = 20; |
| 28 | 35 |
| 29 // Unsafe traps can only be turned on, if the user explicitly allowed them | 36 // Unsafe traps can only be turned on, if the user explicitly allowed them |
| 30 // by setting the CHROME_SANDBOX_DEBUGGING environment variable. | 37 // by setting the CHROME_SANDBOX_DEBUGGING environment variable. |
| 31 const char kSandboxDebuggingEnv[] = "CHROME_SANDBOX_DEBUGGING"; | 38 const char kSandboxDebuggingEnv[] = "CHROME_SANDBOX_DEBUGGING"; |
| 32 | 39 |
| 33 // We need to tell whether we are performing a "normal" callback, or | 40 // We need to tell whether we are performing a "normal" callback, or |
| 34 // whether we were called recursively from within a UnsafeTrap() callback. | 41 // 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 | 42 // 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 | 43 // per-thread data from within a signal context. Normal TLS storage is not |
| (...skipping 156 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 193 #else | 200 #else |
| 194 rc = Syscall::Call(SECCOMP_SYSCALL(ctx), | 201 rc = Syscall::Call(SECCOMP_SYSCALL(ctx), |
| 195 SECCOMP_PARM1(ctx), | 202 SECCOMP_PARM1(ctx), |
| 196 SECCOMP_PARM2(ctx), | 203 SECCOMP_PARM2(ctx), |
| 197 SECCOMP_PARM3(ctx), | 204 SECCOMP_PARM3(ctx), |
| 198 SECCOMP_PARM4(ctx), | 205 SECCOMP_PARM4(ctx), |
| 199 SECCOMP_PARM5(ctx), | 206 SECCOMP_PARM5(ctx), |
| 200 SECCOMP_PARM6(ctx)); | 207 SECCOMP_PARM6(ctx)); |
| 201 #endif // defined(__mips__) | 208 #endif // defined(__mips__) |
| 202 } else { | 209 } else { |
| 203 const ErrorCode& err = trap_array_[info->si_errno - 1]; | 210 const TrapKey& trap = trap_array_[info->si_errno - 1]; |
| 204 if (!err.safe_) { | 211 if (!trap.safe) { |
| 205 SetIsInSigHandler(); | 212 SetIsInSigHandler(); |
| 206 } | 213 } |
| 207 | 214 |
| 208 // Copy the seccomp-specific data into a arch_seccomp_data structure. This | 215 // Copy the seccomp-specific data into a arch_seccomp_data structure. This |
| 209 // is what we are showing to TrapFnc callbacks that the system call | 216 // is what we are showing to TrapFnc callbacks that the system call |
| 210 // evaluator registered with the sandbox. | 217 // evaluator registered with the sandbox. |
| 211 struct arch_seccomp_data data = { | 218 struct arch_seccomp_data data = { |
| 212 static_cast<int>(SECCOMP_SYSCALL(ctx)), | 219 static_cast<int>(SECCOMP_SYSCALL(ctx)), |
| 213 SECCOMP_ARCH, | 220 SECCOMP_ARCH, |
| 214 reinterpret_cast<uint64_t>(sigsys.ip), | 221 reinterpret_cast<uint64_t>(sigsys.ip), |
| 215 {static_cast<uint64_t>(SECCOMP_PARM1(ctx)), | 222 {static_cast<uint64_t>(SECCOMP_PARM1(ctx)), |
| 216 static_cast<uint64_t>(SECCOMP_PARM2(ctx)), | 223 static_cast<uint64_t>(SECCOMP_PARM2(ctx)), |
| 217 static_cast<uint64_t>(SECCOMP_PARM3(ctx)), | 224 static_cast<uint64_t>(SECCOMP_PARM3(ctx)), |
| 218 static_cast<uint64_t>(SECCOMP_PARM4(ctx)), | 225 static_cast<uint64_t>(SECCOMP_PARM4(ctx)), |
| 219 static_cast<uint64_t>(SECCOMP_PARM5(ctx)), | 226 static_cast<uint64_t>(SECCOMP_PARM5(ctx)), |
| 220 static_cast<uint64_t>(SECCOMP_PARM6(ctx))}}; | 227 static_cast<uint64_t>(SECCOMP_PARM6(ctx))}}; |
| 221 | 228 |
| 222 // Now call the TrapFnc callback associated with this particular instance | 229 // Now call the TrapFnc callback associated with this particular instance |
| 223 // of SECCOMP_RET_TRAP. | 230 // of SECCOMP_RET_TRAP. |
| 224 rc = err.fnc_(data, err.aux_); | 231 rc = trap.fnc(data, const_cast<void*>(trap.aux)); |
| 225 } | 232 } |
| 226 | 233 |
| 227 // Update the CPU register that stores the return code of the system call | 234 // Update the CPU register that stores the return code of the system call |
| 228 // that we just handled, and restore "errno" to the value that it had | 235 // that we just handled, and restore "errno" to the value that it had |
| 229 // before entering the signal handler. | 236 // before entering the signal handler. |
| 230 Syscall::PutValueInUcontext(rc, ctx); | 237 Syscall::PutValueInUcontext(rc, ctx); |
| 231 errno = old_errno; | 238 errno = old_errno; |
| 232 | 239 |
| 233 return; | 240 return; |
| 234 } | 241 } |
| 235 | 242 |
| 236 bool Trap::TrapKey::operator<(const TrapKey& o) const { | 243 bool Trap::TrapKey::operator<(const TrapKey& o) const { |
| 237 if (fnc != o.fnc) { | 244 if (fnc != o.fnc) { |
| 238 return fnc < o.fnc; | 245 return fnc < o.fnc; |
| 239 } else if (aux != o.aux) { | 246 } else if (aux != o.aux) { |
| 240 return aux < o.aux; | 247 return aux < o.aux; |
| 241 } else { | 248 } else { |
| 242 return safe < o.safe; | 249 return safe < o.safe; |
| 243 } | 250 } |
| 244 } | 251 } |
| 245 | 252 |
| 246 ErrorCode Trap::MakeTrap(TrapFnc fnc, const void* aux, bool safe) { | 253 uint16_t Trap::MakeTrap(TrapFnc fnc, const void* aux, bool safe) { |
| 247 return GetInstance()->MakeTrapImpl(fnc, aux, safe); | 254 return GetInstance()->MakeTrapImpl(fnc, aux, safe); |
| 248 } | 255 } |
| 249 | 256 |
| 250 ErrorCode Trap::MakeTrapImpl(TrapFnc fnc, const void* aux, bool safe) { | 257 uint16_t Trap::MakeTrapImpl(TrapFnc fnc, const void* aux, bool safe) { |
| 251 if (!safe && !SandboxDebuggingAllowedByUser()) { | 258 if (!safe && !SandboxDebuggingAllowedByUser()) { |
| 252 // Unless the user set the CHROME_SANDBOX_DEBUGGING environment variable, | 259 // Unless the user set the CHROME_SANDBOX_DEBUGGING environment variable, |
| 253 // we never return an ErrorCode that is marked as "unsafe". This also | 260 // we never return an ErrorCode that is marked as "unsafe". This also |
| 254 // means, the BPF compiler will never emit code that allow unsafe system | 261 // means, the BPF compiler will never emit code that allow unsafe system |
| 255 // calls to by-pass the filter (because they use the magic return address | 262 // calls to by-pass the filter (because they use the magic return address |
| 256 // from Syscall::Call(-1)). | 263 // from Syscall::Call(-1)). |
| 257 | 264 |
| 258 // This SANDBOX_DIE() can optionally be removed. It won't break security, | 265 // This SANDBOX_DIE() can optionally be removed. It won't break security, |
| 259 // but it might make error messages from the BPF compiler a little harder | 266 // but it might make error messages from the BPF compiler a little harder |
| 260 // to understand. Removing the SANDBOX_DIE() allows callers to easyly check | 267 // to understand. Removing the SANDBOX_DIE() allows callers to easily check |
| 261 // whether unsafe traps are supported (by checking whether the returned | 268 // whether unsafe traps are supported (by checking whether the returned |
| 262 // ErrorCode is ET_INVALID). | 269 // ErrorCode is ET_INVALID). |
| 263 SANDBOX_DIE( | 270 SANDBOX_DIE( |
| 264 "Cannot use unsafe traps unless CHROME_SANDBOX_DEBUGGING " | 271 "Cannot use unsafe traps unless CHROME_SANDBOX_DEBUGGING " |
| 265 "is enabled"); | 272 "is enabled"); |
| 266 | 273 |
| 267 return ErrorCode(); | 274 return 0; |
| 268 } | 275 } |
| 269 | 276 |
| 270 // Each unique pair of TrapFnc and auxiliary data make up a distinct instance | 277 // Each unique pair of TrapFnc and auxiliary data make up a distinct instance |
| 271 // of a SECCOMP_RET_TRAP. | 278 // of a SECCOMP_RET_TRAP. |
| 272 TrapKey key(fnc, aux, safe); | 279 TrapKey key(fnc, aux, safe); |
| 273 TrapIds::const_iterator iter = trap_ids_.find(key); | |
| 274 | 280 |
| 275 // We return unique identifiers together with SECCOMP_RET_TRAP. This allows | 281 // We return unique identifiers together with SECCOMP_RET_TRAP. This allows |
| 276 // us to associate trap with the appropriate handler. The kernel allows us | 282 // us to associate trap with the appropriate handler. The kernel allows us |
| 277 // identifiers in the range from 0 to SECCOMP_RET_DATA (0xFFFF). We want to | 283 // identifiers in the range from 0 to SECCOMP_RET_DATA (0xFFFF). We want to |
| 278 // avoid 0, as it could be confused for a trap without any specific id. | 284 // avoid 0, as it could be confused for a trap without any specific id. |
| 279 // The nice thing about sequentially numbered identifiers is that we can also | 285 // The nice thing about sequentially numbered identifiers is that we can also |
| 280 // trivially look them up from our signal handler without making any system | 286 // trivially look them up from our signal handler without making any system |
| 281 // calls that might be async-signal-unsafe. | 287 // calls that might be async-signal-unsafe. |
| 282 // In order to do so, we store all of our traps in a C-style trap_array_. | 288 // In order to do so, we store all of our traps in a C-style trap_array_. |
| 283 uint16_t id; | 289 |
| 290 TrapIds::const_iterator iter = trap_ids_.find(key); | |
| 284 if (iter != trap_ids_.end()) { | 291 if (iter != trap_ids_.end()) { |
| 285 // We have seen this pair before. Return the same id that we assigned | 292 // We have seen this pair before. Return the same id that we assigned |
| 286 // earlier. | 293 // earlier. |
| 287 id = iter->second; | 294 return iter->second; |
| 288 } else { | 295 } |
| 289 // This is a new pair. Remember it and assign a new id. | 296 |
| 290 if (trap_array_size_ >= SECCOMP_RET_DATA /* 0xFFFF */ || | 297 // This is a new pair. Remember it and assign a new id. |
| 291 trap_array_size_ >= std::numeric_limits<typeof(id)>::max()) { | 298 if (trap_array_size_ >= SECCOMP_RET_DATA /* 0xFFFF */ || |
| 299 trap_array_size_ >= std::numeric_limits<uint16_t>::max()) { | |
| 292 // In practice, this is pretty much impossible to trigger, as there | 300 // In practice, this is pretty much impossible to trigger, as there |
| 293 // are other kernel limitations that restrict overall BPF program sizes. | 301 // are other kernel limitations that restrict overall BPF program sizes. |
| 294 SANDBOX_DIE("Too many SECCOMP_RET_TRAP callback instances"); | 302 SANDBOX_DIE("Too many SECCOMP_RET_TRAP callback instances"); |
| 295 } | 303 } |
| 296 id = trap_array_size_ + 1; | |
| 297 | 304 |
| 298 // Our callers ensure that there are no other threads accessing trap_array_ | 305 // Our callers ensure that there are no other threads accessing trap_array_ |
| 299 // concurrently (typically this is done by ensuring that we are single- | 306 // concurrently (typically this is done by ensuring that we are single- |
| 300 // threaded while the sandbox is being set up). But we nonetheless are | 307 // threaded while the sandbox is being set up). But we nonetheless are |
| 301 // modifying a life data structure that could be accessed any time a | 308 // modifying a live data structure that could be accessed any time a |
| 302 // system call is made; as system calls could be triggering SIGSYS. | 309 // system call is made; as system calls could be triggering SIGSYS. |
| 303 // So, we have to be extra careful that we update trap_array_ atomically. | 310 // So, we have to be extra careful that we update trap_array_ atomically. |
| 304 // In particular, this means we shouldn't be using realloc() to resize it. | 311 // In particular, this means we shouldn't be using realloc() to resize it. |
| 305 // Instead, we allocate a new array, copy the values, and then switch the | 312 // Instead, we allocate a new array, copy the values, and then switch the |
| 306 // pointer. We only really care about the pointer being updated atomically | 313 // pointer. We only really care about the pointer being updated atomically |
| 307 // and the data that is pointed to being valid, as these are the only | 314 // and the data that is pointed to being valid, as these are the only |
| 308 // values accessed from the signal handler. It is OK if trap_array_size_ | 315 // values accessed from the signal handler. It is OK if trap_array_size_ |
| 309 // is inconsistent with the pointer, as it is monotonously increasing. | 316 // is inconsistent with the pointer, as it is monotonously increasing. |
| 310 // Also, we only care about compiler barriers, as the signal handler is | 317 // Also, we only care about compiler barriers, as the signal handler is |
| 311 // triggered synchronously from a system call. We don't have to protect | 318 // triggered synchronously from a system call. We don't have to protect |
| 312 // against issues with the memory model or with completely asynchronous | 319 // against issues with the memory model or with completely asynchronous |
| 313 // events. | 320 // events. |
|
leecam
2014/09/16 12:36:44
This code is to ensure that we can add new Traps a
mdempsky
2014/09/16 18:48:19
Yeah, more or less.
| |
| 314 if (trap_array_size_ >= trap_array_capacity_) { | 321 if (trap_array_size_ >= trap_array_capacity_) { |
| 315 trap_array_capacity_ += kCapacityIncrement; | 322 trap_array_capacity_ += kCapacityIncrement; |
| 316 ErrorCode* old_trap_array = trap_array_; | 323 TrapKey* old_trap_array = trap_array_; |
| 317 ErrorCode* new_trap_array = new ErrorCode[trap_array_capacity_]; | 324 TrapKey* new_trap_array = new TrapKey[trap_array_capacity_]; |
| 325 std::copy_n(old_trap_array, trap_array_size_, new_trap_array); | |
| 318 | 326 |
| 319 // Language specs are unclear on whether the compiler is allowed to move | 327 // Language specs are unclear on whether the compiler is allowed to move |
| 320 // the "delete[]" above our preceding assignments and/or memory moves, | 328 // the "delete[]" above our preceding assignments and/or memory moves, |
| 321 // iff the compiler believes that "delete[]" doesn't have any other | 329 // iff the compiler believes that "delete[]" doesn't have any other |
| 322 // global side-effects. | 330 // global side-effects. |
| 323 // We insert optimization barriers to prevent this from happening. | 331 // We insert optimization barriers to prevent this from happening. |
| 324 // The first barrier is probably not needed, but better be explicit in | 332 // The first barrier is probably not needed, but better be explicit in |
| 325 // what we want to tell the compiler. | 333 // what we want to tell the compiler. |
| 326 // The clang developer mailing list couldn't answer whether this is a | 334 // The clang developer mailing list couldn't answer whether this is a |
| 327 // legitimate worry; but they at least thought that the barrier is | 335 // legitimate worry; but they at least thought that the barrier is |
| 328 // sufficient to prevent the (so far hypothetical) problem of re-ordering | 336 // sufficient to prevent the (so far hypothetical) problem of re-ordering |
| 329 // of instructions by the compiler. | 337 // of instructions by the compiler. |
| 330 memcpy(new_trap_array, trap_array_, trap_array_size_ * sizeof(ErrorCode)); | 338 // TODO(mdempsky): Replace with sequentially-consistent atomic store. |
| 331 asm volatile("" : "=r"(new_trap_array) : "0"(new_trap_array) : "memory"); | 339 asm volatile("" : "=r"(new_trap_array) : "0"(new_trap_array) : "memory"); |
| 332 trap_array_ = new_trap_array; | 340 trap_array_ = new_trap_array; |
| 333 asm volatile("" : "=r"(trap_array_) : "0"(trap_array_) : "memory"); | 341 asm volatile("" : "=r"(trap_array_) : "0"(trap_array_) : "memory"); |
| 334 | 342 |
| 335 delete[] old_trap_array; | 343 delete[] old_trap_array; |
| 336 } | 344 } |
| 345 | |
| 346 uint16_t id = trap_array_size_ + 1; | |
| 337 trap_ids_[key] = id; | 347 trap_ids_[key] = id; |
| 338 trap_array_[trap_array_size_] = ErrorCode(fnc, aux, safe, id); | 348 trap_array_[trap_array_size_] = key; |
| 339 return trap_array_[trap_array_size_++]; | 349 // TODO(mdempsky): Atomic increment. |
| 340 } | 350 trap_array_size_++; |
|
leecam
2014/09/16 12:36:44
why don't we just make this an atomic and fix the
mdempsky
2014/09/16 18:48:19
Just because I think doing that correctly is actua
| |
| 341 | 351 return id; |
| 342 return ErrorCode(fnc, aux, safe, id); | |
| 343 } | 352 } |
| 344 | 353 |
| 345 bool Trap::SandboxDebuggingAllowedByUser() const { | 354 bool Trap::SandboxDebuggingAllowedByUser() const { |
| 346 const char* debug_flag = getenv(kSandboxDebuggingEnv); | 355 const char* debug_flag = getenv(kSandboxDebuggingEnv); |
| 347 return debug_flag && *debug_flag; | 356 return debug_flag && *debug_flag; |
| 348 } | 357 } |
| 349 | 358 |
| 350 bool Trap::EnableUnsafeTrapsInSigSysHandler() { | 359 bool Trap::EnableUnsafeTrapsInSigSysHandler() { |
| 351 Trap* trap = GetInstance(); | 360 Trap* trap = GetInstance(); |
| 352 if (!trap->has_unsafe_traps_) { | 361 if (!trap->has_unsafe_traps_) { |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 363 } else { | 372 } else { |
| 364 SANDBOX_INFO( | 373 SANDBOX_INFO( |
| 365 "Cannot disable sandbox and use unsafe traps unless " | 374 "Cannot disable sandbox and use unsafe traps unless " |
| 366 "CHROME_SANDBOX_DEBUGGING is turned on first"); | 375 "CHROME_SANDBOX_DEBUGGING is turned on first"); |
| 367 } | 376 } |
| 368 } | 377 } |
| 369 // Returns the, possibly updated, value of has_unsafe_traps_. | 378 // Returns the, possibly updated, value of has_unsafe_traps_. |
| 370 return trap->has_unsafe_traps_; | 379 return trap->has_unsafe_traps_; |
| 371 } | 380 } |
| 372 | 381 |
| 373 ErrorCode Trap::ErrorCodeFromTrapId(uint16_t id) { | 382 bool Trap::IsSafeTrapId(uint16_t id) { |
| 374 if (global_trap_ && id > 0 && id <= global_trap_->trap_array_size_) { | 383 if (global_trap_ && id > 0 && id <= global_trap_->trap_array_size_) { |
| 375 return global_trap_->trap_array_[id - 1]; | 384 return global_trap_->trap_array_[id - 1].safe; |
| 376 } else { | |
| 377 return ErrorCode(); | |
| 378 } | 385 } |
| 386 return false; | |
| 379 } | 387 } |
| 380 | 388 |
| 381 Trap* Trap::global_trap_; | 389 Trap* Trap::global_trap_; |
| 382 | 390 |
| 383 } // namespace sandbox | 391 } // namespace sandbox |
| OLD | NEW |