Index: sandbox/linux/seccomp-bpf/trap.cc |
diff --git a/sandbox/linux/seccomp-bpf/trap.cc b/sandbox/linux/seccomp-bpf/trap.cc |
index ce906fcb2e7be45d9da985871b5b61fba82fdfc2..bb0245eab07440ec3d54abd98c57638c3ee2aa42 100644 |
--- a/sandbox/linux/seccomp-bpf/trap.cc |
+++ b/sandbox/linux/seccomp-bpf/trap.cc |
@@ -7,14 +7,15 @@ |
#include <errno.h> |
#include <signal.h> |
#include <string.h> |
-#include <sys/prctl.h> |
#include <sys/syscall.h> |
+#include <algorithm> |
#include <limits> |
#include "base/logging.h" |
-#include "sandbox/linux/seccomp-bpf/codegen.h" |
+#include "build/build_config.h" |
#include "sandbox/linux/seccomp-bpf/die.h" |
+#include "sandbox/linux/seccomp-bpf/linux_seccomp.h" |
#include "sandbox/linux/seccomp-bpf/syscall.h" |
// Android's signal.h doesn't define ucontext etc. |
@@ -24,6 +25,12 @@ |
namespace { |
+struct arch_sigsys { |
+ void* ip; |
+ int nr; |
+ unsigned int arch; |
+}; |
+ |
const int kCapacityIncrement = 20; |
// Unsafe traps can only be turned on, if the user explicitly allowed them |
@@ -200,8 +207,8 @@ void Trap::SigSys(int nr, siginfo_t* info, void* void_context) { |
SECCOMP_PARM6(ctx)); |
#endif // defined(__mips__) |
} else { |
- const ErrorCode& err = trap_array_[info->si_errno - 1]; |
- if (!err.safe_) { |
+ const TrapKey& trap = trap_array_[info->si_errno - 1]; |
+ if (!trap.safe) { |
SetIsInSigHandler(); |
} |
@@ -221,7 +228,7 @@ void Trap::SigSys(int nr, siginfo_t* info, void* void_context) { |
// Now call the TrapFnc callback associated with this particular instance |
// of SECCOMP_RET_TRAP. |
- rc = err.fnc_(data, err.aux_); |
+ rc = trap.fnc(data, const_cast<void*>(trap.aux)); |
} |
// Update the CPU register that stores the return code of the system call |
@@ -243,11 +250,11 @@ bool Trap::TrapKey::operator<(const TrapKey& o) const { |
} |
} |
-ErrorCode Trap::MakeTrap(TrapFnc fnc, const void* aux, bool safe) { |
+uint16_t Trap::MakeTrap(TrapFnc fnc, const void* aux, bool safe) { |
return GetInstance()->MakeTrapImpl(fnc, aux, safe); |
} |
-ErrorCode Trap::MakeTrapImpl(TrapFnc fnc, const void* aux, bool safe) { |
+uint16_t Trap::MakeTrapImpl(TrapFnc fnc, const void* aux, bool safe) { |
if (!safe && !SandboxDebuggingAllowedByUser()) { |
// Unless the user set the CHROME_SANDBOX_DEBUGGING environment variable, |
// we never return an ErrorCode that is marked as "unsafe". This also |
@@ -257,20 +264,19 @@ ErrorCode Trap::MakeTrapImpl(TrapFnc fnc, const void* aux, bool safe) { |
// This SANDBOX_DIE() can optionally be removed. It won't break security, |
// but it might make error messages from the BPF compiler a little harder |
- // to understand. Removing the SANDBOX_DIE() allows callers to easyly check |
+ // to understand. Removing the SANDBOX_DIE() allows callers to easily check |
// whether unsafe traps are supported (by checking whether the returned |
// ErrorCode is ET_INVALID). |
SANDBOX_DIE( |
"Cannot use unsafe traps unless CHROME_SANDBOX_DEBUGGING " |
"is enabled"); |
- return ErrorCode(); |
+ return 0; |
} |
// Each unique pair of TrapFnc and auxiliary data make up a distinct instance |
// of a SECCOMP_RET_TRAP. |
TrapKey key(fnc, aux, safe); |
- TrapIds::const_iterator iter = trap_ids_.find(key); |
// We return unique identifiers together with SECCOMP_RET_TRAP. This allows |
// us to associate trap with the appropriate handler. The kernel allows us |
@@ -280,25 +286,26 @@ ErrorCode Trap::MakeTrapImpl(TrapFnc fnc, const void* aux, bool safe) { |
// trivially look them up from our signal handler without making any system |
// calls that might be async-signal-unsafe. |
// In order to do so, we store all of our traps in a C-style trap_array_. |
- uint16_t id; |
+ |
+ TrapIds::const_iterator iter = trap_ids_.find(key); |
if (iter != trap_ids_.end()) { |
// We have seen this pair before. Return the same id that we assigned |
// earlier. |
- id = iter->second; |
- } else { |
- // This is a new pair. Remember it and assign a new id. |
- if (trap_array_size_ >= SECCOMP_RET_DATA /* 0xFFFF */ || |
- trap_array_size_ >= std::numeric_limits<typeof(id)>::max()) { |
+ return iter->second; |
+ } |
+ |
+ // This is a new pair. Remember it and assign a new id. |
+ if (trap_array_size_ >= SECCOMP_RET_DATA /* 0xFFFF */ || |
+ trap_array_size_ >= std::numeric_limits<uint16_t>::max()) { |
// In practice, this is pretty much impossible to trigger, as there |
// are other kernel limitations that restrict overall BPF program sizes. |
SANDBOX_DIE("Too many SECCOMP_RET_TRAP callback instances"); |
} |
- id = trap_array_size_ + 1; |
// Our callers ensure that there are no other threads accessing trap_array_ |
// concurrently (typically this is done by ensuring that we are single- |
// threaded while the sandbox is being set up). But we nonetheless are |
- // modifying a life data structure that could be accessed any time a |
+ // modifying a live data structure that could be accessed any time a |
// system call is made; as system calls could be triggering SIGSYS. |
// So, we have to be extra careful that we update trap_array_ atomically. |
// In particular, this means we shouldn't be using realloc() to resize it. |
@@ -313,8 +320,9 @@ ErrorCode Trap::MakeTrapImpl(TrapFnc fnc, const void* aux, bool safe) { |
// 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.
|
if (trap_array_size_ >= trap_array_capacity_) { |
trap_array_capacity_ += kCapacityIncrement; |
- ErrorCode* old_trap_array = trap_array_; |
- ErrorCode* new_trap_array = new ErrorCode[trap_array_capacity_]; |
+ TrapKey* old_trap_array = trap_array_; |
+ TrapKey* new_trap_array = new TrapKey[trap_array_capacity_]; |
+ std::copy_n(old_trap_array, trap_array_size_, new_trap_array); |
// Language specs are unclear on whether the compiler is allowed to move |
// the "delete[]" above our preceding assignments and/or memory moves, |
@@ -327,19 +335,20 @@ ErrorCode Trap::MakeTrapImpl(TrapFnc fnc, const void* aux, bool safe) { |
// legitimate worry; but they at least thought that the barrier is |
// sufficient to prevent the (so far hypothetical) problem of re-ordering |
// of instructions by the compiler. |
- memcpy(new_trap_array, trap_array_, trap_array_size_ * sizeof(ErrorCode)); |
+ // TODO(mdempsky): Replace with sequentially-consistent atomic store. |
asm volatile("" : "=r"(new_trap_array) : "0"(new_trap_array) : "memory"); |
trap_array_ = new_trap_array; |
asm volatile("" : "=r"(trap_array_) : "0"(trap_array_) : "memory"); |
delete[] old_trap_array; |
} |
- trap_ids_[key] = id; |
- trap_array_[trap_array_size_] = ErrorCode(fnc, aux, safe, id); |
- return trap_array_[trap_array_size_++]; |
- } |
- return ErrorCode(fnc, aux, safe, id); |
+ uint16_t id = trap_array_size_ + 1; |
+ trap_ids_[key] = id; |
+ trap_array_[trap_array_size_] = key; |
+ // TODO(mdempsky): Atomic increment. |
+ 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
|
+ return id; |
} |
bool Trap::SandboxDebuggingAllowedByUser() const { |
@@ -370,12 +379,11 @@ bool Trap::EnableUnsafeTrapsInSigSysHandler() { |
return trap->has_unsafe_traps_; |
} |
-ErrorCode Trap::ErrorCodeFromTrapId(uint16_t id) { |
+bool Trap::IsSafeTrapId(uint16_t id) { |
if (global_trap_ && id > 0 && id <= global_trap_->trap_array_size_) { |
- return global_trap_->trap_array_[id - 1]; |
- } else { |
- return ErrorCode(); |
+ return global_trap_->trap_array_[id - 1].safe; |
} |
+ return false; |
} |
Trap* Trap::global_trap_; |