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/syscall_parameters_restrictions.h"
      6 
      7 #include <errno.h>
      8 #include <sched.h>
      9 #include <sys/resource.h>
     10 #include <sys/syscall.h>
     11 #include <sys/types.h>
     12 #include <time.h>
     13 #include <unistd.h>
     14 
     15 #include "base/bind.h"
     16 #include "base/synchronization/waitable_event.h"
     17 #include "base/sys_info.h"
     18 #include "base/threading/thread.h"
     19 #include "base/time/time.h"
     20 #include "build/build_config.h"
     21 #include "sandbox/linux/bpf_dsl/bpf_dsl.h"
     22 #include "sandbox/linux/bpf_dsl/policy.h"
     23 #include "sandbox/linux/seccomp-bpf-helpers/sigsys_handlers.h"
     24 #include "sandbox/linux/seccomp-bpf/bpf_tests.h"
     25 #include "sandbox/linux/seccomp-bpf/sandbox_bpf.h"
     26 #include "sandbox/linux/seccomp-bpf/syscall.h"
     27 #include "sandbox/linux/services/syscall_wrappers.h"
     28 #include "sandbox/linux/system_headers/linux_syscalls.h"
     29 #include "sandbox/linux/system_headers/linux_time.h"
     30 #include "sandbox/linux/tests/unit_tests.h"
     31 
     32 #if !defined(OS_ANDROID)
     33 #include "third_party/lss/linux_syscall_support.h"  // for MAKE_PROCESS_CPUCLOCK
     34 #endif
     35 
     36 namespace sandbox {
     37 
     38 namespace {
     39 
     40 // NOTE: most of the parameter restrictions are tested in
     41 // baseline_policy_unittest.cc as a more end-to-end test.
     42 
     43 using sandbox::bpf_dsl::Allow;
     44 using sandbox::bpf_dsl::ResultExpr;
     45 
     46 class RestrictClockIdPolicy : public bpf_dsl::Policy {
     47  public:
     48   RestrictClockIdPolicy() {}
     49   ~RestrictClockIdPolicy() override {}
     50 
     51   ResultExpr EvaluateSyscall(int sysno) const override {
     52     switch (sysno) {
     53       case __NR_clock_gettime:
     54       case __NR_clock_getres:
     55         return RestrictClockID();
     56       default:
     57         return Allow();
     58     }
     59   }
     60 };
     61 
     62 void CheckClock(clockid_t clockid) {
     63   struct timespec ts;
     64   ts.tv_sec = -1;
     65   ts.tv_nsec = -1;
     66   BPF_ASSERT_EQ(0, clock_getres(clockid, &ts));
     67   BPF_ASSERT_EQ(0, ts.tv_sec);
     68   BPF_ASSERT_LE(0, ts.tv_nsec);
     69   ts.tv_sec = -1;
     70   ts.tv_nsec = -1;
     71   BPF_ASSERT_EQ(0, clock_gettime(clockid, &ts));
     72   BPF_ASSERT_LE(0, ts.tv_sec);
     73   BPF_ASSERT_LE(0, ts.tv_nsec);
     74 }
     75 
     76 BPF_TEST_C(ParameterRestrictions,
     77            clock_gettime_allowed,
     78            RestrictClockIdPolicy) {
     79   CheckClock(CLOCK_MONOTONIC);
     80   CheckClock(CLOCK_MONOTONIC_COARSE);
     81   CheckClock(CLOCK_PROCESS_CPUTIME_ID);
     82   CheckClock(CLOCK_REALTIME);
     83   CheckClock(CLOCK_REALTIME_COARSE);
     84   CheckClock(CLOCK_THREAD_CPUTIME_ID);
     85 }
     86 
     87 BPF_DEATH_TEST_C(ParameterRestrictions,
     88                  clock_gettime_crash_monotonic_raw,
     89                  DEATH_SEGV_MESSAGE(sandbox::GetErrorMessageContentForTests()),
     90                  RestrictClockIdPolicy) {
     91   struct timespec ts;
     92   clock_gettime(CLOCK_MONOTONIC_RAW, &ts);
     93 }
     94 
     95 #if !defined(OS_ANDROID)
     96 BPF_DEATH_TEST_C(ParameterRestrictions,
     97                  clock_gettime_crash_cpu_clock,
     98                  DEATH_SEGV_MESSAGE(sandbox::GetErrorMessageContentForTests()),
     99                  RestrictClockIdPolicy) {
    100   // We can't use clock_getcpuclockid() because it's not implemented in newlib,
    101   // and it might not work inside the sandbox anyway.
    102   const pid_t kInitPID = 1;
    103   const clockid_t kInitCPUClockID =
    104       MAKE_PROCESS_CPUCLOCK(kInitPID, CPUCLOCK_SCHED);
    105 
    106   struct timespec ts;
    107   clock_gettime(kInitCPUClockID, &ts);
    108 }
    109 #endif  // !defined(OS_ANDROID)
    110 
    111 class RestrictSchedPolicy : public bpf_dsl::Policy {
    112  public:
    113   RestrictSchedPolicy() {}
    114   ~RestrictSchedPolicy() override {}
    115 
    116   ResultExpr EvaluateSyscall(int sysno) const override {
    117     switch (sysno) {
    118       case __NR_sched_getparam:
    119         return RestrictSchedTarget(getpid(), sysno);
    120       default:
    121         return Allow();
    122     }
    123   }
    124 };
    125 
    126 void CheckSchedGetParam(pid_t pid, struct sched_param* param) {
    127   BPF_ASSERT_EQ(0, sched_getparam(pid, param));
    128 }
    129 
    130 void SchedGetParamThread(base::WaitableEvent* thread_run) {
    131   const pid_t pid = getpid();
    132   const pid_t tid = sys_gettid();
    133   BPF_ASSERT_NE(pid, tid);
    134 
    135   struct sched_param current_pid_param;
    136   CheckSchedGetParam(pid, &current_pid_param);
    137 
    138   struct sched_param zero_param;
    139   CheckSchedGetParam(0, &zero_param);
    140 
    141   struct sched_param tid_param;
    142   CheckSchedGetParam(tid, &tid_param);
    143 
    144   BPF_ASSERT_EQ(zero_param.sched_priority, tid_param.sched_priority);
    145 
    146   // Verify that the SIGSYS handler sets errno properly.
    147   errno = 0;
    148   BPF_ASSERT_EQ(-1, sched_getparam(tid, NULL));
    149   BPF_ASSERT_EQ(EINVAL, errno);
    150 
    151   thread_run->Signal();
    152 }
    153 
    154 BPF_TEST_C(ParameterRestrictions,
    155            sched_getparam_allowed,
    156            RestrictSchedPolicy) {
    157   base::WaitableEvent thread_run(true, false);
    158   // Run the actual test in a new thread so that the current pid and tid are
    159   // different.
    160   base::Thread getparam_thread("sched_getparam_thread");
    161   BPF_ASSERT(getparam_thread.Start());
    162   getparam_thread.message_loop()->PostTask(
    163       FROM_HERE, base::Bind(&SchedGetParamThread, &thread_run));
    164   BPF_ASSERT(thread_run.TimedWait(base::TimeDelta::FromMilliseconds(5000)));
    165   getparam_thread.Stop();
    166 }
    167 
    168 BPF_DEATH_TEST_C(ParameterRestrictions,
    169                  sched_getparam_crash_non_zero,
    170                  DEATH_SEGV_MESSAGE(sandbox::GetErrorMessageContentForTests()),
    171                  RestrictSchedPolicy) {
    172   const pid_t kInitPID = 1;
    173   struct sched_param param;
    174   sched_getparam(kInitPID, &param);
    175 }
    176 
    177 class RestrictPrlimit64Policy : public bpf_dsl::Policy {
    178  public:
    179   RestrictPrlimit64Policy() {}
    180   ~RestrictPrlimit64Policy() override {}
    181 
    182   ResultExpr EvaluateSyscall(int sysno) const override {
    183     switch (sysno) {
    184       case __NR_prlimit64:
    185         return RestrictPrlimit64(getpid());
    186       default:
    187         return Allow();
    188     }
    189   }
    190 };
    191 
    192 BPF_TEST_C(ParameterRestrictions, prlimit64_allowed, RestrictPrlimit64Policy) {
    193   BPF_ASSERT_EQ(0, sys_prlimit64(0, RLIMIT_AS, NULL, NULL));
    194   BPF_ASSERT_EQ(0, sys_prlimit64(getpid(), RLIMIT_AS, NULL, NULL));
    195 }
    196 
    197 BPF_DEATH_TEST_C(ParameterRestrictions,
    198                  prlimit64_crash_not_self,
    199                  DEATH_SEGV_MESSAGE(sandbox::GetErrorMessageContentForTests()),
    200                  RestrictPrlimit64Policy) {
    201   const pid_t kInitPID = 1;
    202   BPF_ASSERT_NE(kInitPID, getpid());
    203   sys_prlimit64(kInitPID, RLIMIT_AS, NULL, NULL);
    204 }
    205 
    206 class RestrictGetrusagePolicy : public bpf_dsl::Policy {
    207  public:
    208   RestrictGetrusagePolicy() {}
    209   ~RestrictGetrusagePolicy() override {}
    210 
    211   ResultExpr EvaluateSyscall(int sysno) const override {
    212     switch (sysno) {
    213       case __NR_getrusage:
    214         return RestrictGetrusage();
    215       default:
    216         return Allow();
    217     }
    218   }
    219 };
    220 
    221 BPF_TEST_C(ParameterRestrictions, getrusage_allowed, RestrictGetrusagePolicy) {
    222   struct rusage usage;
    223   BPF_ASSERT_EQ(0, getrusage(RUSAGE_SELF, &usage));
    224 }
    225 
    226 BPF_DEATH_TEST_C(ParameterRestrictions,
    227                  getrusage_crash_not_self,
    228                  DEATH_SEGV_MESSAGE(sandbox::GetErrorMessageContentForTests()),
    229                  RestrictGetrusagePolicy) {
    230   struct rusage usage;
    231   getrusage(RUSAGE_CHILDREN, &usage);
    232 }
    233 
    234 }  // namespace
    235 
    236 }  // namespace sandbox
    237