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 #if defined(OS_ANDROID)
     83   CheckClock(CLOCK_BOOTTIME);
     84 #endif
     85   CheckClock(CLOCK_REALTIME);
     86   CheckClock(CLOCK_REALTIME_COARSE);
     87   CheckClock(CLOCK_THREAD_CPUTIME_ID);
     88 }
     89 
     90 BPF_DEATH_TEST_C(ParameterRestrictions,
     91                  clock_gettime_crash_monotonic_raw,
     92                  DEATH_SEGV_MESSAGE(sandbox::GetErrorMessageContentForTests()),
     93                  RestrictClockIdPolicy) {
     94   struct timespec ts;
     95   clock_gettime(CLOCK_MONOTONIC_RAW, &ts);
     96 }
     97 
     98 #if !defined(OS_ANDROID)
     99 BPF_DEATH_TEST_C(ParameterRestrictions,
    100                  clock_gettime_crash_cpu_clock,
    101                  DEATH_SEGV_MESSAGE(sandbox::GetErrorMessageContentForTests()),
    102                  RestrictClockIdPolicy) {
    103   // We can't use clock_getcpuclockid() because it's not implemented in newlib,
    104   // and it might not work inside the sandbox anyway.
    105   const pid_t kInitPID = 1;
    106   const clockid_t kInitCPUClockID =
    107       MAKE_PROCESS_CPUCLOCK(kInitPID, CPUCLOCK_SCHED);
    108 
    109   struct timespec ts;
    110   clock_gettime(kInitCPUClockID, &ts);
    111 }
    112 #endif  // !defined(OS_ANDROID)
    113 
    114 class RestrictSchedPolicy : public bpf_dsl::Policy {
    115  public:
    116   RestrictSchedPolicy() {}
    117   ~RestrictSchedPolicy() override {}
    118 
    119   ResultExpr EvaluateSyscall(int sysno) const override {
    120     switch (sysno) {
    121       case __NR_sched_getparam:
    122         return RestrictSchedTarget(getpid(), sysno);
    123       default:
    124         return Allow();
    125     }
    126   }
    127 };
    128 
    129 void CheckSchedGetParam(pid_t pid, struct sched_param* param) {
    130   BPF_ASSERT_EQ(0, sched_getparam(pid, param));
    131 }
    132 
    133 void SchedGetParamThread(base::WaitableEvent* thread_run) {
    134   const pid_t pid = getpid();
    135   const pid_t tid = sys_gettid();
    136   BPF_ASSERT_NE(pid, tid);
    137 
    138   struct sched_param current_pid_param;
    139   CheckSchedGetParam(pid, &current_pid_param);
    140 
    141   struct sched_param zero_param;
    142   CheckSchedGetParam(0, &zero_param);
    143 
    144   struct sched_param tid_param;
    145   CheckSchedGetParam(tid, &tid_param);
    146 
    147   BPF_ASSERT_EQ(zero_param.sched_priority, tid_param.sched_priority);
    148 
    149   // Verify that the SIGSYS handler sets errno properly.
    150   errno = 0;
    151   BPF_ASSERT_EQ(-1, sched_getparam(tid, NULL));
    152   BPF_ASSERT_EQ(EINVAL, errno);
    153 
    154   thread_run->Signal();
    155 }
    156 
    157 BPF_TEST_C(ParameterRestrictions,
    158            sched_getparam_allowed,
    159            RestrictSchedPolicy) {
    160   base::WaitableEvent thread_run(
    161       base::WaitableEvent::ResetPolicy::MANUAL,
    162       base::WaitableEvent::InitialState::NOT_SIGNALED);
    163   // Run the actual test in a new thread so that the current pid and tid are
    164   // different.
    165   base::Thread getparam_thread("sched_getparam_thread");
    166   BPF_ASSERT(getparam_thread.Start());
    167   getparam_thread.message_loop()->PostTask(
    168       FROM_HERE, base::Bind(&SchedGetParamThread, &thread_run));
    169   BPF_ASSERT(thread_run.TimedWait(base::TimeDelta::FromMilliseconds(5000)));
    170   getparam_thread.Stop();
    171 }
    172 
    173 BPF_DEATH_TEST_C(ParameterRestrictions,
    174                  sched_getparam_crash_non_zero,
    175                  DEATH_SEGV_MESSAGE(sandbox::GetErrorMessageContentForTests()),
    176                  RestrictSchedPolicy) {
    177   const pid_t kInitPID = 1;
    178   struct sched_param param;
    179   sched_getparam(kInitPID, &param);
    180 }
    181 
    182 class RestrictPrlimit64Policy : public bpf_dsl::Policy {
    183  public:
    184   RestrictPrlimit64Policy() {}
    185   ~RestrictPrlimit64Policy() override {}
    186 
    187   ResultExpr EvaluateSyscall(int sysno) const override {
    188     switch (sysno) {
    189       case __NR_prlimit64:
    190         return RestrictPrlimit64(getpid());
    191       default:
    192         return Allow();
    193     }
    194   }
    195 };
    196 
    197 BPF_TEST_C(ParameterRestrictions, prlimit64_allowed, RestrictPrlimit64Policy) {
    198   BPF_ASSERT_EQ(0, sys_prlimit64(0, RLIMIT_AS, NULL, NULL));
    199   BPF_ASSERT_EQ(0, sys_prlimit64(getpid(), RLIMIT_AS, NULL, NULL));
    200 }
    201 
    202 BPF_DEATH_TEST_C(ParameterRestrictions,
    203                  prlimit64_crash_not_self,
    204                  DEATH_SEGV_MESSAGE(sandbox::GetErrorMessageContentForTests()),
    205                  RestrictPrlimit64Policy) {
    206   const pid_t kInitPID = 1;
    207   BPF_ASSERT_NE(kInitPID, getpid());
    208   sys_prlimit64(kInitPID, RLIMIT_AS, NULL, NULL);
    209 }
    210 
    211 class RestrictGetrusagePolicy : public bpf_dsl::Policy {
    212  public:
    213   RestrictGetrusagePolicy() {}
    214   ~RestrictGetrusagePolicy() override {}
    215 
    216   ResultExpr EvaluateSyscall(int sysno) const override {
    217     switch (sysno) {
    218       case __NR_getrusage:
    219         return RestrictGetrusage();
    220       default:
    221         return Allow();
    222     }
    223   }
    224 };
    225 
    226 BPF_TEST_C(ParameterRestrictions, getrusage_allowed, RestrictGetrusagePolicy) {
    227   struct rusage usage;
    228   BPF_ASSERT_EQ(0, getrusage(RUSAGE_SELF, &usage));
    229 }
    230 
    231 BPF_DEATH_TEST_C(ParameterRestrictions,
    232                  getrusage_crash_not_self,
    233                  DEATH_SEGV_MESSAGE(sandbox::GetErrorMessageContentForTests()),
    234                  RestrictGetrusagePolicy) {
    235   struct rusage usage;
    236   getrusage(RUSAGE_CHILDREN, &usage);
    237 }
    238 
    239 }  // namespace
    240 
    241 }  // namespace sandbox
    242