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 36namespace sandbox { 37 38namespace { 39 40// NOTE: most of the parameter restrictions are tested in 41// baseline_policy_unittest.cc as a more end-to-end test. 42 43using sandbox::bpf_dsl::Allow; 44using sandbox::bpf_dsl::ResultExpr; 45 46class 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 62void 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 76BPF_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 90BPF_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) 99BPF_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 114class 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 129void CheckSchedGetParam(pid_t pid, struct sched_param* param) { 130 BPF_ASSERT_EQ(0, sched_getparam(pid, param)); 131} 132 133void 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, ¤t_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 157BPF_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 173BPF_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, ¶m); 180} 181 182class 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 197BPF_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 202BPF_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 211class 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 226BPF_TEST_C(ParameterRestrictions, getrusage_allowed, RestrictGetrusagePolicy) { 227 struct rusage usage; 228 BPF_ASSERT_EQ(0, getrusage(RUSAGE_SELF, &usage)); 229} 230 231BPF_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