Home | History | Annotate | Download | only in seccomp-bpf-helpers
      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-helpers/baseline_policy.h"
      6 
      7 #include <errno.h>
      8 #include <fcntl.h>
      9 #include <linux/futex.h>
     10 #include <sched.h>
     11 #include <signal.h>
     12 #include <string.h>
     13 #include <sys/prctl.h>
     14 #include <sys/resource.h>
     15 #include <sys/socket.h>
     16 #include <sys/stat.h>
     17 #include <sys/syscall.h>
     18 #include <sys/time.h>
     19 #include <sys/types.h>
     20 #include <sys/wait.h>
     21 #include <time.h>
     22 #include <unistd.h>
     23 
     24 #include "base/files/scoped_file.h"
     25 #include "base/macros.h"
     26 #include "base/posix/eintr_wrapper.h"
     27 #include "base/threading/thread.h"
     28 #include "build/build_config.h"
     29 #include "sandbox/linux/seccomp-bpf-helpers/sigsys_handlers.h"
     30 #include "sandbox/linux/seccomp-bpf/bpf_tests.h"
     31 #include "sandbox/linux/seccomp-bpf/sandbox_bpf.h"
     32 #include "sandbox/linux/seccomp-bpf/syscall.h"
     33 #include "sandbox/linux/services/android_futex.h"
     34 #include "sandbox/linux/services/linux_syscalls.h"
     35 #include "sandbox/linux/services/thread_helpers.h"
     36 #include "sandbox/linux/tests/unit_tests.h"
     37 
     38 namespace sandbox {
     39 
     40 namespace {
     41 
     42 // |pid| is the return value of a fork()-like call. This
     43 // makes sure that if fork() succeeded the child exits
     44 // and the parent waits for it.
     45 void HandlePostForkReturn(pid_t pid) {
     46   const int kChildExitCode = 1;
     47   if (pid > 0) {
     48     int status = 0;
     49     PCHECK(pid == HANDLE_EINTR(waitpid(pid, &status, 0)));
     50     CHECK(WIFEXITED(status));
     51     CHECK_EQ(kChildExitCode, WEXITSTATUS(status));
     52   } else if (pid == 0) {
     53     _exit(kChildExitCode);
     54   }
     55 }
     56 
     57 // Check that HandlePostForkReturn works.
     58 TEST(BaselinePolicy, HandlePostForkReturn) {
     59   pid_t pid = fork();
     60   HandlePostForkReturn(pid);
     61 }
     62 
     63 // This also tests that read(), write() and fstat() are allowed.
     64 void TestPipeOrSocketPair(base::ScopedFD read_end, base::ScopedFD write_end) {
     65   BPF_ASSERT_LE(0, read_end.get());
     66   BPF_ASSERT_LE(0, write_end.get());
     67   struct stat stat_buf;
     68   int sys_ret = fstat(read_end.get(), &stat_buf);
     69   BPF_ASSERT_EQ(0, sys_ret);
     70   BPF_ASSERT(S_ISFIFO(stat_buf.st_mode) || S_ISSOCK(stat_buf.st_mode));
     71 
     72   const ssize_t kTestTransferSize = 4;
     73   static const char kTestString[kTestTransferSize] = {'T', 'E', 'S', 'T'};
     74   ssize_t transfered = 0;
     75 
     76   transfered =
     77       HANDLE_EINTR(write(write_end.get(), kTestString, kTestTransferSize));
     78   BPF_ASSERT_EQ(kTestTransferSize, transfered);
     79   char read_buf[kTestTransferSize + 1] = {0};
     80   transfered = HANDLE_EINTR(read(read_end.get(), read_buf, sizeof(read_buf)));
     81   BPF_ASSERT_EQ(kTestTransferSize, transfered);
     82   BPF_ASSERT_EQ(0, memcmp(kTestString, read_buf, kTestTransferSize));
     83 }
     84 
     85 // Test that a few easy-to-test system calls are allowed.
     86 BPF_TEST_C(BaselinePolicy, BaselinePolicyBasicAllowed, BaselinePolicy) {
     87   BPF_ASSERT_EQ(0, sched_yield());
     88 
     89   int pipefd[2];
     90   int sys_ret = pipe(pipefd);
     91   BPF_ASSERT_EQ(0, sys_ret);
     92   TestPipeOrSocketPair(base::ScopedFD(pipefd[0]), base::ScopedFD(pipefd[1]));
     93 
     94   BPF_ASSERT_LE(1, getpid());
     95   BPF_ASSERT_LE(0, getuid());
     96 }
     97 
     98 BPF_TEST_C(BaselinePolicy, FchmodErrno, BaselinePolicy) {
     99   int ret = fchmod(-1, 07777);
    100   BPF_ASSERT_EQ(-1, ret);
    101   // Without the sandbox, this would EBADF instead.
    102   BPF_ASSERT_EQ(EPERM, errno);
    103 }
    104 
    105 BPF_TEST_C(BaselinePolicy, ForkErrno, BaselinePolicy) {
    106   errno = 0;
    107   pid_t pid = fork();
    108   const int fork_errno = errno;
    109   HandlePostForkReturn(pid);
    110 
    111   BPF_ASSERT_EQ(-1, pid);
    112   BPF_ASSERT_EQ(EPERM, fork_errno);
    113 }
    114 
    115 pid_t ForkX86Glibc() {
    116   return syscall(__NR_clone, CLONE_PARENT_SETTID | SIGCHLD);
    117 }
    118 
    119 BPF_TEST_C(BaselinePolicy, ForkX86Eperm, BaselinePolicy) {
    120   errno = 0;
    121   pid_t pid = ForkX86Glibc();
    122   const int fork_errno = errno;
    123   HandlePostForkReturn(pid);
    124 
    125   BPF_ASSERT_EQ(-1, pid);
    126   BPF_ASSERT_EQ(EPERM, fork_errno);
    127 }
    128 
    129 pid_t ForkARMGlibc() {
    130   return syscall(__NR_clone,
    131                  CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID | SIGCHLD);
    132 }
    133 
    134 BPF_TEST_C(BaselinePolicy, ForkArmEperm, BaselinePolicy) {
    135   errno = 0;
    136   pid_t pid = ForkARMGlibc();
    137   const int fork_errno = errno;
    138   HandlePostForkReturn(pid);
    139 
    140   BPF_ASSERT_EQ(-1, pid);
    141   BPF_ASSERT_EQ(EPERM, fork_errno);
    142 }
    143 
    144 BPF_TEST_C(BaselinePolicy, CreateThread, BaselinePolicy) {
    145   base::Thread thread("sandbox_tests");
    146   BPF_ASSERT(thread.Start());
    147 }
    148 
    149 BPF_DEATH_TEST_C(BaselinePolicy,
    150                  DisallowedCloneFlagCrashes,
    151                  DEATH_SEGV_MESSAGE(GetCloneErrorMessageContentForTests()),
    152                  BaselinePolicy) {
    153   pid_t pid = syscall(__NR_clone, CLONE_THREAD | SIGCHLD);
    154   HandlePostForkReturn(pid);
    155 }
    156 
    157 BPF_DEATH_TEST_C(BaselinePolicy,
    158                  DisallowedKillCrashes,
    159                  DEATH_SEGV_MESSAGE(GetKillErrorMessageContentForTests()),
    160                  BaselinePolicy) {
    161   BPF_ASSERT_NE(1, getpid());
    162   kill(1, 0);
    163   _exit(0);
    164 }
    165 
    166 BPF_TEST_C(BaselinePolicy, CanKillSelf, BaselinePolicy) {
    167   int sys_ret = kill(getpid(), 0);
    168   BPF_ASSERT_EQ(0, sys_ret);
    169 }
    170 
    171 BPF_TEST_C(BaselinePolicy, Socketpair, BaselinePolicy) {
    172   int sv[2];
    173   int sys_ret = socketpair(AF_UNIX, SOCK_DGRAM, 0, sv);
    174   BPF_ASSERT_EQ(0, sys_ret);
    175   TestPipeOrSocketPair(base::ScopedFD(sv[0]), base::ScopedFD(sv[1]));
    176 
    177   sys_ret = socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sv);
    178   BPF_ASSERT_EQ(0, sys_ret);
    179   TestPipeOrSocketPair(base::ScopedFD(sv[0]), base::ScopedFD(sv[1]));
    180 }
    181 
    182 // Not all architectures can restrict the domain for socketpair().
    183 #if defined(__x86_64__) || defined(__arm__) || defined(__aarch64__)
    184 BPF_DEATH_TEST_C(BaselinePolicy,
    185                  SocketpairWrongDomain,
    186                  DEATH_SEGV_MESSAGE(GetErrorMessageContentForTests()),
    187                  BaselinePolicy) {
    188   int sv[2];
    189   ignore_result(socketpair(AF_INET, SOCK_STREAM, 0, sv));
    190   _exit(1);
    191 }
    192 #endif  // defined(__x86_64__) || defined(__arm__) || defined(__aarch64__)
    193 
    194 BPF_TEST_C(BaselinePolicy, EPERM_open, BaselinePolicy) {
    195   errno = 0;
    196   int sys_ret = open("/proc/cpuinfo", O_RDONLY);
    197   BPF_ASSERT_EQ(-1, sys_ret);
    198   BPF_ASSERT_EQ(EPERM, errno);
    199 }
    200 
    201 BPF_TEST_C(BaselinePolicy, EPERM_access, BaselinePolicy) {
    202   errno = 0;
    203   int sys_ret = access("/proc/cpuinfo", R_OK);
    204   BPF_ASSERT_EQ(-1, sys_ret);
    205   BPF_ASSERT_EQ(EPERM, errno);
    206 }
    207 
    208 BPF_TEST_C(BaselinePolicy, EPERM_getcwd, BaselinePolicy) {
    209   errno = 0;
    210   char buf[1024];
    211   char* cwd = getcwd(buf, sizeof(buf));
    212   BPF_ASSERT_EQ(NULL, cwd);
    213   BPF_ASSERT_EQ(EPERM, errno);
    214 }
    215 
    216 BPF_DEATH_TEST_C(BaselinePolicy,
    217                  SIGSYS_InvalidSyscall,
    218                  DEATH_SEGV_MESSAGE(GetErrorMessageContentForTests()),
    219                  BaselinePolicy) {
    220   Syscall::InvalidCall();
    221 }
    222 
    223 // A failing test using this macro could be problematic since we perform
    224 // system calls by passing "0" as every argument.
    225 // The kernel could SIGSEGV the process or the system call itself could reboot
    226 // the machine. Some thoughts have been given when hand-picking the system
    227 // calls below to limit any potential side effects outside of the current
    228 // process.
    229 #define TEST_BASELINE_SIGSYS(sysno)                                      \
    230   BPF_DEATH_TEST_C(BaselinePolicy,                                       \
    231                    SIGSYS_##sysno,                                       \
    232                    DEATH_SEGV_MESSAGE(GetErrorMessageContentForTests()), \
    233                    BaselinePolicy) {                                     \
    234     syscall(sysno, 0, 0, 0, 0, 0, 0);                                    \
    235     _exit(1);                                                            \
    236   }
    237 
    238 TEST_BASELINE_SIGSYS(__NR_acct);
    239 TEST_BASELINE_SIGSYS(__NR_chroot);
    240 TEST_BASELINE_SIGSYS(__NR_fanotify_init);
    241 TEST_BASELINE_SIGSYS(__NR_fgetxattr);
    242 TEST_BASELINE_SIGSYS(__NR_getcpu);
    243 TEST_BASELINE_SIGSYS(__NR_getitimer);
    244 TEST_BASELINE_SIGSYS(__NR_init_module);
    245 TEST_BASELINE_SIGSYS(__NR_io_cancel);
    246 TEST_BASELINE_SIGSYS(__NR_keyctl);
    247 TEST_BASELINE_SIGSYS(__NR_mq_open);
    248 TEST_BASELINE_SIGSYS(__NR_ptrace);
    249 TEST_BASELINE_SIGSYS(__NR_sched_setaffinity);
    250 TEST_BASELINE_SIGSYS(__NR_setpgid);
    251 TEST_BASELINE_SIGSYS(__NR_swapon);
    252 TEST_BASELINE_SIGSYS(__NR_sysinfo);
    253 TEST_BASELINE_SIGSYS(__NR_syslog);
    254 TEST_BASELINE_SIGSYS(__NR_timer_create);
    255 
    256 #if !defined(__aarch64__)
    257 TEST_BASELINE_SIGSYS(__NR_eventfd);
    258 TEST_BASELINE_SIGSYS(__NR_inotify_init);
    259 TEST_BASELINE_SIGSYS(__NR_vserver);
    260 #endif
    261 
    262 BPF_DEATH_TEST_C(BaselinePolicy,
    263                  FutexWithRequeuePriorityInheritence,
    264                  DEATH_SEGV_MESSAGE(GetFutexErrorMessageContentForTests()),
    265                  BaselinePolicy) {
    266   syscall(__NR_futex, NULL, FUTEX_CMP_REQUEUE_PI, 0, NULL, NULL, 0);
    267   _exit(1);
    268 }
    269 
    270 BPF_DEATH_TEST_C(BaselinePolicy,
    271                  FutexWithRequeuePriorityInheritencePrivate,
    272                  DEATH_SEGV_MESSAGE(GetFutexErrorMessageContentForTests()),
    273                  BaselinePolicy) {
    274   syscall(__NR_futex, NULL, FUTEX_CMP_REQUEUE_PI_PRIVATE, 0, NULL, NULL, 0);
    275   _exit(1);
    276 }
    277 
    278 BPF_DEATH_TEST_C(BaselinePolicy,
    279                  FutexWithUnlockPIPrivate,
    280                  DEATH_SEGV_MESSAGE(GetFutexErrorMessageContentForTests()),
    281                  BaselinePolicy) {
    282   syscall(__NR_futex, NULL, FUTEX_UNLOCK_PI_PRIVATE, 0, NULL, NULL, 0);
    283   _exit(1);
    284 }
    285 
    286 BPF_TEST_C(BaselinePolicy, PrctlDumpable, BaselinePolicy) {
    287   const int is_dumpable = prctl(PR_GET_DUMPABLE, 0, 0, 0, 0);
    288   BPF_ASSERT(is_dumpable == 1 || is_dumpable == 0);
    289   const int prctl_ret = prctl(PR_SET_DUMPABLE, is_dumpable, 0, 0, 0, 0);
    290   BPF_ASSERT_EQ(0, prctl_ret);
    291 }
    292 
    293 // Workaround incomplete Android headers.
    294 #if !defined(PR_CAPBSET_READ)
    295 #define PR_CAPBSET_READ 23
    296 #endif
    297 
    298 BPF_DEATH_TEST_C(BaselinePolicy,
    299                  PrctlSigsys,
    300                  DEATH_SEGV_MESSAGE(GetPrctlErrorMessageContentForTests()),
    301                  BaselinePolicy) {
    302   prctl(PR_CAPBSET_READ, 0, 0, 0, 0);
    303   _exit(1);
    304 }
    305 
    306 BPF_TEST_C(BaselinePolicy, GetOrSetPriority, BaselinePolicy) {
    307   errno = 0;
    308   const int original_prio = getpriority(PRIO_PROCESS, 0);
    309   // Check errno instead of the return value since this system call can return
    310   // -1 as a valid value.
    311   BPF_ASSERT_EQ(0, errno);
    312 
    313   errno = 0;
    314   int rc = getpriority(PRIO_PROCESS, getpid());
    315   BPF_ASSERT_EQ(0, errno);
    316 
    317   rc = getpriority(PRIO_PROCESS, getpid() + 1);
    318   BPF_ASSERT_EQ(-1, rc);
    319   BPF_ASSERT_EQ(EPERM, errno);
    320 
    321   rc = setpriority(PRIO_PROCESS, 0, original_prio);
    322   BPF_ASSERT_EQ(0, rc);
    323 
    324   rc = setpriority(PRIO_PROCESS, getpid(), original_prio);
    325   BPF_ASSERT_EQ(0, rc);
    326 
    327   errno = 0;
    328   rc = setpriority(PRIO_PROCESS, getpid() + 1, original_prio);
    329   BPF_ASSERT_EQ(-1, rc);
    330   BPF_ASSERT_EQ(EPERM, errno);
    331 }
    332 
    333 BPF_DEATH_TEST_C(BaselinePolicy,
    334                  GetPrioritySigsys,
    335                  DEATH_SEGV_MESSAGE(GetErrorMessageContentForTests()),
    336                  BaselinePolicy) {
    337   getpriority(PRIO_USER, 0);
    338   _exit(1);
    339 }
    340 
    341 BPF_DEATH_TEST_C(BaselinePolicy,
    342                  ClockGettimeWithDisallowedClockCrashes,
    343                  DEATH_SEGV_MESSAGE(sandbox::GetErrorMessageContentForTests()),
    344                  BaselinePolicy) {
    345   struct timespec ts;
    346   clock_gettime(CLOCK_MONOTONIC_RAW, &ts);
    347 }
    348 
    349 }  // namespace
    350 
    351 }  // namespace sandbox
    352