1 // Copyright 2014 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "sandbox/linux/seccomp-bpf/bpf_tests.h" 6 7 #include <errno.h> 8 #include <sys/ptrace.h> 9 #include <sys/syscall.h> 10 #include <sys/types.h> 11 #include <unistd.h> 12 13 #include "base/logging.h" 14 #include "base/memory/scoped_ptr.h" 15 #include "build/build_config.h" 16 #include "sandbox/linux/seccomp-bpf/sandbox_bpf.h" 17 #include "sandbox/linux/services/linux_syscalls.h" 18 #include "sandbox/linux/tests/unit_tests.h" 19 #include "testing/gtest/include/gtest/gtest.h" 20 21 namespace sandbox { 22 23 namespace { 24 25 class FourtyTwo { 26 public: 27 static const int kMagicValue = 42; 28 FourtyTwo() : value_(kMagicValue) {} 29 int value() { return value_; } 30 31 private: 32 int value_; 33 DISALLOW_COPY_AND_ASSIGN(FourtyTwo); 34 }; 35 36 class EmptyClassTakingPolicy : public SandboxBPFPolicy { 37 public: 38 explicit EmptyClassTakingPolicy(FourtyTwo* fourty_two) { 39 BPF_ASSERT(fourty_two); 40 BPF_ASSERT(FourtyTwo::kMagicValue == fourty_two->value()); 41 } 42 virtual ~EmptyClassTakingPolicy() {} 43 44 virtual ErrorCode EvaluateSyscall(SandboxBPF* sandbox, 45 int sysno) const OVERRIDE { 46 DCHECK(SandboxBPF::IsValidSyscallNumber(sysno)); 47 return ErrorCode(ErrorCode::ERR_ALLOWED); 48 } 49 }; 50 51 BPF_TEST(BPFTest, 52 BPFAUXPointsToClass, 53 EmptyClassTakingPolicy, 54 FourtyTwo /* *BPF_AUX */) { 55 // BPF_AUX should point to an instance of FourtyTwo. 56 BPF_ASSERT(BPF_AUX); 57 BPF_ASSERT(FourtyTwo::kMagicValue == BPF_AUX->value()); 58 } 59 60 void DummyTestFunction(FourtyTwo *fourty_two) { 61 } 62 63 TEST(BPFTest, BPFTesterCompatibilityDelegateLeakTest) { 64 // Don't do anything, simply gives dynamic tools an opportunity to detect 65 // leaks. 66 { 67 BPFTesterCompatibilityDelegate<EmptyClassTakingPolicy, FourtyTwo> 68 simple_delegate(DummyTestFunction); 69 } 70 { 71 // Test polymorphism. 72 scoped_ptr<BPFTesterDelegate> simple_delegate( 73 new BPFTesterCompatibilityDelegate<EmptyClassTakingPolicy, FourtyTwo>( 74 DummyTestFunction)); 75 } 76 } 77 78 class EnosysPtracePolicy : public SandboxBPFPolicy { 79 public: 80 EnosysPtracePolicy() { 81 my_pid_ = syscall(__NR_getpid); 82 } 83 virtual ~EnosysPtracePolicy() { 84 // Policies should be able to bind with the process on which they are 85 // created. They should never be created in a parent process. 86 BPF_ASSERT_EQ(my_pid_, syscall(__NR_getpid)); 87 } 88 89 virtual ErrorCode EvaluateSyscall(SandboxBPF* sandbox_compiler, 90 int system_call_number) const OVERRIDE { 91 if (!SandboxBPF::IsValidSyscallNumber(system_call_number)) { 92 return ErrorCode(ENOSYS); 93 } else if (system_call_number == __NR_ptrace) { 94 // The EvaluateSyscall function should run in the process that created 95 // the current object. 96 BPF_ASSERT_EQ(my_pid_, syscall(__NR_getpid)); 97 return ErrorCode(ENOSYS); 98 } else { 99 return ErrorCode(ErrorCode::ERR_ALLOWED); 100 } 101 } 102 103 private: 104 pid_t my_pid_; 105 DISALLOW_COPY_AND_ASSIGN(EnosysPtracePolicy); 106 }; 107 108 class BasicBPFTesterDelegate : public BPFTesterDelegate { 109 public: 110 BasicBPFTesterDelegate() {} 111 virtual ~BasicBPFTesterDelegate() {} 112 113 virtual scoped_ptr<SandboxBPFPolicy> GetSandboxBPFPolicy() OVERRIDE { 114 return scoped_ptr<SandboxBPFPolicy>(new EnosysPtracePolicy()); 115 } 116 virtual void RunTestFunction() OVERRIDE { 117 errno = 0; 118 int ret = ptrace(PTRACE_TRACEME, -1, NULL, NULL); 119 BPF_ASSERT(-1 == ret); 120 BPF_ASSERT(ENOSYS == errno); 121 } 122 123 private: 124 DISALLOW_COPY_AND_ASSIGN(BasicBPFTesterDelegate); 125 }; 126 127 // This is the most powerful and complex way to create a BPF test, but it 128 // requires a full class definition (BasicBPFTesterDelegate). 129 BPF_TEST_D(BPFTest, BPFTestWithDelegateClass, BasicBPFTesterDelegate); 130 131 // This is the simplest form of BPF tests. 132 BPF_TEST_C(BPFTest, BPFTestWithInlineTest, EnosysPtracePolicy) { 133 errno = 0; 134 int ret = ptrace(PTRACE_TRACEME, -1, NULL, NULL); 135 BPF_ASSERT(-1 == ret); 136 BPF_ASSERT(ENOSYS == errno); 137 } 138 139 const char kHelloMessage[] = "Hello"; 140 141 BPF_DEATH_TEST_C(BPFTest, 142 BPFDeathTestWithInlineTest, 143 DEATH_MESSAGE(kHelloMessage), 144 EnosysPtracePolicy) { 145 LOG(ERROR) << kHelloMessage; 146 _exit(1); 147 } 148 149 } // namespace 150 151 } // namespace sandbox 152