• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/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/stat.h>
18 #include <sys/types.h>
19 #include <unistd.h>
20 
21 #include "base/basictypes.h"
22 #include "base/logging.h"
23 #include "base/macros.h"
24 #include "build/build_config.h"
25 #include "sandbox/linux/seccomp-bpf-helpers/sigsys_handlers.h"
26 #include "sandbox/linux/seccomp-bpf/linux_seccomp.h"
27 #include "sandbox/linux/seccomp-bpf/sandbox_bpf.h"
28 #include "sandbox/linux/services/android_futex.h"
29 
30 #if defined(OS_ANDROID)
31 #if !defined(F_DUPFD_CLOEXEC)
32 #define F_DUPFD_CLOEXEC (F_LINUX_SPECIFIC_BASE + 6)
33 #endif
34 #endif
35 
36 #if defined(__arm__) && !defined(MAP_STACK)
37 #define MAP_STACK 0x20000  // Daisy build environment has old headers.
38 #endif
39 
40 namespace {
41 
IsArchitectureX86_64()42 inline bool IsArchitectureX86_64() {
43 #if defined(__x86_64__)
44   return true;
45 #else
46   return false;
47 #endif
48 }
49 
IsArchitectureI386()50 inline bool IsArchitectureI386() {
51 #if defined(__i386__)
52   return true;
53 #else
54   return false;
55 #endif
56 }
57 
IsAndroid()58 inline bool IsAndroid() {
59 #if defined(OS_ANDROID)
60   return true;
61 #else
62   return false;
63 #endif
64 }
65 
66 }  // namespace.
67 
68 namespace sandbox {
69 
70 // Allow Glibc's and Android pthread creation flags, crash on any other
71 // thread creation attempts and EPERM attempts to use neither
72 // CLONE_VM, nor CLONE_THREAD, which includes all fork() implementations.
RestrictCloneToThreadsAndEPERMFork(SandboxBPF * sandbox)73 ErrorCode RestrictCloneToThreadsAndEPERMFork(SandboxBPF* sandbox) {
74   if (!IsAndroid()) {
75     const uint64_t kGlibcPthreadFlags =
76         CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | CLONE_THREAD |
77         CLONE_SYSVSEM | CLONE_SETTLS | CLONE_PARENT_SETTID |
78         CLONE_CHILD_CLEARTID;
79 
80     return sandbox->Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL,
81                          kGlibcPthreadFlags,
82                          ErrorCode(ErrorCode::ERR_ALLOWED),
83            sandbox->Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_HAS_ANY_BITS,
84                          CLONE_VM | CLONE_THREAD,
85                          sandbox->Trap(SIGSYSCloneFailure, NULL),
86                          ErrorCode(EPERM)));
87   } else {
88     const uint64_t kAndroidCloneMask = CLONE_VM | CLONE_FS | CLONE_FILES |
89                                        CLONE_SIGHAND | CLONE_THREAD |
90                                        CLONE_SYSVSEM;
91     const uint64_t kObsoleteAndroidCloneMask =
92         kAndroidCloneMask | CLONE_DETACHED;
93 
94     return sandbox->Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL,
95                          kAndroidCloneMask,
96                          ErrorCode(ErrorCode::ERR_ALLOWED),
97            sandbox->Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL,
98                          kObsoleteAndroidCloneMask,
99                          ErrorCode(ErrorCode::ERR_ALLOWED),
100            sandbox->Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_HAS_ANY_BITS,
101                          CLONE_VM | CLONE_THREAD,
102                          sandbox->Trap(SIGSYSCloneFailure, NULL),
103                          ErrorCode(EPERM))));
104   }
105 }
106 
RestrictPrctl(SandboxBPF * sandbox)107 ErrorCode RestrictPrctl(SandboxBPF* sandbox) {
108   // Will need to add seccomp compositing in the future. PR_SET_PTRACER is
109   // used by breakpad but not needed anymore.
110   return sandbox->Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL,
111                        PR_SET_NAME, ErrorCode(ErrorCode::ERR_ALLOWED),
112          sandbox->Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL,
113                        PR_SET_DUMPABLE, ErrorCode(ErrorCode::ERR_ALLOWED),
114          sandbox->Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL,
115                        PR_GET_DUMPABLE, ErrorCode(ErrorCode::ERR_ALLOWED),
116          sandbox->Trap(SIGSYSPrctlFailure, NULL))));
117 }
118 
RestrictIoctl(SandboxBPF * sandbox)119 ErrorCode RestrictIoctl(SandboxBPF* sandbox) {
120   return sandbox->Cond(1, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL, TCGETS,
121                        ErrorCode(ErrorCode::ERR_ALLOWED),
122          sandbox->Cond(1, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL, FIONREAD,
123                        ErrorCode(ErrorCode::ERR_ALLOWED),
124                        sandbox->Trap(SIGSYSIoctlFailure, NULL)));
125 }
126 
RestrictMmapFlags(SandboxBPF * sandbox)127 ErrorCode RestrictMmapFlags(SandboxBPF* sandbox) {
128   // The flags you see are actually the allowed ones, and the variable is a
129   // "denied" mask because of the negation operator.
130   // Significantly, we don't permit MAP_HUGETLB, or the newer flags such as
131   // MAP_POPULATE.
132   // TODO(davidung), remove MAP_DENYWRITE with updated Tegra libraries.
133   uint32_t denied_mask = ~(MAP_SHARED | MAP_PRIVATE | MAP_ANONYMOUS |
134                            MAP_STACK | MAP_NORESERVE | MAP_FIXED |
135                            MAP_DENYWRITE);
136   return sandbox->Cond(3, ErrorCode::TP_32BIT, ErrorCode::OP_HAS_ANY_BITS,
137                        denied_mask,
138                        sandbox->Trap(CrashSIGSYS_Handler, NULL),
139                        ErrorCode(ErrorCode::ERR_ALLOWED));
140 }
141 
RestrictMprotectFlags(SandboxBPF * sandbox)142 ErrorCode RestrictMprotectFlags(SandboxBPF* sandbox) {
143   // The flags you see are actually the allowed ones, and the variable is a
144   // "denied" mask because of the negation operator.
145   // Significantly, we don't permit weird undocumented flags such as
146   // PROT_GROWSDOWN.
147   uint32_t denied_mask = ~(PROT_READ | PROT_WRITE | PROT_EXEC);
148   return sandbox->Cond(2, ErrorCode::TP_32BIT, ErrorCode::OP_HAS_ANY_BITS,
149                        denied_mask,
150                        sandbox->Trap(CrashSIGSYS_Handler, NULL),
151                        ErrorCode(ErrorCode::ERR_ALLOWED));
152 }
153 
RestrictFcntlCommands(SandboxBPF * sandbox)154 ErrorCode RestrictFcntlCommands(SandboxBPF* sandbox) {
155   // We also restrict the flags in F_SETFL. We don't want to permit flags with
156   // a history of trouble such as O_DIRECT. The flags you see are actually the
157   // allowed ones, and the variable is a "denied" mask because of the negation
158   // operator.
159   // Glibc overrides the kernel's O_LARGEFILE value. Account for this.
160   int kOLargeFileFlag = O_LARGEFILE;
161   if (IsArchitectureX86_64() || IsArchitectureI386())
162     kOLargeFileFlag = 0100000;
163 
164   // TODO(jln): add TP_LONG/TP_SIZET types.
165   ErrorCode::ArgType mask_long_type;
166   if (sizeof(long) == 8)
167     mask_long_type = ErrorCode::TP_64BIT;
168   else if (sizeof(long) == 4)
169     mask_long_type = ErrorCode::TP_32BIT;
170   else
171     NOTREACHED();
172 
173   unsigned long denied_mask = ~(O_ACCMODE | O_APPEND | O_NONBLOCK | O_SYNC |
174                                 kOLargeFileFlag | O_CLOEXEC | O_NOATIME);
175   return sandbox->Cond(1, ErrorCode::TP_32BIT,
176                        ErrorCode::OP_EQUAL, F_GETFL,
177                        ErrorCode(ErrorCode::ERR_ALLOWED),
178          sandbox->Cond(1, ErrorCode::TP_32BIT,
179                        ErrorCode::OP_EQUAL, F_SETFL,
180                        sandbox->Cond(2, mask_long_type,
181                                      ErrorCode::OP_HAS_ANY_BITS, denied_mask,
182                                      sandbox->Trap(CrashSIGSYS_Handler, NULL),
183                                      ErrorCode(ErrorCode::ERR_ALLOWED)),
184          sandbox->Cond(1, ErrorCode::TP_32BIT,
185                        ErrorCode::OP_EQUAL, F_GETFD,
186                        ErrorCode(ErrorCode::ERR_ALLOWED),
187          sandbox->Cond(1, ErrorCode::TP_32BIT,
188                        ErrorCode::OP_EQUAL, F_SETFD,
189                        ErrorCode(ErrorCode::ERR_ALLOWED),
190          sandbox->Cond(1, ErrorCode::TP_32BIT,
191                        ErrorCode::OP_EQUAL, F_DUPFD,
192                        ErrorCode(ErrorCode::ERR_ALLOWED),
193          sandbox->Cond(1, ErrorCode::TP_32BIT,
194                        ErrorCode::OP_EQUAL, F_SETLK,
195                        ErrorCode(ErrorCode::ERR_ALLOWED),
196          sandbox->Cond(1, ErrorCode::TP_32BIT,
197                        ErrorCode::OP_EQUAL, F_SETLKW,
198                        ErrorCode(ErrorCode::ERR_ALLOWED),
199          sandbox->Cond(1, ErrorCode::TP_32BIT,
200                        ErrorCode::OP_EQUAL, F_GETLK,
201                        ErrorCode(ErrorCode::ERR_ALLOWED),
202          sandbox->Cond(1, ErrorCode::TP_32BIT,
203                        ErrorCode::OP_EQUAL, F_DUPFD_CLOEXEC,
204                        ErrorCode(ErrorCode::ERR_ALLOWED),
205          sandbox->Trap(CrashSIGSYS_Handler, NULL))))))))));
206 }
207 
208 #if defined(__i386__)
RestrictSocketcallCommand(SandboxBPF * sandbox)209 ErrorCode RestrictSocketcallCommand(SandboxBPF* sandbox) {
210   // Unfortunately, we are unable to restrict the first parameter to
211   // socketpair(2). Whilst initially sounding bad, it's noteworthy that very
212   // few protocols actually support socketpair(2). The scary call that we're
213   // worried about, socket(2), remains blocked.
214   return sandbox->Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL,
215                        SYS_SOCKETPAIR, ErrorCode(ErrorCode::ERR_ALLOWED),
216          sandbox->Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL,
217                        SYS_SEND, ErrorCode(ErrorCode::ERR_ALLOWED),
218          sandbox->Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL,
219                        SYS_RECV, ErrorCode(ErrorCode::ERR_ALLOWED),
220          sandbox->Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL,
221                        SYS_SENDTO, ErrorCode(ErrorCode::ERR_ALLOWED),
222          sandbox->Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL,
223                        SYS_RECVFROM, ErrorCode(ErrorCode::ERR_ALLOWED),
224          sandbox->Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL,
225                        SYS_SHUTDOWN, ErrorCode(ErrorCode::ERR_ALLOWED),
226          sandbox->Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL,
227                        SYS_SENDMSG, ErrorCode(ErrorCode::ERR_ALLOWED),
228          sandbox->Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL,
229                        SYS_RECVMSG, ErrorCode(ErrorCode::ERR_ALLOWED),
230          ErrorCode(EPERM)))))))));
231 }
232 #endif
233 
RestrictKillTarget(pid_t target_pid,SandboxBPF * sandbox,int sysno)234 ErrorCode RestrictKillTarget(pid_t target_pid, SandboxBPF* sandbox, int sysno) {
235   switch (sysno) {
236     case __NR_kill:
237     case __NR_tgkill:
238       return sandbox->Cond(0,
239                            ErrorCode::TP_32BIT,
240                            ErrorCode::OP_EQUAL,
241                            target_pid,
242                            ErrorCode(ErrorCode::ERR_ALLOWED),
243                            sandbox->Trap(SIGSYSKillFailure, NULL));
244     case __NR_tkill:
245       return sandbox->Trap(SIGSYSKillFailure, NULL);
246     default:
247       NOTREACHED();
248       return sandbox->Trap(CrashSIGSYS_Handler, NULL);
249   }
250 }
251 
RestrictFutex(SandboxBPF * sandbox)252 ErrorCode RestrictFutex(SandboxBPF* sandbox) {
253   // In futex.c, the kernel does "int cmd = op & FUTEX_CMD_MASK;". We need to
254   // make sure that the combination below will cover every way to get
255   // FUTEX_CMP_REQUEUE_PI.
256   const int kBannedFutexBits =
257       ~(FUTEX_CMD_MASK | FUTEX_PRIVATE_FLAG | FUTEX_CLOCK_REALTIME);
258   COMPILE_ASSERT(0 == kBannedFutexBits,
259                  need_to_explicitly_blacklist_more_bits);
260 
261   return sandbox->Cond(1, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL,
262                        FUTEX_CMP_REQUEUE_PI,
263                        sandbox->Trap(SIGSYSFutexFailure, NULL),
264          sandbox->Cond(1, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL,
265                        FUTEX_CMP_REQUEUE_PI_PRIVATE,
266                        sandbox->Trap(SIGSYSFutexFailure, NULL),
267          sandbox->Cond(1, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL,
268                        FUTEX_CMP_REQUEUE_PI | FUTEX_CLOCK_REALTIME,
269                        sandbox->Trap(SIGSYSFutexFailure, NULL),
270          sandbox->Cond(1, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL,
271                        FUTEX_CMP_REQUEUE_PI_PRIVATE | FUTEX_CLOCK_REALTIME,
272                        sandbox->Trap(SIGSYSFutexFailure, NULL),
273          ErrorCode(ErrorCode::ERR_ALLOWED)))));
274 }
275 
276 }  // namespace sandbox.
277