Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(498)

Side by Side Diff: sandbox/linux/seccomp-bpf/sandbox_bpf_unittest.cc

Issue 11411254: SECCOMP-BPF: Added supported for inspection system call arguments from BPF filters. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Another attempt at fixing the rebase Created 8 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « sandbox/linux/seccomp-bpf/sandbox_bpf.cc ('k') | sandbox/linux/seccomp-bpf/syscall_iterator.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include <sys/prctl.h> 5 #include <sys/prctl.h>
6 #include <sys/utsname.h> 6 #include <sys/utsname.h>
7 7
8 #include <ostream> 8 #include <ostream>
9 9
10 #include "base/memory/scoped_ptr.h" 10 #include "base/memory/scoped_ptr.h"
11 #include "sandbox/linux/seccomp-bpf/bpf_tests.h" 11 #include "sandbox/linux/seccomp-bpf/bpf_tests.h"
12 #include "sandbox/linux/seccomp-bpf/syscall.h"
12 #include "sandbox/linux/seccomp-bpf/verifier.h" 13 #include "sandbox/linux/seccomp-bpf/verifier.h"
13 #include "sandbox/linux/services/broker_process.h" 14 #include "sandbox/linux/services/broker_process.h"
14 #include "testing/gtest/include/gtest/gtest.h" 15 #include "testing/gtest/include/gtest/gtest.h"
15 16
16 using namespace playground2; 17 using namespace playground2;
17 using sandbox::BrokerProcess; 18 using sandbox::BrokerProcess;
18 19
19 namespace { 20 namespace {
20 21
21 const int kExpectedReturnValue = 42; 22 const int kExpectedReturnValue = 42;
22 23
23 // This test should execute no matter whether we have kernel support. So, 24 // This test should execute no matter whether we have kernel support. So,
24 // we make it a TEST() instead of a BPF_TEST(). 25 // we make it a TEST() instead of a BPF_TEST().
25 TEST(SandboxBpf, CallSupports) { 26 TEST(SandboxBpf, CallSupports) {
26 // We check that we don't crash, but it's ok if the kernel doesn't 27 // We check that we don't crash, but it's ok if the kernel doesn't
27 // support it. 28 // support it.
28 bool seccomp_bpf_supported = 29 bool seccomp_bpf_supported =
29 Sandbox::supportsSeccompSandbox(-1) == Sandbox::STATUS_AVAILABLE; 30 Sandbox::SupportsSeccompSandbox(-1) == Sandbox::STATUS_AVAILABLE;
30 // We want to log whether or not seccomp BPF is actually supported 31 // We want to log whether or not seccomp BPF is actually supported
31 // since actual test coverage depends on it. 32 // since actual test coverage depends on it.
32 RecordProperty("SeccompBPFSupported", 33 RecordProperty("SeccompBPFSupported",
33 seccomp_bpf_supported ? "true." : "false."); 34 seccomp_bpf_supported ? "true." : "false.");
34 std::cout << "Seccomp BPF supported: " 35 std::cout << "Seccomp BPF supported: "
35 << (seccomp_bpf_supported ? "true." : "false.") 36 << (seccomp_bpf_supported ? "true." : "false.")
36 << "\n"; 37 << "\n";
37 RecordProperty("PointerSize", sizeof(void*)); 38 RecordProperty("PointerSize", sizeof(void*));
38 std::cout << "Pointer size: " << sizeof(void*) << "\n"; 39 std::cout << "Pointer size: " << sizeof(void*) << "\n";
39 } 40 }
40 41
41 SANDBOX_TEST(SandboxBpf, CallSupportsTwice) { 42 SANDBOX_TEST(SandboxBpf, CallSupportsTwice) {
42 Sandbox::supportsSeccompSandbox(-1); 43 Sandbox::SupportsSeccompSandbox(-1);
43 Sandbox::supportsSeccompSandbox(-1); 44 Sandbox::SupportsSeccompSandbox(-1);
44 } 45 }
45 46
46 // BPF_TEST does a lot of the boiler-plate code around setting up a 47 // BPF_TEST does a lot of the boiler-plate code around setting up a
47 // policy and optional passing data between the caller, the policy and 48 // policy and optional passing data between the caller, the policy and
48 // any Trap() handlers. This is great for writing short and concise tests, 49 // any Trap() handlers. This is great for writing short and concise tests,
49 // and it helps us accidentally forgetting any of the crucial steps in 50 // and it helps us accidentally forgetting any of the crucial steps in
50 // setting up the sandbox. But it wouldn't hurt to have at least one test 51 // setting up the sandbox. But it wouldn't hurt to have at least one test
51 // that explicitly walks through all these steps. 52 // that explicitly walks through all these steps.
52 53
53 intptr_t FakeGetPid(const struct arch_seccomp_data& args, void *aux) { 54 intptr_t FakeGetPid(const struct arch_seccomp_data& args, void *aux) {
54 BPF_ASSERT(aux); 55 BPF_ASSERT(aux);
55 pid_t *pid_ptr = static_cast<pid_t *>(aux); 56 pid_t *pid_ptr = static_cast<pid_t *>(aux);
56 return (*pid_ptr)++; 57 return (*pid_ptr)++;
57 } 58 }
58 59
59 ErrorCode VerboseAPITestingPolicy(int sysno, void *aux) { 60 ErrorCode VerboseAPITestingPolicy(int sysno, void *aux) {
60 if (!Sandbox::isValidSyscallNumber(sysno)) { 61 if (!Sandbox::IsValidSyscallNumber(sysno)) {
61 return ErrorCode(ENOSYS); 62 return ErrorCode(ENOSYS);
62 } else if (sysno == __NR_getpid) { 63 } else if (sysno == __NR_getpid) {
63 return Sandbox::Trap(FakeGetPid, aux); 64 return Sandbox::Trap(FakeGetPid, aux);
64 } else { 65 } else {
65 return ErrorCode(ErrorCode::ERR_ALLOWED); 66 return ErrorCode(ErrorCode::ERR_ALLOWED);
66 } 67 }
67 } 68 }
68 69
69 SANDBOX_TEST(SandboxBpf, VerboseAPITesting) { 70 SANDBOX_TEST(SandboxBpf, VerboseAPITesting) {
70 if (Sandbox::supportsSeccompSandbox(-1) == 71 if (Sandbox::SupportsSeccompSandbox(-1) ==
71 playground2::Sandbox::STATUS_AVAILABLE) { 72 playground2::Sandbox::STATUS_AVAILABLE) {
72 pid_t test_var = 0; 73 pid_t test_var = 0;
73 playground2::Sandbox::setSandboxPolicy(VerboseAPITestingPolicy, &test_var); 74 playground2::Sandbox::SetSandboxPolicy(VerboseAPITestingPolicy, &test_var);
74 playground2::Sandbox::startSandbox(); 75 playground2::Sandbox::StartSandbox();
75 76
76 BPF_ASSERT(test_var == 0); 77 BPF_ASSERT(test_var == 0);
77 BPF_ASSERT(syscall(__NR_getpid) == 0); 78 BPF_ASSERT(syscall(__NR_getpid) == 0);
78 BPF_ASSERT(test_var == 1); 79 BPF_ASSERT(test_var == 1);
79 BPF_ASSERT(syscall(__NR_getpid) == 1); 80 BPF_ASSERT(syscall(__NR_getpid) == 1);
80 BPF_ASSERT(test_var == 2); 81 BPF_ASSERT(test_var == 2);
81 82
82 // N.B.: Any future call to getpid() would corrupt the stack. 83 // N.B.: Any future call to getpid() would corrupt the stack.
83 // This is OK. The SANDBOX_TEST() macro is guaranteed to 84 // This is OK. The SANDBOX_TEST() macro is guaranteed to
84 // only ever call _exit() after the test completes. 85 // only ever call _exit() after the test completes.
85 } 86 }
86 } 87 }
87 88
88 // A simple blacklist test 89 // A simple blacklist test
89 90
90 ErrorCode BlacklistNanosleepPolicy(int sysno, void *) { 91 ErrorCode BlacklistNanosleepPolicy(int sysno, void *) {
91 if (!Sandbox::isValidSyscallNumber(sysno)) { 92 if (!Sandbox::IsValidSyscallNumber(sysno)) {
92 // FIXME: we should really not have to do that in a trivial policy 93 // FIXME: we should really not have to do that in a trivial policy
93 return ErrorCode(ENOSYS); 94 return ErrorCode(ENOSYS);
94 } 95 }
95 96
96 switch (sysno) { 97 switch (sysno) {
97 case __NR_nanosleep: 98 case __NR_nanosleep:
98 return ErrorCode(EACCES); 99 return ErrorCode(EACCES);
99 default: 100 default:
100 return ErrorCode(ErrorCode::ERR_ALLOWED); 101 return ErrorCode(ErrorCode::ERR_ALLOWED);
101 } 102 }
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
135 // A simple blacklist policy, with a SIGSYS handler 136 // A simple blacklist policy, with a SIGSYS handler
136 137
137 intptr_t EnomemHandler(const struct arch_seccomp_data& args, void *aux) { 138 intptr_t EnomemHandler(const struct arch_seccomp_data& args, void *aux) {
138 // We also check that the auxiliary data is correct 139 // We also check that the auxiliary data is correct
139 SANDBOX_ASSERT(aux); 140 SANDBOX_ASSERT(aux);
140 *(static_cast<int*>(aux)) = kExpectedReturnValue; 141 *(static_cast<int*>(aux)) = kExpectedReturnValue;
141 return -ENOMEM; 142 return -ENOMEM;
142 } 143 }
143 144
144 ErrorCode BlacklistNanosleepPolicySigsys(int sysno, void *aux) { 145 ErrorCode BlacklistNanosleepPolicySigsys(int sysno, void *aux) {
145 if (!Sandbox::isValidSyscallNumber(sysno)) { 146 if (!Sandbox::IsValidSyscallNumber(sysno)) {
146 // FIXME: we should really not have to do that in a trivial policy 147 // FIXME: we should really not have to do that in a trivial policy
147 return ErrorCode(ENOSYS); 148 return ErrorCode(ENOSYS);
148 } 149 }
149 150
150 switch (sysno) { 151 switch (sysno) {
151 case __NR_nanosleep: 152 case __NR_nanosleep:
152 return Sandbox::Trap(EnomemHandler, aux); 153 return Sandbox::Trap(EnomemHandler, aux);
153 default: 154 default:
154 return ErrorCode(ErrorCode::ERR_ALLOWED); 155 return ErrorCode(ErrorCode::ERR_ALLOWED);
155 } 156 }
(...skipping 25 matching lines...) Expand all
181 // sure that the compiler can have an opportunity to coalesce syscalls with 182 // sure that the compiler can have an opportunity to coalesce syscalls with
182 // contiguous numbers and we also make sure that disjoint sets can return the 183 // contiguous numbers and we also make sure that disjoint sets can return the
183 // same errno. 184 // same errno.
184 int SysnoToRandomErrno(int sysno) { 185 int SysnoToRandomErrno(int sysno) {
185 // Small contiguous sets of 3 system calls return an errno equal to the 186 // Small contiguous sets of 3 system calls return an errno equal to the
186 // index of that set + 1 (so that we never return a NUL errno). 187 // index of that set + 1 (so that we never return a NUL errno).
187 return ((sysno & ~3) >> 2) % 29 + 1; 188 return ((sysno & ~3) >> 2) % 29 + 1;
188 } 189 }
189 190
190 ErrorCode SyntheticPolicy(int sysno, void *) { 191 ErrorCode SyntheticPolicy(int sysno, void *) {
191 if (!Sandbox::isValidSyscallNumber(sysno)) { 192 if (!Sandbox::IsValidSyscallNumber(sysno)) {
192 // FIXME: we should really not have to do that in a trivial policy 193 // FIXME: we should really not have to do that in a trivial policy
193 return ErrorCode(ENOSYS); 194 return ErrorCode(ENOSYS);
194 } 195 }
195 196
196 // TODO(jorgelo): remove this once the new code generator lands. 197 // TODO(jorgelo): remove this once the new code generator lands.
197 #if defined(__arm__) 198 #if defined(__arm__)
198 if (sysno > static_cast<int>(MAX_PUBLIC_SYSCALL)) { 199 if (sysno > static_cast<int>(MAX_PUBLIC_SYSCALL)) {
199 return ErrorCode(ENOSYS); 200 return ErrorCode(ENOSYS);
200 } 201 }
201 #endif 202 #endif
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
239 int ArmPrivateSysnoToErrno(int sysno) { 240 int ArmPrivateSysnoToErrno(int sysno) {
240 if (sysno >= static_cast<int>(MIN_PRIVATE_SYSCALL) && 241 if (sysno >= static_cast<int>(MIN_PRIVATE_SYSCALL) &&
241 sysno <= static_cast<int>(MAX_PRIVATE_SYSCALL)) { 242 sysno <= static_cast<int>(MAX_PRIVATE_SYSCALL)) {
242 return (sysno - MIN_PRIVATE_SYSCALL) + 1; 243 return (sysno - MIN_PRIVATE_SYSCALL) + 1;
243 } else { 244 } else {
244 return ENOSYS; 245 return ENOSYS;
245 } 246 }
246 } 247 }
247 248
248 ErrorCode ArmPrivatePolicy(int sysno, void *) { 249 ErrorCode ArmPrivatePolicy(int sysno, void *) {
249 if (!Sandbox::isValidSyscallNumber(sysno)) { 250 if (!Sandbox::IsValidSyscallNumber(sysno)) {
250 // FIXME: we should really not have to do that in a trivial policy. 251 // FIXME: we should really not have to do that in a trivial policy.
251 return ErrorCode(ENOSYS); 252 return ErrorCode(ENOSYS);
252 } 253 }
253 254
254 // Start from |__ARM_NR_set_tls + 1| so as not to mess with actual 255 // Start from |__ARM_NR_set_tls + 1| so as not to mess with actual
255 // ARM private system calls. 256 // ARM private system calls.
256 if (sysno >= static_cast<int>(__ARM_NR_set_tls + 1) && 257 if (sysno >= static_cast<int>(__ARM_NR_set_tls + 1) &&
257 sysno <= static_cast<int>(MAX_PRIVATE_SYSCALL)) { 258 sysno <= static_cast<int>(MAX_PRIVATE_SYSCALL)) {
258 return ErrorCode(ArmPrivateSysnoToErrno(sysno)); 259 return ErrorCode(ArmPrivateSysnoToErrno(sysno));
259 } else { 260 } else {
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
301 || sysno == __NR_sigprocmask 302 || sysno == __NR_sigprocmask
302 #endif 303 #endif
303 #if defined(__NR_sigreturn) 304 #if defined(__NR_sigreturn)
304 || sysno == __NR_sigreturn 305 || sysno == __NR_sigreturn
305 #endif 306 #endif
306 ) { 307 ) {
307 return ErrorCode(ErrorCode::ERR_ALLOWED); 308 return ErrorCode(ErrorCode::ERR_ALLOWED);
308 } else if (sysno == __NR_getpid) { 309 } else if (sysno == __NR_getpid) {
309 // Disallow getpid() 310 // Disallow getpid()
310 return ErrorCode(EPERM); 311 return ErrorCode(EPERM);
311 } else if (Sandbox::isValidSyscallNumber(sysno)) { 312 } else if (Sandbox::IsValidSyscallNumber(sysno)) {
312 // Allow (and count) all other system calls. 313 // Allow (and count) all other system calls.
313 return Sandbox::UnsafeTrap(CountSyscalls, aux); 314 return Sandbox::UnsafeTrap(CountSyscalls, aux);
314 } else { 315 } else {
315 return ErrorCode(ENOSYS); 316 return ErrorCode(ENOSYS);
316 } 317 }
317 } 318 }
318 319
319 BPF_TEST(SandboxBpf, GreyListedPolicy, 320 BPF_TEST(SandboxBpf, GreyListedPolicy,
320 GreyListedPolicy, int /* BPF_AUX */) { 321 GreyListedPolicy, int /* BPF_AUX */) {
321 BPF_ASSERT(syscall(__NR_getpid) == -1); 322 BPF_ASSERT(syscall(__NR_getpid) == -1);
(...skipping 18 matching lines...) Expand all
340 return Sandbox::ForwardSyscall(args); 341 return Sandbox::ForwardSyscall(args);
341 } 342 }
342 } 343 }
343 344
344 ErrorCode PrctlPolicy(int sysno, void *aux) { 345 ErrorCode PrctlPolicy(int sysno, void *aux) {
345 Die::SuppressInfoMessages(true); 346 Die::SuppressInfoMessages(true);
346 347
347 if (sysno == __NR_prctl) { 348 if (sysno == __NR_prctl) {
348 // Handle prctl() inside an UnsafeTrap() 349 // Handle prctl() inside an UnsafeTrap()
349 return Sandbox::UnsafeTrap(PrctlHandler, NULL); 350 return Sandbox::UnsafeTrap(PrctlHandler, NULL);
350 } else if (Sandbox::isValidSyscallNumber(sysno)) { 351 } else if (Sandbox::IsValidSyscallNumber(sysno)) {
351 // Allow all other system calls. 352 // Allow all other system calls.
352 return ErrorCode(ErrorCode::ERR_ALLOWED); 353 return ErrorCode(ErrorCode::ERR_ALLOWED);
353 } else { 354 } else {
354 return ErrorCode(ENOSYS); 355 return ErrorCode(ENOSYS);
355 } 356 }
356 } 357 }
357 358
358 BPF_TEST(SandboxBpf, ForwardSyscall, PrctlPolicy) { 359 BPF_TEST(SandboxBpf, ForwardSyscall, PrctlPolicy) {
359 // This call should never be allowed. But our policy will intercept it and 360 // This call should never be allowed. But our policy will intercept it and
360 // let it pass successfully. 361 // let it pass successfully.
(...skipping 29 matching lines...) Expand all
390 if (sysno == __NR_rt_sigprocmask || 391 if (sysno == __NR_rt_sigprocmask ||
391 sysno == __NR_rt_sigreturn 392 sysno == __NR_rt_sigreturn
392 #if defined(__NR_sigprocmask) 393 #if defined(__NR_sigprocmask)
393 || sysno == __NR_sigprocmask 394 || sysno == __NR_sigprocmask
394 #endif 395 #endif
395 #if defined(__NR_sigreturn) 396 #if defined(__NR_sigreturn)
396 || sysno == __NR_sigreturn 397 || sysno == __NR_sigreturn
397 #endif 398 #endif
398 ) { 399 ) {
399 return ErrorCode(ErrorCode::ERR_ALLOWED); 400 return ErrorCode(ErrorCode::ERR_ALLOWED);
400 } else if (Sandbox::isValidSyscallNumber(sysno)) { 401 } else if (Sandbox::IsValidSyscallNumber(sysno)) {
401 return Sandbox::UnsafeTrap(AllowRedirectedSyscall, aux); 402 return Sandbox::UnsafeTrap(AllowRedirectedSyscall, aux);
402 } else { 403 } else {
403 return ErrorCode(ENOSYS); 404 return ErrorCode(ENOSYS);
404 } 405 }
405 } 406 }
406 407
407 int bus_handler_fd_ = -1; 408 int bus_handler_fd_ = -1;
408 409
409 void SigBusHandler(int, siginfo_t *info, void *void_context) { 410 void SigBusHandler(int, siginfo_t *info, void *void_context) {
410 BPF_ASSERT(write(bus_handler_fd_, "\x55", 1) == 1); 411 BPF_ASSERT(write(bus_handler_fd_, "\x55", 1) == 1);
(...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after
522 return broker_process->Open(reinterpret_cast<const char*>(args.args[1]), 523 return broker_process->Open(reinterpret_cast<const char*>(args.args[1]),
523 static_cast<int>(args.args[2])); 524 static_cast<int>(args.args[2]));
524 default: 525 default:
525 BPF_ASSERT(false); 526 BPF_ASSERT(false);
526 return -ENOSYS; 527 return -ENOSYS;
527 } 528 }
528 } 529 }
529 530
530 ErrorCode DenyOpenPolicy(int sysno, void *aux) { 531 ErrorCode DenyOpenPolicy(int sysno, void *aux) {
531 InitializedOpenBroker* iob = static_cast<InitializedOpenBroker*>(aux); 532 InitializedOpenBroker* iob = static_cast<InitializedOpenBroker*>(aux);
532 if (!Sandbox::isValidSyscallNumber(sysno)) { 533 if (!Sandbox::IsValidSyscallNumber(sysno)) {
533 return ErrorCode(ENOSYS); 534 return ErrorCode(ENOSYS);
534 } 535 }
535 536
536 switch (sysno) { 537 switch (sysno) {
537 case __NR_open: 538 case __NR_open:
538 case __NR_openat: 539 case __NR_openat:
539 // We get a InitializedOpenBroker class, but our trap handler wants 540 // We get a InitializedOpenBroker class, but our trap handler wants
540 // the BrokerProcess object. 541 // the BrokerProcess object.
541 return ErrorCode(Sandbox::Trap(BrokerOpenTrapHandler, 542 return ErrorCode(Sandbox::Trap(BrokerOpenTrapHandler,
542 iob->broker_process())); 543 iob->broker_process()));
(...skipping 30 matching lines...) Expand all
573 BPF_ASSERT(errno == ENOENT); 574 BPF_ASSERT(errno == ENOENT);
574 575
575 576
576 // This is also white listed and does exist. 577 // This is also white listed and does exist.
577 int cpu_info_fd = open("/proc/cpuinfo", O_RDONLY); 578 int cpu_info_fd = open("/proc/cpuinfo", O_RDONLY);
578 BPF_ASSERT(cpu_info_fd >= 0); 579 BPF_ASSERT(cpu_info_fd >= 0);
579 char buf[1024]; 580 char buf[1024];
580 BPF_ASSERT(read(cpu_info_fd, buf, sizeof(buf)) > 0); 581 BPF_ASSERT(read(cpu_info_fd, buf, sizeof(buf)) > 0);
581 } 582 }
582 583
584 // This test exercises the Sandbox::Cond() method by building a complex
585 // tree of conditional equality operations. It then makes system calls and
586 // verifies that they return the values that we expected from our BPF
587 // program.
588 class EqualityStressTest {
589 public:
590 EqualityStressTest() {
591 // We want a deterministic test
592 srand(0);
593
594 // Iterates over system call numbers and builds a random tree of
595 // equality tests.
596 // We are actually constructing a graph of ArgValue objects. This
597 // graph will later be used to a) compute our sandbox policy, and
598 // b) drive the code that verifies the output from the BPF program.
599 COMPILE_ASSERT(kNumTestCases < (int)(MAX_PUBLIC_SYSCALL-MIN_SYSCALL-10),
600 num_test_cases_must_be_significantly_smaller_than_num_system_calls);
601 for (int sysno = MIN_SYSCALL, end = kNumTestCases; sysno < end; ++sysno) {
602 if (IsReservedSyscall(sysno)) {
603 // Skip reserved system calls. This ensures that our test frame
604 // work isn't impacted by the fact that we are overriding
605 // a lot of different system calls.
606 ++end;
607 arg_values_.push_back(NULL);
608 } else {
609 arg_values_.push_back(RandomArgValue(rand() % kMaxArgs, 0,
610 rand() % kMaxArgs));
611 }
612 }
613 }
614
615 ~EqualityStressTest() {
616 for (std::vector<ArgValue *>::iterator iter = arg_values_.begin();
617 iter != arg_values_.end();
618 ++iter) {
619 DeleteArgValue(*iter);
620 }
621 }
622
623 ErrorCode Policy(int sysno) {
624 if (!Sandbox::IsValidSyscallNumber(sysno)) {
625 // FIXME: we should really not have to do that in a trivial policy
626 return ErrorCode(ENOSYS);
627 } else if (sysno < 0 || sysno >= (int)arg_values_.size() ||
628 IsReservedSyscall(sysno)) {
629 // We only return ErrorCode values for the system calls that
630 // are part of our test data. Every other system call remains
631 // allowed.
632 return ErrorCode(ErrorCode::ERR_ALLOWED);
633 } else {
634 // ToErrorCode() turns an ArgValue object into an ErrorCode that is
635 // suitable for use by a sandbox policy.
636 return ToErrorCode(arg_values_[sysno]);
637 }
638 }
639
640 void VerifyFilter() {
641 // Iterate over all system calls. Skip the system calls that have
642 // previously been determined as being reserved.
643 for (int sysno = 0; sysno < (int)arg_values_.size(); ++sysno) {
644 if (!arg_values_[sysno]) {
645 // Skip reserved system calls.
646 continue;
647 }
648 // Verify that system calls return the values that we expect them to
649 // return. This involves passing different combinations of system call
650 // parameters in order to exercise all possible code paths through the
651 // BPF filter program.
652 // We arbitrarily start by setting all six system call arguments to
653 // zero. And we then recursive traverse our tree of ArgValues to
654 // determine the necessary combinations of parameters.
655 intptr_t args[6] = { };
656 Verify(sysno, args, *arg_values_[sysno]);
657 }
658 }
659
660 private:
661 struct ArgValue {
662 int argno; // Argument number to inspect.
663 int size; // Number of test cases (must be > 0).
664 struct Tests {
665 uint32_t k_value; // Value to compare syscall arg against.
666 int err; // If non-zero, errno value to return.
667 struct ArgValue *arg_value; // Otherwise, more args needs inspecting.
668 } *tests;
669 int err; // If none of the tests passed, this is what
670 struct ArgValue *arg_value; // we'll return (this is the "else" branch).
671 };
672
673 bool IsReservedSyscall(int sysno) {
674 // There are a handful of system calls that we should never use in our
675 // test cases. These system calls are needed to allow the test framework
676 // to run properly.
677 // If we wanted to write fully generic code, there are more system calls
678 // that could be listed here, and it is quite difficult to come up with a
679 // truly comprehensive list. After all, we are deliberately making system
680 // calls unavailable. In practice, we have a pretty good idea of the system
681 // calls that will be made by this particular test. So, this small list is
682 // sufficient. But if anybody copy'n'pasted this code for other uses, they
683 // would have to review that the list.
684 return sysno == __NR_read ||
685 sysno == __NR_write ||
686 sysno == __NR_exit ||
687 sysno == __NR_exit_group ||
688 sysno == __NR_restart_syscall;
689 }
690
691 ArgValue *RandomArgValue(int argno, int args_mask, int remaining_args) {
692 // Create a new ArgValue and fill it with random data. We use as bit mask
693 // to keep track of the system call parameters that have previously been
694 // set; this ensures that we won't accidentally define a contradictory
695 // set of equality tests.
696 struct ArgValue *arg_value = new ArgValue();
697 args_mask |= 1 << argno;
698 arg_value->argno = argno;
699
700 // Apply some restrictions on just how complex our tests can be.
701 // Otherwise, we end up with a BPF program that is too complicated for
702 // the kernel to load.
703 int fan_out = kMaxFanOut;
704 if (remaining_args > 3) {
705 fan_out = 1;
706 } else if (remaining_args > 2) {
707 fan_out = 2;
708 }
709
710 // Create a couple of different test cases with randomized values that
711 // we want to use when comparing system call parameter number "argno".
712 arg_value->size = rand() % fan_out + 1;
713 arg_value->tests = new ArgValue::Tests[arg_value->size];
714
715 uint32_t k_value = rand();
716 for (int n = 0; n < arg_value->size; ++n) {
717 // Ensure that we have unique values
718 k_value += rand() % (RAND_MAX/(kMaxFanOut+1)) + 1;
719
720 // There are two possible types of nodes. Either this is a leaf node;
721 // in that case, we have completed all the equality tests that we
722 // wanted to perform, and we can now compute a random "errno" value that
723 // we should return. Or this is part of a more complex boolean
724 // expression; in that case, we have to recursively add tests for some
725 // of system call parameters that we have not yet included in our
726 // tests.
727 arg_value->tests[n].k_value = k_value;
728 if (!remaining_args || (rand() & 1)) {
729 arg_value->tests[n].err = (rand() % 1000) + 1;
730 arg_value->tests[n].arg_value = NULL;
731 } else {
732 arg_value->tests[n].err = 0;
733 arg_value->tests[n].arg_value =
734 RandomArgValue(RandomArg(args_mask), args_mask, remaining_args - 1);
735 }
736 }
737 // Finally, we have to define what we should return if none of the
738 // previous equality tests pass. Again, we can either deal with a leaf
739 // node, or we can randomly add another couple of tests.
740 if (!remaining_args || (rand() & 1)) {
741 arg_value->err = (rand() % 1000) + 1;
742 arg_value->arg_value = NULL;
743 } else {
744 arg_value->err = 0;
745 arg_value->arg_value =
746 RandomArgValue(RandomArg(args_mask), args_mask, remaining_args - 1);
747 }
748 // We have now built a new (sub-)tree of ArgValues defining a set of
749 // boolean expressions for testing random system call arguments against
750 // random values. Return this tree to our caller.
751 return arg_value;
752 }
753
754 int RandomArg(int args_mask) {
755 // Compute a random system call parameter number.
756 int argno = rand() % kMaxArgs;
757
758 // Make sure that this same parameter number has not previously been
759 // used. Otherwise, we could end up with a test that is impossible to
760 // satisfy (e.g. args[0] == 1 && args[0] == 2).
761 while (args_mask & (1 << argno)) {
762 argno = (argno + 1) % kMaxArgs;
763 }
764 return argno;
765 }
766
767 void DeleteArgValue(ArgValue *arg_value) {
768 // Delete an ArgValue and all of its child nodes. This requires
769 // recursively descending into the tree.
770 if (arg_value) {
771 if (arg_value->size) {
772 for (int n = 0; n < arg_value->size; ++n) {
773 if (!arg_value->tests[n].err) {
774 DeleteArgValue(arg_value->tests[n].arg_value);
775 }
776 }
777 delete[] arg_value->tests;
778 }
779 if (!arg_value->err) {
780 DeleteArgValue(arg_value->arg_value);
781 }
782 delete arg_value;
783 }
784 }
785
786 ErrorCode ToErrorCode(ArgValue *arg_value) {
787 // Compute the ErrorCode that should be returned, if none of our
788 // tests succeed (i.e. the system call parameter doesn't match any
789 // of the values in arg_value->tests[].k_value).
790 ErrorCode err;
791 if (arg_value->err) {
792 // If this was a leaf node, return the errno value that we expect to
793 // return from the BPF filter program.
794 err = ErrorCode(arg_value->err);
795 } else {
796 // If this wasn't a leaf node yet, recursively descend into the rest
797 // of the tree. This will end up adding a few more Sandbox::Cond()
798 // tests to our ErrorCode.
799 err = ToErrorCode(arg_value->arg_value);
800 }
801
802 // Now, iterate over all the test cases that we want to compare against.
803 // This builds a chain of Sandbox::Cond() tests
804 // (aka "if ... elif ... elif ... elif ... fi")
805 for (int n = arg_value->size; n-- > 0; ) {
806 ErrorCode matched;
807 // Again, we distinguish between leaf nodes and subtrees.
808 if (arg_value->tests[n].err) {
809 matched = ErrorCode(arg_value->tests[n].err);
810 } else {
811 matched = ToErrorCode(arg_value->tests[n].arg_value);
812 }
813 // For now, all of our tests are limited to 32bit.
814 // We have separate tests that check the behavior of 32bit vs. 64bit
815 // conditional expressions.
816 err = Sandbox::Cond(arg_value->argno, ErrorCode::TP_32BIT,
817 ErrorCode::OP_EQUAL, arg_value->tests[n].k_value,
818 matched, err);
819 }
820 return err;
821 }
822
823 void Verify(int sysno, intptr_t *args, const ArgValue& arg_value) {
824 uint32_t mismatched = 0;
825 // Iterate over all the k_values in arg_value.tests[] and verify that
826 // we see the expected return values from system calls, when we pass
827 // the k_value as a parameter in a system call.
828 for (int n = arg_value.size; n-- > 0; ) {
829 mismatched += arg_value.tests[n].k_value;
830 args[arg_value.argno] = arg_value.tests[n].k_value;
831 if (arg_value.tests[n].err) {
832 VerifyErrno(sysno, args, arg_value.tests[n].err);
833 } else {
834 Verify(sysno, args, *arg_value.tests[n].arg_value);
835 }
836 }
837 // Find a k_value that doesn't match any of the k_values in
838 // arg_value.tests[]. In most cases, the current value of "mismatched"
839 // would fit this requirement. But on the off-chance that it happens
840 // to collide, we double-check.
841 try_again:
842 for (int n = arg_value.size; n-- > 0; ) {
843 if (mismatched == arg_value.tests[n].k_value) {
844 ++mismatched;
845 goto try_again;
846 }
847 }
848 // Now verify that we see the expected return value from system calls,
849 // if we pass a value that doesn't match any of the conditions (i.e. this
850 // is testing the "else" clause of the conditions).
851 args[arg_value.argno] = mismatched;
852 if (arg_value.err) {
853 VerifyErrno(sysno, args, arg_value.err);
854 } else {
855 Verify(sysno, args, *arg_value.arg_value);
856 }
857 // Reset args[arg_value.argno]. This is not technically needed, but it
858 // makes it easier to reason about the correctness of our tests.
859 args[arg_value.argno] = 0;
860 }
861
862 void VerifyErrno(int sysno, intptr_t *args, int err) {
863 // We installed BPF filters that return different errno values
864 // based on the system call number and the parameters that we decided
865 // to pass in. Verify that this condition holds true.
866 BPF_ASSERT(SandboxSyscall(sysno,
867 args[0], args[1], args[2],
868 args[3], args[4], args[5]) == -err);
869 }
870
871 // Vector of ArgValue trees. These trees define all the possible boolean
872 // expressions that we want to turn into a BPF filter program.
873 std::vector<ArgValue *> arg_values_;
874
875 // Don't increase these values. We are pushing the limits of the maximum
876 // BPF program that the kernel will allow us to load. If the values are
877 // increased too much, the test will start failing.
878 static const int kNumIterations = 3;
879 static const int kNumTestCases = 40;
880 static const int kMaxFanOut = 3;
881 static const int kMaxArgs = 6;
882 };
883
884 ErrorCode EqualityStressTestPolicy(int sysno, void *aux) {
885 return reinterpret_cast<EqualityStressTest *>(aux)->Policy(sysno);
886 }
887
888 BPF_TEST(SandboxBpf, EqualityTests, EqualityStressTestPolicy,
889 EqualityStressTest /* BPF_AUX */) {
890 BPF_AUX.VerifyFilter();
891 }
892
893 ErrorCode EqualityArgumentWidthPolicy(int sysno, void *) {
894 if (!Sandbox::IsValidSyscallNumber(sysno)) {
895 // FIXME: we should really not have to do that in a trivial policy
896 return ErrorCode(ENOSYS);
897 } else if (sysno == __NR_uname) {
898 return Sandbox::Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL, 0,
899 Sandbox::Cond(1, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL,
900 0x55555555, ErrorCode(1), ErrorCode(2)),
901 Sandbox::Cond(1, ErrorCode::TP_64BIT, ErrorCode::OP_EQUAL,
902 0x55555555AAAAAAAAull, ErrorCode(1), ErrorCode(2)));
903 } else {
904 return ErrorCode(ErrorCode::ERR_ALLOWED);
905 }
906 }
907
908 BPF_TEST(SandboxBpf, EqualityArgumentWidth, EqualityArgumentWidthPolicy) {
909 BPF_ASSERT(SandboxSyscall(__NR_uname, 0, 0x55555555) == -1);
910 BPF_ASSERT(SandboxSyscall(__NR_uname, 0, 0xAAAAAAAA) == -2);
911 #if __SIZEOF_POINTER__ > 4
912 // On 32bit machines, there is no way to pass a 64bit argument through the
913 // syscall interface. So, we have to skip the part of the test that requires
914 // 64bit arguments.
915 BPF_ASSERT(SandboxSyscall(__NR_uname, 1, 0x55555555AAAAAAAAull) == -1);
916 BPF_ASSERT(SandboxSyscall(__NR_uname, 1, 0x5555555500000000ull) == -2);
917 BPF_ASSERT(SandboxSyscall(__NR_uname, 1, 0x5555555511111111ull) == -2);
918 BPF_ASSERT(SandboxSyscall(__NR_uname, 1, 0x11111111AAAAAAAAull) == -2);
919 #endif
920 }
921
922 #if __SIZEOF_POINTER__ > 4
923 // On 32bit machines, there is no way to pass a 64bit argument through the
924 // syscall interface. So, we have to skip the part of the test that requires
925 // 64bit arguments.
926 BPF_DEATH_TEST(SandboxBpf, EqualityArgumentUnallowed64bit,
927 DEATH_MESSAGE("Unexpected 64bit argument detected"),
928 EqualityArgumentWidthPolicy) {
929 SandboxSyscall(__NR_uname, 0, 0x5555555555555555ull);
930 }
931 #endif
932
933 ErrorCode EqualityWithNegativeArgumentsPolicy(int sysno, void *) {
934 if (!Sandbox::IsValidSyscallNumber(sysno)) {
935 // FIXME: we should really not have to do that in a trivial policy
936 return ErrorCode(ENOSYS);
937 } else if (sysno == __NR_uname) {
938 return Sandbox::Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL,
939 0xFFFFFFFF, ErrorCode(1), ErrorCode(2));
940 } else {
941 return ErrorCode(ErrorCode::ERR_ALLOWED);
942 }
943 }
944
945 BPF_TEST(SandboxBpf, EqualityWithNegativeArguments,
946 EqualityWithNegativeArgumentsPolicy) {
947 BPF_ASSERT(SandboxSyscall(__NR_uname, 0xFFFFFFFF) == -1);
948 BPF_ASSERT(SandboxSyscall(__NR_uname, -1) == -1);
949 BPF_ASSERT(SandboxSyscall(__NR_uname, -1ll) == -1);
950 }
951
952 #if __SIZEOF_POINTER__ > 4
953 BPF_DEATH_TEST(SandboxBpf, EqualityWithNegative64bitArguments,
954 DEATH_MESSAGE("Unexpected 64bit argument detected"),
955 EqualityWithNegativeArgumentsPolicy) {
956 // When expecting a 32bit system call argument, we look at the MSB of the
957 // 64bit value and allow both "0" and "-1". But the latter is allowed only
958 // iff the LSB was negative. So, this death test should error out.
959 BPF_ASSERT(SandboxSyscall(__NR_uname, 0xFFFFFFFF00000000ll) == -1);
960 }
961 #endif
962
583 } // namespace 963 } // namespace
OLDNEW
« no previous file with comments | « sandbox/linux/seccomp-bpf/sandbox_bpf.cc ('k') | sandbox/linux/seccomp-bpf/syscall_iterator.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698