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:
RestrictClockIdPolicy()48 RestrictClockIdPolicy() {}
~RestrictClockIdPolicy()49 ~RestrictClockIdPolicy() override {}
50
EvaluateSyscall(int sysno) const51 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
CheckClock(clockid_t clockid)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
BPF_TEST_C(ParameterRestrictions,clock_gettime_allowed,RestrictClockIdPolicy)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
BPF_DEATH_TEST_C(ParameterRestrictions,clock_gettime_crash_monotonic_raw,DEATH_SEGV_MESSAGE (sandbox::GetErrorMessageContentForTests ()),RestrictClockIdPolicy)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)
BPF_DEATH_TEST_C(ParameterRestrictions,clock_gettime_crash_cpu_clock,DEATH_SEGV_MESSAGE (sandbox::GetErrorMessageContentForTests ()),RestrictClockIdPolicy)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:
RestrictSchedPolicy()113 RestrictSchedPolicy() {}
~RestrictSchedPolicy()114 ~RestrictSchedPolicy() override {}
115
EvaluateSyscall(int sysno) const116 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
CheckSchedGetParam(pid_t pid,struct sched_param * param)126 void CheckSchedGetParam(pid_t pid, struct sched_param* param) {
127 BPF_ASSERT_EQ(0, sched_getparam(pid, param));
128 }
129
SchedGetParamThread(base::WaitableEvent * thread_run)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
BPF_TEST_C(ParameterRestrictions,sched_getparam_allowed,RestrictSchedPolicy)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
BPF_DEATH_TEST_C(ParameterRestrictions,sched_getparam_crash_non_zero,DEATH_SEGV_MESSAGE (sandbox::GetErrorMessageContentForTests ()),RestrictSchedPolicy)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:
RestrictPrlimit64Policy()179 RestrictPrlimit64Policy() {}
~RestrictPrlimit64Policy()180 ~RestrictPrlimit64Policy() override {}
181
EvaluateSyscall(int sysno) const182 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
BPF_TEST_C(ParameterRestrictions,prlimit64_allowed,RestrictPrlimit64Policy)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
BPF_DEATH_TEST_C(ParameterRestrictions,prlimit64_crash_not_self,DEATH_SEGV_MESSAGE (sandbox::GetErrorMessageContentForTests ()),RestrictPrlimit64Policy)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:
RestrictGetrusagePolicy()208 RestrictGetrusagePolicy() {}
~RestrictGetrusagePolicy()209 ~RestrictGetrusagePolicy() override {}
210
EvaluateSyscall(int sysno) const211 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
BPF_TEST_C(ParameterRestrictions,getrusage_allowed,RestrictGetrusagePolicy)221 BPF_TEST_C(ParameterRestrictions, getrusage_allowed, RestrictGetrusagePolicy) {
222 struct rusage usage;
223 BPF_ASSERT_EQ(0, getrusage(RUSAGE_SELF, &usage));
224 }
225
BPF_DEATH_TEST_C(ParameterRestrictions,getrusage_crash_not_self,DEATH_SEGV_MESSAGE (sandbox::GetErrorMessageContentForTests ()),RestrictGetrusagePolicy)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