Index: sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions_unittests.cc |
diff --git a/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions_unittests.cc b/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions_unittests.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..c865e7ec4799b2bc1d523843c181c43bef78d6a7 |
--- /dev/null |
+++ b/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions_unittests.cc |
@@ -0,0 +1,215 @@ |
+// Copyright 2014 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.h" |
+ |
+#include <errno.h> |
+#include <sched.h> |
+#include <sys/syscall.h> |
+#include <time.h> |
+#include <unistd.h> |
+ |
+#include "base/bind.h" |
+#include "base/synchronization/waitable_event.h" |
+#include "base/sys_info.h" |
+#include "base/threading/thread.h" |
+#include "base/time/time.h" |
+#include "build/build_config.h" |
+#include "sandbox/linux/bpf_dsl/bpf_dsl.h" |
+#include "sandbox/linux/seccomp-bpf-helpers/sigsys_handlers.h" |
+#include "sandbox/linux/seccomp-bpf/bpf_tests.h" |
+#include "sandbox/linux/seccomp-bpf/sandbox_bpf.h" |
+#include "sandbox/linux/seccomp-bpf/syscall.h" |
+#include "sandbox/linux/services/linux_syscalls.h" |
+#include "sandbox/linux/tests/unit_tests.h" |
+ |
+#if !defined(OS_ANDROID) |
+#include "third_party/lss/linux_syscall_support.h" // for MAKE_PROCESS_CPUCLOCK |
+#endif |
+ |
+namespace sandbox { |
+ |
+namespace { |
+ |
+// NOTE: most of the parameter restrictions are tested in |
+// baseline_policy_unittest.cc as a more end-to-end test. |
+ |
+using sandbox::bpf_dsl::Allow; |
+using sandbox::bpf_dsl::ResultExpr; |
+using sandbox::bpf_dsl::SandboxBPFDSLPolicy; |
+ |
+class RestrictClockIdPolicy : public SandboxBPFDSLPolicy { |
+ public: |
+ RestrictClockIdPolicy() {} |
+ virtual ~RestrictClockIdPolicy() {} |
+ |
+ virtual ResultExpr EvaluateSyscall(int sysno) const override { |
+ switch (sysno) { |
+ case __NR_clock_gettime: |
+ case __NR_clock_getres: |
+ return RestrictClockID(); |
+ default: |
+ return Allow(); |
+ } |
+ } |
+}; |
+ |
+void CheckClock(clockid_t clockid) { |
+ struct timespec ts; |
+ ts.tv_sec = ts.tv_nsec = -1; |
+ BPF_ASSERT_EQ(0, clock_gettime(clockid, &ts)); |
+ BPF_ASSERT_LE(0, ts.tv_sec); |
+ BPF_ASSERT_LE(0, ts.tv_nsec); |
+} |
+ |
+BPF_TEST_C(ParameterRestrictions, |
+ clock_gettime_allowed, |
+ RestrictClockIdPolicy) { |
+ CheckClock(CLOCK_MONOTONIC); |
+ CheckClock(CLOCK_PROCESS_CPUTIME_ID); |
+ CheckClock(CLOCK_REALTIME); |
+ CheckClock(CLOCK_THREAD_CPUTIME_ID); |
+} |
+ |
+BPF_DEATH_TEST_C(ParameterRestrictions, |
+ clock_gettime_crash_monotonic_raw, |
+ DEATH_SEGV_MESSAGE(sandbox::GetErrorMessageContentForTests()), |
+ RestrictClockIdPolicy) { |
+ struct timespec ts; |
+ clock_gettime(CLOCK_MONOTONIC_RAW, &ts); |
+} |
+ |
+#if defined(OS_CHROMEOS) |
+ |
+// A custom BPF tester delegate to run IsRunningOnChromeOS() before |
+// the sandbox is enabled because we cannot run it with non-SFI BPF |
+// sandbox enabled. |
+class ClockSystemTesterDelegate : public sandbox::BPFTesterDelegate { |
+ public: |
+ ClockSystemTesterDelegate() |
+ : is_running_on_chromeos_(base::SysInfo::IsRunningOnChromeOS()) {} |
+ virtual ~ClockSystemTesterDelegate() {} |
+ |
+ virtual scoped_ptr<sandbox::bpf_dsl::SandboxBPFDSLPolicy> |
+ GetSandboxBPFPolicy() override { |
+ return scoped_ptr<sandbox::bpf_dsl::SandboxBPFDSLPolicy>( |
+ new RestrictClockIdPolicy()); |
+ } |
+ virtual void RunTestFunction() override { |
+ if (is_running_on_chromeos_) { |
+ CheckClock(base::TimeTicks::kClockSystemTrace); |
+ } else { |
+ struct timespec ts; |
+ // kClockSystemTrace is 11, which is CLOCK_THREAD_CPUTIME_ID of |
+ // the init process (pid=1). If kernel supports this feature, |
+ // this may succeed even if this is not running on Chrome OS. We |
+ // just check this clock_gettime call does not crash. |
+ clock_gettime(base::TimeTicks::kClockSystemTrace, &ts); |
+ } |
+ } |
+ |
+ private: |
+ const bool is_running_on_chromeos_; |
+ DISALLOW_COPY_AND_ASSIGN(ClockSystemTesterDelegate); |
+}; |
+ |
+BPF_TEST_D(BPFTest, BPFTestWithDelegateClass, ClockSystemTesterDelegate); |
+ |
+#elif defined(OS_LINUX) |
+ |
+BPF_DEATH_TEST_C(ParameterRestrictions, |
+ clock_gettime_crash_system_trace, |
+ DEATH_SEGV_MESSAGE(sandbox::GetErrorMessageContentForTests()), |
+ RestrictClockIdPolicy) { |
+ struct timespec ts; |
+ clock_gettime(base::TimeTicks::kClockSystemTrace, &ts); |
+} |
+ |
+#endif // defined(OS_CHROMEOS) |
+ |
+#if !defined(OS_ANDROID) |
+BPF_DEATH_TEST_C(ParameterRestrictions, |
+ clock_gettime_crash_cpu_clock, |
+ DEATH_SEGV_MESSAGE(sandbox::GetErrorMessageContentForTests()), |
+ RestrictClockIdPolicy) { |
+ // We can't use clock_getcpuclockid() because it's not implemented in newlib, |
+ // and it might not work inside the sandbox anyway. |
+ const pid_t kInitPID = 1; |
+ const clockid_t kInitCPUClockID = |
+ MAKE_PROCESS_CPUCLOCK(kInitPID, CPUCLOCK_SCHED); |
+ |
+ struct timespec ts; |
+ clock_gettime(kInitCPUClockID, &ts); |
+} |
+#endif // !defined(OS_ANDROID) |
+ |
+class RestrictSchedPolicy : public SandboxBPFDSLPolicy { |
+ public: |
+ RestrictSchedPolicy() {} |
+ virtual ~RestrictSchedPolicy() {} |
+ |
+ virtual ResultExpr EvaluateSyscall(int sysno) const override { |
+ switch (sysno) { |
+ case __NR_sched_getparam: |
+ return RestrictSchedTarget(getpid(), sysno); |
+ default: |
+ return Allow(); |
+ } |
+ } |
+}; |
+ |
+void CheckSchedGetParam(pid_t pid, struct sched_param* param) { |
+ BPF_ASSERT_EQ(0, sched_getparam(pid, param)); |
+} |
+ |
+void SchedGetParamThread(base::WaitableEvent* thread_run) { |
+ const pid_t pid = getpid(); |
+ const pid_t tid = syscall(__NR_gettid); |
+ BPF_ASSERT_NE(pid, tid); |
+ |
+ struct sched_param current_pid_param; |
+ CheckSchedGetParam(pid, ¤t_pid_param); |
+ |
+ struct sched_param zero_param; |
+ CheckSchedGetParam(0, &zero_param); |
+ |
+ struct sched_param tid_param; |
+ CheckSchedGetParam(tid, &tid_param); |
+ |
+ BPF_ASSERT_EQ(zero_param.sched_priority, tid_param.sched_priority); |
+ |
+ // Verify that the SIGSYS handler sets errno properly. |
+ errno = 0; |
+ BPF_ASSERT_EQ(-1, sched_getparam(tid, NULL)); |
+ BPF_ASSERT_EQ(EINVAL, errno); |
+ |
+ thread_run->Signal(); |
+} |
+ |
+BPF_TEST_C(ParameterRestrictions, |
+ sched_getparam_allowed, |
+ RestrictSchedPolicy) { |
+ base::WaitableEvent thread_run(true, false); |
+ // Run the actual test in a new thread so that the current pid and tid are |
+ // different. |
+ base::Thread getparam_thread("sched_getparam_thread"); |
+ BPF_ASSERT(getparam_thread.Start()); |
+ getparam_thread.message_loop()->PostTask( |
+ FROM_HERE, base::Bind(&SchedGetParamThread, &thread_run)); |
+ BPF_ASSERT(thread_run.TimedWait(base::TimeDelta::FromMilliseconds(5000))); |
+ getparam_thread.Stop(); |
+} |
+ |
+BPF_DEATH_TEST_C(ParameterRestrictions, |
+ sched_getparam_crash_non_zero, |
+ DEATH_SEGV_MESSAGE(sandbox::GetErrorMessageContentForTests()), |
+ RestrictSchedPolicy) { |
+ const pid_t kInitPID = 1; |
+ struct sched_param param; |
+ sched_getparam(kInitPID, ¶m); |
+} |
+ |
+} // namespace |
+ |
+} // namespace sandbox |