OLD | NEW |
---|---|
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 |
OLD | NEW |