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

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: Changelist is ready for initial review; still needs a few TODO()s to be resolved, though. 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
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 "sandbox/linux/seccomp-bpf/bpf_tests.h" 10 #include "sandbox/linux/seccomp-bpf/bpf_tests.h"
11 #include "sandbox/linux/seccomp-bpf/syscall.h"
11 #include "sandbox/linux/seccomp-bpf/verifier.h" 12 #include "sandbox/linux/seccomp-bpf/verifier.h"
12 #include "testing/gtest/include/gtest/gtest.h" 13 #include "testing/gtest/include/gtest/gtest.h"
13 14
14 using namespace playground2; 15 using namespace playground2;
15 16
16 namespace { 17 namespace {
17 18
18 const int kExpectedReturnValue = 42; 19 const int kExpectedReturnValue = 42;
19 20
20 // This test should execute no matter whether we have kernel support. So, 21 // This test should execute no matter whether we have kernel support. So,
21 // we make it a TEST() instead of a BPF_TEST(). 22 // we make it a TEST() instead of a BPF_TEST().
22 TEST(SandboxBpf, CallSupports) { 23 TEST(SandboxBpf, CallSupports) {
23 // We check that we don't crash, but it's ok if the kernel doesn't 24 // We check that we don't crash, but it's ok if the kernel doesn't
24 // support it. 25 // support it.
25 bool seccomp_bpf_supported = 26 bool seccomp_bpf_supported =
26 Sandbox::supportsSeccompSandbox(-1) == Sandbox::STATUS_AVAILABLE; 27 Sandbox::SupportsSeccompSandbox(-1) == Sandbox::STATUS_AVAILABLE;
27 // We want to log whether or not seccomp BPF is actually supported 28 // We want to log whether or not seccomp BPF is actually supported
28 // since actual test coverage depends on it. 29 // since actual test coverage depends on it.
29 RecordProperty("SeccompBPFSupported", 30 RecordProperty("SeccompBPFSupported",
30 seccomp_bpf_supported ? "true." : "false."); 31 seccomp_bpf_supported ? "true." : "false.");
31 std::cout << "Seccomp BPF supported: " 32 std::cout << "Seccomp BPF supported: "
32 << (seccomp_bpf_supported ? "true." : "false.") 33 << (seccomp_bpf_supported ? "true." : "false.")
33 << "\n"; 34 << "\n";
34 RecordProperty("PointerSize", sizeof(void*)); 35 RecordProperty("PointerSize", sizeof(void*));
35 std::cout << "Pointer size: " << sizeof(void*) << "\n"; 36 std::cout << "Pointer size: " << sizeof(void*) << "\n";
36 } 37 }
37 38
38 SANDBOX_TEST(SandboxBpf, CallSupportsTwice) { 39 SANDBOX_TEST(SandboxBpf, CallSupportsTwice) {
39 Sandbox::supportsSeccompSandbox(-1); 40 Sandbox::SupportsSeccompSandbox(-1);
40 Sandbox::supportsSeccompSandbox(-1); 41 Sandbox::SupportsSeccompSandbox(-1);
41 } 42 }
42 43
43 // BPF_TEST does a lot of the boiler-plate code around setting up a 44 // BPF_TEST does a lot of the boiler-plate code around setting up a
44 // policy and optional passing data between the caller, the policy and 45 // policy and optional passing data between the caller, the policy and
45 // any Trap() handlers. This is great for writing short and concise tests, 46 // any Trap() handlers. This is great for writing short and concise tests,
46 // and it helps us accidentally forgetting any of the crucial steps in 47 // and it helps us accidentally forgetting any of the crucial steps in
47 // setting up the sandbox. But it wouldn't hurt to have at least one test 48 // setting up the sandbox. But it wouldn't hurt to have at least one test
48 // that explicitly walks through all these steps. 49 // that explicitly walks through all these steps.
49 50
50 intptr_t FakeGetPid(const struct arch_seccomp_data& args, void *aux) { 51 intptr_t FakeGetPid(const struct arch_seccomp_data& args, void *aux) {
51 BPF_ASSERT(aux); 52 BPF_ASSERT(aux);
52 pid_t *pid_ptr = static_cast<pid_t *>(aux); 53 pid_t *pid_ptr = static_cast<pid_t *>(aux);
53 return (*pid_ptr)++; 54 return (*pid_ptr)++;
54 } 55 }
55 56
56 ErrorCode VerboseAPITestingPolicy(int sysno, void *aux) { 57 ErrorCode VerboseAPITestingPolicy(int sysno, void *aux) {
57 if (!Sandbox::isValidSyscallNumber(sysno)) { 58 if (!Sandbox::IsValidSyscallNumber(sysno)) {
58 return ErrorCode(ENOSYS); 59 return ErrorCode(ENOSYS);
59 } else if (sysno == __NR_getpid) { 60 } else if (sysno == __NR_getpid) {
60 return Sandbox::Trap(FakeGetPid, aux); 61 return Sandbox::Trap(FakeGetPid, aux);
61 } else { 62 } else {
62 return ErrorCode(ErrorCode::ERR_ALLOWED); 63 return ErrorCode(ErrorCode::ERR_ALLOWED);
63 } 64 }
64 } 65 }
65 66
66 SANDBOX_TEST(SandboxBpf, VerboseAPITesting) { 67 SANDBOX_TEST(SandboxBpf, VerboseAPITesting) {
67 if (Sandbox::supportsSeccompSandbox(-1) == 68 if (Sandbox::SupportsSeccompSandbox(-1) ==
68 playground2::Sandbox::STATUS_AVAILABLE) { 69 playground2::Sandbox::STATUS_AVAILABLE) {
69 pid_t test_var = 0; 70 pid_t test_var = 0;
70 playground2::Sandbox::setSandboxPolicy(VerboseAPITestingPolicy, &test_var); 71 playground2::Sandbox::SetSandboxPolicy(VerboseAPITestingPolicy, &test_var);
71 playground2::Sandbox::startSandbox(); 72 playground2::Sandbox::StartSandbox();
72 73
73 BPF_ASSERT(test_var == 0); 74 BPF_ASSERT(test_var == 0);
74 BPF_ASSERT(syscall(__NR_getpid) == 0); 75 BPF_ASSERT(syscall(__NR_getpid) == 0);
75 BPF_ASSERT(test_var == 1); 76 BPF_ASSERT(test_var == 1);
76 BPF_ASSERT(syscall(__NR_getpid) == 1); 77 BPF_ASSERT(syscall(__NR_getpid) == 1);
77 BPF_ASSERT(test_var == 2); 78 BPF_ASSERT(test_var == 2);
78 79
79 // N.B.: Any future call to getpid() would corrupt the stack. 80 // N.B.: Any future call to getpid() would corrupt the stack.
80 // This is OK. The SANDBOX_TEST() macro is guaranteed to 81 // This is OK. The SANDBOX_TEST() macro is guaranteed to
81 // only ever call _exit() after the test completes. 82 // only ever call _exit() after the test completes.
82 } 83 }
83 } 84 }
84 85
85 // A simple blacklist test 86 // A simple blacklist test
86 87
87 ErrorCode BlacklistNanosleepPolicy(int sysno, void *) { 88 ErrorCode BlacklistNanosleepPolicy(int sysno, void *) {
88 if (!Sandbox::isValidSyscallNumber(sysno)) { 89 if (!Sandbox::IsValidSyscallNumber(sysno)) {
89 // FIXME: we should really not have to do that in a trivial policy 90 // FIXME: we should really not have to do that in a trivial policy
90 return ErrorCode(ENOSYS); 91 return ErrorCode(ENOSYS);
91 } 92 }
92 93
93 switch (sysno) { 94 switch (sysno) {
94 case __NR_nanosleep: 95 case __NR_nanosleep:
95 return ErrorCode(EACCES); 96 return ErrorCode(EACCES);
96 default: 97 default:
97 return ErrorCode(ErrorCode::ERR_ALLOWED); 98 return ErrorCode(ErrorCode::ERR_ALLOWED);
98 } 99 }
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
132 // A simple blacklist policy, with a SIGSYS handler 133 // A simple blacklist policy, with a SIGSYS handler
133 134
134 intptr_t EnomemHandler(const struct arch_seccomp_data& args, void *aux) { 135 intptr_t EnomemHandler(const struct arch_seccomp_data& args, void *aux) {
135 // We also check that the auxiliary data is correct 136 // We also check that the auxiliary data is correct
136 SANDBOX_ASSERT(aux); 137 SANDBOX_ASSERT(aux);
137 *(static_cast<int*>(aux)) = kExpectedReturnValue; 138 *(static_cast<int*>(aux)) = kExpectedReturnValue;
138 return -ENOMEM; 139 return -ENOMEM;
139 } 140 }
140 141
141 ErrorCode BlacklistNanosleepPolicySigsys(int sysno, void *aux) { 142 ErrorCode BlacklistNanosleepPolicySigsys(int sysno, void *aux) {
142 if (!Sandbox::isValidSyscallNumber(sysno)) { 143 if (!Sandbox::IsValidSyscallNumber(sysno)) {
143 // FIXME: we should really not have to do that in a trivial policy 144 // FIXME: we should really not have to do that in a trivial policy
144 return ErrorCode(ENOSYS); 145 return ErrorCode(ENOSYS);
145 } 146 }
146 147
147 switch (sysno) { 148 switch (sysno) {
148 case __NR_nanosleep: 149 case __NR_nanosleep:
149 return Sandbox::Trap(EnomemHandler, aux); 150 return Sandbox::Trap(EnomemHandler, aux);
150 default: 151 default:
151 return ErrorCode(ErrorCode::ERR_ALLOWED); 152 return ErrorCode(ErrorCode::ERR_ALLOWED);
152 } 153 }
(...skipping 25 matching lines...) Expand all
178 // sure that the compiler can have an opportunity to coalesce syscalls with 179 // sure that the compiler can have an opportunity to coalesce syscalls with
179 // contiguous numbers and we also make sure that disjoint sets can return the 180 // contiguous numbers and we also make sure that disjoint sets can return the
180 // same errno. 181 // same errno.
181 int SysnoToRandomErrno(int sysno) { 182 int SysnoToRandomErrno(int sysno) {
182 // Small contiguous sets of 3 system calls return an errno equal to the 183 // Small contiguous sets of 3 system calls return an errno equal to the
183 // index of that set + 1 (so that we never return a NUL errno). 184 // index of that set + 1 (so that we never return a NUL errno).
184 return ((sysno & ~3) >> 2) % 29 + 1; 185 return ((sysno & ~3) >> 2) % 29 + 1;
185 } 186 }
186 187
187 ErrorCode SyntheticPolicy(int sysno, void *) { 188 ErrorCode SyntheticPolicy(int sysno, void *) {
188 if (!Sandbox::isValidSyscallNumber(sysno)) { 189 if (!Sandbox::IsValidSyscallNumber(sysno)) {
189 // FIXME: we should really not have to do that in a trivial policy 190 // FIXME: we should really not have to do that in a trivial policy
190 return ErrorCode(ENOSYS); 191 return ErrorCode(ENOSYS);
191 } 192 }
192 193
193 // TODO(jorgelo): remove this once the new code generator lands. 194 // TODO(jorgelo): remove this once the new code generator lands.
194 #if defined(__arm__) 195 #if defined(__arm__)
195 if (sysno > static_cast<int>(MAX_PUBLIC_SYSCALL)) { 196 if (sysno > static_cast<int>(MAX_PUBLIC_SYSCALL)) {
196 return ErrorCode(ENOSYS); 197 return ErrorCode(ENOSYS);
197 } 198 }
198 #endif 199 #endif
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
236 int ArmPrivateSysnoToErrno(int sysno) { 237 int ArmPrivateSysnoToErrno(int sysno) {
237 if (sysno >= static_cast<int>(MIN_PRIVATE_SYSCALL) && 238 if (sysno >= static_cast<int>(MIN_PRIVATE_SYSCALL) &&
238 sysno <= static_cast<int>(MAX_PRIVATE_SYSCALL)) { 239 sysno <= static_cast<int>(MAX_PRIVATE_SYSCALL)) {
239 return (sysno - MIN_PRIVATE_SYSCALL) + 1; 240 return (sysno - MIN_PRIVATE_SYSCALL) + 1;
240 } else { 241 } else {
241 return ENOSYS; 242 return ENOSYS;
242 } 243 }
243 } 244 }
244 245
245 ErrorCode ArmPrivatePolicy(int sysno, void *) { 246 ErrorCode ArmPrivatePolicy(int sysno, void *) {
246 if (!Sandbox::isValidSyscallNumber(sysno)) { 247 if (!Sandbox::IsValidSyscallNumber(sysno)) {
247 // FIXME: we should really not have to do that in a trivial policy. 248 // FIXME: we should really not have to do that in a trivial policy.
248 return ErrorCode(ENOSYS); 249 return ErrorCode(ENOSYS);
249 } 250 }
250 251
251 // Start from |__ARM_NR_set_tls + 1| so as not to mess with actual 252 // Start from |__ARM_NR_set_tls + 1| so as not to mess with actual
252 // ARM private system calls. 253 // ARM private system calls.
253 if (sysno >= static_cast<int>(__ARM_NR_set_tls + 1) && 254 if (sysno >= static_cast<int>(__ARM_NR_set_tls + 1) &&
254 sysno <= static_cast<int>(MAX_PRIVATE_SYSCALL)) { 255 sysno <= static_cast<int>(MAX_PRIVATE_SYSCALL)) {
255 return ErrorCode(ArmPrivateSysnoToErrno(sysno)); 256 return ErrorCode(ArmPrivateSysnoToErrno(sysno));
256 } else { 257 } else {
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
298 || sysno == __NR_sigprocmask 299 || sysno == __NR_sigprocmask
299 #endif 300 #endif
300 #if defined(__NR_sigreturn) 301 #if defined(__NR_sigreturn)
301 || sysno == __NR_sigreturn 302 || sysno == __NR_sigreturn
302 #endif 303 #endif
303 ) { 304 ) {
304 return ErrorCode(ErrorCode::ERR_ALLOWED); 305 return ErrorCode(ErrorCode::ERR_ALLOWED);
305 } else if (sysno == __NR_getpid) { 306 } else if (sysno == __NR_getpid) {
306 // Disallow getpid() 307 // Disallow getpid()
307 return ErrorCode(EPERM); 308 return ErrorCode(EPERM);
308 } else if (Sandbox::isValidSyscallNumber(sysno)) { 309 } else if (Sandbox::IsValidSyscallNumber(sysno)) {
309 // Allow (and count) all other system calls. 310 // Allow (and count) all other system calls.
310 return Sandbox::UnsafeTrap(CountSyscalls, aux); 311 return Sandbox::UnsafeTrap(CountSyscalls, aux);
311 } else { 312 } else {
312 return ErrorCode(ENOSYS); 313 return ErrorCode(ENOSYS);
313 } 314 }
314 } 315 }
315 316
316 BPF_TEST(SandboxBpf, GreyListedPolicy, 317 BPF_TEST(SandboxBpf, GreyListedPolicy,
317 GreyListedPolicy, int /* BPF_AUX */) { 318 GreyListedPolicy, int /* BPF_AUX */) {
318 BPF_ASSERT(syscall(__NR_getpid) == -1); 319 BPF_ASSERT(syscall(__NR_getpid) == -1);
(...skipping 18 matching lines...) Expand all
337 return Sandbox::ForwardSyscall(args); 338 return Sandbox::ForwardSyscall(args);
338 } 339 }
339 } 340 }
340 341
341 ErrorCode PrctlPolicy(int sysno, void *aux) { 342 ErrorCode PrctlPolicy(int sysno, void *aux) {
342 Die::SuppressInfoMessages(true); 343 Die::SuppressInfoMessages(true);
343 344
344 if (sysno == __NR_prctl) { 345 if (sysno == __NR_prctl) {
345 // Handle prctl() inside an UnsafeTrap() 346 // Handle prctl() inside an UnsafeTrap()
346 return Sandbox::UnsafeTrap(PrctlHandler, NULL); 347 return Sandbox::UnsafeTrap(PrctlHandler, NULL);
347 } else if (Sandbox::isValidSyscallNumber(sysno)) { 348 } else if (Sandbox::IsValidSyscallNumber(sysno)) {
348 // Allow all other system calls. 349 // Allow all other system calls.
349 return ErrorCode(ErrorCode::ERR_ALLOWED); 350 return ErrorCode(ErrorCode::ERR_ALLOWED);
350 } else { 351 } else {
351 return ErrorCode(ENOSYS); 352 return ErrorCode(ENOSYS);
352 } 353 }
353 } 354 }
354 355
355 BPF_TEST(SandboxBpf, ForwardSyscall, PrctlPolicy) { 356 BPF_TEST(SandboxBpf, ForwardSyscall, PrctlPolicy) {
356 // This call should never be allowed. But our policy will intercept it and 357 // This call should never be allowed. But our policy will intercept it and
357 // let it pass successfully. 358 // let it pass successfully.
(...skipping 29 matching lines...) Expand all
387 if (sysno == __NR_rt_sigprocmask || 388 if (sysno == __NR_rt_sigprocmask ||
388 sysno == __NR_rt_sigreturn 389 sysno == __NR_rt_sigreturn
389 #if defined(__NR_sigprocmask) 390 #if defined(__NR_sigprocmask)
390 || sysno == __NR_sigprocmask 391 || sysno == __NR_sigprocmask
391 #endif 392 #endif
392 #if defined(__NR_sigreturn) 393 #if defined(__NR_sigreturn)
393 || sysno == __NR_sigreturn 394 || sysno == __NR_sigreturn
394 #endif 395 #endif
395 ) { 396 ) {
396 return ErrorCode(ErrorCode::ERR_ALLOWED); 397 return ErrorCode(ErrorCode::ERR_ALLOWED);
397 } else if (Sandbox::isValidSyscallNumber(sysno)) { 398 } else if (Sandbox::IsValidSyscallNumber(sysno)) {
398 return Sandbox::UnsafeTrap(AllowRedirectedSyscall, aux); 399 return Sandbox::UnsafeTrap(AllowRedirectedSyscall, aux);
399 } else { 400 } else {
400 return ErrorCode(ENOSYS); 401 return ErrorCode(ENOSYS);
401 } 402 }
402 } 403 }
403 404
404 int bus_handler_fd_ = -1; 405 int bus_handler_fd_ = -1;
405 406
406 void SigBusHandler(int, siginfo_t *info, void *void_context) { 407 void SigBusHandler(int, siginfo_t *info, void *void_context) {
407 BPF_ASSERT(write(bus_handler_fd_, "\x55", 1) == 1); 408 BPF_ASSERT(write(bus_handler_fd_, "\x55", 1) == 1);
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after
473 // would make system calls, but it allows us to verify that we don't 474 // would make system calls, but it allows us to verify that we don't
474 // accidentally mess with errno, when we shouldn't. 475 // accidentally mess with errno, when we shouldn't.
475 errno = 0; 476 errno = 0;
476 struct arch_seccomp_data args = { }; 477 struct arch_seccomp_data args = { };
477 args.nr = __NR_close; 478 args.nr = __NR_close;
478 args.args[0] = -1; 479 args.args[0] = -1;
479 BPF_ASSERT(Sandbox::ForwardSyscall(args) == -EBADF); 480 BPF_ASSERT(Sandbox::ForwardSyscall(args) == -EBADF);
480 BPF_ASSERT(errno == 0); 481 BPF_ASSERT(errno == 0);
481 } 482 }
482 483
484 // This test exercises the Sandbox::Cond() method by building a complex
485 // tree of conditional equality operations. It then makes system calls and
486 // verifies that they return the values that we expected from our BPF
487 // program.
488 class EqualityStressTest {
jln (very slow on Chromium) 2012/12/06 01:48:12 I didn't read this yet. But please consider at lea
Markus (顧孟勤) 2012/12/12 20:54:35 I believe that is done now. The tests at the end o
489 public:
490 EqualityStressTest() {
491 // We want a deterministic test
492 srand(0);
493
494 // Iterates over system call numbers and builds a random tree of
495 // equality tests.
496 // We are actually constructing a graph of ArgValue objects. This
497 // graph will later be used to a) compute our sandbox policy, and
498 // b) drive the code that verifies the output from the BPF program.
499 for (int sysno = 0, end = kNumTestCases; sysno < end; ++sysno) {
500 if (IsReservedSyscall(sysno)) {
501 // Skip reserved system calls. This ensures that our test frame
502 // work isn't impacted by the fact that we are overriding
503 // a lot of different system calls.
504 ++end;
505 arg_values_.push_back(NULL);
506 } else {
507 arg_values_.push_back(RandomArgValue(rand() % kMaxArgs, 0,
508 rand() % kMaxArgs));
509 }
510 }
511 }
512
513 ~EqualityStressTest() {
514 for (std::vector<ArgValue *>::iterator iter = arg_values_.begin();
515 iter != arg_values_.end();
516 ++iter) {
517 DeleteArgValue(*iter);
518 }
519 }
520
521 ErrorCode Policy(int sysno) {
522 if (!Sandbox::IsValidSyscallNumber(sysno)) {
523 // FIXME: we should really not have to do that in a trivial policy
524 return ErrorCode(ENOSYS);
525 } else if (sysno < 0 || sysno >= (int)arg_values_.size() ||
526 IsReservedSyscall(sysno)) {
527 // We only return ErrorCode values for the system calls that
528 // are part of our test data. Every other system call remains
529 // allowed.
530 return ErrorCode(ErrorCode::ERR_ALLOWED);
531 } else {
532 // ToErrorCode() turns an ArgValue object into an ErrorCode that is
533 // suitable for use by a sandbox policy.
534 return ToErrorCode(arg_values_[sysno]);
535 }
536 }
537
538 void VerifyFilter() {
539 // Iterate over all system calls. Skip the system calls that have
540 // previously been determined as being reserved.
541 for (int sysno = 0; sysno < (int)arg_values_.size(); ++sysno) {
542 if (!arg_values[sysno]) {
543 // Skip reserved system calls.
544 continue;
545 }
546 // Verify that system calls return the values that we expect them to
547 // return. This involves passing different combinations of system call
548 // parameters in order to exercise all possible code paths through the
549 // BPF filter program.
550 // We arbitrarily start by setting all six system call arguments to
551 // zero. And we then recursive traverse our tree of ArgValues to
552 // determine the necessary combinations of parameters.
553 intptr_t args[6] = { };
554 Verify(sysno, args, *arg_values_[sysno]);
555 }
556 }
557
558 private:
559 struct ArgValue {
560 int argno; // Argument number to inspect.
561 int size; // Number of test cases (must be > 0).
562 struct Tests {
563 uint32_t k_value; // Value to compare syscall arg against.
564 int err; // If non-zero, errno value to return.
565 struct ArgValue *arg_value; // Otherwise, more args needs inspecting.
566 } *tests;
567 int err; // If none of the tests passed, this is what
568 struct ArgValue *arg_value; // we'll return (this is the "else" branch).
569 };
570
571 bool IsReservedSyscall(int sysno) {
572 // There are a handful of system calls that we should never use in our
573 // test cases. These system calls are needed to allow the test framework
574 // to run properly.
575 return sysno == __NR_read ||
576 sysno == __NR_write ||
577 sysno == __NR_exit ||
578 sysno == __NR_exit_group ||
579 sysno == __NR_restart_syscall;
580 }
581
582 ArgValue *RandomArgValue(int argno, int args_mask, int remaining_args) {
583 // Create a new ArgValue and fill it with random data. We use as bit mask
584 // to keep track of the system call parameters that have previously been
585 // set; this ensures that we won't accidentally define a contradictory
586 // set of equality tests.
587 struct ArgValue *arg_value = new ArgValue();
588 args_mask |= 1 << argno;
589 arg_value->argno = argno;
590
591 // Apply some restrictions on just how complex our tests can be.
592 // Otherwise, we end up with a BPF program that is too complicated for
593 // the kernel to load.
594 int fan_out = kMaxFanOut;
595 if (remaining_args > 3) {
596 fan_out = 1;
597 } else if (remaining_args > 2) {
598 fan_out = 2;
599 }
600
601 // Create a couple of different test cases with randomized values that
602 // we want to use when comparing system call parameter number "argno".
603 arg_value->size = rand() % fan_out + 1;
604 arg_value->tests = new ArgValue::Tests[arg_value->size];
605
606 uint32_t k_value = rand();
607 for (int n = 0; n < arg_value->size; ++n) {
608 // Ensure that we have unique values
609 k_value += rand() % (RAND_MAX/(kMaxFanOut+1)) + 1;
610
611 // There are two possible types of nodes. Either this is a leaf node;
612 // in that case, we have completed all the equality tests that we
613 // wanted to perform, and we can now compute a random "errno" value that
614 // we should return. Or this is part of a more complex boolean
615 // expression; in that case, we have to recursively add tests for some
616 // of system call parameters that we have not yet included in our
617 // tests.
618 arg_value->tests[n].k_value = k_value;
619 if (!remaining_args || (rand() & 1)) {
620 arg_value->tests[n].err = (rand() % 1000) + 1;
621 arg_value->tests[n].arg_value = NULL;
622 } else {
623 arg_value->tests[n].err = 0;
624 arg_value->tests[n].arg_value =
625 RandomArgValue(RandomArg(args_mask), args_mask, remaining_args - 1);
626 }
627 }
628 // Finally, we have to define what we should return if none of the
629 // previous equality tests pass. Again, we can either deal with a leaf
630 // node, or we can randomly add another couple of tests.
631 if (!remaining_args || (rand() & 1)) {
632 arg_value->err = (rand() % 1000) + 1;
633 arg_value->arg_value = NULL;
634 } else {
635 arg_value->err = 0;
636 arg_value->arg_value =
637 RandomArgValue(RandomArg(args_mask), args_mask, remaining_args - 1);
638 }
639 // We have now built a new (sub-)tree of ArgValues defining a set of
640 // boolean expressions for testing random system call arguments against
641 // random values. Return this tree to our caller.
642 return arg_value;
643 }
644
645 int RandomArg(int args_mask) {
646 // Compute a random system call parameter number.
647 int argno = rand() % kMaxArgs;
648
649 // Make sure that this same parameter number has not previously been
650 // used. Otherwise, we could end up with a test that is impossible to
651 // satisfy (e.g. args[0] == 1 && args[0] == 2).
652 while (args_mask & (1 << argno)) {
653 argno = (argno + 1) % kMaxArgs;
654 }
655 return argno;
656 }
657
658 void DeleteArgValue(ArgValue *arg_value) {
659 // Delete an ArgValue and all of its child nodes. This requires
660 // recursively descending into the tree.
661 if (arg_value) {
662 if (arg_value->size) {
663 for (int n = 0; n < arg_value->size; ++n) {
664 if (!arg_value->tests[n].err) {
665 DeleteArgValue(arg_value->tests[n].arg_value);
666 }
667 }
668 delete[] arg_value->tests;
669 }
670 if (!arg_value->err) {
671 DeleteArgValue(arg_value->arg_value);
672 }
673 delete arg_value;
674 }
675 }
676
677 ErrorCode ToErrorCode(ArgValue *arg_value) {
678 // Compute the ErrorCode that should be returned, if none of our
679 // tests succeed (i.e. the system call parameter doesn't match any
680 // of the values in arg_value->tests[].k_value).
681 ErrorCode err;
682 if (arg_value->err) {
683 // If this was a leaf node, return the errno value that we expect to
684 // return from the BPF filter program.
685 err = ErrorCode(arg_value->err);
686 } else {
687 // If this wasn't a leaf node yet, recursively descend into the rest
688 // of the tree. This will end up adding a few more Sandbox::Cond()
689 // tests to our ErrorCode.
690 err = ToErrorCode(arg_value->arg_value);
691 }
692
693 // Now, iterate over all the test cases that we want to compare against.
694 // This builds a chain of Sandbox::Cond() tests
695 // (aka "if ... elif ... elif ... elif ... fi")
696 for (int n = arg_value->size; n-- > 0; ) {
697 ErrorCode matched;
698 // Again, we distinguish between leaf nodes and subtrees.
699 if (arg_value->tests[n].err) {
700 matched = ErrorCode(arg_value->tests[n].err);
701 } else {
702 matched = ToErrorCode(arg_value->tests[n].arg_value);
703 }
704 // TODO(markus): For now, all of our tests are limited to 32bit.
705 err = Sandbox::Cond(arg_value->argno, ErrorCode::TP_32BIT,
706 ErrorCode::OP_EQUAL, arg_value->tests[n].k_value,
707 matched, err);
708 }
709 return err;
710 }
711
712 void Verify(int sysno, intptr_t *args, const ArgValue& arg_value) {
713 uint32_t mismatched = 0;
714 // Iterate over all the k_values in arg_value.tests[] and verify that
715 // we see the expected return values from system calls, when we pass
716 // the k_value as a parameter in a system call.
717 for (int n = arg_value.size; n-- > 0; ) {
718 mismatched += arg_value.tests[n].k_value;
719 args[arg_value.argno] = arg_value.tests[n].k_value;
720 if (arg_value.tests[n].err) {
721 VerifyErrno(sysno, args, arg_value.tests[n].err);
722 } else {
723 Verify(sysno, args, *arg_value.tests[n].arg_value);
724 }
725 }
726 // Find a k_value that doesn't match any of the k_values in
727 // arg_value.tests[]. In most cases, the current value of "mismatched"
728 // would fit this requirement. But on the off-chance that it happens
729 // to collide, we double-check.
730 try_again:
731 for (int n = arg_value.size; n-- > 0; ) {
732 if (mismatched == arg_value.tests[n].k_value) {
733 ++mismatched;
734 goto try_again;
735 }
736 }
737 // Now verify that we see the expected return value from system calls,
738 // if we pass a value that doesn't match any of the conditions (i.e. this
739 // is testing the "else" clause of the conditions).
740 args[arg_value.argno] = mismatched;
741 if (arg_value.err) {
742 VerifyErrno(sysno, args, arg_value.err);
743 } else {
744 Verify(sysno, args, *arg_value.arg_value);
745 }
746 // Reset args[arg_value.argno]. This is not technically needed, but it
747 // makes it easier to reason about the correctness of our tests.
748 args[arg_value.argno] = 0;
749 }
750
751 void VerifyErrno(int sysno, intptr_t *args, int err) {
752 // We installed BPF filters that return different errno values
753 // based on the system call number and the parameters that we decided
754 // to pass in. Verify that this condition holds true.
755 BPF_ASSERT(SandboxSyscall(sysno,
756 args[0], args[1], args[2],
757 args[3], args[4], args[5]) == -err);
758 }
759
760 // Vector of ArgValue trees. These trees define all the possible boolean
761 // expressions that we want to turn into a BPF filter program.
762 std::vector<ArgValue *> arg_values_;
763
764 // Don't increase these values. We are pushing the limits of the maximum
765 // BPF program that the kernel will allow us to load. If the values are
766 // increased too much, the test will start failing.
767 static const int kNumTestCases = 50;
768 static const int kMaxFanOut = 3;
769 static const int kMaxArgs = 6;
770 };
771
772 ErrorCode EqualityStressTestPolicy(int sysno, void *aux) {
773 return reinterpret_cast<EqualityStressTest *>(aux)->Policy(sysno);
774 }
775
776 BPF_TEST(SandboxBpf, EqualityTests, EqualityStressTestPolicy,
777 EqualityStressTest /* BPF_AUX */) {
778 BPF_AUX.VerifyFilter();
779 }
780
483 } // namespace 781 } // namespace
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698