Home | History | Annotate | Download | only in seccomp-bpf
      1 // Copyright (c) 2012 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 <asm/unistd.h>
      6 #include <fcntl.h>
      7 #include <sys/mman.h>
      8 #include <sys/syscall.h>
      9 #include <unistd.h>
     10 
     11 #include <vector>
     12 
     13 #include "base/basictypes.h"
     14 #include "base/posix/eintr_wrapper.h"
     15 #include "sandbox/linux/seccomp-bpf/bpf_tests.h"
     16 #include "sandbox/linux/seccomp-bpf/sandbox_bpf.h"
     17 #include "sandbox/linux/seccomp-bpf/syscall.h"
     18 #include "sandbox/linux/tests/unit_tests.h"
     19 #include "testing/gtest/include/gtest/gtest.h"
     20 
     21 using namespace playground2;
     22 
     23 namespace {
     24 
     25 // Different platforms use different symbols for the six-argument version
     26 // of the mmap() system call. Test for the correct symbol at compile time.
     27 #ifdef __NR_mmap2
     28 const int kMMapNr = __NR_mmap2;
     29 #else
     30 const int kMMapNr = __NR_mmap;
     31 #endif
     32 
     33 TEST(Syscall, WellKnownEntryPoint) {
     34   // Test that SandboxSyscall(-1) is handled specially. Don't do this on ARM,
     35   // where syscall(-1) crashes with SIGILL. Not running the test is fine, as we
     36   // are still testing ARM code in the next set of tests.
     37 #if !defined(__arm__)
     38   EXPECT_NE(SandboxSyscall(-1), syscall(-1));
     39 #endif
     40 
     41   // If possible, test that SandboxSyscall(-1) returns the address right after
     42   // a kernel entry point.
     43 #if defined(__i386__)
     44   EXPECT_EQ(0x80CDu, ((uint16_t *)SandboxSyscall(-1))[-1]);      // INT 0x80
     45 #elif defined(__x86_64__)
     46   EXPECT_EQ(0x050Fu, ((uint16_t *)SandboxSyscall(-1))[-1]);      // SYSCALL
     47 #elif defined(__arm__)
     48 #if defined(__thumb__)
     49   EXPECT_EQ(0xDF00u, ((uint16_t *)SandboxSyscall(-1))[-1]);      // SWI 0
     50 #else
     51   EXPECT_EQ(0xEF000000u, ((uint32_t *)SandboxSyscall(-1))[-1]);  // SVC 0
     52 #endif
     53 #else
     54   #warning Incomplete test case; need port for target platform
     55 #endif
     56 }
     57 
     58 TEST(Syscall, TrivialSyscallNoArgs) {
     59   // Test that we can do basic system calls
     60   EXPECT_EQ(SandboxSyscall(__NR_getpid), syscall(__NR_getpid));
     61 }
     62 
     63 TEST(Syscall, TrivialSyscallOneArg) {
     64   int new_fd;
     65   // Duplicate standard error and close it.
     66   ASSERT_GE(new_fd = SandboxSyscall(__NR_dup, 2), 0);
     67   int close_return_value = HANDLE_EINTR(SandboxSyscall(__NR_close, new_fd));
     68   ASSERT_EQ(close_return_value, 0);
     69 }
     70 
     71 // SIGSYS trap handler that will be called on __NR_uname.
     72 intptr_t CopySyscallArgsToAux(const struct arch_seccomp_data& args, void *aux) {
     73   // |aux| is a pointer to our BPF_AUX.
     74   std::vector<uint64_t>* const seen_syscall_args =
     75       static_cast<std::vector<uint64_t>*>(aux);
     76   BPF_ASSERT(arraysize(args.args) == 6);
     77   seen_syscall_args->assign(args.args, args.args + arraysize(args.args));
     78   return -ENOMEM;
     79 }
     80 
     81 ErrorCode CopyAllArgsOnUnamePolicy(Sandbox *sandbox, int sysno, void *aux) {
     82   if (!Sandbox::IsValidSyscallNumber(sysno)) {
     83     return ErrorCode(ENOSYS);
     84   }
     85   if (sysno == __NR_uname) {
     86     return sandbox->Trap(CopySyscallArgsToAux, aux);
     87   } else {
     88     return ErrorCode(ErrorCode::ERR_ALLOWED);
     89   }
     90 }
     91 
     92 // We are testing SandboxSyscall() by making use of a BPF filter that allows us
     93 // to inspect the system call arguments that the kernel saw.
     94 BPF_TEST(Syscall, SyntheticSixArgs, CopyAllArgsOnUnamePolicy,
     95          std::vector<uint64_t> /* BPF_AUX */) {
     96   const int kExpectedValue = 42;
     97   // In this test we only pass integers to the kernel. We might want to make
     98   // additional tests to try other types. What we will see depends on
     99   // implementation details of kernel BPF filters and we will need to document
    100   // the expected behavior very clearly.
    101   int syscall_args[6];
    102   for (size_t i = 0; i < arraysize(syscall_args); ++i) {
    103     syscall_args[i] = kExpectedValue + i;
    104   }
    105 
    106   // We could use pretty much any system call we don't need here. uname() is
    107   // nice because it doesn't have any dangerous side effects.
    108   BPF_ASSERT(SandboxSyscall(__NR_uname, syscall_args[0],
    109                                         syscall_args[1],
    110                                         syscall_args[2],
    111                                         syscall_args[3],
    112                                         syscall_args[4],
    113                                         syscall_args[5]) == -ENOMEM);
    114 
    115   // We expect the trap handler to have copied the 6 arguments.
    116   BPF_ASSERT(BPF_AUX.size() == 6);
    117 
    118   // Don't loop here so that we can see which argument does cause the failure
    119   // easily from the failing line.
    120   // uint64_t is the type passed to our SIGSYS handler.
    121   BPF_ASSERT(BPF_AUX[0] == static_cast<uint64_t>(syscall_args[0]));
    122   BPF_ASSERT(BPF_AUX[1] == static_cast<uint64_t>(syscall_args[1]));
    123   BPF_ASSERT(BPF_AUX[2] == static_cast<uint64_t>(syscall_args[2]));
    124   BPF_ASSERT(BPF_AUX[3] == static_cast<uint64_t>(syscall_args[3]));
    125   BPF_ASSERT(BPF_AUX[4] == static_cast<uint64_t>(syscall_args[4]));
    126   BPF_ASSERT(BPF_AUX[5] == static_cast<uint64_t>(syscall_args[5]));
    127 }
    128 
    129 TEST(Syscall, ComplexSyscallSixArgs) {
    130   int fd;
    131   ASSERT_LE(0, fd = SandboxSyscall(__NR_open, "/dev/null", O_RDWR, 0L));
    132 
    133   // Use mmap() to allocate some read-only memory
    134   char *addr0;
    135   ASSERT_NE((char *)NULL,
    136             addr0 = reinterpret_cast<char *>(
    137               SandboxSyscall(kMMapNr, (void *)NULL, 4096, PROT_READ,
    138                              MAP_PRIVATE|MAP_ANONYMOUS, fd, 0L)));
    139 
    140   // Try to replace the existing mapping with a read-write mapping
    141   char *addr1;
    142   ASSERT_EQ(addr0,
    143             addr1 = reinterpret_cast<char *>(
    144               SandboxSyscall(kMMapNr, addr0, 4096L, PROT_READ|PROT_WRITE,
    145                              MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED,
    146                              fd, 0L)));
    147   ++*addr1; // This should not seg fault
    148 
    149   // Clean up
    150   EXPECT_EQ(0, SandboxSyscall(__NR_munmap, addr1, 4096L));
    151   EXPECT_EQ(0, HANDLE_EINTR(SandboxSyscall(__NR_close, fd)));
    152 
    153   // Check that the offset argument (i.e. the sixth argument) is processed
    154   // correctly.
    155   ASSERT_GE(fd = SandboxSyscall(__NR_open, "/proc/self/exe", O_RDONLY, 0L), 0);
    156   char *addr2, *addr3;
    157   ASSERT_NE((char *)NULL,
    158             addr2 = reinterpret_cast<char *>(
    159               SandboxSyscall(kMMapNr, (void *)NULL, 8192L, PROT_READ,
    160                              MAP_PRIVATE, fd, 0L)));
    161   ASSERT_NE((char *)NULL,
    162             addr3 = reinterpret_cast<char *>(
    163               SandboxSyscall(kMMapNr, (void *)NULL, 4096L, PROT_READ,
    164                              MAP_PRIVATE, fd,
    165 #if defined(__NR_mmap2)
    166                       1L
    167 #else
    168                       4096L
    169 #endif
    170                       )));
    171   EXPECT_EQ(0, memcmp(addr2 + 4096, addr3, 4096));
    172 
    173   // Just to be absolutely on the safe side, also verify that the file
    174   // contents matches what we are getting from a read() operation.
    175   char buf[8192];
    176   EXPECT_EQ(8192, SandboxSyscall(__NR_read, fd, buf, 8192L));
    177   EXPECT_EQ(0, memcmp(addr2, buf, 8192));
    178 
    179   // Clean up
    180   EXPECT_EQ(0, SandboxSyscall(__NR_munmap, addr2, 8192L));
    181   EXPECT_EQ(0, SandboxSyscall(__NR_munmap, addr3, 4096L));
    182   EXPECT_EQ(0, HANDLE_EINTR(SandboxSyscall(__NR_close, fd)));
    183 }
    184 
    185 } // namespace
    186