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, ¤t_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, ¶m); 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