Chromium Code Reviews| Index: sandbox/linux/seccomp-bpf/sandbox_bpf_unittest.cc |
| diff --git a/sandbox/linux/seccomp-bpf/sandbox_bpf_unittest.cc b/sandbox/linux/seccomp-bpf/sandbox_bpf_unittest.cc |
| index 06ba2090c915a4ba2429406943da893ec906d76f..95fcbc6b5eb800906fe6e2ef319066825b48b5b5 100644 |
| --- a/sandbox/linux/seccomp-bpf/sandbox_bpf_unittest.cc |
| +++ b/sandbox/linux/seccomp-bpf/sandbox_bpf_unittest.cc |
| @@ -34,6 +34,7 @@ |
| #include "sandbox/linux/seccomp-bpf/verifier.h" |
| #include "sandbox/linux/services/broker_process.h" |
| #include "sandbox/linux/services/linux_syscalls.h" |
| +#include "sandbox/linux/tests/scoped_temporary_file.h" |
| #include "sandbox/linux/tests/unit_tests.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| @@ -53,6 +54,17 @@ namespace { |
| const int kExpectedReturnValue = 42; |
| const char kSandboxDebuggingEnv[] = "CHROME_SANDBOX_DEBUGGING"; |
| +// Set the global environment to allow the use of UnsafeTrap() policies. |
| +void EnableUnsafeTraps() { |
| + // The use of UnsafeTrap() causes us to print a warning message. This is |
| + // generally desirable, but it results in the unittest failing, as it doesn't |
| + // expect any messages on "stderr". So, temporarily disable messages. The |
| + // BPF_TEST() is guaranteed to turn messages back on, after the policy |
| + // function has completed. |
| + setenv(kSandboxDebuggingEnv, "t", 0); |
| + Die::SuppressInfoMessages(true); |
| +} |
| + |
| // This test should execute no matter whether we have kernel support. So, |
| // we make it a TEST() instead of a BPF_TEST(). |
| TEST(SandboxBPF, DISABLE_ON_TSAN(CallSupports)) { |
| @@ -480,13 +492,10 @@ intptr_t CountSyscalls(const struct arch_seccomp_data& args, void* aux) { |
| } |
| ErrorCode GreyListedPolicy(SandboxBPF* sandbox, int sysno, int* aux) { |
| - // The use of UnsafeTrap() causes us to print a warning message. This is |
| - // generally desirable, but it results in the unittest failing, as it doesn't |
| - // expect any messages on "stderr". So, temporarily disable messages. The |
| - // BPF_TEST() is guaranteed to turn messages back on, after the policy |
| - // function has completed. |
| - setenv(kSandboxDebuggingEnv, "t", 0); |
| - Die::SuppressInfoMessages(true); |
| + // Set the global environment for unsafe traps once. |
| + if (sysno == MIN_SYSCALL) { |
| + EnableUnsafeTraps(); |
| + } |
| // Some system calls must always be allowed, if our policy wants to make |
| // use of UnsafeTrap() |
| @@ -2059,6 +2068,88 @@ SANDBOX_TEST(SandboxBPF, DISABLE_ON_TSAN(SeccompRetTrace)) { |
| } |
| } |
| +// Android does not expose pread64 nor pwrite64. |
| +#if !defined(OS_ANDROID) |
| + |
| +bool FullPwrite64(int fd, const char* buffer, size_t count, off64_t offset) { |
| + while (count > 0) { |
| + const ssize_t transfered = |
| + HANDLE_EINTR(pwrite64(fd, buffer, count, offset)); |
| + if (transfered <= 0 || static_cast<size_t>(transfered) > count) { |
| + return false; |
| + } |
| + count -= transfered; |
| + buffer += transfered; |
| + offset += transfered; |
| + } |
| + return true; |
| +} |
| + |
| +bool FullPread64(int fd, char* buffer, size_t count, off64_t offset) { |
| + while (count > 0) { |
| + const ssize_t transfered = HANDLE_EINTR(pread64(fd, buffer, count, offset)); |
| + if (transfered <= 0 || static_cast<size_t>(transfered) > count) { |
| + return false; |
| + } |
| + count -= transfered; |
| + buffer += transfered; |
| + offset += transfered; |
| + } |
| + return true; |
| +} |
| + |
| +bool pread_64_was_forwarded = false; |
| + |
| +class TrapPread64Policy : public SandboxBPFPolicy { |
| + public: |
| + TrapPread64Policy() {} |
| + virtual ~TrapPread64Policy() {} |
| + |
| + virtual ErrorCode EvaluateSyscall(SandboxBPF* sandbox_compiler, |
| + int system_call_number) const OVERRIDE { |
| + // Set the global environment for unsafe traps once. |
| + if (system_call_number == MIN_SYSCALL) { |
| + EnableUnsafeTraps(); |
| + } |
| + |
| + if (system_call_number == __NR_pread64) { |
| + return sandbox_compiler->UnsafeTrap(ForwardPreadHandler, NULL); |
| + } |
| + return ErrorCode(ErrorCode::ERR_ALLOWED); |
| + } |
| + |
| + private: |
| + static intptr_t ForwardPreadHandler(const struct arch_seccomp_data& args, |
| + void* aux) { |
| + BPF_ASSERT(args.nr == __NR_pread64); |
| + pread_64_was_forwarded = true; |
| + |
| + return SandboxBPF::ForwardSyscall(args); |
| + } |
| + DISALLOW_COPY_AND_ASSIGN(TrapPread64Policy); |
| +}; |
| + |
| +// pread(2) takes a 64 bits offset. On 32 bits systems, it will be split |
| +// between two arguments. In this test, we make sure that ForwardSyscall() can |
| +// forward it properly. |
| +BPF_TEST_C(SandboxBPF, Pread64, TrapPread64Policy) { |
| + ScopedTemporaryFile temp_file; |
| + const uint64_t kLargeOffset = (static_cast<uint64_t>(1) << 32) | 0xBEEF; |
|
mdempsky
2014/06/27 00:37:24
Might also be worth testing an offset in [2^31, 2^
jln (very slow on Chromium)
2014/06/27 01:25:14
Great point! I'll land as-is because of a time con
|
| + const char kTestString[] = "This is a test!"; |
| + BPF_ASSERT(FullPwrite64( |
| + temp_file.fd(), kTestString, sizeof(kTestString), kLargeOffset)); |
| + |
| + char read_test_string[sizeof(kTestString)] = {0}; |
| + BPF_ASSERT(FullPread64(temp_file.fd(), |
| + read_test_string, |
| + sizeof(read_test_string), |
| + kLargeOffset)); |
| + BPF_ASSERT_EQ(0, memcmp(kTestString, read_test_string, sizeof(kTestString))); |
| + BPF_ASSERT(pread_64_was_forwarded); |
| +} |
| + |
| +#endif // !defined(OS_ANDROID) |
| + |
| } // namespace |
| } // namespace sandbox |