Chromium Code Reviews| Index: sandbox/linux/bpf_dsl/bpf_dsl_more_unittest.cc |
| diff --git a/sandbox/linux/seccomp-bpf/sandbox_bpf_unittest.cc b/sandbox/linux/bpf_dsl/bpf_dsl_more_unittest.cc |
| similarity index 78% |
| rename from sandbox/linux/seccomp-bpf/sandbox_bpf_unittest.cc |
| rename to sandbox/linux/bpf_dsl/bpf_dsl_more_unittest.cc |
| index 356731e770dde584d1e1080bf031f78ba26102ed..b5d04e1da455d624bec5eea13b2f0e1af4e4dcf0 100644 |
| --- a/sandbox/linux/seccomp-bpf/sandbox_bpf_unittest.cc |
| +++ b/sandbox/linux/bpf_dsl/bpf_dsl_more_unittest.cc |
| @@ -31,6 +31,7 @@ |
| #include "base/synchronization/waitable_event.h" |
| #include "base/threading/thread.h" |
| #include "build/build_config.h" |
| +#include "sandbox/linux/bpf_dsl/bpf_dsl.h" |
| #include "sandbox/linux/seccomp-bpf/bpf_tests.h" |
| #include "sandbox/linux/seccomp-bpf/syscall.h" |
| #include "sandbox/linux/seccomp-bpf/trap.h" |
| @@ -51,6 +52,7 @@ |
| #endif |
| namespace sandbox { |
| +namespace bpf_dsl { |
| namespace { |
| @@ -103,21 +105,22 @@ intptr_t IncreaseCounter(const struct arch_seccomp_data& args, void* aux) { |
| return (*counter)++; |
| } |
| -class VerboseAPITestingPolicy : public SandboxBPFPolicy { |
| +class VerboseAPITestingPolicy : public SandboxBPFDSLPolicy { |
| public: |
| VerboseAPITestingPolicy(int* counter_ptr) : counter_ptr_(counter_ptr) {} |
| + virtual ~VerboseAPITestingPolicy() {} |
| - virtual ErrorCode EvaluateSyscall(SandboxBPF* sandbox, |
| - int sysno) const OVERRIDE { |
| + virtual ResultExpr EvaluateSyscall(int sysno) const OVERRIDE { |
| DCHECK(SandboxBPF::IsValidSyscallNumber(sysno)); |
| if (sysno == __NR_uname) { |
| - return sandbox->Trap(IncreaseCounter, counter_ptr_); |
| + return Trap(IncreaseCounter, counter_ptr_); |
| } |
| - return ErrorCode(ErrorCode::ERR_ALLOWED); |
| + return Allow(); |
| } |
| private: |
| int* counter_ptr_; |
| + |
| DISALLOW_COPY_AND_ASSIGN(VerboseAPITestingPolicy); |
| }; |
| @@ -140,16 +143,18 @@ SANDBOX_TEST(SandboxBPF, DISABLE_ON_TSAN(VerboseAPITesting)) { |
| // A simple blacklist test |
| -class BlacklistNanosleepPolicy : public SandboxBPFPolicy { |
| +class BlacklistNanosleepPolicy : public SandboxBPFDSLPolicy { |
| public: |
| BlacklistNanosleepPolicy() {} |
| - virtual ErrorCode EvaluateSyscall(SandboxBPF*, int sysno) const OVERRIDE { |
| + virtual ~BlacklistNanosleepPolicy() {} |
| + |
| + virtual ResultExpr EvaluateSyscall(int sysno) const OVERRIDE { |
| DCHECK(SandboxBPF::IsValidSyscallNumber(sysno)); |
| switch (sysno) { |
| case __NR_nanosleep: |
| - return ErrorCode(EACCES); |
| + return Error(EACCES); |
| default: |
| - return ErrorCode(ErrorCode::ERR_ALLOWED); |
| + return Allow(); |
| } |
| } |
| @@ -170,17 +175,19 @@ BPF_TEST_C(SandboxBPF, ApplyBasicBlacklistPolicy, BlacklistNanosleepPolicy) { |
| // Now do a simple whitelist test |
| -class WhitelistGetpidPolicy : public SandboxBPFPolicy { |
| +class WhitelistGetpidPolicy : public SandboxBPFDSLPolicy { |
| public: |
| WhitelistGetpidPolicy() {} |
| - virtual ErrorCode EvaluateSyscall(SandboxBPF*, int sysno) const OVERRIDE { |
| + virtual ~WhitelistGetpidPolicy() {} |
| + |
| + virtual ResultExpr EvaluateSyscall(int sysno) const OVERRIDE { |
| DCHECK(SandboxBPF::IsValidSyscallNumber(sysno)); |
| switch (sysno) { |
| case __NR_getpid: |
| case __NR_exit_group: |
| - return ErrorCode(ErrorCode::ERR_ALLOWED); |
| + return Allow(); |
| default: |
| - return ErrorCode(ENOMEM); |
| + return Error(ENOMEM); |
| } |
| } |
| @@ -240,41 +247,43 @@ BPF_TEST(SandboxBPF, |
| // A simple test that verifies we can return arbitrary errno values. |
| -class ErrnoTestPolicy : public SandboxBPFPolicy { |
| +class ErrnoTestPolicy : public SandboxBPFDSLPolicy { |
| public: |
| ErrnoTestPolicy() {} |
| - virtual ErrorCode EvaluateSyscall(SandboxBPF*, int sysno) const OVERRIDE; |
| + virtual ~ErrnoTestPolicy() {} |
| + |
| + virtual ResultExpr EvaluateSyscall(int sysno) const OVERRIDE; |
| private: |
| DISALLOW_COPY_AND_ASSIGN(ErrnoTestPolicy); |
| }; |
| -ErrorCode ErrnoTestPolicy::EvaluateSyscall(SandboxBPF*, int sysno) const { |
| +ResultExpr ErrnoTestPolicy::EvaluateSyscall(int sysno) const { |
| DCHECK(SandboxBPF::IsValidSyscallNumber(sysno)); |
| switch (sysno) { |
| - case __NR_dup3: // dup2 is a wrapper of dup3 in android |
| + case __NR_dup3: // dup2 is a wrapper of dup3 in android |
| #if defined(__NR_dup2) |
| case __NR_dup2: |
| #endif |
| // Pretend that dup2() worked, but don't actually do anything. |
| - return ErrorCode(0); |
| + return Error(0); |
| case __NR_setuid: |
| #if defined(__NR_setuid32) |
| case __NR_setuid32: |
| #endif |
| // Return errno = 1. |
| - return ErrorCode(1); |
| + return Error(1); |
| case __NR_setgid: |
| #if defined(__NR_setgid32) |
| case __NR_setgid32: |
| #endif |
| // Return maximum errno value (typically 4095). |
| - return ErrorCode(ErrorCode::ERR_MAX_ERRNO); |
| + return Error(ErrorCode::ERR_MAX_ERRNO); |
| case __NR_uname: |
| // Return errno = 42; |
| - return ErrorCode(42); |
| + return Error(42); |
| default: |
| - return ErrorCode(ErrorCode::ERR_ALLOWED); |
| + return Allow(); |
| } |
| } |
| @@ -320,22 +329,20 @@ BPF_TEST_C(SandboxBPF, ErrnoTest, ErrnoTestPolicy) { |
| // Testing the stacking of two sandboxes |
| -class StackingPolicyPartOne : public SandboxBPFPolicy { |
| +class StackingPolicyPartOne : public SandboxBPFDSLPolicy { |
| public: |
| StackingPolicyPartOne() {} |
| - virtual ErrorCode EvaluateSyscall(SandboxBPF* sandbox, |
| - int sysno) const OVERRIDE { |
| + virtual ~StackingPolicyPartOne() {} |
| + |
| + virtual ResultExpr EvaluateSyscall(int sysno) const OVERRIDE { |
| DCHECK(SandboxBPF::IsValidSyscallNumber(sysno)); |
| switch (sysno) { |
| - case __NR_getppid: |
| - return sandbox->Cond(0, |
| - ErrorCode::TP_32BIT, |
| - ErrorCode::OP_EQUAL, |
| - 0, |
| - ErrorCode(ErrorCode::ERR_ALLOWED), |
| - ErrorCode(EPERM)); |
| + case __NR_getppid: { |
| + const Arg<int> arg(0); |
| + return If(arg == 0, Allow()).Else(Error(EPERM)); |
| + } |
| default: |
| - return ErrorCode(ErrorCode::ERR_ALLOWED); |
| + return Allow(); |
| } |
| } |
| @@ -343,22 +350,20 @@ class StackingPolicyPartOne : public SandboxBPFPolicy { |
| DISALLOW_COPY_AND_ASSIGN(StackingPolicyPartOne); |
| }; |
| -class StackingPolicyPartTwo : public SandboxBPFPolicy { |
| +class StackingPolicyPartTwo : public SandboxBPFDSLPolicy { |
| public: |
| StackingPolicyPartTwo() {} |
| - virtual ErrorCode EvaluateSyscall(SandboxBPF* sandbox, |
| - int sysno) const OVERRIDE { |
| + virtual ~StackingPolicyPartTwo() {} |
| + |
| + virtual ResultExpr EvaluateSyscall(int sysno) const OVERRIDE { |
| DCHECK(SandboxBPF::IsValidSyscallNumber(sysno)); |
| switch (sysno) { |
| - case __NR_getppid: |
| - return sandbox->Cond(0, |
| - ErrorCode::TP_32BIT, |
| - ErrorCode::OP_EQUAL, |
| - 0, |
| - ErrorCode(EINVAL), |
| - ErrorCode(ErrorCode::ERR_ALLOWED)); |
| + case __NR_getppid: { |
| + const Arg<int> arg(0); |
| + return If(arg == 0, Error(EINVAL)).Else(Allow()); |
| + } |
| default: |
| - return ErrorCode(ErrorCode::ERR_ALLOWED); |
| + return Allow(); |
| } |
| } |
| @@ -403,17 +408,19 @@ int SysnoToRandomErrno(int sysno) { |
| return ((sysno & ~3) >> 2) % 29 + 1; |
| } |
| -class SyntheticPolicy : public SandboxBPFPolicy { |
| +class SyntheticPolicy : public SandboxBPFDSLPolicy { |
| public: |
| SyntheticPolicy() {} |
| - virtual ErrorCode EvaluateSyscall(SandboxBPF*, int sysno) const OVERRIDE { |
| + virtual ~SyntheticPolicy() {} |
| + |
| + virtual ResultExpr EvaluateSyscall(int sysno) const OVERRIDE { |
| DCHECK(SandboxBPF::IsValidSyscallNumber(sysno)); |
| if (sysno == __NR_exit_group || sysno == __NR_write) { |
| // exit_group() is special, we really need it to work. |
| // write() is needed for BPF_ASSERT() to report a useful error message. |
| - return ErrorCode(ErrorCode::ERR_ALLOWED); |
| + return Allow(); |
| } |
| - return ErrorCode(SysnoToRandomErrno(sysno)); |
| + return Error(SysnoToRandomErrno(sysno)); |
| } |
| private: |
| @@ -454,18 +461,20 @@ int ArmPrivateSysnoToErrno(int sysno) { |
| } |
| } |
| -class ArmPrivatePolicy : public SandboxBPFPolicy { |
| +class ArmPrivatePolicy : public SandboxBPFDSLPolicy { |
| public: |
| ArmPrivatePolicy() {} |
| - virtual ErrorCode EvaluateSyscall(SandboxBPF*, int sysno) const OVERRIDE { |
| + virtual ~ArmPrivatePolicy() {} |
| + |
| + virtual ResultExpr EvaluateSyscall(int sysno) const OVERRIDE { |
| DCHECK(SandboxBPF::IsValidSyscallNumber(sysno)); |
| // Start from |__ARM_NR_set_tls + 1| so as not to mess with actual |
| // ARM private system calls. |
| if (sysno >= static_cast<int>(__ARM_NR_set_tls + 1) && |
| sysno <= static_cast<int>(MAX_PRIVATE_SYSCALL)) { |
| - return ErrorCode(ArmPrivateSysnoToErrno(sysno)); |
| + return Error(ArmPrivateSysnoToErrno(sysno)); |
| } |
| - return ErrorCode(ErrorCode::ERR_ALLOWED); |
| + return Allow(); |
| } |
| private: |
| @@ -557,22 +566,23 @@ intptr_t PrctlHandler(const struct arch_seccomp_data& args, void*) { |
| } |
| } |
| -class PrctlPolicy : public SandboxBPFPolicy { |
| +class PrctlPolicy : public SandboxBPFDSLPolicy { |
| public: |
| PrctlPolicy() {} |
| - virtual ErrorCode EvaluateSyscall(SandboxBPF* sandbox, |
| - int sysno) const OVERRIDE { |
| + virtual ~PrctlPolicy() {} |
| + |
| + virtual ResultExpr EvaluateSyscall(int sysno) const OVERRIDE { |
| DCHECK(SandboxBPF::IsValidSyscallNumber(sysno)); |
| setenv(kSandboxDebuggingEnv, "t", 0); |
| Die::SuppressInfoMessages(true); |
| if (sysno == __NR_prctl) { |
| // Handle prctl() inside an UnsafeTrap() |
| - return sandbox->UnsafeTrap(PrctlHandler, NULL); |
| + return UnsafeTrap(PrctlHandler, NULL); |
| } |
| // Allow all other system calls. |
| - return ErrorCode(ErrorCode::ERR_ALLOWED); |
| + return Allow(); |
| } |
| private: |
| @@ -610,18 +620,18 @@ intptr_t AllowRedirectedSyscall(const struct arch_seccomp_data& args, void*) { |
| return SandboxBPF::ForwardSyscall(args); |
| } |
| -class RedirectAllSyscallsPolicy : public SandboxBPFPolicy { |
| +class RedirectAllSyscallsPolicy : public SandboxBPFDSLPolicy { |
| public: |
| RedirectAllSyscallsPolicy() {} |
| - virtual ErrorCode EvaluateSyscall(SandboxBPF* sandbox, |
| - int sysno) const OVERRIDE; |
| + virtual ~RedirectAllSyscallsPolicy() {} |
| + |
| + virtual ResultExpr EvaluateSyscall(int sysno) const OVERRIDE; |
| private: |
| DISALLOW_COPY_AND_ASSIGN(RedirectAllSyscallsPolicy); |
| }; |
| -ErrorCode RedirectAllSyscallsPolicy::EvaluateSyscall(SandboxBPF* sandbox, |
| - int sysno) const { |
| +ResultExpr RedirectAllSyscallsPolicy::EvaluateSyscall(int sysno) const { |
| DCHECK(SandboxBPF::IsValidSyscallNumber(sysno)); |
| setenv(kSandboxDebuggingEnv, "t", 0); |
| Die::SuppressInfoMessages(true); |
| @@ -629,8 +639,8 @@ ErrorCode RedirectAllSyscallsPolicy::EvaluateSyscall(SandboxBPF* sandbox, |
| // Some system calls must always be allowed, if our policy wants to make |
| // use of UnsafeTrap() |
| if (SandboxBPF::IsRequiredForUnsafeTrap(sysno)) |
| - return ErrorCode(ErrorCode::ERR_ALLOWED); |
| - return sandbox->UnsafeTrap(AllowRedirectedSyscall, NULL); |
| + return Allow(); |
| + return UnsafeTrap(AllowRedirectedSyscall, NULL); |
| } |
| int bus_handler_fd_ = -1; |
| @@ -714,7 +724,9 @@ BPF_TEST_C(SandboxBPF, UnsafeTrapWithErrno, RedirectAllSyscallsPolicy) { |
| BPF_ASSERT(errno == 0); |
| } |
| -bool NoOpCallback() { return true; } |
| +bool NoOpCallback() { |
| + return true; |
| +} |
| // Test a trap handler that makes use of a broker process to open(). |
| @@ -746,7 +758,7 @@ intptr_t BrokerOpenTrapHandler(const struct arch_seccomp_data& args, |
| BPF_ASSERT(aux); |
| BrokerProcess* broker_process = static_cast<BrokerProcess*>(aux); |
| switch (args.nr) { |
| - case __NR_faccessat: // access is a wrapper of faccessat in android |
| + case __NR_faccessat: // access is a wrapper of faccessat in android |
| BPF_ASSERT(static_cast<int>(args.args[0]) == AT_FDCWD); |
| return broker_process->Access(reinterpret_cast<const char*>(args.args[1]), |
| static_cast<int>(args.args[2])); |
| @@ -846,18 +858,18 @@ BPF_TEST(SandboxBPF, |
| // Simple test demonstrating how to use SandboxBPF::Cond() |
| -class SimpleCondTestPolicy : public SandboxBPFPolicy { |
| +class SimpleCondTestPolicy : public SandboxBPFDSLPolicy { |
| public: |
| SimpleCondTestPolicy() {} |
| - virtual ErrorCode EvaluateSyscall(SandboxBPF* sandbox, |
| - int sysno) const OVERRIDE; |
| + virtual ~SimpleCondTestPolicy() {} |
| + |
| + virtual ResultExpr EvaluateSyscall(int sysno) const OVERRIDE; |
| private: |
| DISALLOW_COPY_AND_ASSIGN(SimpleCondTestPolicy); |
| }; |
| -ErrorCode SimpleCondTestPolicy::EvaluateSyscall(SandboxBPF* sandbox, |
| - int sysno) const { |
| +ResultExpr SimpleCondTestPolicy::EvaluateSyscall(int sysno) const { |
| DCHECK(SandboxBPF::IsValidSyscallNumber(sysno)); |
| // We deliberately return unusual errno values upon failure, so that we |
| @@ -869,34 +881,24 @@ ErrorCode SimpleCondTestPolicy::EvaluateSyscall(SandboxBPF* sandbox, |
| case __NR_open: |
| flags_argument_position = 1; |
| #endif |
| - case __NR_openat: // open can be a wrapper for openat(2). |
| + case __NR_openat: { // open can be a wrapper for openat(2). |
| if (sysno == __NR_openat) |
| flags_argument_position = 2; |
| // Allow opening files for reading, but don't allow writing. |
| COMPILE_ASSERT(O_RDONLY == 0, O_RDONLY_must_be_all_zero_bits); |
| - return sandbox->Cond(flags_argument_position, |
| - ErrorCode::TP_32BIT, |
| - ErrorCode::OP_HAS_ANY_BITS, |
| - O_ACCMODE /* 0x3 */, |
| - ErrorCode(EROFS), |
| - ErrorCode(ErrorCode::ERR_ALLOWED)); |
| - case __NR_prctl: |
| + const Arg<int> flags(flags_argument_position); |
| + return If((flags & O_ACCMODE) != 0, Error(EROFS)).Else(Allow()); |
| + } |
| + case __NR_prctl: { |
| // Allow prctl(PR_SET_DUMPABLE) and prctl(PR_GET_DUMPABLE), but |
| // disallow everything else. |
| - return sandbox->Cond(0, |
| - ErrorCode::TP_32BIT, |
| - ErrorCode::OP_EQUAL, |
| - PR_SET_DUMPABLE, |
| - ErrorCode(ErrorCode::ERR_ALLOWED), |
| - sandbox->Cond(0, |
| - ErrorCode::TP_32BIT, |
| - ErrorCode::OP_EQUAL, |
| - PR_GET_DUMPABLE, |
| - ErrorCode(ErrorCode::ERR_ALLOWED), |
| - ErrorCode(ENOMEM))); |
| + const Arg<int> option(0); |
| + return If(option == PR_SET_DUMPABLE || option == PR_GET_DUMPABLE, Allow()) |
| + .Else(Error(ENOMEM)); |
| + } |
| default: |
| - return ErrorCode(ErrorCode::ERR_ALLOWED); |
| + return Allow(); |
| } |
| } |
| @@ -1233,47 +1235,31 @@ BPF_TEST(SandboxBPF, |
| BPF_AUX->VerifyFilter(); |
| } |
| -class EqualityArgumentWidthPolicy : public SandboxBPFPolicy { |
| +class EqualityArgumentWidthPolicy : public SandboxBPFDSLPolicy { |
| public: |
| EqualityArgumentWidthPolicy() {} |
| - virtual ErrorCode EvaluateSyscall(SandboxBPF* sandbox, |
| - int sysno) const OVERRIDE; |
| + virtual ~EqualityArgumentWidthPolicy() {} |
| + |
| + virtual ResultExpr EvaluateSyscall(int sysno) const OVERRIDE; |
| private: |
| DISALLOW_COPY_AND_ASSIGN(EqualityArgumentWidthPolicy); |
| }; |
| -ErrorCode EqualityArgumentWidthPolicy::EvaluateSyscall(SandboxBPF* sandbox, |
| - int sysno) const { |
| +ResultExpr EqualityArgumentWidthPolicy::EvaluateSyscall(int sysno) const { |
| DCHECK(SandboxBPF::IsValidSyscallNumber(sysno)); |
| if (sysno == __NR_uname) { |
| - return sandbox->Cond( |
| - 0, |
| - ErrorCode::TP_32BIT, |
| - ErrorCode::OP_EQUAL, |
| - 0, |
| - sandbox->Cond(1, |
| - ErrorCode::TP_32BIT, |
| - ErrorCode::OP_EQUAL, |
| - 0x55555555, |
| - ErrorCode(1), |
| - ErrorCode(2)), |
| - // The BPF compiler and the BPF interpreter in the kernel are |
| - // (mostly) agnostic of the host platform's word size. The compiler |
| - // will happily generate code that tests a 64bit value, and the |
| - // interpreter will happily perform this test. |
| - // But unless there is a kernel bug, there is no way for us to pass |
| - // in a 64bit quantity on a 32bit platform. The upper 32bits should |
| - // always be zero. So, this test should always evaluate as false on |
| - // 32bit systems. |
| - sandbox->Cond(1, |
| - ErrorCode::TP_64BIT, |
| - ErrorCode::OP_EQUAL, |
| - 0x55555555AAAAAAAAULL, |
| - ErrorCode(1), |
| - ErrorCode(2))); |
| + const Arg<int> option(0); |
| + const Arg<uint32_t> arg32(1); |
| + const Arg<uint64_t> arg64(1); |
| + return Switch(option) |
| + .Case(0, If(arg32 == 0x55555555, Error(1)).Else(Error(2))) |
| +#if __SIZEOF_POINTER__ > 4 |
| + .Case(1, If(arg64 == 0x55555555AAAAAAAAULL, Error(1)).Else(Error(2))) |
| +#endif |
| + .Default(Error(3)); |
| } |
| - return ErrorCode(ErrorCode::ERR_ALLOWED); |
| + return Allow(); |
| } |
| BPF_TEST_C(SandboxBPF, EqualityArgumentWidth, EqualityArgumentWidthPolicy) { |
| @@ -1287,8 +1273,6 @@ BPF_TEST_C(SandboxBPF, EqualityArgumentWidth, EqualityArgumentWidthPolicy) { |
| BPF_ASSERT(Syscall::Call(__NR_uname, 1, 0x5555555500000000ULL) == -2); |
| BPF_ASSERT(Syscall::Call(__NR_uname, 1, 0x5555555511111111ULL) == -2); |
| BPF_ASSERT(Syscall::Call(__NR_uname, 1, 0x11111111AAAAAAAAULL) == -2); |
| -#else |
| - BPF_ASSERT(Syscall::Call(__NR_uname, 1, 0x55555555) == -2); |
|
jln (very slow on Chromium)
2014/09/12 23:52:57
Why removed?
mdempsky
2014/09/13 00:20:24
This assert was testing TP_64BIT on a 32-bit syste
|
| #endif |
| } |
| @@ -1304,21 +1288,21 @@ BPF_DEATH_TEST_C(SandboxBPF, |
| } |
| #endif |
| -class EqualityWithNegativeArgumentsPolicy : public SandboxBPFPolicy { |
| +class EqualityWithNegativeArgumentsPolicy : public SandboxBPFDSLPolicy { |
| public: |
| EqualityWithNegativeArgumentsPolicy() {} |
| - virtual ErrorCode EvaluateSyscall(SandboxBPF* sandbox, |
| - int sysno) const OVERRIDE { |
| + virtual ~EqualityWithNegativeArgumentsPolicy() {} |
| + |
| + virtual ResultExpr EvaluateSyscall(int sysno) const OVERRIDE { |
| DCHECK(SandboxBPF::IsValidSyscallNumber(sysno)); |
| if (sysno == __NR_uname) { |
| - return sandbox->Cond(0, |
| - ErrorCode::TP_32BIT, |
| - ErrorCode::OP_EQUAL, |
| - 0xFFFFFFFF, |
| - ErrorCode(1), |
| - ErrorCode(2)); |
| + // TODO(mdempsky): This currently can't be Arg<int> because then |
| + // 0xFFFFFFFF will be treated as a (signed) int, and then when |
| + // Arg::EqualTo casts it to uint64_t, it will be sign extended. |
| + const Arg<unsigned> arg(0); |
| + return If(arg == 0xFFFFFFFF, Error(1)).Else(Error(2)); |
| } |
| - return ErrorCode(ErrorCode::ERR_ALLOWED); |
| + return Allow(); |
| } |
| private: |
| @@ -1344,83 +1328,64 @@ BPF_DEATH_TEST_C(SandboxBPF, |
| BPF_ASSERT(Syscall::Call(__NR_uname, 0xFFFFFFFF00000000LL) == -1); |
| } |
| #endif |
| -class AllBitTestPolicy : public SandboxBPFPolicy { |
| + |
| +class AllBitTestPolicy : public SandboxBPFDSLPolicy { |
| public: |
| AllBitTestPolicy() {} |
| - virtual ErrorCode EvaluateSyscall(SandboxBPF* sandbox, |
| - int sysno) const OVERRIDE; |
| + virtual ~AllBitTestPolicy() {} |
| + |
| + virtual ResultExpr EvaluateSyscall(int sysno) const OVERRIDE; |
| private: |
| + static ResultExpr HasAllBits32(uint32_t bits); |
| + static ResultExpr HasAllBits64(uint64_t bits); |
| + |
| DISALLOW_COPY_AND_ASSIGN(AllBitTestPolicy); |
| }; |
| -ErrorCode AllBitTestPolicy::EvaluateSyscall(SandboxBPF* sandbox, |
| - int sysno) const { |
| +ResultExpr AllBitTestPolicy::HasAllBits32(uint32_t bits) { |
| + if (bits == 0) { |
| + return Error(1); |
| + } |
| + const Arg<uint32_t> arg(1); |
| + return If((arg & bits) == bits, Error(1)).Else(Error(0)); |
| +} |
| + |
| +ResultExpr AllBitTestPolicy::HasAllBits64(uint64_t bits) { |
| + if (bits == 0) { |
| + return Error(1); |
| + } |
| + const Arg<uint64_t> arg(1); |
| + return If((arg & bits) == bits, Error(1)).Else(Error(0)); |
| +} |
| + |
| +ResultExpr AllBitTestPolicy::EvaluateSyscall(int sysno) const { |
| DCHECK(SandboxBPF::IsValidSyscallNumber(sysno)); |
| - // Test the OP_HAS_ALL_BITS conditional test operator with a couple of |
| - // different bitmasks. We try to find bitmasks that could conceivably |
| + // Test masked-equality cases that should trigger the "has all bits" |
| + // peephole optimizations. We try to find bitmasks that could conceivably |
| // touch corner cases. |
| // For all of these tests, we override the uname(). We can make use with |
| // a single system call number, as we use the first system call argument to |
| // select the different bit masks that we want to test against. |
| if (sysno == __NR_uname) { |
| - return sandbox->Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL, 0, |
| - sandbox->Cond(1, ErrorCode::TP_32BIT, ErrorCode::OP_HAS_ALL_BITS, |
| - 0x0, |
| - ErrorCode(1), ErrorCode(0)), |
| - |
| - sandbox->Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL, 1, |
| - sandbox->Cond(1, ErrorCode::TP_32BIT, ErrorCode::OP_HAS_ALL_BITS, |
| - 0x1, |
| - ErrorCode(1), ErrorCode(0)), |
| - |
| - sandbox->Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL, 2, |
| - sandbox->Cond(1, ErrorCode::TP_32BIT, ErrorCode::OP_HAS_ALL_BITS, |
| - 0x3, |
| - ErrorCode(1), ErrorCode(0)), |
| - |
| - sandbox->Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL, 3, |
| - sandbox->Cond(1, ErrorCode::TP_32BIT, ErrorCode::OP_HAS_ALL_BITS, |
| - 0x80000000, |
| - ErrorCode(1), ErrorCode(0)), |
| - sandbox->Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL, 4, |
| - sandbox->Cond(1, ErrorCode::TP_64BIT, ErrorCode::OP_HAS_ALL_BITS, |
| - 0x0, |
| - ErrorCode(1), ErrorCode(0)), |
| - |
| - sandbox->Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL, 5, |
| - sandbox->Cond(1, ErrorCode::TP_64BIT, ErrorCode::OP_HAS_ALL_BITS, |
| - 0x1, |
| - ErrorCode(1), ErrorCode(0)), |
| - |
| - sandbox->Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL, 6, |
| - sandbox->Cond(1, ErrorCode::TP_64BIT, ErrorCode::OP_HAS_ALL_BITS, |
| - 0x3, |
| - ErrorCode(1), ErrorCode(0)), |
| - |
| - sandbox->Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL, 7, |
| - sandbox->Cond(1, ErrorCode::TP_64BIT, ErrorCode::OP_HAS_ALL_BITS, |
| - 0x80000000, |
| - ErrorCode(1), ErrorCode(0)), |
| - |
| - sandbox->Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL, 8, |
| - sandbox->Cond(1, ErrorCode::TP_64BIT, ErrorCode::OP_HAS_ALL_BITS, |
| - 0x100000000ULL, |
| - ErrorCode(1), ErrorCode(0)), |
| - |
| - sandbox->Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL, 9, |
| - sandbox->Cond(1, ErrorCode::TP_64BIT, ErrorCode::OP_HAS_ALL_BITS, |
| - 0x300000000ULL, |
| - ErrorCode(1), ErrorCode(0)), |
| - |
| - sandbox->Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL, 10, |
| - sandbox->Cond(1, ErrorCode::TP_64BIT, ErrorCode::OP_HAS_ALL_BITS, |
| - 0x100000001ULL, |
| - ErrorCode(1), ErrorCode(0)), |
| - |
| - sandbox->Kill("Invalid test case number")))))))))))); |
| + const Arg<int> option(0); |
| + return Switch(option) |
| + .Case(0, HasAllBits32(0x0)) |
| + .Case(1, HasAllBits32(0x1)) |
| + .Case(2, HasAllBits32(0x3)) |
| + .Case(3, HasAllBits32(0x80000000)) |
| +#if __SIZEOF_POINTER__ > 4 |
| + .Case(4, HasAllBits64(0x0)) |
| + .Case(5, HasAllBits64(0x1)) |
| + .Case(6, HasAllBits64(0x3)) |
| + .Case(7, HasAllBits64(0x80000000)) |
| + .Case(8, HasAllBits64(0x100000000ULL)) |
| + .Case(9, HasAllBits64(0x300000000ULL)) |
| + .Case(10, HasAllBits64(0x100000001ULL)) |
| +#endif |
| + .Default(Kill("Invalid test case number")); |
| } |
| - return ErrorCode(ErrorCode::ERR_ALLOWED); |
| + return Allow(); |
| } |
| // Define a macro that performs tests using our test policy. |
| @@ -1473,6 +1438,7 @@ BPF_TEST_C(SandboxBPF, AllBitTests, AllBitTestPolicy) { |
| BITMASK_TEST( 3, 0xC0000000U, ALLBITS32, 0x80000000, EXPECT_SUCCESS); |
| BITMASK_TEST( 3, -0x80000000LL, ALLBITS32, 0x80000000, EXPECT_SUCCESS); |
| +#if __SIZEOF_POINTER__ > 4 |
| // 64bit test: all of 0x0 (should always be true) |
| BITMASK_TEST( 4, 0, ALLBITS64, 0, EXPECT_SUCCESS); |
| BITMASK_TEST( 4, 1, ALLBITS64, 0, EXPECT_SUCCESS); |
| @@ -1546,88 +1512,66 @@ BPF_TEST_C(SandboxBPF, AllBitTests, AllBitTestPolicy) { |
| BITMASK_TEST(10, 0x100000001LL, ALLBITS64,0x100000001, EXPT64_SUCCESS); |
| BITMASK_TEST(10, 0xFFFFFFFFU, ALLBITS64,0x100000001, EXPECT_FAILURE); |
| BITMASK_TEST(10, -1L, ALLBITS64,0x100000001, EXPT64_SUCCESS); |
| +#endif |
| } |
| -class AnyBitTestPolicy : public SandboxBPFPolicy { |
| +class AnyBitTestPolicy : public SandboxBPFDSLPolicy { |
| public: |
| AnyBitTestPolicy() {} |
| - virtual ErrorCode EvaluateSyscall(SandboxBPF* sandbox, |
| - int sysno) const OVERRIDE; |
| + virtual ~AnyBitTestPolicy() {} |
| + |
| + virtual ResultExpr EvaluateSyscall(int sysno) const OVERRIDE; |
| private: |
| + static ResultExpr HasAnyBits32(uint32_t); |
| + static ResultExpr HasAnyBits64(uint64_t); |
| + |
| DISALLOW_COPY_AND_ASSIGN(AnyBitTestPolicy); |
| }; |
| -ErrorCode AnyBitTestPolicy::EvaluateSyscall(SandboxBPF* sandbox, |
| - int sysno) const { |
| +ResultExpr AnyBitTestPolicy::HasAnyBits32(uint32_t bits) { |
| + if (bits == 0) { |
| + return Error(0); |
| + } |
| + const Arg<uint32_t> arg(1); |
| + return If((arg & bits) != 0, Error(1)).Else(Error(0)); |
| +} |
| + |
| +ResultExpr AnyBitTestPolicy::HasAnyBits64(uint64_t bits) { |
| + if (bits == 0) { |
| + return Error(0); |
| + } |
| + const Arg<uint64_t> arg(1); |
| + return If((arg & bits) != 0, Error(1)).Else(Error(0)); |
| +} |
| + |
| +ResultExpr AnyBitTestPolicy::EvaluateSyscall(int sysno) const { |
| DCHECK(SandboxBPF::IsValidSyscallNumber(sysno)); |
| - // Test the OP_HAS_ANY_BITS conditional test operator with a couple of |
| - // different bitmasks. We try to find bitmasks that could conceivably |
| + // Test masked-equality cases that should trigger the "has any bits" |
| + // peephole optimizations. We try to find bitmasks that could conceivably |
| // touch corner cases. |
| // For all of these tests, we override the uname(). We can make use with |
| // a single system call number, as we use the first system call argument to |
| // select the different bit masks that we want to test against. |
| if (sysno == __NR_uname) { |
| - return sandbox->Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL, 0, |
| - sandbox->Cond(1, ErrorCode::TP_32BIT, ErrorCode::OP_HAS_ANY_BITS, |
| - 0x0, |
| - ErrorCode(1), ErrorCode(0)), |
| - |
| - sandbox->Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL, 1, |
| - sandbox->Cond(1, ErrorCode::TP_32BIT, ErrorCode::OP_HAS_ANY_BITS, |
| - 0x1, |
| - ErrorCode(1), ErrorCode(0)), |
| - |
| - sandbox->Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL, 2, |
| - sandbox->Cond(1, ErrorCode::TP_32BIT, ErrorCode::OP_HAS_ANY_BITS, |
| - 0x3, |
| - ErrorCode(1), ErrorCode(0)), |
| - |
| - sandbox->Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL, 3, |
| - sandbox->Cond(1, ErrorCode::TP_32BIT, ErrorCode::OP_HAS_ANY_BITS, |
| - 0x80000000, |
| - ErrorCode(1), ErrorCode(0)), |
| - |
| - // All the following tests don't really make much sense on 32bit |
| - // systems. They will always evaluate as false. |
| - sandbox->Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL, 4, |
| - sandbox->Cond(1, ErrorCode::TP_64BIT, ErrorCode::OP_HAS_ANY_BITS, |
| - 0x0, |
| - ErrorCode(1), ErrorCode(0)), |
| - |
| - sandbox->Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL, 5, |
| - sandbox->Cond(1, ErrorCode::TP_64BIT, ErrorCode::OP_HAS_ANY_BITS, |
| - 0x1, |
| - ErrorCode(1), ErrorCode(0)), |
| - |
| - sandbox->Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL, 6, |
| - sandbox->Cond(1, ErrorCode::TP_64BIT, ErrorCode::OP_HAS_ANY_BITS, |
| - 0x3, |
| - ErrorCode(1), ErrorCode(0)), |
| - |
| - sandbox->Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL, 7, |
| - sandbox->Cond(1, ErrorCode::TP_64BIT, ErrorCode::OP_HAS_ANY_BITS, |
| - 0x80000000, |
| - ErrorCode(1), ErrorCode(0)), |
| - |
| - sandbox->Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL, 8, |
| - sandbox->Cond(1, ErrorCode::TP_64BIT, ErrorCode::OP_HAS_ANY_BITS, |
| - 0x100000000ULL, |
| - ErrorCode(1), ErrorCode(0)), |
| - |
| - sandbox->Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL, 9, |
| - sandbox->Cond(1, ErrorCode::TP_64BIT, ErrorCode::OP_HAS_ANY_BITS, |
| - 0x300000000ULL, |
| - ErrorCode(1), ErrorCode(0)), |
| - |
| - sandbox->Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL, 10, |
| - sandbox->Cond(1, ErrorCode::TP_64BIT, ErrorCode::OP_HAS_ANY_BITS, |
| - 0x100000001ULL, |
| - ErrorCode(1), ErrorCode(0)), |
| - |
| - sandbox->Kill("Invalid test case number")))))))))))); |
| + const Arg<int> option(0); |
| + return Switch(option) |
| + .Case(0, HasAnyBits32(0x0)) |
| + .Case(1, HasAnyBits32(0x1)) |
| + .Case(2, HasAnyBits32(0x3)) |
| + .Case(3, HasAnyBits32(0x80000000)) |
| +#if __SIZEOF_POINTER__ > 4 |
| + .Case(4, HasAnyBits64(0x0)) |
| + .Case(5, HasAnyBits64(0x1)) |
| + .Case(6, HasAnyBits64(0x3)) |
| + .Case(7, HasAnyBits64(0x80000000)) |
| + .Case(8, HasAnyBits64(0x100000000ULL)) |
| + .Case(9, HasAnyBits64(0x300000000ULL)) |
| + .Case(10, HasAnyBits64(0x100000001ULL)) |
| +#endif |
| + .Default(Kill("Invalid test case number")); |
| } |
| - return ErrorCode(ErrorCode::ERR_ALLOWED); |
| + return Allow(); |
| } |
| BPF_TEST_C(SandboxBPF, AnyBitTests, AnyBitTestPolicy) { |
| @@ -1658,6 +1602,7 @@ BPF_TEST_C(SandboxBPF, AnyBitTests, AnyBitTestPolicy) { |
| BITMASK_TEST( 3, 0xC0000000U, ANYBITS32, 0x80000000, EXPECT_SUCCESS); |
| BITMASK_TEST( 3, -0x80000000LL, ANYBITS32, 0x80000000, EXPECT_SUCCESS); |
| +#if __SIZEOF_POINTER__ > 4 |
| // 64bit test: any of 0x0 (should always be false) |
| BITMASK_TEST( 4, 0, ANYBITS64, 0x0, EXPECT_FAILURE); |
| BITMASK_TEST( 4, 1, ANYBITS64, 0x0, EXPECT_FAILURE); |
| @@ -1731,57 +1676,48 @@ BPF_TEST_C(SandboxBPF, AnyBitTests, AnyBitTestPolicy) { |
| BITMASK_TEST( 10, 0x100000001LL, ANYBITS64,0x100000001, EXPECT_SUCCESS); |
| BITMASK_TEST( 10, 0xFFFFFFFFU, ANYBITS64,0x100000001, EXPECT_SUCCESS); |
| BITMASK_TEST( 10, -1L, ANYBITS64,0x100000001, EXPECT_SUCCESS); |
| +#endif |
| } |
| -class MaskedEqualTestPolicy : public SandboxBPFPolicy { |
| +class MaskedEqualTestPolicy : public SandboxBPFDSLPolicy { |
| public: |
| MaskedEqualTestPolicy() {} |
| - virtual ErrorCode EvaluateSyscall(SandboxBPF* sandbox, |
| - int sysno) const OVERRIDE; |
| + virtual ~MaskedEqualTestPolicy() {} |
| - private: |
| - struct Rule { |
| - ErrorCode::ArgType arg_type; |
| - uint64_t mask; |
| - uint64_t value; |
| - }; |
| + virtual ResultExpr EvaluateSyscall(int sysno) const OVERRIDE; |
| - static Rule rules[]; |
| + private: |
| + static ResultExpr MaskedEqual32(uint32_t mask, uint32_t value); |
| + static ResultExpr MaskedEqual64(uint64_t mask, uint64_t value); |
| DISALLOW_COPY_AND_ASSIGN(MaskedEqualTestPolicy); |
| }; |
| -MaskedEqualTestPolicy::Rule MaskedEqualTestPolicy::rules[] = { |
| - /* 0 = */ {ErrorCode::TP_32BIT, 0x0000000000ff00ff, 0x00000000005500aa}, |
| +ResultExpr MaskedEqualTestPolicy::MaskedEqual32(uint32_t mask, uint32_t value) { |
| + const Arg<uint32_t> arg(1); |
| + return If((arg & mask) == value, Error(1)).Else(Error(0)); |
| +} |
| -#if __SIZEOF_POINTER__ > 4 |
| - /* 1 = */ {ErrorCode::TP_64BIT, 0x00ff00ff00000000, 0x005500aa00000000}, |
| - /* 2 = */ {ErrorCode::TP_64BIT, 0x00ff00ff00ff00ff, 0x005500aa005500aa}, |
| -#endif |
| -}; |
| +ResultExpr MaskedEqualTestPolicy::MaskedEqual64(uint64_t mask, uint64_t value) { |
| + const Arg<uint64_t> arg(1); |
| + return If((arg & mask) == value, Error(1)).Else(Error(0)); |
| +} |
| -ErrorCode MaskedEqualTestPolicy::EvaluateSyscall(SandboxBPF* sandbox, |
| - int sysno) const { |
| +ResultExpr MaskedEqualTestPolicy::EvaluateSyscall(int sysno) const { |
| DCHECK(SandboxBPF::IsValidSyscallNumber(sysno)); |
| if (sysno == __NR_uname) { |
| - ErrorCode err = sandbox->Kill("Invalid test case number"); |
| - for (size_t i = 0; i < arraysize(rules); i++) { |
| - err = sandbox->Cond(0, |
| - ErrorCode::TP_32BIT, |
| - ErrorCode::OP_EQUAL, |
| - i, |
| - sandbox->CondMaskedEqual(1, |
| - rules[i].arg_type, |
| - rules[i].mask, |
| - rules[i].value, |
| - ErrorCode(1), |
| - ErrorCode(0)), |
| - err); |
| - } |
| - return err; |
| + const Arg<int> option(0); |
| + return Switch(option) |
| + .Case(0, MaskedEqual32(0x00ff00ff, 0x005500aa)) |
| +#if __SIZEOF_POINTER__ > 4 |
| + .Case(1, MaskedEqual64(0x00ff00ff00000000, 0x005500aa00000000)) |
| + .Case(2, MaskedEqual64(0x00ff00ff00ff00ff, 0x005500aa005500aa)) |
| +#endif |
| + .Default(Kill("Invalid test case number")); |
| } |
| - return ErrorCode(ErrorCode::ERR_ALLOWED); |
| + |
| + return Allow(); |
| } |
| #define MASKEQ_TEST(rulenum, arg, expected_result) \ |
| @@ -1870,18 +1806,18 @@ intptr_t PthreadTrapHandler(const struct arch_seccomp_data& args, void* aux) { |
| return -EPERM; |
| } |
| -class PthreadPolicyEquality : public SandboxBPFPolicy { |
| +class PthreadPolicyEquality : public SandboxBPFDSLPolicy { |
| public: |
| PthreadPolicyEquality() {} |
| - virtual ErrorCode EvaluateSyscall(SandboxBPF* sandbox, |
| - int sysno) const OVERRIDE; |
| + virtual ~PthreadPolicyEquality() {} |
| + |
| + virtual ResultExpr EvaluateSyscall(int sysno) const OVERRIDE; |
| private: |
| DISALLOW_COPY_AND_ASSIGN(PthreadPolicyEquality); |
| }; |
| -ErrorCode PthreadPolicyEquality::EvaluateSyscall(SandboxBPF* sandbox, |
| - int sysno) const { |
| +ResultExpr PthreadPolicyEquality::EvaluateSyscall(int sysno) const { |
| DCHECK(SandboxBPF::IsValidSyscallNumber(sysno)); |
| // This policy allows creating threads with pthread_create(). But it |
| // doesn't allow any other uses of clone(). Most notably, it does not |
| @@ -1897,39 +1833,48 @@ ErrorCode PthreadPolicyEquality::EvaluateSyscall(SandboxBPF* sandbox, |
| // The following policy is very strict. It only allows the exact masks |
| // that we have seen in known implementations. It is probably somewhat |
| // stricter than what we would want to do. |
| - const uint64_t kGlibcCloneMask = |
| - CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | |
| - CLONE_THREAD | CLONE_SYSVSEM | CLONE_SETTLS | |
| - CLONE_PARENT_SETTID | CLONE_CHILD_CLEARTID; |
| - const uint64_t kBaseAndroidCloneMask = |
| - CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | |
| - CLONE_THREAD | CLONE_SYSVSEM; |
| - return sandbox->Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL, |
| - kGlibcCloneMask, |
| - ErrorCode(ErrorCode::ERR_ALLOWED), |
| - sandbox->Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL, |
| - kBaseAndroidCloneMask | CLONE_DETACHED, |
| - ErrorCode(ErrorCode::ERR_ALLOWED), |
| - sandbox->Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL, |
| - kBaseAndroidCloneMask, |
| - ErrorCode(ErrorCode::ERR_ALLOWED), |
| - sandbox->Trap(PthreadTrapHandler, "Unknown mask")))); |
| + const uint64_t kGlibcCloneMask = CLONE_VM | CLONE_FS | CLONE_FILES | |
| + CLONE_SIGHAND | CLONE_THREAD | |
| + CLONE_SYSVSEM | CLONE_SETTLS | |
| + CLONE_PARENT_SETTID | CLONE_CHILD_CLEARTID; |
| + const uint64_t kBaseAndroidCloneMask = CLONE_VM | CLONE_FS | CLONE_FILES | |
| + CLONE_SIGHAND | CLONE_THREAD | |
| + CLONE_SYSVSEM; |
| + const Arg<unsigned long> flags(0); |
| + return If(flags == kGlibcCloneMask || |
| + flags == (kBaseAndroidCloneMask | CLONE_DETACHED) || |
| + flags == kBaseAndroidCloneMask, |
| + Allow()).Else(Trap(PthreadTrapHandler, "Unknown mask")); |
| } |
| - return ErrorCode(ErrorCode::ERR_ALLOWED); |
| + |
| + return Allow(); |
| } |
| -class PthreadPolicyBitMask : public SandboxBPFPolicy { |
| +class PthreadPolicyBitMask : public SandboxBPFDSLPolicy { |
| public: |
| PthreadPolicyBitMask() {} |
| - virtual ErrorCode EvaluateSyscall(SandboxBPF* sandbox, |
| - int sysno) const OVERRIDE; |
| + virtual ~PthreadPolicyBitMask() {} |
| + |
| + virtual ResultExpr EvaluateSyscall(int sysno) const OVERRIDE; |
| private: |
| + static BoolExpr HasAnyBits(const Arg<unsigned long>& arg, unsigned long bits); |
| + static BoolExpr HasAllBits(const Arg<unsigned long>& arg, unsigned long bits); |
| + |
| DISALLOW_COPY_AND_ASSIGN(PthreadPolicyBitMask); |
| }; |
| -ErrorCode PthreadPolicyBitMask::EvaluateSyscall(SandboxBPF* sandbox, |
| - int sysno) const { |
| +BoolExpr PthreadPolicyBitMask::HasAnyBits(const Arg<unsigned long>& arg, |
| + unsigned long bits) { |
| + return (arg & bits) != 0; |
| +} |
| + |
| +BoolExpr PthreadPolicyBitMask::HasAllBits(const Arg<unsigned long>& arg, |
| + unsigned long bits) { |
| + return (arg & bits) == bits; |
| +} |
| + |
| +ResultExpr PthreadPolicyBitMask::EvaluateSyscall(int sysno) const { |
| DCHECK(SandboxBPF::IsValidSyscallNumber(sysno)); |
| // This policy allows creating threads with pthread_create(). But it |
| // doesn't allow any other uses of clone(). Most notably, it does not |
| @@ -1945,30 +1890,31 @@ ErrorCode PthreadPolicyBitMask::EvaluateSyscall(SandboxBPF* sandbox, |
| // err on the side of rather safe than sorry. |
| // Very noticeably though, we disallow fork() (which is often just a |
| // wrapper around clone()). |
| - return sandbox->Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_HAS_ANY_BITS, |
| - ~uint32(CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND| |
| - CLONE_THREAD|CLONE_SYSVSEM|CLONE_SETTLS| |
| - CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTID| |
| - CLONE_DETACHED), |
| - sandbox->Trap(PthreadTrapHandler, |
| - "Unexpected CLONE_XXX flag found"), |
| - sandbox->Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_HAS_ALL_BITS, |
| - CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND| |
| - CLONE_THREAD|CLONE_SYSVSEM, |
| - sandbox->Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_HAS_ALL_BITS, |
| - CLONE_SETTLS|CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTID, |
| - ErrorCode(ErrorCode::ERR_ALLOWED), |
| - sandbox->Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_HAS_ANY_BITS, |
| - CLONE_SETTLS|CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTID, |
| - sandbox->Trap(PthreadTrapHandler, |
| - "Must set either all or none of the TLS" |
| - " and futex bits in call to clone()"), |
| - ErrorCode(ErrorCode::ERR_ALLOWED))), |
| - sandbox->Trap(PthreadTrapHandler, |
| - "Missing mandatory CLONE_XXX flags " |
| - "when creating new thread"))); |
| + const unsigned long kMandatoryFlags = CLONE_VM | CLONE_FS | CLONE_FILES | |
| + CLONE_SIGHAND | CLONE_THREAD | |
| + CLONE_SYSVSEM; |
| + const unsigned long kFutexFlags = |
| + CLONE_SETTLS | CLONE_PARENT_SETTID | CLONE_CHILD_CLEARTID; |
| + const unsigned long kNoopFlags = CLONE_DETACHED; |
| + const unsigned long kKnownFlags = |
| + kMandatoryFlags | kFutexFlags | kNoopFlags; |
| + |
| + const Arg<unsigned long> flags(0); |
| + return If(HasAnyBits(flags, ~kKnownFlags), |
| + Trap(PthreadTrapHandler, "Unexpected CLONE_XXX flag found")) |
| + .ElseIf(!HasAllBits(flags, kMandatoryFlags), |
| + Trap(PthreadTrapHandler, |
| + "Missing mandatory CLONE_XXX flags " |
| + "when creating new thread")) |
| + .ElseIf( |
| + !HasAllBits(flags, kFutexFlags) && HasAnyBits(flags, kFutexFlags), |
| + Trap(PthreadTrapHandler, |
| + "Must set either all or none of the TLS and futex bits in " |
| + "call to clone()")) |
| + .Else(Allow()); |
| } |
| - return ErrorCode(ErrorCode::ERR_ALLOWED); |
| + |
| + return Allow(); |
| } |
| static void* ThreadFnc(void* arg) { |
| @@ -2075,14 +2021,13 @@ long SetSyscall(pid_t pid, regs_struct* regs, int syscall_number) { |
| const uint16_t kTraceData = 0xcc; |
| -class TraceAllPolicy : public SandboxBPFPolicy { |
| +class TraceAllPolicy : public SandboxBPFDSLPolicy { |
| public: |
| TraceAllPolicy() {} |
| virtual ~TraceAllPolicy() {} |
| - virtual ErrorCode EvaluateSyscall(SandboxBPF* sandbox_compiler, |
| - int system_call_number) const OVERRIDE { |
| - return ErrorCode(ErrorCode::ERR_TRACE + kTraceData); |
| + virtual ResultExpr EvaluateSyscall(int system_call_number) const OVERRIDE { |
| + return Trace(kTraceData); |
| } |
| private: |
| @@ -2137,8 +2082,11 @@ SANDBOX_TEST(SandboxBPF, DISABLE_ON_TSAN(SeccompRetTrace)) { |
| BPF_ASSERT(HANDLE_EINTR(waitpid(pid, &status, WUNTRACED)) != -1); |
| BPF_ASSERT(WIFSTOPPED(status)); |
| - BPF_ASSERT_NE(-1, ptrace(PTRACE_SETOPTIONS, pid, NULL, |
| - reinterpret_cast<void*>(PTRACE_O_TRACESECCOMP))); |
| + BPF_ASSERT_NE(-1, |
| + ptrace(PTRACE_SETOPTIONS, |
| + pid, |
| + NULL, |
| + reinterpret_cast<void*>(PTRACE_O_TRACESECCOMP))); |
| BPF_ASSERT_NE(-1, ptrace(PTRACE_CONT, pid, NULL, NULL)); |
| while (true) { |
| BPF_ASSERT(HANDLE_EINTR(waitpid(pid, &status, 0)) != -1); |
| @@ -2219,22 +2167,21 @@ bool FullPread64(int fd, char* buffer, size_t count, off64_t offset) { |
| bool pread_64_was_forwarded = false; |
| -class TrapPread64Policy : public SandboxBPFPolicy { |
| +class TrapPread64Policy : public SandboxBPFDSLPolicy { |
| public: |
| TrapPread64Policy() {} |
| virtual ~TrapPread64Policy() {} |
| - virtual ErrorCode EvaluateSyscall(SandboxBPF* sandbox_compiler, |
| - int system_call_number) const OVERRIDE { |
| + virtual ResultExpr EvaluateSyscall(int system_call_number) const OVERRIDE { |
| // Set the global environment for unsafe traps once. |
| if (system_call_number == MIN_SYSCALL) { |
| EnableUnsafeTraps(); |
| } |
| if (system_call_number == __NR_pread64) { |
| - return sandbox_compiler->UnsafeTrap(ForwardPreadHandler, NULL); |
| + return UnsafeTrap(ForwardPreadHandler, NULL); |
| } |
| - return ErrorCode(ErrorCode::ERR_ALLOWED); |
| + return Allow(); |
| } |
| private: |
| @@ -2245,6 +2192,7 @@ class TrapPread64Policy : public SandboxBPFPolicy { |
| return SandboxBPF::ForwardSyscall(args); |
| } |
| + |
| DISALLOW_COPY_AND_ASSIGN(TrapPread64Policy); |
| }; |
| @@ -2286,7 +2234,7 @@ void* TsyncApplyToTwoThreadsFunc(void* cond_ptr) { |
| SANDBOX_TEST(SandboxBPF, Tsync) { |
| if (SandboxBPF::SupportsSeccompThreadFilterSynchronization() != |
| - SandboxBPF::STATUS_AVAILABLE) { |
| + SandboxBPF::STATUS_AVAILABLE) { |
| return; |
| } |
| @@ -2294,8 +2242,8 @@ SANDBOX_TEST(SandboxBPF, Tsync) { |
| // Create a thread on which to invoke the blocked syscall. |
| pthread_t thread; |
| - BPF_ASSERT_EQ(0, |
| - pthread_create(&thread, NULL, &TsyncApplyToTwoThreadsFunc, &event)); |
| + BPF_ASSERT_EQ( |
| + 0, pthread_create(&thread, NULL, &TsyncApplyToTwoThreadsFunc, &event)); |
| // Test that nanoseelp success. |
| const struct timespec ts = {0, 0}; |
| @@ -2316,21 +2264,22 @@ SANDBOX_TEST(SandboxBPF, Tsync) { |
| BPF_ASSERT_EQ(0, pthread_join(thread, NULL)); |
| } |
| -class AllowAllPolicy : public SandboxBPFPolicy { |
| +class AllowAllPolicy : public SandboxBPFDSLPolicy { |
| public: |
| - AllowAllPolicy() : SandboxBPFPolicy() {} |
| + AllowAllPolicy() {} |
| virtual ~AllowAllPolicy() {} |
| - virtual ErrorCode EvaluateSyscall(SandboxBPF* sandbox, |
| - int sysno) const OVERRIDE { |
| - return ErrorCode(ErrorCode::ERR_ALLOWED); |
| + virtual ResultExpr EvaluateSyscall(int sysno) const OVERRIDE { |
| + return Allow(); |
| } |
| private: |
| DISALLOW_COPY_AND_ASSIGN(AllowAllPolicy); |
| }; |
| -SANDBOX_DEATH_TEST(SandboxBPF, StartMultiThreadedAsSingleThreaded, |
| +SANDBOX_DEATH_TEST( |
| + SandboxBPF, |
| + StartMultiThreadedAsSingleThreaded, |
| DEATH_MESSAGE("Cannot start sandbox; process is already multi-threaded")) { |
| base::Thread thread("sandbox.linux.StartMultiThreadedAsSingleThreaded"); |
| BPF_ASSERT(thread.Start()); |
| @@ -2342,9 +2291,12 @@ SANDBOX_DEATH_TEST(SandboxBPF, StartMultiThreadedAsSingleThreaded, |
| // http://crbug.com/407357 |
| #if !defined(THREAD_SANITIZER) |
| -SANDBOX_DEATH_TEST(SandboxBPF, StartSingleThreadedAsMultiThreaded, |
| - DEATH_MESSAGE("Cannot start sandbox; process may be single-threaded when " |
| - "reported as not")) { |
| +SANDBOX_DEATH_TEST( |
| + SandboxBPF, |
| + StartSingleThreadedAsMultiThreaded, |
| + DEATH_MESSAGE( |
| + "Cannot start sandbox; process may be single-threaded when " |
| + "reported as not")) { |
| SandboxBPF sandbox; |
| sandbox.SetSandboxPolicy(new AllowAllPolicy()); |
| BPF_ASSERT(!sandbox.StartSandbox(SandboxBPF::PROCESS_MULTI_THREADED)); |
| @@ -2356,46 +2308,39 @@ intptr_t NoOpHandler(const struct arch_seccomp_data& args, void*) { |
| return -1; |
| } |
| -class UnsafeTrapWithCondPolicy : public SandboxBPFPolicy { |
| +class UnsafeTrapWithCondPolicy : public SandboxBPFDSLPolicy { |
| public: |
| UnsafeTrapWithCondPolicy() {} |
| - virtual ErrorCode EvaluateSyscall(SandboxBPF* sandbox, |
| - int sysno) const OVERRIDE { |
| + virtual ~UnsafeTrapWithCondPolicy() {} |
| + |
| + virtual ResultExpr EvaluateSyscall(int sysno) const OVERRIDE { |
| DCHECK(SandboxBPF::IsValidSyscallNumber(sysno)); |
| setenv(kSandboxDebuggingEnv, "t", 0); |
| Die::SuppressInfoMessages(true); |
| if (SandboxBPF::IsRequiredForUnsafeTrap(sysno)) |
| - return ErrorCode(ErrorCode::ERR_ALLOWED); |
| + return Allow(); |
| switch (sysno) { |
| - case __NR_uname: |
| - return sandbox->Cond(0, |
| - ErrorCode::TP_32BIT, |
| - ErrorCode::OP_EQUAL, |
| - 0, |
| - ErrorCode(ErrorCode::ERR_ALLOWED), |
| - ErrorCode(EPERM)); |
| - case __NR_setgid: |
| - return sandbox->Cond(0, |
| - ErrorCode::TP_32BIT, |
| - ErrorCode::OP_EQUAL, |
| - 100, |
| - ErrorCode(ErrorCode(ENOMEM)), |
| - sandbox->Cond(0, |
| - ErrorCode::TP_32BIT, |
| - ErrorCode::OP_EQUAL, |
| - 200, |
| - ErrorCode(ENOSYS), |
| - ErrorCode(EPERM))); |
| + case __NR_uname: { |
| + const Arg<uint32_t> arg(0); |
| + return If(arg == 0, Allow()).Else(Error(EPERM)); |
| + } |
| + case __NR_setgid: { |
| + const Arg<uint32_t> arg(0); |
| + return Switch(arg) |
| + .Case(100, Error(ENOMEM)) |
| + .Case(200, Error(ENOSYS)) |
| + .Default(Error(EPERM)); |
| + } |
| case __NR_close: |
| case __NR_exit_group: |
| case __NR_write: |
| - return ErrorCode(ErrorCode::ERR_ALLOWED); |
| + return Allow(); |
| case __NR_getppid: |
| - return sandbox->UnsafeTrap(NoOpHandler, NULL); |
| + return UnsafeTrap(NoOpHandler, NULL); |
| default: |
| - return ErrorCode(EPERM); |
| + return Error(EPERM); |
| } |
| } |
| @@ -2422,4 +2367,5 @@ BPF_TEST_C(SandboxBPF, UnsafeTrapWithCond, UnsafeTrapWithCondPolicy) { |
| } // namespace |
| +} // namespace bpf_dsl |
| } // namespace sandbox |