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