| 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 "sandbox/linux/bpf_dsl/bpf_dsl.h" | 5 #include "sandbox/linux/bpf_dsl/bpf_dsl.h" |
| 6 | 6 |
| 7 #include <errno.h> | 7 #include <errno.h> |
| 8 #include <fcntl.h> | 8 #include <fcntl.h> |
| 9 #include <pthread.h> | 9 #include <pthread.h> |
| 10 #include <sched.h> | 10 #include <sched.h> |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 73 // function has completed. | 73 // function has completed. |
| 74 setenv(kSandboxDebuggingEnv, "t", 0); | 74 setenv(kSandboxDebuggingEnv, "t", 0); |
| 75 Die::SuppressInfoMessages(true); | 75 Die::SuppressInfoMessages(true); |
| 76 } | 76 } |
| 77 | 77 |
| 78 // This test should execute no matter whether we have kernel support. So, | 78 // This test should execute no matter whether we have kernel support. So, |
| 79 // we make it a TEST() instead of a BPF_TEST(). | 79 // we make it a TEST() instead of a BPF_TEST(). |
| 80 TEST(SandboxBPF, DISABLE_ON_TSAN(CallSupports)) { | 80 TEST(SandboxBPF, DISABLE_ON_TSAN(CallSupports)) { |
| 81 // We check that we don't crash, but it's ok if the kernel doesn't | 81 // We check that we don't crash, but it's ok if the kernel doesn't |
| 82 // support it. | 82 // support it. |
| 83 const int seccomp_support = SandboxBPF::SupportsSeccompSandbox(); |
| 83 bool seccomp_bpf_supported = | 84 bool seccomp_bpf_supported = |
| 84 SandboxBPF::SupportsSeccompSandbox() == SandboxBPF::STATUS_AVAILABLE; | 85 seccomp_support & SandboxBPF::SECCOMP_SINGLE_THREADED; |
| 86 bool seccomp_bpf_tsync_supported = |
| 87 seccomp_support & SandboxBPF::SECCOMP_MULTI_THREADED; |
| 88 |
| 85 // We want to log whether or not seccomp BPF is actually supported | 89 // We want to log whether or not seccomp BPF is actually supported |
| 86 // since actual test coverage depends on it. | 90 // since actual test coverage depends on it. |
| 87 RecordProperty("SeccompBPFSupported", | 91 std::cout << "Seccomp BPF supported (single thread): " |
| 88 seccomp_bpf_supported ? "true." : "false."); | |
| 89 std::cout << "Seccomp BPF supported: " | |
| 90 << (seccomp_bpf_supported ? "true." : "false.") << "\n"; | 92 << (seccomp_bpf_supported ? "true." : "false.") << "\n"; |
| 91 RecordProperty("PointerSize", sizeof(void*)); | 93 std::cout << "Seccomp BPF supported (multi thread): " |
| 94 << (seccomp_bpf_tsync_supported ? "true." : "false.") << "\n"; |
| 92 std::cout << "Pointer size: " << sizeof(void*) << "\n"; | 95 std::cout << "Pointer size: " << sizeof(void*) << "\n"; |
| 93 } | 96 } |
| 94 | 97 |
| 95 SANDBOX_TEST(SandboxBPF, DISABLE_ON_TSAN(CallSupportsTwice)) { | 98 SANDBOX_TEST(SandboxBPF, DISABLE_ON_TSAN(CallSupportsTwice)) { |
| 96 SandboxBPF::SupportsSeccompSandbox(); | 99 SandboxBPF::SupportsSeccompSandbox(); |
| 97 SandboxBPF::SupportsSeccompSandbox(); | 100 SandboxBPF::SupportsSeccompSandbox(); |
| 98 } | 101 } |
| 99 | 102 |
| 100 // BPF_TEST does a lot of the boiler-plate code around setting up a | 103 // BPF_TEST does a lot of the boiler-plate code around setting up a |
| 101 // policy and optional passing data between the caller, the policy and | 104 // policy and optional passing data between the caller, the policy and |
| (...skipping 22 matching lines...) Expand all Loading... |
| 124 return Allow(); | 127 return Allow(); |
| 125 } | 128 } |
| 126 | 129 |
| 127 private: | 130 private: |
| 128 int* counter_ptr_; | 131 int* counter_ptr_; |
| 129 | 132 |
| 130 DISALLOW_COPY_AND_ASSIGN(VerboseAPITestingPolicy); | 133 DISALLOW_COPY_AND_ASSIGN(VerboseAPITestingPolicy); |
| 131 }; | 134 }; |
| 132 | 135 |
| 133 SANDBOX_TEST(SandboxBPF, DISABLE_ON_TSAN(VerboseAPITesting)) { | 136 SANDBOX_TEST(SandboxBPF, DISABLE_ON_TSAN(VerboseAPITesting)) { |
| 134 if (SandboxBPF::SupportsSeccompSandbox() == | 137 if (SandboxBPF::SupportsSeccompSandbox() & |
| 135 sandbox::SandboxBPF::STATUS_AVAILABLE) { | 138 SandboxBPF::SECCOMP_SINGLE_THREADED) { |
| 136 static int counter = 0; | 139 static int counter = 0; |
| 137 | 140 |
| 138 SandboxBPF sandbox; | 141 SandboxBPF sandbox; |
| 139 sandbox.SetSandboxPolicy(new VerboseAPITestingPolicy(&counter)); | 142 sandbox.SetSandboxPolicy(new VerboseAPITestingPolicy(&counter)); |
| 140 BPF_ASSERT(sandbox.StartSandbox(SandboxBPF::PROCESS_SINGLE_THREADED)); | 143 BPF_ASSERT(sandbox.StartSandbox(SandboxBPF::SECCOMP_SINGLE_THREADED)); |
| 141 | 144 |
| 142 BPF_ASSERT_EQ(0, counter); | 145 BPF_ASSERT_EQ(0, counter); |
| 143 BPF_ASSERT_EQ(0, syscall(__NR_uname, 0)); | 146 BPF_ASSERT_EQ(0, syscall(__NR_uname, 0)); |
| 144 BPF_ASSERT_EQ(1, counter); | 147 BPF_ASSERT_EQ(1, counter); |
| 145 BPF_ASSERT_EQ(1, syscall(__NR_uname, 0)); | 148 BPF_ASSERT_EQ(1, syscall(__NR_uname, 0)); |
| 146 BPF_ASSERT_EQ(2, counter); | 149 BPF_ASSERT_EQ(2, counter); |
| 147 } | 150 } |
| 148 } | 151 } |
| 149 | 152 |
| 150 // A simple blacklist test | 153 // A simple blacklist test |
| (...skipping 21 matching lines...) Expand all Loading... |
| 172 } | 175 } |
| 173 | 176 |
| 174 private: | 177 private: |
| 175 DISALLOW_COPY_AND_ASSIGN(BlacklistNanosleepPolicy); | 178 DISALLOW_COPY_AND_ASSIGN(BlacklistNanosleepPolicy); |
| 176 }; | 179 }; |
| 177 | 180 |
| 178 BPF_TEST_C(SandboxBPF, ApplyBasicBlacklistPolicy, BlacklistNanosleepPolicy) { | 181 BPF_TEST_C(SandboxBPF, ApplyBasicBlacklistPolicy, BlacklistNanosleepPolicy) { |
| 179 BlacklistNanosleepPolicy::AssertNanosleepFails(); | 182 BlacklistNanosleepPolicy::AssertNanosleepFails(); |
| 180 } | 183 } |
| 181 | 184 |
| 185 BPF_TEST_C(SandboxBPF, UseVsyscall, BlacklistNanosleepPolicy) { |
| 186 time_t current_time; |
| 187 // time() is implemented as a vsyscall. With an older glibc, with |
| 188 // vsyscall=emulate and some versions of the seccomp BPF patch |
| 189 // we may get SIGKILL-ed. Detect this! |
| 190 BPF_ASSERT_NE(static_cast<time_t>(-1), time(¤t_time)); |
| 191 } |
| 192 |
| 182 // Now do a simple whitelist test | 193 // Now do a simple whitelist test |
| 183 | 194 |
| 184 class WhitelistGetpidPolicy : public Policy { | 195 class WhitelistGetpidPolicy : public Policy { |
| 185 public: | 196 public: |
| 186 WhitelistGetpidPolicy() {} | 197 WhitelistGetpidPolicy() {} |
| 187 ~WhitelistGetpidPolicy() override {} | 198 ~WhitelistGetpidPolicy() override {} |
| 188 | 199 |
| 189 ResultExpr EvaluateSyscall(int sysno) const override { | 200 ResultExpr EvaluateSyscall(int sysno) const override { |
| 190 DCHECK(SandboxBPF::IsValidSyscallNumber(sysno)); | 201 DCHECK(SandboxBPF::IsValidSyscallNumber(sysno)); |
| 191 switch (sysno) { | 202 switch (sysno) { |
| (...skipping 199 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 391 BPF_ASSERT(syscall(__NR_getppid, 0) > 0); | 402 BPF_ASSERT(syscall(__NR_getppid, 0) > 0); |
| 392 BPF_ASSERT(errno == 0); | 403 BPF_ASSERT(errno == 0); |
| 393 | 404 |
| 394 BPF_ASSERT(syscall(__NR_getppid, 1) == -1); | 405 BPF_ASSERT(syscall(__NR_getppid, 1) == -1); |
| 395 BPF_ASSERT(errno == EPERM); | 406 BPF_ASSERT(errno == EPERM); |
| 396 | 407 |
| 397 // Stack a second sandbox with its own policy. Verify that we can further | 408 // Stack a second sandbox with its own policy. Verify that we can further |
| 398 // restrict filters, but we cannot relax existing filters. | 409 // restrict filters, but we cannot relax existing filters. |
| 399 SandboxBPF sandbox; | 410 SandboxBPF sandbox; |
| 400 sandbox.SetSandboxPolicy(new StackingPolicyPartTwo()); | 411 sandbox.SetSandboxPolicy(new StackingPolicyPartTwo()); |
| 401 BPF_ASSERT(sandbox.StartSandbox(SandboxBPF::PROCESS_SINGLE_THREADED)); | 412 BPF_ASSERT(sandbox.StartSandbox(SandboxBPF::SECCOMP_SINGLE_THREADED)); |
| 402 | 413 |
| 403 errno = 0; | 414 errno = 0; |
| 404 BPF_ASSERT(syscall(__NR_getppid, 0) == -1); | 415 BPF_ASSERT(syscall(__NR_getppid, 0) == -1); |
| 405 BPF_ASSERT(errno == EINVAL); | 416 BPF_ASSERT(errno == EINVAL); |
| 406 | 417 |
| 407 BPF_ASSERT(syscall(__NR_getppid, 1) == -1); | 418 BPF_ASSERT(syscall(__NR_getppid, 1) == -1); |
| 408 BPF_ASSERT(errno == EPERM); | 419 BPF_ASSERT(errno == EPERM); |
| 409 } | 420 } |
| 410 | 421 |
| 411 // A more complex, but synthetic policy. This tests the correctness of the BPF | 422 // A more complex, but synthetic policy. This tests the correctness of the BPF |
| (...skipping 1650 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2062 | 2073 |
| 2063 ResultExpr EvaluateSyscall(int system_call_number) const override { | 2074 ResultExpr EvaluateSyscall(int system_call_number) const override { |
| 2064 return Trace(kTraceData); | 2075 return Trace(kTraceData); |
| 2065 } | 2076 } |
| 2066 | 2077 |
| 2067 private: | 2078 private: |
| 2068 DISALLOW_COPY_AND_ASSIGN(TraceAllPolicy); | 2079 DISALLOW_COPY_AND_ASSIGN(TraceAllPolicy); |
| 2069 }; | 2080 }; |
| 2070 | 2081 |
| 2071 SANDBOX_TEST(SandboxBPF, DISABLE_ON_TSAN(SeccompRetTrace)) { | 2082 SANDBOX_TEST(SandboxBPF, DISABLE_ON_TSAN(SeccompRetTrace)) { |
| 2072 if (SandboxBPF::SupportsSeccompSandbox() != | 2083 if (SandboxBPF::SupportsSeccompSandbox() == SandboxBPF::SECCOMP_NONE) { |
| 2073 sandbox::SandboxBPF::STATUS_AVAILABLE) { | |
| 2074 return; | 2084 return; |
| 2075 } | 2085 } |
| 2076 | 2086 |
| 2077 // This test is disabled on arm due to a kernel bug. | 2087 // This test is disabled on arm due to a kernel bug. |
| 2078 // See https://code.google.com/p/chromium/issues/detail?id=383977 | 2088 // See https://code.google.com/p/chromium/issues/detail?id=383977 |
| 2079 #if defined(__arm__) || defined(__aarch64__) | 2089 #if defined(__arm__) || defined(__aarch64__) |
| 2080 printf("This test is currently disabled on ARM32/64 due to a kernel bug."); | 2090 printf("This test is currently disabled on ARM32/64 due to a kernel bug."); |
| 2081 return; | 2091 return; |
| 2082 #endif | 2092 #endif |
| 2083 | 2093 |
| 2084 #if defined(__mips__) | 2094 #if defined(__mips__) |
| 2085 // TODO: Figure out how to support specificity of handling indirect syscalls | 2095 // TODO: Figure out how to support specificity of handling indirect syscalls |
| 2086 // in this test and enable it. | 2096 // in this test and enable it. |
| 2087 printf("This test is currently disabled on MIPS."); | 2097 printf("This test is currently disabled on MIPS."); |
| 2088 return; | 2098 return; |
| 2089 #endif | 2099 #endif |
| 2090 | 2100 |
| 2091 pid_t pid = fork(); | 2101 pid_t pid = fork(); |
| 2092 BPF_ASSERT_NE(-1, pid); | 2102 BPF_ASSERT_NE(-1, pid); |
| 2093 if (pid == 0) { | 2103 if (pid == 0) { |
| 2094 pid_t my_pid = getpid(); | 2104 pid_t my_pid = getpid(); |
| 2095 BPF_ASSERT_NE(-1, ptrace(PTRACE_TRACEME, -1, NULL, NULL)); | 2105 BPF_ASSERT_NE(-1, ptrace(PTRACE_TRACEME, -1, NULL, NULL)); |
| 2096 BPF_ASSERT_EQ(0, raise(SIGSTOP)); | 2106 BPF_ASSERT_EQ(0, raise(SIGSTOP)); |
| 2097 SandboxBPF sandbox; | 2107 SandboxBPF sandbox; |
| 2098 sandbox.SetSandboxPolicy(new TraceAllPolicy); | 2108 sandbox.SetSandboxPolicy(new TraceAllPolicy); |
| 2099 BPF_ASSERT(sandbox.StartSandbox(SandboxBPF::PROCESS_SINGLE_THREADED)); | 2109 BPF_ASSERT(sandbox.StartSandbox(SandboxBPF::SECCOMP_SINGLE_THREADED)); |
| 2100 | 2110 |
| 2101 // getpid is allowed. | 2111 // getpid is allowed. |
| 2102 BPF_ASSERT_EQ(my_pid, sys_getpid()); | 2112 BPF_ASSERT_EQ(my_pid, sys_getpid()); |
| 2103 | 2113 |
| 2104 // write to stdout is skipped and returns a fake value. | 2114 // write to stdout is skipped and returns a fake value. |
| 2105 BPF_ASSERT_EQ(kExpectedReturnValue, | 2115 BPF_ASSERT_EQ(kExpectedReturnValue, |
| 2106 syscall(__NR_write, STDOUT_FILENO, "A", 1)); | 2116 syscall(__NR_write, STDOUT_FILENO, "A", 1)); |
| 2107 | 2117 |
| 2108 // kill is rewritten to exit(kExpectedReturnValue). | 2118 // kill is rewritten to exit(kExpectedReturnValue). |
| 2109 syscall(__NR_kill, my_pid, SIGKILL); | 2119 syscall(__NR_kill, my_pid, SIGKILL); |
| (...skipping 150 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2260 } | 2270 } |
| 2261 | 2271 |
| 2262 BPF_ASSERT(event->IsSignaled()); | 2272 BPF_ASSERT(event->IsSignaled()); |
| 2263 | 2273 |
| 2264 BlacklistNanosleepPolicy::AssertNanosleepFails(); | 2274 BlacklistNanosleepPolicy::AssertNanosleepFails(); |
| 2265 | 2275 |
| 2266 return NULL; | 2276 return NULL; |
| 2267 } | 2277 } |
| 2268 | 2278 |
| 2269 SANDBOX_TEST(SandboxBPF, Tsync) { | 2279 SANDBOX_TEST(SandboxBPF, Tsync) { |
| 2270 if (SandboxBPF::SupportsSeccompThreadFilterSynchronization() != | 2280 if ((SandboxBPF::SupportsSeccompSandbox() & |
| 2271 SandboxBPF::STATUS_AVAILABLE) { | 2281 SandboxBPF::SECCOMP_MULTI_THREADED) == 0) { |
| 2272 return; | 2282 return; |
| 2273 } | 2283 } |
| 2274 | 2284 |
| 2275 base::WaitableEvent event(true, false); | 2285 base::WaitableEvent event(true, false); |
| 2276 | 2286 |
| 2277 // Create a thread on which to invoke the blocked syscall. | 2287 // Create a thread on which to invoke the blocked syscall. |
| 2278 pthread_t thread; | 2288 pthread_t thread; |
| 2279 BPF_ASSERT_EQ( | 2289 BPF_ASSERT_EQ( |
| 2280 0, pthread_create(&thread, NULL, &TsyncApplyToTwoThreadsFunc, &event)); | 2290 0, pthread_create(&thread, NULL, &TsyncApplyToTwoThreadsFunc, &event)); |
| 2281 | 2291 |
| 2282 // Test that nanoseelp success. | 2292 // Test that nanoseelp success. |
| 2283 const struct timespec ts = {0, 0}; | 2293 const struct timespec ts = {0, 0}; |
| 2284 BPF_ASSERT_EQ(0, HANDLE_EINTR(syscall(__NR_nanosleep, &ts, NULL))); | 2294 BPF_ASSERT_EQ(0, HANDLE_EINTR(syscall(__NR_nanosleep, &ts, NULL))); |
| 2285 | 2295 |
| 2286 // Engage the sandbox. | 2296 // Engage the sandbox. |
| 2287 SandboxBPF sandbox; | 2297 SandboxBPF sandbox; |
| 2288 sandbox.SetSandboxPolicy(new BlacklistNanosleepPolicy()); | 2298 sandbox.SetSandboxPolicy(new BlacklistNanosleepPolicy()); |
| 2289 BPF_ASSERT(sandbox.StartSandbox(SandboxBPF::PROCESS_MULTI_THREADED)); | 2299 BPF_ASSERT(sandbox.StartSandbox(SandboxBPF::SECCOMP_MULTI_THREADED)); |
| 2290 | 2300 |
| 2291 // This thread should have the filter applied as well. | 2301 // This thread should have the filter applied as well. |
| 2292 BlacklistNanosleepPolicy::AssertNanosleepFails(); | 2302 BlacklistNanosleepPolicy::AssertNanosleepFails(); |
| 2293 | 2303 |
| 2294 // Signal the condition to invoke the system call. | 2304 // Signal the condition to invoke the system call. |
| 2295 event.Signal(); | 2305 event.Signal(); |
| 2296 | 2306 |
| 2297 // Wait for the thread to finish. | 2307 // Wait for the thread to finish. |
| 2298 BPF_ASSERT_EQ(0, pthread_join(thread, NULL)); | 2308 BPF_ASSERT_EQ(0, pthread_join(thread, NULL)); |
| 2299 } | 2309 } |
| (...skipping 11 matching lines...) Expand all Loading... |
| 2311 | 2321 |
| 2312 SANDBOX_DEATH_TEST( | 2322 SANDBOX_DEATH_TEST( |
| 2313 SandboxBPF, | 2323 SandboxBPF, |
| 2314 StartMultiThreadedAsSingleThreaded, | 2324 StartMultiThreadedAsSingleThreaded, |
| 2315 DEATH_MESSAGE("Cannot start sandbox; process is already multi-threaded")) { | 2325 DEATH_MESSAGE("Cannot start sandbox; process is already multi-threaded")) { |
| 2316 base::Thread thread("sandbox.linux.StartMultiThreadedAsSingleThreaded"); | 2326 base::Thread thread("sandbox.linux.StartMultiThreadedAsSingleThreaded"); |
| 2317 BPF_ASSERT(thread.Start()); | 2327 BPF_ASSERT(thread.Start()); |
| 2318 | 2328 |
| 2319 SandboxBPF sandbox; | 2329 SandboxBPF sandbox; |
| 2320 sandbox.SetSandboxPolicy(new AllowAllPolicy()); | 2330 sandbox.SetSandboxPolicy(new AllowAllPolicy()); |
| 2321 BPF_ASSERT(!sandbox.StartSandbox(SandboxBPF::PROCESS_SINGLE_THREADED)); | 2331 BPF_ASSERT(!sandbox.StartSandbox(SandboxBPF::SECCOMP_SINGLE_THREADED)); |
| 2322 } | 2332 } |
| 2323 | 2333 |
| 2324 // http://crbug.com/407357 | 2334 // http://crbug.com/407357 |
| 2325 #if !defined(THREAD_SANITIZER) | 2335 #if !defined(THREAD_SANITIZER) |
| 2326 SANDBOX_DEATH_TEST( | 2336 SANDBOX_DEATH_TEST( |
| 2327 SandboxBPF, | 2337 SandboxBPF, |
| 2328 StartSingleThreadedAsMultiThreaded, | 2338 StartSingleThreadedAsMultiThreaded, |
| 2329 DEATH_MESSAGE( | 2339 DEATH_MESSAGE( |
| 2330 "Cannot start sandbox; process may be single-threaded when " | 2340 "Cannot start sandbox; process may be single-threaded when " |
| 2331 "reported as not")) { | 2341 "reported as not")) { |
| 2332 SandboxBPF sandbox; | 2342 SandboxBPF sandbox; |
| 2333 sandbox.SetSandboxPolicy(new AllowAllPolicy()); | 2343 sandbox.SetSandboxPolicy(new AllowAllPolicy()); |
| 2334 BPF_ASSERT(!sandbox.StartSandbox(SandboxBPF::PROCESS_MULTI_THREADED)); | 2344 BPF_ASSERT(!sandbox.StartSandbox(SandboxBPF::SECCOMP_MULTI_THREADED)); |
| 2335 } | 2345 } |
| 2336 #endif // !defined(THREAD_SANITIZER) | 2346 #endif // !defined(THREAD_SANITIZER) |
| 2337 | 2347 |
| 2338 // A stub handler for the UnsafeTrap. Never called. | 2348 // A stub handler for the UnsafeTrap. Never called. |
| 2339 intptr_t NoOpHandler(const struct arch_seccomp_data& args, void*) { | 2349 intptr_t NoOpHandler(const struct arch_seccomp_data& args, void*) { |
| 2340 return -1; | 2350 return -1; |
| 2341 } | 2351 } |
| 2342 | 2352 |
| 2343 class UnsafeTrapWithCondPolicy : public Policy { | 2353 class UnsafeTrapWithCondPolicy : public Policy { |
| 2344 public: | 2354 public: |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2394 BPF_ASSERT_EQ(ENOSYS, errno); | 2404 BPF_ASSERT_EQ(ENOSYS, errno); |
| 2395 | 2405 |
| 2396 BPF_ASSERT_EQ(-1, syscall(__NR_setgid, 300)); | 2406 BPF_ASSERT_EQ(-1, syscall(__NR_setgid, 300)); |
| 2397 BPF_ASSERT_EQ(EPERM, errno); | 2407 BPF_ASSERT_EQ(EPERM, errno); |
| 2398 } | 2408 } |
| 2399 | 2409 |
| 2400 } // namespace | 2410 } // namespace |
| 2401 | 2411 |
| 2402 } // namespace bpf_dsl | 2412 } // namespace bpf_dsl |
| 2403 } // namespace sandbox | 2413 } // namespace sandbox |
| OLD | NEW |