| Index: sandbox/linux/bpf_dsl/policy_compiler.cc
|
| diff --git a/sandbox/linux/bpf_dsl/policy_compiler.cc b/sandbox/linux/bpf_dsl/policy_compiler.cc
|
| index 2bc22e92aa939ba001347f207517417db36c4f90..f91f70c5d7d51199c5b4c983b866cb647ff8d8aa 100644
|
| --- a/sandbox/linux/bpf_dsl/policy_compiler.cc
|
| +++ b/sandbox/linux/bpf_dsl/policy_compiler.cc
|
| @@ -54,12 +54,6 @@ bool HasExactlyOneBit(uint64_t x) {
|
| return x != 0 && (x & (x - 1)) == 0;
|
| }
|
|
|
| -bool IsDenied(const ErrorCode& code) {
|
| - return (code.err() & SECCOMP_RET_ACTION) == SECCOMP_RET_TRAP ||
|
| - (code.err() >= (SECCOMP_RET_ERRNO + ErrorCode::ERR_MIN_ERRNO) &&
|
| - code.err() <= (SECCOMP_RET_ERRNO + ErrorCode::ERR_MAX_ERRNO));
|
| -}
|
| -
|
| // A Trap() handler that returns an "errno" value. The value is encoded
|
| // in the "aux" parameter.
|
| intptr_t ReturnErrno(const struct arch_seccomp_data&, void* aux) {
|
| @@ -71,11 +65,8 @@ intptr_t ReturnErrno(const struct arch_seccomp_data&, void* aux) {
|
| return -err;
|
| }
|
|
|
| -intptr_t BPFFailure(const struct arch_seccomp_data&, void* aux) {
|
| - SANDBOX_DIE(static_cast<char*>(aux));
|
| -}
|
| -
|
| bool HasUnsafeTraps(const Policy* policy) {
|
| + DCHECK(policy);
|
| for (uint32_t sysnum : SyscallSet::ValidOnly()) {
|
| if (policy->EvaluateSyscall(sysnum)->HasUnsafeTraps()) {
|
| return true;
|
| @@ -87,9 +78,8 @@ bool HasUnsafeTraps(const Policy* policy) {
|
| } // namespace
|
|
|
| struct PolicyCompiler::Range {
|
| - Range(uint32_t f, const ErrorCode& e) : from(f), err(e) {}
|
| uint32_t from;
|
| - ErrorCode err;
|
| + CodeGen::Node node;
|
| };
|
|
|
| PolicyCompiler::PolicyCompiler(const Policy* policy, TrapRegistry* registry)
|
| @@ -98,13 +88,14 @@ PolicyCompiler::PolicyCompiler(const Policy* policy, TrapRegistry* registry)
|
| conds_(),
|
| gen_(),
|
| has_unsafe_traps_(HasUnsafeTraps(policy_)) {
|
| + DCHECK(policy);
|
| }
|
|
|
| PolicyCompiler::~PolicyCompiler() {
|
| }
|
|
|
| scoped_ptr<CodeGen::Program> PolicyCompiler::Compile() {
|
| - if (!IsDenied(policy_->InvalidSyscall()->Compile(this))) {
|
| + if (!policy_->InvalidSyscall()->IsDeny()) {
|
| SANDBOX_DIE("Policies should deny invalid system calls.");
|
| }
|
|
|
| @@ -121,8 +112,7 @@ scoped_ptr<CodeGen::Program> PolicyCompiler::Compile() {
|
| }
|
|
|
| for (int sysnum : kSyscallsRequiredForUnsafeTraps) {
|
| - if (!policy_->EvaluateSyscall(sysnum)->Compile(this)
|
| - .Equals(ErrorCode(ErrorCode::ERR_ALLOWED))) {
|
| + if (!policy_->EvaluateSyscall(sysnum)->IsAllow()) {
|
| SANDBOX_DIE(
|
| "Policies that use UnsafeTrap() must unconditionally allow all "
|
| "required system calls");
|
| @@ -159,13 +149,10 @@ CodeGen::Node PolicyCompiler::CheckArch(CodeGen::Node passed) {
|
| // If the architecture doesn't match SECCOMP_ARCH, disallow the
|
| // system call.
|
| return gen_.MakeInstruction(
|
| - BPF_LD + BPF_W + BPF_ABS,
|
| - SECCOMP_ARCH_IDX,
|
| + BPF_LD + BPF_W + BPF_ABS, SECCOMP_ARCH_IDX,
|
| gen_.MakeInstruction(
|
| - BPF_JMP + BPF_JEQ + BPF_K,
|
| - SECCOMP_ARCH,
|
| - passed,
|
| - RetExpression(Kill("Invalid audit architecture in BPF filter"))));
|
| + BPF_JMP + BPF_JEQ + BPF_K, SECCOMP_ARCH, passed,
|
| + CompileResult(Kill("Invalid audit architecture in BPF filter"))));
|
| }
|
|
|
| CodeGen::Node PolicyCompiler::MaybeAddEscapeHatch(CodeGen::Node rest) {
|
| @@ -189,19 +176,13 @@ CodeGen::Node PolicyCompiler::MaybeAddEscapeHatch(CodeGen::Node rest) {
|
| // For simplicity, we check the full 64-bit instruction pointer even
|
| // on 32-bit architectures.
|
| return gen_.MakeInstruction(
|
| - BPF_LD + BPF_W + BPF_ABS,
|
| - SECCOMP_IP_LSB_IDX,
|
| + BPF_LD + BPF_W + BPF_ABS, SECCOMP_IP_LSB_IDX,
|
| gen_.MakeInstruction(
|
| - BPF_JMP + BPF_JEQ + BPF_K,
|
| - low,
|
| + BPF_JMP + BPF_JEQ + BPF_K, low,
|
| gen_.MakeInstruction(
|
| - BPF_LD + BPF_W + BPF_ABS,
|
| - SECCOMP_IP_MSB_IDX,
|
| - gen_.MakeInstruction(
|
| - BPF_JMP + BPF_JEQ + BPF_K,
|
| - hi,
|
| - RetExpression(ErrorCode(ErrorCode::ERR_ALLOWED)),
|
| - rest)),
|
| + BPF_LD + BPF_W + BPF_ABS, SECCOMP_IP_MSB_IDX,
|
| + gen_.MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, hi,
|
| + CompileResult(Allow()), rest)),
|
| rest));
|
| }
|
|
|
| @@ -225,7 +206,7 @@ CodeGen::Node PolicyCompiler::CheckSyscallNumber(CodeGen::Node passed) {
|
| // On Intel architectures, verify that system call numbers are in the
|
| // expected number range.
|
| CodeGen::Node invalidX32 =
|
| - RetExpression(Kill("Illegal mixing of system call ABIs"));
|
| + CompileResult(Kill("Illegal mixing of system call ABIs"));
|
| if (kIsX32) {
|
| // The newer x32 API always sets bit 30.
|
| return gen_.MakeInstruction(
|
| @@ -247,24 +228,28 @@ void PolicyCompiler::FindRanges(Ranges* ranges) {
|
| // deal with this disparity by enumerating from MIN_SYSCALL to MAX_SYSCALL,
|
| // and then verifying that the rest of the number range (both positive and
|
| // negative) all return the same ErrorCode.
|
| - const ErrorCode invalid_err = policy_->InvalidSyscall()->Compile(this);
|
| + const CodeGen::Node invalid_node = CompileResult(policy_->InvalidSyscall());
|
| uint32_t old_sysnum = 0;
|
| - ErrorCode old_err = SyscallSet::IsValid(old_sysnum)
|
| - ? policy_->EvaluateSyscall(old_sysnum)->Compile(this)
|
| - : invalid_err;
|
| + CodeGen::Node old_node =
|
| + SyscallSet::IsValid(old_sysnum)
|
| + ? CompileResult(policy_->EvaluateSyscall(old_sysnum))
|
| + : invalid_node;
|
|
|
| for (uint32_t sysnum : SyscallSet::All()) {
|
| - ErrorCode err =
|
| + CodeGen::Node node =
|
| SyscallSet::IsValid(sysnum)
|
| - ? policy_->EvaluateSyscall(static_cast<int>(sysnum))->Compile(this)
|
| - : invalid_err;
|
| - if (!err.Equals(old_err)) {
|
| - ranges->push_back(Range(old_sysnum, old_err));
|
| + ? CompileResult(policy_->EvaluateSyscall(static_cast<int>(sysnum)))
|
| + : invalid_node;
|
| + // N.B., here we rely on CodeGen folding (i.e., returning the same
|
| + // node value for) identical code sequences, otherwise our jump
|
| + // table will blow up in size.
|
| + if (node != old_node) {
|
| + ranges->push_back(Range{old_sysnum, old_node});
|
| old_sysnum = sysnum;
|
| - old_err = err;
|
| + old_node = node;
|
| }
|
| }
|
| - ranges->push_back(Range(old_sysnum, old_err));
|
| + ranges->push_back(Range{old_sysnum, old_node});
|
| }
|
|
|
| CodeGen::Node PolicyCompiler::AssembleJumpTable(Ranges::const_iterator start,
|
| @@ -278,7 +263,7 @@ CodeGen::Node PolicyCompiler::AssembleJumpTable(Ranges::const_iterator start,
|
| } else if (stop - start == 1) {
|
| // If we have narrowed things down to a single range object, we can
|
| // return from the BPF filter program.
|
| - return RetExpression(start->err);
|
| + return start->node;
|
| }
|
|
|
| // Pick the range object that is located at the mid point of our list.
|
| @@ -293,6 +278,10 @@ CodeGen::Node PolicyCompiler::AssembleJumpTable(Ranges::const_iterator start,
|
| return gen_.MakeInstruction(BPF_JMP + BPF_JGE + BPF_K, mid->from, jt, jf);
|
| }
|
|
|
| +CodeGen::Node PolicyCompiler::CompileResult(const ResultExpr& res) {
|
| + return RetExpression(res->Compile(this));
|
| +}
|
| +
|
| CodeGen::Node PolicyCompiler::RetExpression(const ErrorCode& err) {
|
| switch (err.error_type()) {
|
| case ErrorCode::ET_COND:
|
| @@ -454,7 +443,7 @@ CodeGen::Node PolicyCompiler::CondExpressionHalf(const ErrorCode& cond,
|
| }
|
|
|
| ErrorCode PolicyCompiler::Unexpected64bitArgument() {
|
| - return Kill("Unexpected 64bit argument detected");
|
| + return Kill("Unexpected 64bit argument detected")->Compile(this);
|
| }
|
|
|
| ErrorCode PolicyCompiler::Error(int err) {
|
| @@ -468,28 +457,19 @@ ErrorCode PolicyCompiler::Error(int err) {
|
| // The performance penalty for this extra round-trip to user-space is not
|
| // actually that bad, as we only ever pay it for denied system calls; and a
|
| // typical program has very few of these.
|
| - return Trap(ReturnErrno, reinterpret_cast<void*>(err));
|
| + return Trap(ReturnErrno, reinterpret_cast<void*>(err), true);
|
| }
|
|
|
| return ErrorCode(err);
|
| }
|
|
|
| -ErrorCode PolicyCompiler::MakeTrap(TrapRegistry::TrapFnc fnc,
|
| - const void* aux,
|
| - bool safe) {
|
| +ErrorCode PolicyCompiler::Trap(TrapRegistry::TrapFnc fnc,
|
| + const void* aux,
|
| + bool safe) {
|
| uint16_t trap_id = registry_->Add(fnc, aux, safe);
|
| return ErrorCode(trap_id, fnc, aux, safe);
|
| }
|
|
|
| -ErrorCode PolicyCompiler::Trap(TrapRegistry::TrapFnc fnc, const void* aux) {
|
| - return MakeTrap(fnc, aux, true /* Safe Trap */);
|
| -}
|
| -
|
| -ErrorCode PolicyCompiler::UnsafeTrap(TrapRegistry::TrapFnc fnc,
|
| - const void* aux) {
|
| - return MakeTrap(fnc, aux, false /* Unsafe Trap */);
|
| -}
|
| -
|
| bool PolicyCompiler::IsRequiredForUnsafeTrap(int sysno) {
|
| for (size_t i = 0; i < arraysize(kSyscallsRequiredForUnsafeTraps); ++i) {
|
| if (sysno == kSyscallsRequiredForUnsafeTraps[i]) {
|
| @@ -513,9 +493,5 @@ ErrorCode PolicyCompiler::CondMaskedEqual(int argno,
|
| &*conds_.insert(failed).first);
|
| }
|
|
|
| -ErrorCode PolicyCompiler::Kill(const char* msg) {
|
| - return Trap(BPFFailure, const_cast<char*>(msg));
|
| -}
|
| -
|
| } // namespace bpf_dsl
|
| } // namespace sandbox
|
|
|