| Index: sandbox/linux/seccomp-bpf/sandbox_bpf_unittest.cc
|
| diff --git a/sandbox/linux/seccomp-bpf/sandbox_bpf_unittest.cc b/sandbox/linux/seccomp-bpf/sandbox_bpf_unittest.cc
|
| index 54fe7a7bff7bec3748b7a3a4c54eddb007724f07..19c64a9bd2983591a2e2d08fd80bdf2841ca47a1 100644
|
| --- a/sandbox/linux/seccomp-bpf/sandbox_bpf_unittest.cc
|
| +++ b/sandbox/linux/seccomp-bpf/sandbox_bpf_unittest.cc
|
| @@ -4,7 +4,7 @@
|
|
|
| #include <ostream>
|
|
|
| -#include "sandbox/linux/seccomp-bpf/sandbox_bpf.h"
|
| +#include "sandbox/linux/seccomp-bpf/bpf_tests.h"
|
| #include "sandbox/linux/seccomp-bpf/verifier.h"
|
| #include "testing/gtest/include/gtest/gtest.h"
|
|
|
| @@ -17,6 +17,8 @@ const int kExpectedReturnValue = 42;
|
| const int kArmPublicSysnoCeiling = __NR_SYSCALL_BASE + 1024;
|
| #endif
|
|
|
| +// This test should execute no matter whether we have kernel support. So,
|
| +// we make it a TEST() instead of a BPF_TEST().
|
| TEST(SandboxBpf, CallSupports) {
|
| // We check that we don't crash, but it's ok if the kernel doesn't
|
| // support it.
|
| @@ -31,9 +33,10 @@ TEST(SandboxBpf, CallSupports) {
|
| << "\n";
|
| }
|
|
|
| -TEST(SandboxBpf, CallSupportsTwice) {
|
| +BPF_TEST(SandboxBpf, CallSupportsTwice) {
|
| Sandbox::supportsSeccompSandbox(-1);
|
| Sandbox::supportsSeccompSandbox(-1);
|
| + return true;
|
| }
|
|
|
| __attribute__((noreturn)) void DoCrash() {
|
| @@ -63,50 +66,20 @@ __attribute__((noreturn)) void ExitGroup(int status) {
|
| // Helper function to start a sandbox with a policy specified in
|
| // evaluator
|
| void StartSandboxOrDie(Sandbox::EvaluateSyscall evaluator) {
|
| - int proc_fd = open("/proc", O_RDONLY|O_DIRECTORY);
|
| - if (proc_fd < 0 || !evaluator) {
|
| - ExitGroup(1);
|
| - }
|
| - if (Sandbox::supportsSeccompSandbox(proc_fd) !=
|
| - Sandbox::STATUS_AVAILABLE) {
|
| - ExitGroup(1);
|
| - }
|
| + BPF_ASSERT(evaluator);
|
| +
|
| + // Ensure the the sandbox is actually available at this time
|
| + int proc_fd;
|
| + BPF_ASSERT((proc_fd = open("/proc", O_RDONLY|O_DIRECTORY)) >= 0);
|
| + BPF_ASSERT(Sandbox::supportsSeccompSandbox(proc_fd) ==
|
| + Sandbox::STATUS_AVAILABLE);
|
| +
|
| + // Initialize and then start the sandbox with our custom policy
|
| Sandbox::setProcFd(proc_fd);
|
| Sandbox::setSandboxPolicy(evaluator, NULL);
|
| Sandbox::startSandbox();
|
| }
|
|
|
| -void RunInSandbox(Sandbox::EvaluateSyscall evaluator,
|
| - void (*SandboxedCode)()) {
|
| - // TODO(markus): Implement IsEqual for ErrorCode
|
| - // IsEqual(evaluator(__NR_exit_group), Sandbox::SB_ALLOWED) <<
|
| - // "You need to always allow exit_group() in your test policy";
|
| - StartSandboxOrDie(evaluator);
|
| - // TODO(jln): find a way to use the testing framework inside
|
| - // SandboxedCode() or at the very least to surface errors
|
| - SandboxedCode();
|
| - // SandboxedCode() should have exited, this is a failure
|
| - ExitGroup(1);
|
| -}
|
| -
|
| -// evaluator should always allow ExitGroup
|
| -// SandboxedCode should ExitGroup(kExpectedReturnValue) if and only if
|
| -// things go as expected.
|
| -void TryPolicyInProcess(Sandbox::EvaluateSyscall evaluator,
|
| - void (*SandboxedCode)()) {
|
| - // TODO(jln) figure out a way to surface whether we're actually testing
|
| - // something or not.
|
| - if (Sandbox::supportsSeccompSandbox(-1) == Sandbox::STATUS_AVAILABLE) {
|
| - EXPECT_EXIT(RunInSandbox(evaluator, SandboxedCode),
|
| - ::testing::ExitedWithCode(kExpectedReturnValue),
|
| - "");
|
| - } else {
|
| - // The sandbox is not available. We should still try to exercise what we
|
| - // can.
|
| - // TODO(markus): (crbug.com/141545) let us call the compiler from here.
|
| - Sandbox::setSandboxPolicy(evaluator, NULL);
|
| - }
|
| -}
|
|
|
| // A simple blacklist test
|
|
|
| @@ -124,17 +97,16 @@ Sandbox::ErrorCode BlacklistNanosleepPolicy(int sysno) {
|
| }
|
| }
|
|
|
| -void NanosleepProcess(void) {
|
| +BPF_TEST(SandboxBpf, ApplyBasicBlacklistPolicy) {
|
| + StartSandboxOrDie(BlacklistNanosleepPolicy);
|
| +
|
| + // nanosleep() should be denied
|
| const struct timespec ts = {0, 0};
|
| errno = 0;
|
| - if(syscall(__NR_nanosleep, &ts, NULL) != -1 || errno != EACCES) {
|
| - ExitGroup(1);
|
| - }
|
| - ExitGroup(kExpectedReturnValue);
|
| -}
|
| + BPF_ASSERT(syscall(__NR_nanosleep, &ts, NULL) == -1);
|
| + BPF_ASSERT(errno == EACCES);
|
|
|
| -TEST(SandboxBpf, ApplyBasicBlacklistPolicy) {
|
| - TryPolicyInProcess(BlacklistNanosleepPolicy, NanosleepProcess);
|
| + return true;
|
| }
|
|
|
| // Now do a simple whitelist test
|
| @@ -149,19 +121,19 @@ Sandbox::ErrorCode WhitelistGetpidPolicy(int sysno) {
|
| }
|
| }
|
|
|
| -void GetpidProcess(void) {
|
| - errno = 0;
|
| +BPF_TEST(SandboxBpf, ApplyBasicWhitelistPolicy) {
|
| + StartSandboxOrDie(WhitelistGetpidPolicy);
|
| +
|
| // getpid() should be allowed
|
| - if (syscall(__NR_getpid) < 0 || errno)
|
| - ExitGroup(1);
|
| + errno = 0;
|
| + BPF_ASSERT(syscall(__NR_getpid) > 0);
|
| + BPF_ASSERT(errno == 0);
|
| +
|
| // getpgid() should be denied
|
| - if (getpgid(0) != -1 || errno != ENOMEM)
|
| - ExitGroup(1);
|
| - ExitGroup(kExpectedReturnValue);
|
| -}
|
| + BPF_ASSERT(getpgid(0) == -1);
|
| + BPF_ASSERT(errno == ENOMEM);
|
|
|
| -TEST(SandboxBpf, ApplyBasicWhitelistPolicy) {
|
| - TryPolicyInProcess(WhitelistGetpidPolicy, GetpidProcess);
|
| + return true;
|
| }
|
|
|
| // A simple blacklist policy, with a SIGSYS handler
|
| @@ -194,26 +166,25 @@ Sandbox::ErrorCode BlacklistNanosleepPolicySigsys(int sysno) {
|
| }
|
| }
|
|
|
| -void NanosleepProcessSigsys(void) {
|
| - const struct timespec ts = {0, 0};
|
| - errno = 0;
|
| +BPF_TEST(SandboxBpf, BasicBlacklistWithSigsys) {
|
| + StartSandboxOrDie(BlacklistNanosleepPolicySigsys);
|
| +
|
| // getpid() should work properly
|
| - if (syscall(__NR_getpid) < 0)
|
| - ExitGroup(1);
|
| + errno = 0;
|
| + BPF_ASSERT(syscall(__NR_getpid) > 0);
|
| + BPF_ASSERT(errno == 0);
|
| +
|
| // Our Auxiliary Data, should be reset by the signal handler
|
| BlacklistNanosleepPolicySigsysAuxData = -1;
|
| - errno = 0;
|
| - if (syscall(__NR_nanosleep, &ts, NULL) != -1 || errno != ENOMEM)
|
| - ExitGroup(1);
|
| + const struct timespec ts = {0, 0};
|
| + BPF_ASSERT(syscall(__NR_nanosleep, &ts, NULL) == -1);
|
| + BPF_ASSERT(errno == ENOMEM);
|
| +
|
| // We expect the signal handler to modify AuxData
|
| - if (BlacklistNanosleepPolicySigsysAuxData != kExpectedReturnValue)
|
| - ExitGroup(1);
|
| - else
|
| - ExitGroup(kExpectedReturnValue);
|
| -}
|
| + BPF_ASSERT(
|
| + BlacklistNanosleepPolicySigsysAuxData == kExpectedReturnValue);
|
|
|
| -TEST(SandboxBpf, BasicBlacklistWithSigsys) {
|
| - TryPolicyInProcess(BlacklistNanosleepPolicySigsys, NanosleepProcessSigsys);
|
| + return true;
|
| }
|
|
|
| // A more complex, but synthetic policy. This tests the correctness of the BPF
|
| @@ -252,13 +223,14 @@ Sandbox::ErrorCode SyntheticPolicy(int sysno) {
|
| }
|
| }
|
|
|
| -void SyntheticProcess(void) {
|
| +BPF_TEST(SandboxBpf, SyntheticPolicy) {
|
| // Ensure that that kExpectedReturnValue + syscallnumber + 1 does not int
|
| // overflow.
|
| - if (std::numeric_limits<int>::max() - kExpectedReturnValue - 1 <
|
| - static_cast<int>(MAX_SYSCALL)) {
|
| - ExitGroup(1);
|
| - }
|
| + BPF_ASSERT(
|
| + std::numeric_limits<int>::max() - kExpectedReturnValue - 1 >=
|
| + static_cast<int>(MAX_SYSCALL));
|
| +
|
| + StartSandboxOrDie(SyntheticPolicy);
|
|
|
| // TODO(jorgelo): remove this limit once crbug.com/141694 is fixed.
|
| #if defined(__arm__)
|
| @@ -275,19 +247,10 @@ void SyntheticProcess(void) {
|
| continue;
|
| }
|
| errno = 0;
|
| - if (syscall(syscall_number) != -1 ||
|
| - errno != SysnoToRandomErrno(syscall_number)) {
|
| - // Exit with a return value that is different than kExpectedReturnValue
|
| - // to signal an error. Make it easy to see what syscall_number failed in
|
| - // the test report.
|
| - ExitGroup(kExpectedReturnValue + syscall_number + 1);
|
| - }
|
| + BPF_ASSERT(syscall(syscall_number) == -1);
|
| + BPF_ASSERT(errno == SysnoToRandomErrno(syscall_number));
|
| }
|
| - ExitGroup(kExpectedReturnValue);
|
| -}
|
| -
|
| -TEST(SandboxBpf, SyntheticPolicy) {
|
| - TryPolicyInProcess(SyntheticPolicy, SyntheticProcess);
|
| + return true;
|
| }
|
|
|
| } // namespace
|
|
|