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, &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
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, &param);
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