summaryrefslogtreecommitdiffstats
path: root/security/sandbox/chromium/sandbox/linux/seccomp-bpf/bpf_tests_unittest.cc
blob: d45bc87292d2f400b4a3769c45b433e2453e46f2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "sandbox/linux/seccomp-bpf/bpf_tests.h"

#include <errno.h>
#include <sys/ptrace.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <unistd.h>

#include <memory>

#include "base/logging.h"
#include "base/macros.h"
#include "build/build_config.h"
#include "sandbox/linux/bpf_dsl/bpf_dsl.h"
#include "sandbox/linux/bpf_dsl/policy.h"
#include "sandbox/linux/seccomp-bpf/sandbox_bpf.h"
#include "sandbox/linux/services/syscall_wrappers.h"
#include "sandbox/linux/system_headers/linux_syscalls.h"
#include "sandbox/linux/tests/unit_tests.h"
#include "testing/gtest/include/gtest/gtest.h"

using sandbox::bpf_dsl::Allow;
using sandbox::bpf_dsl::Error;
using sandbox::bpf_dsl::ResultExpr;

namespace sandbox {

namespace {

class FourtyTwo {
 public:
  static const int kMagicValue = 42;
  FourtyTwo() : value_(kMagicValue) {}
  int value() { return value_; }

 private:
  int value_;
  DISALLOW_COPY_AND_ASSIGN(FourtyTwo);
};

class EmptyClassTakingPolicy : public bpf_dsl::Policy {
 public:
  explicit EmptyClassTakingPolicy(FourtyTwo* fourty_two) {
    BPF_ASSERT(fourty_two);
    BPF_ASSERT(FourtyTwo::kMagicValue == fourty_two->value());
  }
  ~EmptyClassTakingPolicy() override {}

  ResultExpr EvaluateSyscall(int sysno) const override {
    DCHECK(SandboxBPF::IsValidSyscallNumber(sysno));
    return Allow();
  }
};

BPF_TEST(BPFTest,
         BPFAUXPointsToClass,
         EmptyClassTakingPolicy,
         FourtyTwo /* *BPF_AUX */) {
  // BPF_AUX should point to an instance of FourtyTwo.
  BPF_ASSERT(BPF_AUX);
  BPF_ASSERT(FourtyTwo::kMagicValue == BPF_AUX->value());
}

void DummyTestFunction(FourtyTwo *fourty_two) {
}

TEST(BPFTest, BPFTesterCompatibilityDelegateLeakTest) {
  // Don't do anything, simply gives dynamic tools an opportunity to detect
  // leaks.
  {
    BPFTesterCompatibilityDelegate<EmptyClassTakingPolicy, FourtyTwo>
        simple_delegate(DummyTestFunction);
  }
  {
    // Test polymorphism.
    std::unique_ptr<BPFTesterDelegate> simple_delegate(
        new BPFTesterCompatibilityDelegate<EmptyClassTakingPolicy, FourtyTwo>(
            DummyTestFunction));
  }
}

class EnosysPtracePolicy : public bpf_dsl::Policy {
 public:
  EnosysPtracePolicy() { my_pid_ = sys_getpid(); }
  ~EnosysPtracePolicy() override {
    // Policies should be able to bind with the process on which they are
    // created. They should never be created in a parent process.
    BPF_ASSERT_EQ(my_pid_, sys_getpid());
  }

  ResultExpr EvaluateSyscall(int system_call_number) const override {
    CHECK(SandboxBPF::IsValidSyscallNumber(system_call_number));
    if (system_call_number == __NR_ptrace) {
      // The EvaluateSyscall function should run in the process that created
      // the current object.
      BPF_ASSERT_EQ(my_pid_, sys_getpid());
      return Error(ENOSYS);
    } else {
      return Allow();
    }
  }

 private:
  pid_t my_pid_;
  DISALLOW_COPY_AND_ASSIGN(EnosysPtracePolicy);
};

class BasicBPFTesterDelegate : public BPFTesterDelegate {
 public:
  BasicBPFTesterDelegate() {}
  ~BasicBPFTesterDelegate() override {}

  std::unique_ptr<bpf_dsl::Policy> GetSandboxBPFPolicy() override {
    return std::unique_ptr<bpf_dsl::Policy>(new EnosysPtracePolicy());
  }
  void RunTestFunction() override {
    errno = 0;
    int ret = ptrace(PTRACE_TRACEME, -1, NULL, NULL);
    BPF_ASSERT(-1 == ret);
    BPF_ASSERT(ENOSYS == errno);
  }

 private:
  DISALLOW_COPY_AND_ASSIGN(BasicBPFTesterDelegate);
};

// This is the most powerful and complex way to create a BPF test, but it
// requires a full class definition (BasicBPFTesterDelegate).
BPF_TEST_D(BPFTest, BPFTestWithDelegateClass, BasicBPFTesterDelegate)

// This is the simplest form of BPF tests.
BPF_TEST_C(BPFTest, BPFTestWithInlineTest, EnosysPtracePolicy) {
  errno = 0;
  int ret = ptrace(PTRACE_TRACEME, -1, NULL, NULL);
  BPF_ASSERT(-1 == ret);
  BPF_ASSERT(ENOSYS == errno);
}

const char kHelloMessage[] = "Hello";

BPF_DEATH_TEST_C(BPFTest,
                 BPFDeathTestWithInlineTest,
                 DEATH_MESSAGE(kHelloMessage),
                 EnosysPtracePolicy) {
  LOG(ERROR) << kHelloMessage;
  _exit(1);
}

}  // namespace

}  // namespace sandbox