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/syscall.h> 10 #include <time.h> 11 #include <unistd.h> 12 13 #include "base/bind.h" 14 #include "base/synchronization/waitable_event.h" 15 #include "base/sys_info.h" 16 #include "base/threading/thread.h" 17 #include "base/time/time.h" 18 #include "build/build_config.h" 19 #include "sandbox/linux/bpf_dsl/bpf_dsl.h" 20 #include "sandbox/linux/seccomp-bpf-helpers/sigsys_handlers.h" 21 #include "sandbox/linux/seccomp-bpf/bpf_tests.h" 22 #include "sandbox/linux/seccomp-bpf/sandbox_bpf.h" 23 #include "sandbox/linux/seccomp-bpf/syscall.h" 24 #include "sandbox/linux/services/linux_syscalls.h" 25 #include "sandbox/linux/tests/unit_tests.h" 26 27 #if !defined(OS_ANDROID) 28 #include "third_party/lss/linux_syscall_support.h" // for MAKE_PROCESS_CPUCLOCK 29 #endif 30 31 namespace sandbox { 32 33 namespace { 34 35 // NOTE: most of the parameter restrictions are tested in 36 // baseline_policy_unittest.cc as a more end-to-end test. 37 38 using sandbox::bpf_dsl::Allow; 39 using sandbox::bpf_dsl::ResultExpr; 40 using sandbox::bpf_dsl::SandboxBPFDSLPolicy; 41 42 class RestrictClockIdPolicy : public SandboxBPFDSLPolicy { 43 public: 44 RestrictClockIdPolicy() {} 45 virtual ~RestrictClockIdPolicy() {} 46 47 virtual ResultExpr EvaluateSyscall(int sysno) const OVERRIDE { 48 switch (sysno) { 49 case __NR_clock_gettime: 50 case __NR_clock_getres: 51 return RestrictClockID(); 52 default: 53 return Allow(); 54 } 55 } 56 }; 57 58 void CheckClock(clockid_t clockid) { 59 struct timespec ts; 60 ts.tv_sec = ts.tv_nsec = -1; 61 BPF_ASSERT_EQ(0, clock_gettime(clockid, &ts)); 62 BPF_ASSERT_LE(0, ts.tv_sec); 63 BPF_ASSERT_LE(0, ts.tv_nsec); 64 } 65 66 BPF_TEST_C(ParameterRestrictions, 67 clock_gettime_allowed, 68 RestrictClockIdPolicy) { 69 CheckClock(CLOCK_MONOTONIC); 70 CheckClock(CLOCK_PROCESS_CPUTIME_ID); 71 CheckClock(CLOCK_REALTIME); 72 CheckClock(CLOCK_THREAD_CPUTIME_ID); 73 } 74 75 BPF_DEATH_TEST_C(ParameterRestrictions, 76 clock_gettime_crash_monotonic_raw, 77 DEATH_SEGV_MESSAGE(sandbox::GetErrorMessageContentForTests()), 78 RestrictClockIdPolicy) { 79 struct timespec ts; 80 clock_gettime(CLOCK_MONOTONIC_RAW, &ts); 81 } 82 83 #if defined(OS_CHROMEOS) 84 85 // A custom BPF tester delegate to run IsRunningOnChromeOS() before 86 // the sandbox is enabled because we cannot run it with non-SFI BPF 87 // sandbox enabled. 88 class ClockSystemTesterDelegate : public sandbox::BPFTesterDelegate { 89 public: 90 ClockSystemTesterDelegate() 91 : is_running_on_chromeos_(base::SysInfo::IsRunningOnChromeOS()) {} 92 virtual ~ClockSystemTesterDelegate() {} 93 94 virtual scoped_ptr<sandbox::SandboxBPFPolicy> GetSandboxBPFPolicy() OVERRIDE { 95 return scoped_ptr<sandbox::SandboxBPFPolicy>( 96 new RestrictClockIdPolicy()); 97 } 98 virtual void RunTestFunction() OVERRIDE { 99 if (is_running_on_chromeos_) { 100 CheckClock(base::TimeTicks::kClockSystemTrace); 101 } else { 102 struct timespec ts; 103 // kClockSystemTrace is 11, which is CLOCK_THREAD_CPUTIME_ID of 104 // the init process (pid=1). If kernel supports this feature, 105 // this may succeed even if this is not running on Chrome OS. We 106 // just check this clock_gettime call does not crash. 107 clock_gettime(base::TimeTicks::kClockSystemTrace, &ts); 108 } 109 } 110 111 private: 112 const bool is_running_on_chromeos_; 113 DISALLOW_COPY_AND_ASSIGN(ClockSystemTesterDelegate); 114 }; 115 116 BPF_TEST_D(BPFTest, BPFTestWithDelegateClass, ClockSystemTesterDelegate); 117 118 #elif defined(OS_LINUX) 119 120 BPF_DEATH_TEST_C(ParameterRestrictions, 121 clock_gettime_crash_system_trace, 122 DEATH_SEGV_MESSAGE(sandbox::GetErrorMessageContentForTests()), 123 RestrictClockIdPolicy) { 124 struct timespec ts; 125 clock_gettime(base::TimeTicks::kClockSystemTrace, &ts); 126 } 127 128 #endif // defined(OS_CHROMEOS) 129 130 #if !defined(OS_ANDROID) 131 BPF_DEATH_TEST_C(ParameterRestrictions, 132 clock_gettime_crash_cpu_clock, 133 DEATH_SEGV_MESSAGE(sandbox::GetErrorMessageContentForTests()), 134 RestrictClockIdPolicy) { 135 // We can't use clock_getcpuclockid() because it's not implemented in newlib, 136 // and it might not work inside the sandbox anyway. 137 const pid_t kInitPID = 1; 138 const clockid_t kInitCPUClockID = 139 MAKE_PROCESS_CPUCLOCK(kInitPID, CPUCLOCK_SCHED); 140 141 struct timespec ts; 142 clock_gettime(kInitCPUClockID, &ts); 143 } 144 #endif // !defined(OS_ANDROID) 145 146 class RestrictSchedPolicy : public SandboxBPFDSLPolicy { 147 public: 148 RestrictSchedPolicy() {} 149 virtual ~RestrictSchedPolicy() {} 150 151 virtual ResultExpr EvaluateSyscall(int sysno) const OVERRIDE { 152 switch (sysno) { 153 case __NR_sched_getparam: 154 return RestrictSchedTarget(getpid(), sysno); 155 default: 156 return Allow(); 157 } 158 } 159 }; 160 161 void CheckSchedGetParam(pid_t pid, struct sched_param* param) { 162 BPF_ASSERT_EQ(0, sched_getparam(pid, param)); 163 } 164 165 void SchedGetParamThread(base::WaitableEvent* thread_run) { 166 const pid_t pid = getpid(); 167 const pid_t tid = syscall(__NR_gettid); 168 BPF_ASSERT_NE(pid, tid); 169 170 struct sched_param current_pid_param; 171 CheckSchedGetParam(pid, ¤t_pid_param); 172 173 struct sched_param zero_param; 174 CheckSchedGetParam(0, &zero_param); 175 176 struct sched_param tid_param; 177 CheckSchedGetParam(tid, &tid_param); 178 179 BPF_ASSERT_EQ(zero_param.sched_priority, tid_param.sched_priority); 180 181 // Verify that the SIGSYS handler sets errno properly. 182 errno = 0; 183 BPF_ASSERT_EQ(-1, sched_getparam(tid, NULL)); 184 BPF_ASSERT_EQ(EINVAL, errno); 185 186 thread_run->Signal(); 187 } 188 189 BPF_TEST_C(ParameterRestrictions, 190 sched_getparam_allowed, 191 RestrictSchedPolicy) { 192 base::WaitableEvent thread_run(true, false); 193 // Run the actual test in a new thread so that the current pid and tid are 194 // different. 195 base::Thread getparam_thread("sched_getparam_thread"); 196 BPF_ASSERT(getparam_thread.Start()); 197 getparam_thread.message_loop()->PostTask( 198 FROM_HERE, base::Bind(&SchedGetParamThread, &thread_run)); 199 BPF_ASSERT(thread_run.TimedWait(base::TimeDelta::FromMilliseconds(5000))); 200 getparam_thread.Stop(); 201 } 202 203 BPF_DEATH_TEST_C(ParameterRestrictions, 204 sched_getparam_crash_non_zero, 205 DEATH_SEGV_MESSAGE(sandbox::GetErrorMessageContentForTests()), 206 RestrictSchedPolicy) { 207 const pid_t kInitPID = 1; 208 struct sched_param param; 209 sched_getparam(kInitPID, ¶m); 210 } 211 212 } // namespace 213 214 } // namespace sandbox 215