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