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 156 157 158 159 160 161
|
// Copyright 2014 The Chromium Authors
// 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 "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) {}
FourtyTwo(const FourtyTwo&) = delete;
FourtyTwo& operator=(const FourtyTwo&) = delete;
int value() { return value_; }
private:
int value_;
};
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(const EnosysPtracePolicy&) = delete;
EnosysPtracePolicy& operator=(const EnosysPtracePolicy&) = delete;
~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_;
};
class BasicBPFTesterDelegate : public BPFTesterDelegate {
public:
BasicBPFTesterDelegate() {}
BasicBPFTesterDelegate(const BasicBPFTesterDelegate&) = delete;
BasicBPFTesterDelegate& operator=(const BasicBPFTesterDelegate&) = delete;
~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);
}
};
// 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
|