Adding Peter Thatcher to the owners file.
[chromium-blink-merge.git] / sandbox / linux / seccomp-bpf-helpers / syscall_parameters_restrictions.cc
blobc081b29cad7a142725b86cb2f39fdff7d27abd5a
1 // Copyright (c) 2013 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.
5 #include "sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.h"
7 #include <errno.h>
8 #include <fcntl.h>
9 #include <fcntl.h>
10 #include <linux/futex.h>
11 #include <linux/net.h>
12 #include <sched.h>
13 #include <signal.h>
14 #include <sys/ioctl.h>
15 #include <sys/mman.h>
16 #include <sys/prctl.h>
17 #include <sys/resource.h>
18 #include <sys/stat.h>
19 #include <sys/time.h>
20 #include <sys/types.h>
21 #include <time.h>
22 #include <unistd.h>
24 #include "base/basictypes.h"
25 #include "base/logging.h"
26 #include "base/macros.h"
27 #include "base/time/time.h"
28 #include "build/build_config.h"
29 #include "sandbox/linux/bpf_dsl/bpf_dsl.h"
30 #include "sandbox/linux/bpf_dsl/seccomp_macros.h"
31 #include "sandbox/linux/seccomp-bpf-helpers/sigsys_handlers.h"
32 #include "sandbox/linux/seccomp-bpf/sandbox_bpf.h"
33 #include "sandbox/linux/system_headers/linux_syscalls.h"
35 #if defined(OS_ANDROID)
37 #include "sandbox/linux/system_headers/android_futex.h"
39 #if !defined(F_DUPFD_CLOEXEC)
40 #define F_DUPFD_CLOEXEC (F_LINUX_SPECIFIC_BASE + 6)
41 #endif
43 // https://android.googlesource.com/platform/bionic/+/lollipop-release/libc/private/bionic_prctl.h
44 #if !defined(PR_SET_VMA)
45 #define PR_SET_VMA 0x53564d41
46 #endif
48 // https://android.googlesource.com/platform/system/core/+/lollipop-release/libcutils/sched_policy.c
49 #if !defined(PR_SET_TIMERSLACK_PID)
50 #define PR_SET_TIMERSLACK_PID 41
51 #endif
53 #endif // defined(OS_ANDROID)
55 #if defined(__arm__) && !defined(MAP_STACK)
56 #define MAP_STACK 0x20000 // Daisy build environment has old headers.
57 #endif
59 #if defined(__mips__) && !defined(MAP_STACK)
60 #define MAP_STACK 0x40000
61 #endif
62 namespace {
64 inline bool IsArchitectureX86_64() {
65 #if defined(__x86_64__)
66 return true;
67 #else
68 return false;
69 #endif
72 inline bool IsArchitectureI386() {
73 #if defined(__i386__)
74 return true;
75 #else
76 return false;
77 #endif
80 inline bool IsAndroid() {
81 #if defined(OS_ANDROID)
82 return true;
83 #else
84 return false;
85 #endif
88 inline bool IsArchitectureMips() {
89 #if defined(__mips__)
90 return true;
91 #else
92 return false;
93 #endif
96 } // namespace.
98 #define CASES SANDBOX_BPF_DSL_CASES
100 using sandbox::bpf_dsl::Allow;
101 using sandbox::bpf_dsl::Arg;
102 using sandbox::bpf_dsl::BoolExpr;
103 using sandbox::bpf_dsl::Error;
104 using sandbox::bpf_dsl::If;
105 using sandbox::bpf_dsl::ResultExpr;
107 namespace sandbox {
109 // Allow Glibc's and Android pthread creation flags, crash on any other
110 // thread creation attempts and EPERM attempts to use neither
111 // CLONE_VM, nor CLONE_THREAD, which includes all fork() implementations.
112 ResultExpr RestrictCloneToThreadsAndEPERMFork() {
113 const Arg<unsigned long> flags(0);
115 // TODO(mdempsky): Extend DSL to support (flags & ~mask1) == mask2.
116 const uint64_t kAndroidCloneMask = CLONE_VM | CLONE_FS | CLONE_FILES |
117 CLONE_SIGHAND | CLONE_THREAD |
118 CLONE_SYSVSEM;
119 const uint64_t kObsoleteAndroidCloneMask = kAndroidCloneMask | CLONE_DETACHED;
121 const uint64_t kGlibcPthreadFlags =
122 CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | CLONE_THREAD |
123 CLONE_SYSVSEM | CLONE_SETTLS | CLONE_PARENT_SETTID | CLONE_CHILD_CLEARTID;
124 const BoolExpr glibc_test = flags == kGlibcPthreadFlags;
126 const BoolExpr android_test = flags == kAndroidCloneMask ||
127 flags == kObsoleteAndroidCloneMask ||
128 flags == kGlibcPthreadFlags;
130 return If(IsAndroid() ? android_test : glibc_test, Allow())
131 .ElseIf((flags & (CLONE_VM | CLONE_THREAD)) == 0, Error(EPERM))
132 .Else(CrashSIGSYSClone());
135 ResultExpr RestrictPrctl() {
136 // Will need to add seccomp compositing in the future. PR_SET_PTRACER is
137 // used by breakpad but not needed anymore.
138 const Arg<int> option(0);
139 return Switch(option)
140 .CASES((PR_GET_NAME, PR_SET_NAME, PR_GET_DUMPABLE, PR_SET_DUMPABLE),
141 Allow())
142 #if defined(OS_ANDROID)
143 .CASES((PR_SET_VMA, PR_SET_TIMERSLACK_PID), Allow())
144 #endif
145 .Default(CrashSIGSYSPrctl());
148 ResultExpr RestrictIoctl() {
149 const Arg<int> request(1);
150 return Switch(request).CASES((TCGETS, FIONREAD), Allow()).Default(
151 CrashSIGSYSIoctl());
154 ResultExpr RestrictMmapFlags() {
155 // The flags you see are actually the allowed ones, and the variable is a
156 // "denied" mask because of the negation operator.
157 // Significantly, we don't permit MAP_HUGETLB, or the newer flags such as
158 // MAP_POPULATE.
159 // TODO(davidung), remove MAP_DENYWRITE with updated Tegra libraries.
160 const uint64_t kAllowedMask = MAP_SHARED | MAP_PRIVATE | MAP_ANONYMOUS |
161 MAP_STACK | MAP_NORESERVE | MAP_FIXED |
162 MAP_DENYWRITE;
163 const Arg<int> flags(3);
164 return If((flags & ~kAllowedMask) == 0, Allow()).Else(CrashSIGSYS());
167 ResultExpr RestrictMprotectFlags() {
168 // The flags you see are actually the allowed ones, and the variable is a
169 // "denied" mask because of the negation operator.
170 // Significantly, we don't permit weird undocumented flags such as
171 // PROT_GROWSDOWN.
172 const uint64_t kAllowedMask = PROT_READ | PROT_WRITE | PROT_EXEC;
173 const Arg<int> prot(2);
174 return If((prot & ~kAllowedMask) == 0, Allow()).Else(CrashSIGSYS());
177 ResultExpr RestrictFcntlCommands() {
178 // We also restrict the flags in F_SETFL. We don't want to permit flags with
179 // a history of trouble such as O_DIRECT. The flags you see are actually the
180 // allowed ones, and the variable is a "denied" mask because of the negation
181 // operator.
182 // Glibc overrides the kernel's O_LARGEFILE value. Account for this.
183 uint64_t kOLargeFileFlag = O_LARGEFILE;
184 if (IsArchitectureX86_64() || IsArchitectureI386() || IsArchitectureMips())
185 kOLargeFileFlag = 0100000;
187 const Arg<int> cmd(1);
188 const Arg<long> long_arg(2);
190 const uint64_t kAllowedMask = O_ACCMODE | O_APPEND | O_NONBLOCK | O_SYNC |
191 kOLargeFileFlag | O_CLOEXEC | O_NOATIME;
192 return Switch(cmd)
193 .CASES((F_GETFL,
194 F_GETFD,
195 F_SETFD,
196 F_SETLK,
197 F_SETLKW,
198 F_GETLK,
199 F_DUPFD,
200 F_DUPFD_CLOEXEC),
201 Allow())
202 .Case(F_SETFL,
203 If((long_arg & ~kAllowedMask) == 0, Allow()).Else(CrashSIGSYS()))
204 .Default(CrashSIGSYS());
207 #if defined(__i386__) || defined(__mips__)
208 ResultExpr RestrictSocketcallCommand() {
209 // Unfortunately, we are unable to restrict the first parameter to
210 // socketpair(2). Whilst initially sounding bad, it's noteworthy that very
211 // few protocols actually support socketpair(2). The scary call that we're
212 // worried about, socket(2), remains blocked.
213 const Arg<int> call(0);
214 return Switch(call)
215 .CASES((SYS_SOCKETPAIR,
216 SYS_SHUTDOWN,
217 SYS_RECV,
218 SYS_SEND,
219 SYS_RECVFROM,
220 SYS_SENDTO,
221 SYS_RECVMSG,
222 SYS_SENDMSG),
223 Allow())
224 .Default(Error(EPERM));
226 #endif
228 ResultExpr RestrictKillTarget(pid_t target_pid, int sysno) {
229 switch (sysno) {
230 case __NR_kill:
231 case __NR_tgkill: {
232 const Arg<pid_t> pid(0);
233 return If(pid == target_pid, Allow()).Else(CrashSIGSYSKill());
235 case __NR_tkill:
236 return CrashSIGSYSKill();
237 default:
238 NOTREACHED();
239 return CrashSIGSYS();
243 ResultExpr RestrictFutex() {
244 const uint64_t kAllowedFutexFlags = FUTEX_PRIVATE_FLAG | FUTEX_CLOCK_REALTIME;
245 const Arg<int> op(1);
246 return Switch(op & ~kAllowedFutexFlags)
247 .CASES((FUTEX_WAIT,
248 FUTEX_WAKE,
249 FUTEX_REQUEUE,
250 FUTEX_CMP_REQUEUE,
251 FUTEX_WAKE_OP,
252 FUTEX_WAIT_BITSET,
253 FUTEX_WAKE_BITSET),
254 Allow())
255 .Default(CrashSIGSYSFutex());
258 ResultExpr RestrictGetSetpriority(pid_t target_pid) {
259 const Arg<int> which(0);
260 const Arg<int> who(1);
261 return If(which == PRIO_PROCESS,
262 If(who == 0 || who == target_pid, Allow()).Else(Error(EPERM)))
263 .Else(CrashSIGSYS());
266 ResultExpr RestrictClockID() {
267 static_assert(4 == sizeof(clockid_t), "clockid_t is not 32bit");
268 const Arg<clockid_t> clockid(0);
269 return If(
270 #if defined(OS_CHROMEOS)
271 // Allow the special clock for Chrome OS used by Chrome tracing.
272 clockid == base::TimeTicks::kClockSystemTrace ||
273 #endif
274 clockid == CLOCK_MONOTONIC ||
275 clockid == CLOCK_PROCESS_CPUTIME_ID ||
276 clockid == CLOCK_REALTIME ||
277 clockid == CLOCK_THREAD_CPUTIME_ID,
278 Allow()).Else(CrashSIGSYS());
281 ResultExpr RestrictSchedTarget(pid_t target_pid, int sysno) {
282 switch (sysno) {
283 case __NR_sched_getaffinity:
284 case __NR_sched_getattr:
285 case __NR_sched_getparam:
286 case __NR_sched_getscheduler:
287 case __NR_sched_rr_get_interval:
288 case __NR_sched_setaffinity:
289 case __NR_sched_setattr:
290 case __NR_sched_setparam:
291 case __NR_sched_setscheduler: {
292 const Arg<pid_t> pid(0);
293 return If(pid == 0 || pid == target_pid, Allow())
294 .Else(RewriteSchedSIGSYS());
296 default:
297 NOTREACHED();
298 return CrashSIGSYS();
302 ResultExpr RestrictPrlimit64(pid_t target_pid) {
303 const Arg<pid_t> pid(0);
304 return If(pid == 0 || pid == target_pid, Allow()).Else(CrashSIGSYS());
307 ResultExpr RestrictGetrusage() {
308 const Arg<int> who(0);
309 return If(who == RUSAGE_SELF, Allow()).Else(CrashSIGSYS());
312 } // namespace sandbox.