summaryrefslogtreecommitdiff
path: root/chromium/sandbox/linux/seccomp-bpf/sandbox_bpf_unittest.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/sandbox/linux/seccomp-bpf/sandbox_bpf_unittest.cc')
-rw-r--r--chromium/sandbox/linux/seccomp-bpf/sandbox_bpf_unittest.cc626
1 files changed, 340 insertions, 286 deletions
diff --git a/chromium/sandbox/linux/seccomp-bpf/sandbox_bpf_unittest.cc b/chromium/sandbox/linux/seccomp-bpf/sandbox_bpf_unittest.cc
index 1713e8f2029..988e29544b0 100644
--- a/chromium/sandbox/linux/seccomp-bpf/sandbox_bpf_unittest.cc
+++ b/chromium/sandbox/linux/seccomp-bpf/sandbox_bpf_unittest.cc
@@ -33,42 +33,40 @@
// Workaround for Android's prctl.h file.
#ifndef PR_GET_ENDIAN
-#define PR_GET_ENDIAN 19
+#define PR_GET_ENDIAN 19
#endif
#ifndef PR_CAPBSET_READ
#define PR_CAPBSET_READ 23
#define PR_CAPBSET_DROP 24
#endif
-using namespace playground2;
-using sandbox::BrokerProcess;
+namespace sandbox {
namespace {
-const int kExpectedReturnValue = 42;
+const int kExpectedReturnValue = 42;
const char kSandboxDebuggingEnv[] = "CHROME_SANDBOX_DEBUGGING";
// 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) {
+TEST(SandboxBPF, CallSupports) {
// We check that we don't crash, but it's ok if the kernel doesn't
// support it.
bool seccomp_bpf_supported =
- Sandbox::SupportsSeccompSandbox(-1) == Sandbox::STATUS_AVAILABLE;
+ SandboxBPF::SupportsSeccompSandbox(-1) == SandboxBPF::STATUS_AVAILABLE;
// We want to log whether or not seccomp BPF is actually supported
// since actual test coverage depends on it.
RecordProperty("SeccompBPFSupported",
seccomp_bpf_supported ? "true." : "false.");
std::cout << "Seccomp BPF supported: "
- << (seccomp_bpf_supported ? "true." : "false.")
- << "\n";
+ << (seccomp_bpf_supported ? "true." : "false.") << "\n";
RecordProperty("PointerSize", sizeof(void*));
std::cout << "Pointer size: " << sizeof(void*) << "\n";
}
-SANDBOX_TEST(SandboxBpf, CallSupportsTwice) {
- Sandbox::SupportsSeccompSandbox(-1);
- Sandbox::SupportsSeccompSandbox(-1);
+SANDBOX_TEST(SandboxBPF, CallSupportsTwice) {
+ SandboxBPF::SupportsSeccompSandbox(-1);
+ SandboxBPF::SupportsSeccompSandbox(-1);
}
// BPF_TEST does a lot of the boiler-plate code around setting up a
@@ -78,14 +76,14 @@ SANDBOX_TEST(SandboxBpf, CallSupportsTwice) {
// setting up the sandbox. But it wouldn't hurt to have at least one test
// that explicitly walks through all these steps.
-intptr_t FakeGetPid(const struct arch_seccomp_data& args, void *aux) {
+intptr_t FakeGetPid(const struct arch_seccomp_data& args, void* aux) {
BPF_ASSERT(aux);
- pid_t *pid_ptr = static_cast<pid_t *>(aux);
+ pid_t* pid_ptr = static_cast<pid_t*>(aux);
return (*pid_ptr)++;
}
-ErrorCode VerboseAPITestingPolicy(Sandbox *sandbox, int sysno, void *aux) {
- if (!Sandbox::IsValidSyscallNumber(sysno)) {
+ErrorCode VerboseAPITestingPolicy(SandboxBPF* sandbox, int sysno, void* aux) {
+ if (!SandboxBPF::IsValidSyscallNumber(sysno)) {
return ErrorCode(ENOSYS);
} else if (sysno == __NR_getpid) {
return sandbox->Trap(FakeGetPid, aux);
@@ -94,12 +92,12 @@ ErrorCode VerboseAPITestingPolicy(Sandbox *sandbox, int sysno, void *aux) {
}
}
-SANDBOX_TEST(SandboxBpf, DISABLE_ON_TSAN(VerboseAPITesting)) {
- if (Sandbox::SupportsSeccompSandbox(-1) ==
- playground2::Sandbox::STATUS_AVAILABLE) {
+SANDBOX_TEST(SandboxBPF, DISABLE_ON_TSAN(VerboseAPITesting)) {
+ if (SandboxBPF::SupportsSeccompSandbox(-1) ==
+ sandbox::SandboxBPF::STATUS_AVAILABLE) {
pid_t test_var = 0;
- Sandbox sandbox;
- sandbox.SetSandboxPolicy(VerboseAPITestingPolicy, &test_var);
+ SandboxBPF sandbox;
+ sandbox.SetSandboxPolicyDeprecated(VerboseAPITestingPolicy, &test_var);
sandbox.StartSandbox();
BPF_ASSERT(test_var == 0);
@@ -116,8 +114,8 @@ SANDBOX_TEST(SandboxBpf, DISABLE_ON_TSAN(VerboseAPITesting)) {
// A simple blacklist test
-ErrorCode BlacklistNanosleepPolicy(Sandbox *, int sysno, void *) {
- if (!Sandbox::IsValidSyscallNumber(sysno)) {
+ErrorCode BlacklistNanosleepPolicy(SandboxBPF*, int sysno, void*) {
+ if (!SandboxBPF::IsValidSyscallNumber(sysno)) {
// FIXME: we should really not have to do that in a trivial policy
return ErrorCode(ENOSYS);
}
@@ -130,7 +128,7 @@ ErrorCode BlacklistNanosleepPolicy(Sandbox *, int sysno, void *) {
}
}
-BPF_TEST(SandboxBpf, ApplyBasicBlacklistPolicy, BlacklistNanosleepPolicy) {
+BPF_TEST(SandboxBPF, ApplyBasicBlacklistPolicy, BlacklistNanosleepPolicy) {
// nanosleep() should be denied
const struct timespec ts = {0, 0};
errno = 0;
@@ -140,7 +138,7 @@ BPF_TEST(SandboxBpf, ApplyBasicBlacklistPolicy, BlacklistNanosleepPolicy) {
// Now do a simple whitelist test
-ErrorCode WhitelistGetpidPolicy(Sandbox *, int sysno, void *) {
+ErrorCode WhitelistGetpidPolicy(SandboxBPF*, int sysno, void*) {
switch (sysno) {
case __NR_getpid:
case __NR_exit_group:
@@ -150,7 +148,7 @@ ErrorCode WhitelistGetpidPolicy(Sandbox *, int sysno, void *) {
}
}
-BPF_TEST(SandboxBpf, ApplyBasicWhitelistPolicy, WhitelistGetpidPolicy) {
+BPF_TEST(SandboxBPF, ApplyBasicWhitelistPolicy, WhitelistGetpidPolicy) {
// getpid() should be allowed
errno = 0;
BPF_ASSERT(syscall(__NR_getpid) > 0);
@@ -163,16 +161,17 @@ BPF_TEST(SandboxBpf, ApplyBasicWhitelistPolicy, WhitelistGetpidPolicy) {
// A simple blacklist policy, with a SIGSYS handler
-intptr_t EnomemHandler(const struct arch_seccomp_data& args, void *aux) {
+intptr_t EnomemHandler(const struct arch_seccomp_data& args, void* aux) {
// We also check that the auxiliary data is correct
SANDBOX_ASSERT(aux);
*(static_cast<int*>(aux)) = kExpectedReturnValue;
return -ENOMEM;
}
-ErrorCode BlacklistNanosleepPolicySigsys(Sandbox *sandbox, int sysno,
- void *aux) {
- if (!Sandbox::IsValidSyscallNumber(sysno)) {
+ErrorCode BlacklistNanosleepPolicySigsys(SandboxBPF* sandbox,
+ int sysno,
+ void* aux) {
+ if (!SandboxBPF::IsValidSyscallNumber(sysno)) {
// FIXME: we should really not have to do that in a trivial policy
return ErrorCode(ENOSYS);
}
@@ -185,8 +184,10 @@ ErrorCode BlacklistNanosleepPolicySigsys(Sandbox *sandbox, int sysno,
}
}
-BPF_TEST(SandboxBpf, BasicBlacklistWithSigsys,
- BlacklistNanosleepPolicySigsys, int /* BPF_AUX */) {
+BPF_TEST(SandboxBPF,
+ BasicBlacklistWithSigsys,
+ BlacklistNanosleepPolicySigsys,
+ int /* BPF_AUX */) {
// getpid() should work properly
errno = 0;
BPF_ASSERT(syscall(__NR_getpid) > 0);
@@ -204,43 +205,43 @@ BPF_TEST(SandboxBpf, BasicBlacklistWithSigsys,
// A simple test that verifies we can return arbitrary errno values.
-ErrorCode ErrnoTestPolicy(Sandbox *, int sysno, void *) {
- if (!Sandbox::IsValidSyscallNumber(sysno)) {
+ErrorCode ErrnoTestPolicy(SandboxBPF*, int sysno, void*) {
+ if (!SandboxBPF::IsValidSyscallNumber(sysno)) {
// FIXME: we should really not have to do that in a trivial policy
return ErrorCode(ENOSYS);
}
switch (sysno) {
- case __NR_dup2:
- // Pretend that dup2() worked, but don't actually do anything.
- return ErrorCode(0);
- case __NR_setuid:
+ case __NR_dup2:
+ // Pretend that dup2() worked, but don't actually do anything.
+ return ErrorCode(0);
+ case __NR_setuid:
#if defined(__NR_setuid32)
- case __NR_setuid32:
+ case __NR_setuid32:
#endif
- // Return errno = 1.
- return ErrorCode(1);
- case __NR_setgid:
+ // Return errno = 1.
+ return ErrorCode(1);
+ case __NR_setgid:
#if defined(__NR_setgid32)
- case __NR_setgid32:
+ case __NR_setgid32:
#endif
- // Return maximum errno value (typically 4095).
- return ErrorCode(ErrorCode::ERR_MAX_ERRNO);
- case __NR_uname:
- // Return errno = 42;
- return ErrorCode(42);
- default:
- return ErrorCode(ErrorCode::ERR_ALLOWED);
+ // Return maximum errno value (typically 4095).
+ return ErrorCode(ErrorCode::ERR_MAX_ERRNO);
+ case __NR_uname:
+ // Return errno = 42;
+ return ErrorCode(42);
+ default:
+ return ErrorCode(ErrorCode::ERR_ALLOWED);
}
}
-BPF_TEST(SandboxBpf, ErrnoTest, ErrnoTestPolicy) {
+BPF_TEST(SandboxBPF, ErrnoTest, ErrnoTestPolicy) {
// Verify that dup2() returns success, but doesn't actually run.
int fds[4];
BPF_ASSERT(pipe(fds) == 0);
- BPF_ASSERT(pipe(fds+2) == 0);
+ BPF_ASSERT(pipe(fds + 2) == 0);
BPF_ASSERT(dup2(fds[2], fds[0]) == 0);
- char buf[1] = { };
+ char buf[1] = {};
BPF_ASSERT(write(fds[1], "\x55", 1) == 1);
BPF_ASSERT(write(fds[3], "\xAA", 1) == 1);
BPF_ASSERT(read(fds[0], buf, 1) == 1);
@@ -276,14 +277,17 @@ BPF_TEST(SandboxBpf, ErrnoTest, ErrnoTestPolicy) {
// Testing the stacking of two sandboxes
-ErrorCode StackingPolicyPartOne(Sandbox *sandbox, int sysno, void *) {
- if (!Sandbox::IsValidSyscallNumber(sysno)) {
+ErrorCode StackingPolicyPartOne(SandboxBPF* sandbox, int sysno, void*) {
+ if (!SandboxBPF::IsValidSyscallNumber(sysno)) {
return ErrorCode(ENOSYS);
}
switch (sysno) {
case __NR_getppid:
- return sandbox->Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL, 0,
+ return sandbox->Cond(0,
+ ErrorCode::TP_32BIT,
+ ErrorCode::OP_EQUAL,
+ 0,
ErrorCode(ErrorCode::ERR_ALLOWED),
ErrorCode(EPERM));
default:
@@ -291,14 +295,17 @@ ErrorCode StackingPolicyPartOne(Sandbox *sandbox, int sysno, void *) {
}
}
-ErrorCode StackingPolicyPartTwo(Sandbox *sandbox, int sysno, void *) {
- if (!Sandbox::IsValidSyscallNumber(sysno)) {
+ErrorCode StackingPolicyPartTwo(SandboxBPF* sandbox, int sysno, void*) {
+ if (!SandboxBPF::IsValidSyscallNumber(sysno)) {
return ErrorCode(ENOSYS);
}
switch (sysno) {
case __NR_getppid:
- return sandbox->Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL, 0,
+ return sandbox->Cond(0,
+ ErrorCode::TP_32BIT,
+ ErrorCode::OP_EQUAL,
+ 0,
ErrorCode(EINVAL),
ErrorCode(ErrorCode::ERR_ALLOWED));
default:
@@ -306,7 +313,7 @@ ErrorCode StackingPolicyPartTwo(Sandbox *sandbox, int sysno, void *) {
}
}
-BPF_TEST(SandboxBpf, StackingPolicy, StackingPolicyPartOne) {
+BPF_TEST(SandboxBPF, StackingPolicy, StackingPolicyPartOne) {
errno = 0;
BPF_ASSERT(syscall(__NR_getppid, 0) > 0);
BPF_ASSERT(errno == 0);
@@ -316,8 +323,8 @@ BPF_TEST(SandboxBpf, StackingPolicy, StackingPolicyPartOne) {
// Stack a second sandbox with its own policy. Verify that we can further
// restrict filters, but we cannot relax existing filters.
- Sandbox sandbox;
- sandbox.SetSandboxPolicy(StackingPolicyPartTwo, NULL);
+ SandboxBPF sandbox;
+ sandbox.SetSandboxPolicyDeprecated(StackingPolicyPartTwo, NULL);
sandbox.StartSandbox();
errno = 0;
@@ -343,8 +350,8 @@ int SysnoToRandomErrno(int sysno) {
return ((sysno & ~3) >> 2) % 29 + 1;
}
-ErrorCode SyntheticPolicy(Sandbox *, int sysno, void *) {
- if (!Sandbox::IsValidSyscallNumber(sysno)) {
+ErrorCode SyntheticPolicy(SandboxBPF*, int sysno, void*) {
+ if (!SandboxBPF::IsValidSyscallNumber(sysno)) {
// FIXME: we should really not have to do that in a trivial policy
return ErrorCode(ENOSYS);
}
@@ -365,18 +372,16 @@ ErrorCode SyntheticPolicy(Sandbox *, int sysno, void *) {
}
}
-BPF_TEST(SandboxBpf, SyntheticPolicy, SyntheticPolicy) {
+BPF_TEST(SandboxBPF, SyntheticPolicy, SyntheticPolicy) {
// Ensure that that kExpectedReturnValue + syscallnumber + 1 does not int
// overflow.
- BPF_ASSERT(
- std::numeric_limits<int>::max() - kExpectedReturnValue - 1 >=
- static_cast<int>(MAX_PUBLIC_SYSCALL));
-
- for (int syscall_number = static_cast<int>(MIN_SYSCALL);
- syscall_number <= static_cast<int>(MAX_PUBLIC_SYSCALL);
- ++syscall_number) {
- if (syscall_number == __NR_exit_group ||
- syscall_number == __NR_write) {
+ BPF_ASSERT(std::numeric_limits<int>::max() - kExpectedReturnValue - 1 >=
+ static_cast<int>(MAX_PUBLIC_SYSCALL));
+
+ for (int syscall_number = static_cast<int>(MIN_SYSCALL);
+ syscall_number <= static_cast<int>(MAX_PUBLIC_SYSCALL);
+ ++syscall_number) {
+ if (syscall_number == __NR_exit_group || syscall_number == __NR_write) {
// exit_group() is special
continue;
}
@@ -401,8 +406,8 @@ int ArmPrivateSysnoToErrno(int sysno) {
}
}
-ErrorCode ArmPrivatePolicy(Sandbox *, int sysno, void *) {
- if (!Sandbox::IsValidSyscallNumber(sysno)) {
+ErrorCode ArmPrivatePolicy(SandboxBPF*, int sysno, void*) {
+ if (!SandboxBPF::IsValidSyscallNumber(sysno)) {
// FIXME: we should really not have to do that in a trivial policy.
return ErrorCode(ENOSYS);
}
@@ -417,10 +422,10 @@ ErrorCode ArmPrivatePolicy(Sandbox *, int sysno, void *) {
}
}
-BPF_TEST(SandboxBpf, ArmPrivatePolicy, ArmPrivatePolicy) {
- for (int syscall_number = static_cast<int>(__ARM_NR_set_tls + 1);
- syscall_number <= static_cast<int>(MAX_PRIVATE_SYSCALL);
- ++syscall_number) {
+BPF_TEST(SandboxBPF, ArmPrivatePolicy, ArmPrivatePolicy) {
+ for (int syscall_number = static_cast<int>(__ARM_NR_set_tls + 1);
+ syscall_number <= static_cast<int>(MAX_PRIVATE_SYSCALL);
+ ++syscall_number) {
errno = 0;
BPF_ASSERT(syscall(syscall_number) == -1);
BPF_ASSERT(errno == ArmPrivateSysnoToErrno(syscall_number));
@@ -428,9 +433,9 @@ BPF_TEST(SandboxBpf, ArmPrivatePolicy, ArmPrivatePolicy) {
}
#endif // defined(__arm__)
-intptr_t CountSyscalls(const struct arch_seccomp_data& args, void *aux) {
+intptr_t CountSyscalls(const struct arch_seccomp_data& args, void* aux) {
// Count all invocations of our callback function.
- ++*reinterpret_cast<int *>(aux);
+ ++*reinterpret_cast<int*>(aux);
// Verify that within the callback function all filtering is temporarily
// disabled.
@@ -438,10 +443,10 @@ intptr_t CountSyscalls(const struct arch_seccomp_data& args, void *aux) {
// Verify that we can now call the underlying system call without causing
// infinite recursion.
- return Sandbox::ForwardSyscall(args);
+ return SandboxBPF::ForwardSyscall(args);
}
-ErrorCode GreyListedPolicy(Sandbox *sandbox, int sysno, void *aux) {
+ErrorCode GreyListedPolicy(SandboxBPF* sandbox, int sysno, void* aux) {
// The use of UnsafeTrap() causes us to print a warning message. This is
// generally desirable, but it results in the unittest failing, as it doesn't
// expect any messages on "stderr". So, temporarily disable messages. The
@@ -452,42 +457,46 @@ ErrorCode GreyListedPolicy(Sandbox *sandbox, int sysno, void *aux) {
// Some system calls must always be allowed, if our policy wants to make
// use of UnsafeTrap()
- if (sysno == __NR_rt_sigprocmask ||
- sysno == __NR_rt_sigreturn
+ if (sysno == __NR_rt_sigprocmask || sysno == __NR_rt_sigreturn
#if defined(__NR_sigprocmask)
- || sysno == __NR_sigprocmask
+ ||
+ sysno == __NR_sigprocmask
#endif
#if defined(__NR_sigreturn)
- || sysno == __NR_sigreturn
+ ||
+ sysno == __NR_sigreturn
#endif
) {
return ErrorCode(ErrorCode::ERR_ALLOWED);
} else if (sysno == __NR_getpid) {
// Disallow getpid()
return ErrorCode(EPERM);
- } else if (Sandbox::IsValidSyscallNumber(sysno)) {
+ } else if (SandboxBPF::IsValidSyscallNumber(sysno)) {
// Allow (and count) all other system calls.
- return sandbox->UnsafeTrap(CountSyscalls, aux);
+ return sandbox->UnsafeTrap(CountSyscalls, aux);
} else {
return ErrorCode(ENOSYS);
}
}
-BPF_TEST(SandboxBpf, GreyListedPolicy,
- GreyListedPolicy, int /* BPF_AUX */) {
+BPF_TEST(SandboxBPF, GreyListedPolicy, GreyListedPolicy, int /* BPF_AUX */) {
BPF_ASSERT(syscall(__NR_getpid) == -1);
BPF_ASSERT(errno == EPERM);
BPF_ASSERT(BPF_AUX == 0);
BPF_ASSERT(syscall(__NR_geteuid) == syscall(__NR_getuid));
BPF_ASSERT(BPF_AUX == 2);
- char name[17] = { };
- BPF_ASSERT(!syscall(__NR_prctl, PR_GET_NAME, name, (void *)NULL,
- (void *)NULL, (void *)NULL));
+ char name[17] = {};
+ BPF_ASSERT(!syscall(__NR_prctl,
+ PR_GET_NAME,
+ name,
+ (void*)NULL,
+ (void*)NULL,
+ (void*)NULL));
BPF_ASSERT(BPF_AUX == 3);
BPF_ASSERT(*name);
}
-SANDBOX_TEST(SandboxBpf, EnableUnsafeTrapsInSigSysHandler) {
+SANDBOX_TEST(SandboxBPF, EnableUnsafeTrapsInSigSysHandler) {
// Disabling warning messages that could confuse our test framework.
setenv(kSandboxDebuggingEnv, "t", 0);
Die::SuppressInfoMessages(true);
@@ -500,25 +509,24 @@ SANDBOX_TEST(SandboxBpf, EnableUnsafeTrapsInSigSysHandler) {
SANDBOX_ASSERT(Trap::EnableUnsafeTrapsInSigSysHandler() == true);
}
-intptr_t PrctlHandler(const struct arch_seccomp_data& args, void *) {
- if (args.args[0] == PR_CAPBSET_DROP &&
- static_cast<int>(args.args[1]) == -1) {
+intptr_t PrctlHandler(const struct arch_seccomp_data& args, void*) {
+ if (args.args[0] == PR_CAPBSET_DROP && static_cast<int>(args.args[1]) == -1) {
// prctl(PR_CAPBSET_DROP, -1) is never valid. The kernel will always
// return an error. But our handler allows this call.
return 0;
} else {
- return Sandbox::ForwardSyscall(args);
+ return SandboxBPF::ForwardSyscall(args);
}
}
-ErrorCode PrctlPolicy(Sandbox *sandbox, int sysno, void *aux) {
+ErrorCode PrctlPolicy(SandboxBPF* sandbox, int sysno, void* aux) {
setenv(kSandboxDebuggingEnv, "t", 0);
Die::SuppressInfoMessages(true);
if (sysno == __NR_prctl) {
// Handle prctl() inside an UnsafeTrap()
return sandbox->UnsafeTrap(PrctlHandler, NULL);
- } else if (Sandbox::IsValidSyscallNumber(sysno)) {
+ } else if (SandboxBPF::IsValidSyscallNumber(sysno)) {
// Allow all other system calls.
return ErrorCode(ErrorCode::ERR_ALLOWED);
} else {
@@ -526,50 +534,55 @@ ErrorCode PrctlPolicy(Sandbox *sandbox, int sysno, void *aux) {
}
}
-BPF_TEST(SandboxBpf, ForwardSyscall, PrctlPolicy) {
+BPF_TEST(SandboxBPF, ForwardSyscall, PrctlPolicy) {
// This call should never be allowed. But our policy will intercept it and
// let it pass successfully.
- BPF_ASSERT(!prctl(PR_CAPBSET_DROP, -1, (void *)NULL, (void *)NULL,
- (void *)NULL));
+ BPF_ASSERT(
+ !prctl(PR_CAPBSET_DROP, -1, (void*)NULL, (void*)NULL, (void*)NULL));
// Verify that the call will fail, if it makes it all the way to the kernel.
- BPF_ASSERT(prctl(PR_CAPBSET_DROP, -2, (void *)NULL, (void *)NULL,
- (void *)NULL) == -1);
+ BPF_ASSERT(
+ prctl(PR_CAPBSET_DROP, -2, (void*)NULL, (void*)NULL, (void*)NULL) == -1);
// And verify that other uses of prctl() work just fine.
- char name[17] = { };
- BPF_ASSERT(!syscall(__NR_prctl, PR_GET_NAME, name, (void *)NULL,
- (void *)NULL, (void *)NULL));
+ char name[17] = {};
+ BPF_ASSERT(!syscall(__NR_prctl,
+ PR_GET_NAME,
+ name,
+ (void*)NULL,
+ (void*)NULL,
+ (void*)NULL));
BPF_ASSERT(*name);
// Finally, verify that system calls other than prctl() are completely
// unaffected by our policy.
- struct utsname uts = { };
+ struct utsname uts = {};
BPF_ASSERT(!uname(&uts));
BPF_ASSERT(!strcmp(uts.sysname, "Linux"));
}
-intptr_t AllowRedirectedSyscall(const struct arch_seccomp_data& args, void *) {
- return Sandbox::ForwardSyscall(args);
+intptr_t AllowRedirectedSyscall(const struct arch_seccomp_data& args, void*) {
+ return SandboxBPF::ForwardSyscall(args);
}
-ErrorCode RedirectAllSyscallsPolicy(Sandbox *sandbox, int sysno, void *aux) {
+ErrorCode RedirectAllSyscallsPolicy(SandboxBPF* sandbox, int sysno, void* aux) {
setenv(kSandboxDebuggingEnv, "t", 0);
Die::SuppressInfoMessages(true);
// Some system calls must always be allowed, if our policy wants to make
// use of UnsafeTrap()
- if (sysno == __NR_rt_sigprocmask ||
- sysno == __NR_rt_sigreturn
+ if (sysno == __NR_rt_sigprocmask || sysno == __NR_rt_sigreturn
#if defined(__NR_sigprocmask)
- || sysno == __NR_sigprocmask
+ ||
+ sysno == __NR_sigprocmask
#endif
#if defined(__NR_sigreturn)
- || sysno == __NR_sigreturn
+ ||
+ sysno == __NR_sigreturn
#endif
) {
return ErrorCode(ErrorCode::ERR_ALLOWED);
- } else if (Sandbox::IsValidSyscallNumber(sysno)) {
+ } else if (SandboxBPF::IsValidSyscallNumber(sysno)) {
return sandbox->UnsafeTrap(AllowRedirectedSyscall, aux);
} else {
return ErrorCode(ENOSYS);
@@ -578,11 +591,11 @@ ErrorCode RedirectAllSyscallsPolicy(Sandbox *sandbox, int sysno, void *aux) {
int bus_handler_fd_ = -1;
-void SigBusHandler(int, siginfo_t *info, void *void_context) {
+void SigBusHandler(int, siginfo_t* info, void* void_context) {
BPF_ASSERT(write(bus_handler_fd_, "\x55", 1) == 1);
}
-BPF_TEST(SandboxBpf, SigBus, RedirectAllSyscallsPolicy) {
+BPF_TEST(SandboxBPF, SigBus, RedirectAllSyscallsPolicy) {
// We use the SIGBUS bit in the signal mask as a thread-local boolean
// value in the implementation of UnsafeTrap(). This is obviously a bit
// of a hack that could conceivably interfere with code that uses SIGBUS
@@ -593,7 +606,7 @@ BPF_TEST(SandboxBpf, SigBus, RedirectAllSyscallsPolicy) {
int fds[2];
BPF_ASSERT(pipe(fds) == 0);
bus_handler_fd_ = fds[1];
- struct sigaction sa = { };
+ struct sigaction sa = {};
sa.sa_sigaction = SigBusHandler;
sa.sa_flags = SA_SIGINFO;
BPF_ASSERT(sigaction(SIGBUS, &sa, NULL) == 0);
@@ -605,7 +618,7 @@ BPF_TEST(SandboxBpf, SigBus, RedirectAllSyscallsPolicy) {
BPF_ASSERT(c == 0x55);
}
-BPF_TEST(SandboxBpf, SigMask, RedirectAllSyscallsPolicy) {
+BPF_TEST(SandboxBPF, SigMask, RedirectAllSyscallsPolicy) {
// Signal masks are potentially tricky to handle. For instance, if we
// ever tried to update them from inside a Trap() or UnsafeTrap() handler,
// the call to sigreturn() at the end of the signal handler would undo
@@ -629,10 +642,10 @@ BPF_TEST(SandboxBpf, SigMask, RedirectAllSyscallsPolicy) {
sigaddset(&mask0, SIGUSR2);
BPF_ASSERT(!sigprocmask(SIG_BLOCK, &mask0, NULL));
BPF_ASSERT(!sigprocmask(SIG_BLOCK, NULL, &mask2));
- BPF_ASSERT( sigismember(&mask2, SIGUSR2));
+ BPF_ASSERT(sigismember(&mask2, SIGUSR2));
}
-BPF_TEST(SandboxBpf, UnsafeTrapWithErrno, RedirectAllSyscallsPolicy) {
+BPF_TEST(SandboxBPF, UnsafeTrapWithErrno, RedirectAllSyscallsPolicy) {
// An UnsafeTrap() (or for that matter, a Trap()) has to report error
// conditions by returning an exit code in the range -1..-4096. This
// should happen automatically if using ForwardSyscall(). If the TrapFnc()
@@ -650,10 +663,10 @@ BPF_TEST(SandboxBpf, UnsafeTrapWithErrno, RedirectAllSyscallsPolicy) {
// would make system calls, but it allows us to verify that we don't
// accidentally mess with errno, when we shouldn't.
errno = 0;
- struct arch_seccomp_data args = { };
- args.nr = __NR_close;
+ struct arch_seccomp_data args = {};
+ args.nr = __NR_close;
args.args[0] = -1;
- BPF_ASSERT(Sandbox::ForwardSyscall(args) == -EBADF);
+ BPF_ASSERT(SandboxBPF::ForwardSyscall(args) == -EBADF);
BPF_ASSERT(errno == 0);
}
@@ -666,8 +679,8 @@ class InitializedOpenBroker {
allowed_files.push_back("/proc/allowed");
allowed_files.push_back("/proc/cpuinfo");
- broker_process_.reset(new BrokerProcess(allowed_files,
- std::vector<std::string>()));
+ broker_process_.reset(
+ new BrokerProcess(EPERM, allowed_files, std::vector<std::string>()));
BPF_ASSERT(broker_process() != NULL);
BPF_ASSERT(broker_process_->Init(NULL));
@@ -675,6 +688,7 @@ class InitializedOpenBroker {
}
bool initialized() { return initialized_; }
class BrokerProcess* broker_process() { return broker_process_.get(); }
+
private:
bool initialized_;
scoped_ptr<class BrokerProcess> broker_process_;
@@ -682,31 +696,31 @@ class InitializedOpenBroker {
};
intptr_t BrokerOpenTrapHandler(const struct arch_seccomp_data& args,
- void *aux) {
+ void* aux) {
BPF_ASSERT(aux);
BrokerProcess* broker_process = static_cast<BrokerProcess*>(aux);
- switch(args.nr) {
+ switch (args.nr) {
case __NR_access:
return broker_process->Access(reinterpret_cast<const char*>(args.args[0]),
- static_cast<int>(args.args[1]));
+ static_cast<int>(args.args[1]));
case __NR_open:
return broker_process->Open(reinterpret_cast<const char*>(args.args[0]),
- static_cast<int>(args.args[1]));
+ static_cast<int>(args.args[1]));
case __NR_openat:
// We only call open() so if we arrive here, it's because glibc uses
// the openat() system call.
BPF_ASSERT(static_cast<int>(args.args[0]) == AT_FDCWD);
return broker_process->Open(reinterpret_cast<const char*>(args.args[1]),
- static_cast<int>(args.args[2]));
+ static_cast<int>(args.args[2]));
default:
BPF_ASSERT(false);
return -ENOSYS;
}
}
-ErrorCode DenyOpenPolicy(Sandbox *sandbox, int sysno, void *aux) {
+ErrorCode DenyOpenPolicy(SandboxBPF* sandbox, int sysno, void* aux) {
InitializedOpenBroker* iob = static_cast<InitializedOpenBroker*>(aux);
- if (!Sandbox::IsValidSyscallNumber(sysno)) {
+ if (!SandboxBPF::IsValidSyscallNumber(sysno)) {
return ErrorCode(ENOSYS);
}
@@ -716,8 +730,8 @@ ErrorCode DenyOpenPolicy(Sandbox *sandbox, int sysno, void *aux) {
case __NR_openat:
// We get a InitializedOpenBroker class, but our trap handler wants
// the BrokerProcess object.
- return ErrorCode(sandbox->Trap(BrokerOpenTrapHandler,
- iob->broker_process()));
+ return ErrorCode(
+ sandbox->Trap(BrokerOpenTrapHandler, iob->broker_process()));
default:
return ErrorCode(ErrorCode::ERR_ALLOWED);
}
@@ -725,10 +739,12 @@ ErrorCode DenyOpenPolicy(Sandbox *sandbox, int sysno, void *aux) {
// We use a InitializedOpenBroker class, so that we can run unsandboxed
// code in its constructor, which is the only way to do so in a BPF_TEST.
-BPF_TEST(SandboxBpf, UseOpenBroker, DenyOpenPolicy,
+BPF_TEST(SandboxBPF,
+ UseOpenBroker,
+ DenyOpenPolicy,
InitializedOpenBroker /* BPF_AUX */) {
BPF_ASSERT(BPF_AUX.initialized());
- BrokerProcess* broker_process = BPF_AUX.broker_process();
+ BrokerProcess* broker_process = BPF_AUX.broker_process();
BPF_ASSERT(broker_process != NULL);
// First, use the broker "manually"
@@ -768,10 +784,10 @@ BPF_TEST(SandboxBpf, UseOpenBroker, DenyOpenPolicy,
BPF_ASSERT(read(cpu_info_fd, buf, sizeof(buf)) > 0);
}
-// Simple test demonstrating how to use Sandbox::Cond()
+// Simple test demonstrating how to use SandboxBPF::Cond()
-ErrorCode SimpleCondTestPolicy(Sandbox *sandbox, int sysno, void *) {
- if (!Sandbox::IsValidSyscallNumber(sysno)) {
+ErrorCode SimpleCondTestPolicy(SandboxBPF* sandbox, int sysno, void*) {
+ if (!SandboxBPF::IsValidSyscallNumber(sysno)) {
// FIXME: we should really not have to do that in a trivial policy
return ErrorCode(ENOSYS);
}
@@ -783,26 +799,32 @@ ErrorCode SimpleCondTestPolicy(Sandbox *sandbox, int sysno, void *) {
case __NR_open:
// 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(1, ErrorCode::TP_32BIT, ErrorCode::OP_HAS_ANY_BITS,
+ return sandbox->Cond(1,
+ ErrorCode::TP_32BIT,
+ ErrorCode::OP_HAS_ANY_BITS,
O_ACCMODE /* 0x3 */,
ErrorCode(EROFS),
ErrorCode(ErrorCode::ERR_ALLOWED));
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,
+ 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)));
+ sandbox->Cond(0,
+ ErrorCode::TP_32BIT,
+ ErrorCode::OP_EQUAL,
+ PR_GET_DUMPABLE,
+ ErrorCode(ErrorCode::ERR_ALLOWED),
+ ErrorCode(ENOMEM)));
default:
return ErrorCode(ErrorCode::ERR_ALLOWED);
}
}
-BPF_TEST(SandboxBpf, SimpleCondTest, SimpleCondTestPolicy) {
+BPF_TEST(SandboxBPF, SimpleCondTest, SimpleCondTestPolicy) {
int fd;
BPF_ASSERT((fd = open("/proc/self/comm", O_RDWR)) == -1);
BPF_ASSERT(errno == EROFS);
@@ -811,12 +833,12 @@ BPF_TEST(SandboxBpf, SimpleCondTest, SimpleCondTestPolicy) {
int ret;
BPF_ASSERT((ret = prctl(PR_GET_DUMPABLE)) >= 0);
- BPF_ASSERT(prctl(PR_SET_DUMPABLE, 1-ret) == 0);
+ BPF_ASSERT(prctl(PR_SET_DUMPABLE, 1 - ret) == 0);
BPF_ASSERT(prctl(PR_GET_ENDIAN, &ret) == -1);
BPF_ASSERT(errno == ENOMEM);
}
-// This test exercises the Sandbox::Cond() method by building a complex
+// This test exercises the SandboxBPF::Cond() method by building a complex
// tree of conditional equality operations. It then makes system calls and
// verifies that they return the values that we expected from our BPF
// program.
@@ -831,8 +853,9 @@ class EqualityStressTest {
// We are actually constructing a graph of ArgValue objects. This
// graph will later be used to a) compute our sandbox policy, and
// b) drive the code that verifies the output from the BPF program.
- COMPILE_ASSERT(kNumTestCases < (int)(MAX_PUBLIC_SYSCALL-MIN_SYSCALL-10),
- num_test_cases_must_be_significantly_smaller_than_num_system_calls);
+ COMPILE_ASSERT(
+ kNumTestCases < (int)(MAX_PUBLIC_SYSCALL - MIN_SYSCALL - 10),
+ num_test_cases_must_be_significantly_smaller_than_num_system_calls);
for (int sysno = MIN_SYSCALL, end = kNumTestCases; sysno < end; ++sysno) {
if (IsReservedSyscall(sysno)) {
// Skip reserved system calls. This ensures that our test frame
@@ -841,22 +864,22 @@ class EqualityStressTest {
++end;
arg_values_.push_back(NULL);
} else {
- arg_values_.push_back(RandomArgValue(rand() % kMaxArgs, 0,
- rand() % kMaxArgs));
+ arg_values_.push_back(
+ RandomArgValue(rand() % kMaxArgs, 0, rand() % kMaxArgs));
}
}
}
~EqualityStressTest() {
- for (std::vector<ArgValue *>::iterator iter = arg_values_.begin();
+ for (std::vector<ArgValue*>::iterator iter = arg_values_.begin();
iter != arg_values_.end();
++iter) {
DeleteArgValue(*iter);
}
}
- ErrorCode Policy(Sandbox *sandbox, int sysno) {
- if (!Sandbox::IsValidSyscallNumber(sysno)) {
+ ErrorCode Policy(SandboxBPF* sandbox, int sysno) {
+ if (!SandboxBPF::IsValidSyscallNumber(sysno)) {
// FIXME: we should really not have to do that in a trivial policy
return ErrorCode(ENOSYS);
} else if (sysno < 0 || sysno >= (int)arg_values_.size() ||
@@ -887,22 +910,22 @@ class EqualityStressTest {
// We arbitrarily start by setting all six system call arguments to
// zero. And we then recursive traverse our tree of ArgValues to
// determine the necessary combinations of parameters.
- intptr_t args[6] = { };
+ intptr_t args[6] = {};
Verify(sysno, args, *arg_values_[sysno]);
}
}
private:
struct ArgValue {
- int argno; // Argument number to inspect.
- int size; // Number of test cases (must be > 0).
+ int argno; // Argument number to inspect.
+ int size; // Number of test cases (must be > 0).
struct Tests {
uint32_t k_value; // Value to compare syscall arg against.
- int err; // If non-zero, errno value to return.
- struct ArgValue *arg_value; // Otherwise, more args needs inspecting.
- } *tests;
- int err; // If none of the tests passed, this is what
- struct ArgValue *arg_value; // we'll return (this is the "else" branch).
+ int err; // If non-zero, errno value to return.
+ struct ArgValue* arg_value; // Otherwise, more args needs inspecting.
+ }* tests;
+ int err; // If none of the tests passed, this is what
+ struct ArgValue* arg_value; // we'll return (this is the "else" branch).
};
bool IsReservedSyscall(int sysno) {
@@ -916,41 +939,38 @@ class EqualityStressTest {
// calls that will be made by this particular test. So, this small list is
// sufficient. But if anybody copy'n'pasted this code for other uses, they
// would have to review that the list.
- return sysno == __NR_read ||
- sysno == __NR_write ||
- sysno == __NR_exit ||
- sysno == __NR_exit_group ||
- sysno == __NR_restart_syscall;
+ return sysno == __NR_read || sysno == __NR_write || sysno == __NR_exit ||
+ sysno == __NR_exit_group || sysno == __NR_restart_syscall;
}
- ArgValue *RandomArgValue(int argno, int args_mask, int remaining_args) {
+ ArgValue* RandomArgValue(int argno, int args_mask, int remaining_args) {
// Create a new ArgValue and fill it with random data. We use as bit mask
// to keep track of the system call parameters that have previously been
// set; this ensures that we won't accidentally define a contradictory
// set of equality tests.
- struct ArgValue *arg_value = new ArgValue();
- args_mask |= 1 << argno;
- arg_value->argno = argno;
+ struct ArgValue* arg_value = new ArgValue();
+ args_mask |= 1 << argno;
+ arg_value->argno = argno;
// Apply some restrictions on just how complex our tests can be.
// Otherwise, we end up with a BPF program that is too complicated for
// the kernel to load.
- int fan_out = kMaxFanOut;
+ int fan_out = kMaxFanOut;
if (remaining_args > 3) {
- fan_out = 1;
+ fan_out = 1;
} else if (remaining_args > 2) {
- fan_out = 2;
+ fan_out = 2;
}
// Create a couple of different test cases with randomized values that
// we want to use when comparing system call parameter number "argno".
- arg_value->size = rand() % fan_out + 1;
- arg_value->tests = new ArgValue::Tests[arg_value->size];
+ arg_value->size = rand() % fan_out + 1;
+ arg_value->tests = new ArgValue::Tests[arg_value->size];
- uint32_t k_value = rand();
+ uint32_t k_value = rand();
for (int n = 0; n < arg_value->size; ++n) {
// Ensure that we have unique values
- k_value += rand() % (RAND_MAX/(kMaxFanOut+1)) + 1;
+ k_value += rand() % (RAND_MAX / (kMaxFanOut + 1)) + 1;
// There are two possible types of nodes. Either this is a leaf node;
// in that case, we have completed all the equality tests that we
@@ -966,7 +986,7 @@ class EqualityStressTest {
} else {
arg_value->tests[n].err = 0;
arg_value->tests[n].arg_value =
- RandomArgValue(RandomArg(args_mask), args_mask, remaining_args - 1);
+ RandomArgValue(RandomArg(args_mask), args_mask, remaining_args - 1);
}
}
// Finally, we have to define what we should return if none of the
@@ -978,7 +998,7 @@ class EqualityStressTest {
} else {
arg_value->err = 0;
arg_value->arg_value =
- RandomArgValue(RandomArg(args_mask), args_mask, remaining_args - 1);
+ RandomArgValue(RandomArg(args_mask), args_mask, remaining_args - 1);
}
// We have now built a new (sub-)tree of ArgValues defining a set of
// boolean expressions for testing random system call arguments against
@@ -999,7 +1019,7 @@ class EqualityStressTest {
return argno;
}
- void DeleteArgValue(ArgValue *arg_value) {
+ void DeleteArgValue(ArgValue* arg_value) {
// Delete an ArgValue and all of its child nodes. This requires
// recursively descending into the tree.
if (arg_value) {
@@ -1018,7 +1038,7 @@ class EqualityStressTest {
}
}
- ErrorCode ToErrorCode(Sandbox *sandbox, ArgValue *arg_value) {
+ ErrorCode ToErrorCode(SandboxBPF* sandbox, ArgValue* arg_value) {
// Compute the ErrorCode that should be returned, if none of our
// tests succeed (i.e. the system call parameter doesn't match any
// of the values in arg_value->tests[].k_value).
@@ -1029,15 +1049,15 @@ class EqualityStressTest {
err = ErrorCode(arg_value->err);
} else {
// If this wasn't a leaf node yet, recursively descend into the rest
- // of the tree. This will end up adding a few more Sandbox::Cond()
+ // of the tree. This will end up adding a few more SandboxBPF::Cond()
// tests to our ErrorCode.
err = ToErrorCode(sandbox, arg_value->arg_value);
}
// Now, iterate over all the test cases that we want to compare against.
- // This builds a chain of Sandbox::Cond() tests
+ // This builds a chain of SandboxBPF::Cond() tests
// (aka "if ... elif ... elif ... elif ... fi")
- for (int n = arg_value->size; n-- > 0; ) {
+ for (int n = arg_value->size; n-- > 0;) {
ErrorCode matched;
// Again, we distinguish between leaf nodes and subtrees.
if (arg_value->tests[n].err) {
@@ -1048,19 +1068,22 @@ class EqualityStressTest {
// For now, all of our tests are limited to 32bit.
// We have separate tests that check the behavior of 32bit vs. 64bit
// conditional expressions.
- err = sandbox->Cond(arg_value->argno, ErrorCode::TP_32BIT,
- ErrorCode::OP_EQUAL, arg_value->tests[n].k_value,
- matched, err);
+ err = sandbox->Cond(arg_value->argno,
+ ErrorCode::TP_32BIT,
+ ErrorCode::OP_EQUAL,
+ arg_value->tests[n].k_value,
+ matched,
+ err);
}
return err;
}
- void Verify(int sysno, intptr_t *args, const ArgValue& arg_value) {
+ void Verify(int sysno, intptr_t* args, const ArgValue& arg_value) {
uint32_t mismatched = 0;
// Iterate over all the k_values in arg_value.tests[] and verify that
// we see the expected return values from system calls, when we pass
// the k_value as a parameter in a system call.
- for (int n = arg_value.size; n-- > 0; ) {
+ for (int n = arg_value.size; n-- > 0;) {
mismatched += arg_value.tests[n].k_value;
args[arg_value.argno] = arg_value.tests[n].k_value;
if (arg_value.tests[n].err) {
@@ -1069,12 +1092,12 @@ class EqualityStressTest {
Verify(sysno, args, *arg_value.tests[n].arg_value);
}
}
- // Find a k_value that doesn't match any of the k_values in
- // arg_value.tests[]. In most cases, the current value of "mismatched"
- // would fit this requirement. But on the off-chance that it happens
- // to collide, we double-check.
+ // Find a k_value that doesn't match any of the k_values in
+ // arg_value.tests[]. In most cases, the current value of "mismatched"
+ // would fit this requirement. But on the off-chance that it happens
+ // to collide, we double-check.
try_again:
- for (int n = arg_value.size; n-- > 0; ) {
+ for (int n = arg_value.size; n-- > 0;) {
if (mismatched == arg_value.tests[n].k_value) {
++mismatched;
goto try_again;
@@ -1094,61 +1117,75 @@ class EqualityStressTest {
args[arg_value.argno] = 0;
}
- void VerifyErrno(int sysno, intptr_t *args, int err) {
+ void VerifyErrno(int sysno, intptr_t* args, int err) {
// We installed BPF filters that return different errno values
// based on the system call number and the parameters that we decided
// to pass in. Verify that this condition holds true.
- BPF_ASSERT(SandboxSyscall(sysno,
- args[0], args[1], args[2],
- args[3], args[4], args[5]) == -err);
+ BPF_ASSERT(
+ SandboxSyscall(
+ sysno, args[0], args[1], args[2], args[3], args[4], args[5]) ==
+ -err);
}
// Vector of ArgValue trees. These trees define all the possible boolean
// expressions that we want to turn into a BPF filter program.
- std::vector<ArgValue *> arg_values_;
+ std::vector<ArgValue*> arg_values_;
// Don't increase these values. We are pushing the limits of the maximum
// BPF program that the kernel will allow us to load. If the values are
// increased too much, the test will start failing.
- static const int kNumIterations = 3;
static const int kNumTestCases = 40;
static const int kMaxFanOut = 3;
static const int kMaxArgs = 6;
};
-ErrorCode EqualityStressTestPolicy(Sandbox *sandbox, int sysno, void *aux) {
- return reinterpret_cast<EqualityStressTest *>(aux)->Policy(sandbox, sysno);
+ErrorCode EqualityStressTestPolicy(SandboxBPF* sandbox, int sysno, void* aux) {
+ return reinterpret_cast<EqualityStressTest*>(aux)->Policy(sandbox, sysno);
}
-BPF_TEST(SandboxBpf, EqualityTests, EqualityStressTestPolicy,
+BPF_TEST(SandboxBPF,
+ EqualityTests,
+ EqualityStressTestPolicy,
EqualityStressTest /* BPF_AUX */) {
BPF_AUX.VerifyFilter();
}
-ErrorCode EqualityArgumentWidthPolicy(Sandbox *sandbox, int sysno, void *) {
- if (!Sandbox::IsValidSyscallNumber(sysno)) {
+ErrorCode EqualityArgumentWidthPolicy(SandboxBPF* sandbox, int sysno, void*) {
+ if (!SandboxBPF::IsValidSyscallNumber(sysno)) {
// FIXME: we should really not have to do that in a trivial policy
return ErrorCode(ENOSYS);
} else 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)));
+ 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)));
} else {
return ErrorCode(ErrorCode::ERR_ALLOWED);
}
}
-BPF_TEST(SandboxBpf, EqualityArgumentWidth, EqualityArgumentWidthPolicy) {
+BPF_TEST(SandboxBPF, EqualityArgumentWidth, EqualityArgumentWidthPolicy) {
BPF_ASSERT(SandboxSyscall(__NR_uname, 0, 0x55555555) == -1);
BPF_ASSERT(SandboxSyscall(__NR_uname, 0, 0xAAAAAAAA) == -2);
#if __SIZEOF_POINTER__ > 4
@@ -1168,27 +1205,34 @@ BPF_TEST(SandboxBpf, EqualityArgumentWidth, EqualityArgumentWidthPolicy) {
// On 32bit machines, there is no way to pass a 64bit argument through the
// syscall interface. So, we have to skip the part of the test that requires
// 64bit arguments.
-BPF_DEATH_TEST(SandboxBpf, EqualityArgumentUnallowed64bit,
+BPF_DEATH_TEST(SandboxBPF,
+ EqualityArgumentUnallowed64bit,
DEATH_MESSAGE("Unexpected 64bit argument detected"),
EqualityArgumentWidthPolicy) {
SandboxSyscall(__NR_uname, 0, 0x5555555555555555ULL);
}
#endif
-ErrorCode EqualityWithNegativeArgumentsPolicy(Sandbox *sandbox, int sysno,
- void *) {
- if (!Sandbox::IsValidSyscallNumber(sysno)) {
+ErrorCode EqualityWithNegativeArgumentsPolicy(SandboxBPF* sandbox,
+ int sysno,
+ void*) {
+ if (!SandboxBPF::IsValidSyscallNumber(sysno)) {
// FIXME: we should really not have to do that in a trivial policy
return ErrorCode(ENOSYS);
} else if (sysno == __NR_uname) {
- return sandbox->Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL,
- 0xFFFFFFFF, ErrorCode(1), ErrorCode(2));
+ return sandbox->Cond(0,
+ ErrorCode::TP_32BIT,
+ ErrorCode::OP_EQUAL,
+ 0xFFFFFFFF,
+ ErrorCode(1),
+ ErrorCode(2));
} else {
return ErrorCode(ErrorCode::ERR_ALLOWED);
}
}
-BPF_TEST(SandboxBpf, EqualityWithNegativeArguments,
+BPF_TEST(SandboxBPF,
+ EqualityWithNegativeArguments,
EqualityWithNegativeArgumentsPolicy) {
BPF_ASSERT(SandboxSyscall(__NR_uname, 0xFFFFFFFF) == -1);
BPF_ASSERT(SandboxSyscall(__NR_uname, -1) == -1);
@@ -1196,7 +1240,8 @@ BPF_TEST(SandboxBpf, EqualityWithNegativeArguments,
}
#if __SIZEOF_POINTER__ > 4
-BPF_DEATH_TEST(SandboxBpf, EqualityWithNegative64bitArguments,
+BPF_DEATH_TEST(SandboxBPF,
+ EqualityWithNegative64bitArguments,
DEATH_MESSAGE("Unexpected 64bit argument detected"),
EqualityWithNegativeArgumentsPolicy) {
// When expecting a 32bit system call argument, we look at the MSB of the
@@ -1205,15 +1250,14 @@ BPF_DEATH_TEST(SandboxBpf, EqualityWithNegative64bitArguments,
BPF_ASSERT(SandboxSyscall(__NR_uname, 0xFFFFFFFF00000000LL) == -1);
}
#endif
-
-ErrorCode AllBitTestPolicy(Sandbox *sandbox, int sysno, void *) {
+ErrorCode AllBitTestPolicy(SandboxBPF* sandbox, int sysno, void *) {
// Test the OP_HAS_ALL_BITS conditional test operator with a couple of
// different bitmasks. 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 (!Sandbox::IsValidSyscallNumber(sysno)) {
+ if (!SandboxBPF::IsValidSyscallNumber(sysno)) {
// FIXME: we should really not have to do that in a trivial policy
return ErrorCode(ENOSYS);
} else if (sysno == __NR_uname) {
@@ -1284,13 +1328,13 @@ ErrorCode AllBitTestPolicy(Sandbox *sandbox, int sysno, void *) {
// Most notably, "op" and "mask" are unused by the macro. If you want
// to make changes to these values, you will have to edit the
// test policy instead.
-#define BITMASK_TEST(testcase, arg, op, mask, expected_value) \
+#define BITMASK_TEST(testcase, arg, op, mask, expected_value) \
BPF_ASSERT(SandboxSyscall(__NR_uname, (testcase), (arg)) == (expected_value))
// Our uname() system call returns ErrorCode(1) for success and
// ErrorCode(0) for failure. SandboxSyscall() turns this into an
// exit code of -1 or 0.
-#define EXPECT_FAILURE 0
+#define EXPECT_FAILURE 0
#define EXPECT_SUCCESS -1
// A couple of our tests behave differently on 32bit and 64bit systems, as
@@ -1298,10 +1342,8 @@ ErrorCode AllBitTestPolicy(Sandbox *sandbox, int sysno, void *) {
// argument "arg".
// We expect these tests to succeed on 64bit systems, but to tail on 32bit
// systems.
-#define EXPT64_SUCCESS \
- (sizeof(void *) > 4 ? EXPECT_SUCCESS : EXPECT_FAILURE)
-
-BPF_TEST(SandboxBpf, AllBitTests, AllBitTestPolicy) {
+#define EXPT64_SUCCESS (sizeof(void*) > 4 ? EXPECT_SUCCESS : EXPECT_FAILURE)
+BPF_TEST(SandboxBPF, AllBitTests, AllBitTestPolicy) {
// 32bit test: all of 0x0 (should always be true)
BITMASK_TEST( 0, 0, ALLBITS32, 0, EXPECT_SUCCESS);
BITMASK_TEST( 0, 1, ALLBITS32, 0, EXPECT_SUCCESS);
@@ -1404,14 +1446,14 @@ BPF_TEST(SandboxBpf, AllBitTests, AllBitTestPolicy) {
BITMASK_TEST(10, -1L, ALLBITS64,0x100000001, EXPT64_SUCCESS);
}
-ErrorCode AnyBitTestPolicy(Sandbox *sandbox, int sysno, void *) {
+ErrorCode AnyBitTestPolicy(SandboxBPF* sandbox, int sysno, void*) {
// Test the OP_HAS_ANY_BITS conditional test operator with a couple of
// different bitmasks. 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 (!Sandbox::IsValidSyscallNumber(sysno)) {
+ if (!SandboxBPF::IsValidSyscallNumber(sysno)) {
// FIXME: we should really not have to do that in a trivial policy
return ErrorCode(ENOSYS);
} else if (sysno == __NR_uname) {
@@ -1478,7 +1520,7 @@ ErrorCode AnyBitTestPolicy(Sandbox *sandbox, int sysno, void *) {
}
}
-BPF_TEST(SandboxBpf, AnyBitTests, AnyBitTestPolicy) {
+BPF_TEST(SandboxBPF, AnyBitTests, AnyBitTestPolicy) {
// 32bit test: any of 0x0 (should always be false)
BITMASK_TEST( 0, 0, ANYBITS32, 0x0, EXPECT_FAILURE);
BITMASK_TEST( 0, 1, ANYBITS32, 0x0, EXPECT_FAILURE);
@@ -1581,36 +1623,39 @@ BPF_TEST(SandboxBpf, AnyBitTests, AnyBitTestPolicy) {
BITMASK_TEST( 10, -1L, ANYBITS64,0x100000001, EXPECT_SUCCESS);
}
-intptr_t PthreadTrapHandler(const struct arch_seccomp_data& args, void *aux) {
- if (args.args[0] != (CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD)) {
+intptr_t PthreadTrapHandler(const struct arch_seccomp_data& args, void* aux) {
+ if (args.args[0] != (CLONE_CHILD_CLEARTID | CLONE_CHILD_SETTID | SIGCHLD)) {
// We expect to get called for an attempt to fork(). No need to log that
// call. But if we ever get called for anything else, we want to verbosely
// print as much information as possible.
- const char *msg = (const char *)aux;
- printf("Clone() was called with unexpected arguments\n"
- " nr: %d\n"
- " 1: 0x%llX\n"
- " 2: 0x%llX\n"
- " 3: 0x%llX\n"
- " 4: 0x%llX\n"
- " 5: 0x%llX\n"
- " 6: 0x%llX\n"
- "%s\n",
- args.nr,
- (long long)args.args[0], (long long)args.args[1],
- (long long)args.args[2], (long long)args.args[3],
- (long long)args.args[4], (long long)args.args[5],
- msg);
+ const char* msg = (const char*)aux;
+ printf(
+ "Clone() was called with unexpected arguments\n"
+ " nr: %d\n"
+ " 1: 0x%llX\n"
+ " 2: 0x%llX\n"
+ " 3: 0x%llX\n"
+ " 4: 0x%llX\n"
+ " 5: 0x%llX\n"
+ " 6: 0x%llX\n"
+ "%s\n",
+ args.nr,
+ (long long)args.args[0],
+ (long long)args.args[1],
+ (long long)args.args[2],
+ (long long)args.args[3],
+ (long long)args.args[4],
+ (long long)args.args[5],
+ msg);
}
return -EPERM;
}
-
-ErrorCode PthreadPolicyEquality(Sandbox *sandbox, int sysno, void *aux) {
+ErrorCode PthreadPolicyEquality(SandboxBPF* sandbox, int sysno, void* aux) {
// This policy allows creating threads with pthread_create(). But it
// doesn't allow any other uses of clone(). Most notably, it does not
// allow callers to implement fork() or vfork() by passing suitable flags
// to the clone() system call.
- if (!Sandbox::IsValidSyscallNumber(sysno)) {
+ if (!SandboxBPF::IsValidSyscallNumber(sysno)) {
// FIXME: we should really not have to do that in a trivial policy
return ErrorCode(ENOSYS);
} else if (sysno == __NR_clone) {
@@ -1618,30 +1663,39 @@ ErrorCode PthreadPolicyEquality(Sandbox *sandbox, int sysno, void *aux) {
// uses the more modern flags, sets the TLS from the call to clone(), and
// uses futexes to monitor threads. Android's C run-time library, doesn't
// do any of this, but it sets the obsolete (and no-op) CLONE_DETACHED.
+ // More recent versions of Android don't set CLONE_DETACHED anymore, so
+ // the last case accounts for that.
// 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,
- CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|
- CLONE_THREAD|CLONE_SYSVSEM|CLONE_SETTLS|
- CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTID,
+ kGlibcCloneMask,
ErrorCode(ErrorCode::ERR_ALLOWED),
sandbox->Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL,
- CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|
- CLONE_THREAD|CLONE_SYSVSEM|CLONE_DETACHED,
+ kBaseAndroidCloneMask | CLONE_DETACHED,
ErrorCode(ErrorCode::ERR_ALLOWED),
- sandbox->Trap(PthreadTrapHandler, aux)));
+ sandbox->Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL,
+ kBaseAndroidCloneMask,
+ ErrorCode(ErrorCode::ERR_ALLOWED),
+ sandbox->Trap(PthreadTrapHandler, "Unknown mask"))));
} else {
return ErrorCode(ErrorCode::ERR_ALLOWED);
}
}
-ErrorCode PthreadPolicyBitMask(Sandbox *sandbox, int sysno, void *aux) {
+ErrorCode PthreadPolicyBitMask(SandboxBPF* sandbox, int sysno, void* aux) {
// This policy allows creating threads with pthread_create(). But it
// doesn't allow any other uses of clone(). Most notably, it does not
// allow callers to implement fork() or vfork() by passing suitable flags
// to the clone() system call.
- if (!Sandbox::IsValidSyscallNumber(sysno)) {
+ if (!SandboxBPF::IsValidSyscallNumber(sysno)) {
// FIXME: we should really not have to do that in a trivial policy
return ErrorCode(ENOSYS);
} else if (sysno == __NR_clone) {
@@ -1681,8 +1735,8 @@ ErrorCode PthreadPolicyBitMask(Sandbox *sandbox, int sysno, void *aux) {
}
}
-static void *ThreadFnc(void *arg) {
- ++*reinterpret_cast<int *>(arg);
+static void* ThreadFnc(void* arg) {
+ ++*reinterpret_cast<int*>(arg);
SandboxSyscall(__NR_futex, arg, FUTEX_WAKE, 1, 0, 0, 0);
return NULL;
}
@@ -1702,8 +1756,8 @@ static void PthreadTest() {
BPF_ASSERT(!pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED));
BPF_ASSERT(!pthread_create(&thread, &attr, ThreadFnc, &thread_ran));
BPF_ASSERT(!pthread_attr_destroy(&attr));
- while (SandboxSyscall(__NR_futex, &thread_ran, FUTEX_WAIT,
- 0, 0, 0, 0) == -EINTR) {
+ while (SandboxSyscall(__NR_futex, &thread_ran, FUTEX_WAIT, 0, 0, 0, 0) ==
+ -EINTR) {
}
BPF_ASSERT(thread_ran);
@@ -1714,16 +1768,16 @@ static void PthreadTest() {
// __NR_clone, and that would introduce a bogus test failure.
int pid;
BPF_ASSERT(SandboxSyscall(__NR_clone,
- CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD,
- 0, 0, &pid) == -EPERM);
+ CLONE_CHILD_CLEARTID | CLONE_CHILD_SETTID | SIGCHLD,
+ 0,
+ 0,
+ &pid) == -EPERM);
}
-BPF_TEST(SandboxBpf, PthreadEquality, PthreadPolicyEquality) {
- PthreadTest();
-}
+BPF_TEST(SandboxBPF, PthreadEquality, PthreadPolicyEquality) { PthreadTest(); }
-BPF_TEST(SandboxBpf, PthreadBitMask, PthreadPolicyBitMask) {
- PthreadTest();
-}
+BPF_TEST(SandboxBPF, PthreadBitMask, PthreadPolicyBitMask) { PthreadTest(); }
+
+} // namespace
-} // namespace
+} // namespace sandbox