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