Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / sandbox / linux / seccomp-bpf-helpers / syscall_parameters_restrictions.cc
blob58ffb843a8717c9f659d95db465b0c56a9f3a3b3
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/net.h>
11 #include <sched.h>
12 #include <signal.h>
13 #include <stdint.h>
14 #include <sys/mman.h>
15 #include <sys/prctl.h>
16 #include <sys/resource.h>
17 #include <sys/stat.h>
18 #include <sys/time.h>
19 #include <sys/types.h>
20 #include <time.h>
21 #include <unistd.h>
23 #include "base/logging.h"
24 #include "base/macros.h"
25 #include "base/time/time.h"
26 #include "build/build_config.h"
27 #include "sandbox/linux/bpf_dsl/bpf_dsl.h"
28 #include "sandbox/linux/bpf_dsl/seccomp_macros.h"
29 #include "sandbox/linux/seccomp-bpf-helpers/sigsys_handlers.h"
30 #include "sandbox/linux/seccomp-bpf/sandbox_bpf.h"
31 #include "sandbox/linux/system_headers/linux_futex.h"
32 #include "sandbox/linux/system_headers/linux_syscalls.h"
33 #include "sandbox/linux/system_headers/linux_time.h"
35 // PNaCl toolchain does not provide sys/ioctl.h header.
36 #if !defined(OS_NACL_NONSFI)
37 #include <sys/ioctl.h>
38 #endif
40 #if defined(OS_ANDROID)
42 #if !defined(F_DUPFD_CLOEXEC)
43 #define F_DUPFD_CLOEXEC (F_LINUX_SPECIFIC_BASE + 6)
44 #endif
46 // https://android.googlesource.com/platform/bionic/+/lollipop-release/libc/private/bionic_prctl.h
47 #if !defined(PR_SET_VMA)
48 #define PR_SET_VMA 0x53564d41
49 #endif
51 // https://android.googlesource.com/platform/system/core/+/lollipop-release/libcutils/sched_policy.c
52 #if !defined(PR_SET_TIMERSLACK_PID)
53 #define PR_SET_TIMERSLACK_PID 41
54 #endif
56 #endif // defined(OS_ANDROID)
58 #if defined(__arm__) && !defined(MAP_STACK)
59 #define MAP_STACK 0x20000 // Daisy build environment has old headers.
60 #endif
62 #if defined(__mips__) && !defined(MAP_STACK)
63 #define MAP_STACK 0x40000
64 #endif
65 namespace {
67 inline bool IsArchitectureX86_64() {
68 #if defined(__x86_64__)
69 return true;
70 #else
71 return false;
72 #endif
75 inline bool IsArchitectureI386() {
76 #if defined(__i386__)
77 return true;
78 #else
79 return false;
80 #endif
83 inline bool IsAndroid() {
84 #if defined(OS_ANDROID)
85 return true;
86 #else
87 return false;
88 #endif
91 inline bool IsArchitectureMips() {
92 #if defined(__mips__)
93 return true;
94 #else
95 return false;
96 #endif
99 } // namespace.
101 #define CASES SANDBOX_BPF_DSL_CASES
103 using sandbox::bpf_dsl::Allow;
104 using sandbox::bpf_dsl::Arg;
105 using sandbox::bpf_dsl::BoolExpr;
106 using sandbox::bpf_dsl::Error;
107 using sandbox::bpf_dsl::If;
108 using sandbox::bpf_dsl::ResultExpr;
110 namespace sandbox {
112 #if !defined(OS_NACL_NONSFI)
113 // Allow Glibc's and Android pthread creation flags, crash on any other
114 // thread creation attempts and EPERM attempts to use neither
115 // CLONE_VM, nor CLONE_THREAD, which includes all fork() implementations.
116 ResultExpr RestrictCloneToThreadsAndEPERMFork() {
117 const Arg<unsigned long> flags(0);
119 // TODO(mdempsky): Extend DSL to support (flags & ~mask1) == mask2.
120 const uint64_t kAndroidCloneMask = CLONE_VM | CLONE_FS | CLONE_FILES |
121 CLONE_SIGHAND | CLONE_THREAD |
122 CLONE_SYSVSEM;
123 const uint64_t kObsoleteAndroidCloneMask = kAndroidCloneMask | CLONE_DETACHED;
125 const uint64_t kGlibcPthreadFlags =
126 CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | CLONE_THREAD |
127 CLONE_SYSVSEM | CLONE_SETTLS | CLONE_PARENT_SETTID | CLONE_CHILD_CLEARTID;
128 const BoolExpr glibc_test = flags == kGlibcPthreadFlags;
130 const BoolExpr android_test = flags == kAndroidCloneMask ||
131 flags == kObsoleteAndroidCloneMask ||
132 flags == kGlibcPthreadFlags;
134 return If(IsAndroid() ? android_test : glibc_test, Allow())
135 .ElseIf((flags & (CLONE_VM | CLONE_THREAD)) == 0, Error(EPERM))
136 .Else(CrashSIGSYSClone());
139 ResultExpr RestrictPrctl() {
140 // Will need to add seccomp compositing in the future. PR_SET_PTRACER is
141 // used by breakpad but not needed anymore.
142 const Arg<int> option(0);
143 return Switch(option)
144 .CASES((PR_GET_NAME, PR_SET_NAME, PR_GET_DUMPABLE, PR_SET_DUMPABLE),
145 Allow())
146 #if defined(OS_ANDROID)
147 .CASES((PR_SET_VMA, PR_SET_TIMERSLACK_PID), Allow())
148 #endif
149 .Default(CrashSIGSYSPrctl());
152 ResultExpr RestrictIoctl() {
153 const Arg<int> request(1);
154 return Switch(request).CASES((TCGETS, FIONREAD), Allow()).Default(
155 CrashSIGSYSIoctl());
158 ResultExpr RestrictMmapFlags() {
159 // The flags you see are actually the allowed ones, and the variable is a
160 // "denied" mask because of the negation operator.
161 // Significantly, we don't permit MAP_HUGETLB, or the newer flags such as
162 // MAP_POPULATE.
163 // TODO(davidung), remove MAP_DENYWRITE with updated Tegra libraries.
164 const uint64_t kAllowedMask = MAP_SHARED | MAP_PRIVATE | MAP_ANONYMOUS |
165 MAP_STACK | MAP_NORESERVE | MAP_FIXED |
166 MAP_DENYWRITE;
167 const Arg<int> flags(3);
168 return If((flags & ~kAllowedMask) == 0, Allow()).Else(CrashSIGSYS());
171 ResultExpr RestrictMprotectFlags() {
172 // The flags you see are actually the allowed ones, and the variable is a
173 // "denied" mask because of the negation operator.
174 // Significantly, we don't permit weird undocumented flags such as
175 // PROT_GROWSDOWN.
176 const uint64_t kAllowedMask = PROT_READ | PROT_WRITE | PROT_EXEC;
177 const Arg<int> prot(2);
178 return If((prot & ~kAllowedMask) == 0, Allow()).Else(CrashSIGSYS());
181 ResultExpr RestrictFcntlCommands() {
182 // We also restrict the flags in F_SETFL. We don't want to permit flags with
183 // a history of trouble such as O_DIRECT. The flags you see are actually the
184 // allowed ones, and the variable is a "denied" mask because of the negation
185 // operator.
186 // Glibc overrides the kernel's O_LARGEFILE value. Account for this.
187 uint64_t kOLargeFileFlag = O_LARGEFILE;
188 if (IsArchitectureX86_64() || IsArchitectureI386() || IsArchitectureMips())
189 kOLargeFileFlag = 0100000;
191 const Arg<int> cmd(1);
192 const Arg<long> long_arg(2);
194 const uint64_t kAllowedMask = O_ACCMODE | O_APPEND | O_NONBLOCK | O_SYNC |
195 kOLargeFileFlag | O_CLOEXEC | O_NOATIME;
196 return Switch(cmd)
197 .CASES((F_GETFL,
198 F_GETFD,
199 F_SETFD,
200 F_SETLK,
201 F_SETLKW,
202 F_GETLK,
203 F_DUPFD,
204 F_DUPFD_CLOEXEC),
205 Allow())
206 .Case(F_SETFL,
207 If((long_arg & ~kAllowedMask) == 0, Allow()).Else(CrashSIGSYS()))
208 .Default(CrashSIGSYS());
211 #if defined(__i386__) || defined(__mips__)
212 ResultExpr RestrictSocketcallCommand() {
213 // Unfortunately, we are unable to restrict the first parameter to
214 // socketpair(2). Whilst initially sounding bad, it's noteworthy that very
215 // few protocols actually support socketpair(2). The scary call that we're
216 // worried about, socket(2), remains blocked.
217 const Arg<int> call(0);
218 return Switch(call)
219 .CASES((SYS_SOCKETPAIR,
220 SYS_SHUTDOWN,
221 SYS_RECV,
222 SYS_SEND,
223 SYS_RECVFROM,
224 SYS_SENDTO,
225 SYS_RECVMSG,
226 SYS_SENDMSG),
227 Allow())
228 .Default(Error(EPERM));
230 #endif
232 ResultExpr RestrictKillTarget(pid_t target_pid, int sysno) {
233 switch (sysno) {
234 case __NR_kill:
235 case __NR_tgkill: {
236 const Arg<pid_t> pid(0);
237 return If(pid == target_pid, Allow()).Else(CrashSIGSYSKill());
239 case __NR_tkill:
240 return CrashSIGSYSKill();
241 default:
242 NOTREACHED();
243 return CrashSIGSYS();
247 ResultExpr RestrictFutex() {
248 const uint64_t kAllowedFutexFlags = FUTEX_PRIVATE_FLAG | FUTEX_CLOCK_REALTIME;
249 const Arg<int> op(1);
250 return Switch(op & ~kAllowedFutexFlags)
251 .CASES((FUTEX_WAIT,
252 FUTEX_WAKE,
253 FUTEX_REQUEUE,
254 FUTEX_CMP_REQUEUE,
255 FUTEX_WAKE_OP,
256 FUTEX_WAIT_BITSET,
257 FUTEX_WAKE_BITSET),
258 Allow())
259 .Default(CrashSIGSYSFutex());
262 ResultExpr RestrictGetSetpriority(pid_t target_pid) {
263 const Arg<int> which(0);
264 const Arg<int> who(1);
265 return If(which == PRIO_PROCESS,
266 If(who == 0 || who == target_pid, Allow()).Else(Error(EPERM)))
267 .Else(CrashSIGSYS());
270 ResultExpr RestrictSchedTarget(pid_t target_pid, int sysno) {
271 switch (sysno) {
272 case __NR_sched_getaffinity:
273 case __NR_sched_getattr:
274 case __NR_sched_getparam:
275 case __NR_sched_getscheduler:
276 case __NR_sched_rr_get_interval:
277 case __NR_sched_setaffinity:
278 case __NR_sched_setattr:
279 case __NR_sched_setparam:
280 case __NR_sched_setscheduler: {
281 const Arg<pid_t> pid(0);
282 return If(pid == 0 || pid == target_pid, Allow())
283 .Else(RewriteSchedSIGSYS());
285 default:
286 NOTREACHED();
287 return CrashSIGSYS();
291 ResultExpr RestrictPrlimit64(pid_t target_pid) {
292 const Arg<pid_t> pid(0);
293 return If(pid == 0 || pid == target_pid, Allow()).Else(CrashSIGSYS());
296 ResultExpr RestrictGetrusage() {
297 const Arg<int> who(0);
298 return If(who == RUSAGE_SELF, Allow()).Else(CrashSIGSYS());
300 #endif // !defined(OS_NACL_NONSFI)
302 ResultExpr RestrictClockID() {
303 static_assert(4 == sizeof(clockid_t), "clockid_t is not 32bit");
304 const Arg<clockid_t> clockid(0);
305 return If(
306 #if defined(OS_CHROMEOS)
307 // Allow the special clock for Chrome OS used by Chrome tracing.
308 clockid == base::TraceTicks::kClockSystemTrace ||
309 #endif
310 clockid == CLOCK_MONOTONIC ||
311 clockid == CLOCK_MONOTONIC_COARSE ||
312 clockid == CLOCK_PROCESS_CPUTIME_ID ||
313 clockid == CLOCK_REALTIME ||
314 clockid == CLOCK_REALTIME_COARSE ||
315 clockid == CLOCK_THREAD_CPUTIME_ID,
316 Allow()).Else(CrashSIGSYS());
319 } // namespace sandbox.