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