• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #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 
BPF_DEATH_TEST_C(ParameterRestrictions,clock_gettime_crash_monotonic_raw,DEATH_SEGV_MESSAGE (sandbox::GetErrorMessageContentForTests ()),RestrictClockIdPolicy)90 BPF_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)
BPF_DEATH_TEST_C(ParameterRestrictions,clock_gettime_crash_cpu_clock,DEATH_SEGV_MESSAGE (sandbox::GetErrorMessageContentForTests ()),RestrictClockIdPolicy)99 BPF_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 
114 class RestrictSchedPolicy : public bpf_dsl::Policy {
115  public:
RestrictSchedPolicy()116   RestrictSchedPolicy() {}
~RestrictSchedPolicy()117   ~RestrictSchedPolicy() override {}
118 
EvaluateSyscall(int sysno) const119   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 
CheckSchedGetParam(pid_t pid,struct sched_param * param)129 void CheckSchedGetParam(pid_t pid, struct sched_param* param) {
130   BPF_ASSERT_EQ(0, sched_getparam(pid, param));
131 }
132 
SchedGetParamThread(base::WaitableEvent * thread_run)133 void 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 
BPF_TEST_C(ParameterRestrictions,sched_getparam_allowed,RestrictSchedPolicy)157 BPF_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 
BPF_DEATH_TEST_C(ParameterRestrictions,sched_getparam_crash_non_zero,DEATH_SEGV_MESSAGE (sandbox::GetErrorMessageContentForTests ()),RestrictSchedPolicy)173 BPF_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 
182 class RestrictPrlimit64Policy : public bpf_dsl::Policy {
183  public:
RestrictPrlimit64Policy()184   RestrictPrlimit64Policy() {}
~RestrictPrlimit64Policy()185   ~RestrictPrlimit64Policy() override {}
186 
EvaluateSyscall(int sysno) const187   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 
BPF_TEST_C(ParameterRestrictions,prlimit64_allowed,RestrictPrlimit64Policy)197 BPF_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 
BPF_DEATH_TEST_C(ParameterRestrictions,prlimit64_crash_not_self,DEATH_SEGV_MESSAGE (sandbox::GetErrorMessageContentForTests ()),RestrictPrlimit64Policy)202 BPF_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 
211 class RestrictGetrusagePolicy : public bpf_dsl::Policy {
212  public:
RestrictGetrusagePolicy()213   RestrictGetrusagePolicy() {}
~RestrictGetrusagePolicy()214   ~RestrictGetrusagePolicy() override {}
215 
EvaluateSyscall(int sysno) const216   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 
BPF_TEST_C(ParameterRestrictions,getrusage_allowed,RestrictGetrusagePolicy)226 BPF_TEST_C(ParameterRestrictions, getrusage_allowed, RestrictGetrusagePolicy) {
227   struct rusage usage;
228   BPF_ASSERT_EQ(0, getrusage(RUSAGE_SELF, &usage));
229 }
230 
BPF_DEATH_TEST_C(ParameterRestrictions,getrusage_crash_not_self,DEATH_SEGV_MESSAGE (sandbox::GetErrorMessageContentForTests ()),RestrictGetrusagePolicy)231 BPF_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