Home | History | Annotate | Download | only in seccomp-bpf
      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