Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / sandbox / linux / seccomp-bpf-helpers / syscall_parameters_restrictions.cc
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 #if defined(__mips__) && !defined(MAP_STACK)
41 #define MAP_STACK 0x40000
42 #endif
43 namespace {
44
45 inline bool IsArchitectureX86_64() {
46 #if defined(__x86_64__)
47   return true;
48 #else
49   return false;
50 #endif
51 }
52
53 inline bool IsArchitectureI386() {
54 #if defined(__i386__)
55   return true;
56 #else
57   return false;
58 #endif
59 }
60
61 inline bool IsAndroid() {
62 #if defined(OS_ANDROID)
63   return true;
64 #else
65   return false;
66 #endif
67 }
68
69 inline bool IsArchitectureMips() {
70 #if defined(__mips__)
71   return true;
72 #else
73   return false;
74 #endif
75 }
76
77 }  // namespace.
78
79 using sandbox::bpf_dsl::Allow;
80 using sandbox::bpf_dsl::Arg;
81 using sandbox::bpf_dsl::BoolExpr;
82 using sandbox::bpf_dsl::Error;
83 using sandbox::bpf_dsl::If;
84 using sandbox::bpf_dsl::ResultExpr;
85
86 // TODO(mdempsky): Make BoolExpr a standalone class so these operators can
87 // be resolved via argument-dependent lookup.
88 using sandbox::bpf_dsl::operator||;
89 using sandbox::bpf_dsl::operator&&;
90
91 namespace sandbox {
92
93 // Allow Glibc's and Android pthread creation flags, crash on any other
94 // thread creation attempts and EPERM attempts to use neither
95 // CLONE_VM, nor CLONE_THREAD, which includes all fork() implementations.
96 ResultExpr RestrictCloneToThreadsAndEPERMFork() {
97   const Arg<unsigned long> flags(0);
98
99   // TODO(mdempsky): Extend DSL to support (flags & ~mask1) == mask2.
100   const uint64_t kAndroidCloneMask = CLONE_VM | CLONE_FS | CLONE_FILES |
101                                      CLONE_SIGHAND | CLONE_THREAD |
102                                      CLONE_SYSVSEM;
103   const uint64_t kObsoleteAndroidCloneMask = kAndroidCloneMask | CLONE_DETACHED;
104   const BoolExpr android_test =
105       flags == kAndroidCloneMask || flags == kObsoleteAndroidCloneMask;
106
107   const uint64_t kGlibcPthreadFlags =
108       CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | CLONE_THREAD |
109       CLONE_SYSVSEM | CLONE_SETTLS | CLONE_PARENT_SETTID | CLONE_CHILD_CLEARTID;
110   const BoolExpr glibc_test = flags == kGlibcPthreadFlags;
111
112   return If(IsAndroid() ? android_test : glibc_test, Allow())
113       .ElseIf((flags & (CLONE_VM | CLONE_THREAD)) == 0, Error(EPERM))
114       .Else(CrashSIGSYSClone());
115 }
116
117 ResultExpr RestrictPrctl() {
118   // Will need to add seccomp compositing in the future. PR_SET_PTRACER is
119   // used by breakpad but not needed anymore.
120   const Arg<int> option(0);
121   return If(option == PR_GET_NAME || option == PR_SET_NAME ||
122                 option == PR_GET_DUMPABLE || option == PR_SET_DUMPABLE,
123             Allow()).Else(CrashSIGSYSPrctl());
124 }
125
126 ResultExpr RestrictIoctl() {
127   const Arg<int> request(1);
128   return If(request == TCGETS || request == FIONREAD, Allow())
129       .Else(CrashSIGSYSIoctl());
130 }
131
132 ResultExpr RestrictMmapFlags() {
133   // The flags you see are actually the allowed ones, and the variable is a
134   // "denied" mask because of the negation operator.
135   // Significantly, we don't permit MAP_HUGETLB, or the newer flags such as
136   // MAP_POPULATE.
137   // TODO(davidung), remove MAP_DENYWRITE with updated Tegra libraries.
138   const uint32_t denied_mask =
139       ~(MAP_SHARED | MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK | MAP_NORESERVE |
140         MAP_FIXED | MAP_DENYWRITE);
141   const Arg<int> flags(3);
142   return If((flags & denied_mask) == 0, Allow()).Else(CrashSIGSYS());
143 }
144
145 ResultExpr RestrictMprotectFlags() {
146   // The flags you see are actually the allowed ones, and the variable is a
147   // "denied" mask because of the negation operator.
148   // Significantly, we don't permit weird undocumented flags such as
149   // PROT_GROWSDOWN.
150   const uint32_t denied_mask = ~(PROT_READ | PROT_WRITE | PROT_EXEC);
151   const Arg<int> prot(2);
152   return If((prot & denied_mask) == 0, Allow()).Else(CrashSIGSYS());
153 }
154
155 ResultExpr RestrictFcntlCommands() {
156   // We also restrict the flags in F_SETFL. We don't want to permit flags with
157   // a history of trouble such as O_DIRECT. The flags you see are actually the
158   // allowed ones, and the variable is a "denied" mask because of the negation
159   // operator.
160   // Glibc overrides the kernel's O_LARGEFILE value. Account for this.
161   int kOLargeFileFlag = O_LARGEFILE;
162   if (IsArchitectureX86_64() || IsArchitectureI386() || IsArchitectureMips())
163     kOLargeFileFlag = 0100000;
164
165   const Arg<int> cmd(1);
166   const Arg<long> long_arg(2);
167
168   unsigned long denied_mask = ~(O_ACCMODE | O_APPEND | O_NONBLOCK | O_SYNC |
169                                 kOLargeFileFlag | O_CLOEXEC | O_NOATIME);
170   return If(cmd == F_GETFL || cmd == F_GETFD || cmd == F_SETFD ||
171                 cmd == F_SETLK || cmd == F_SETLKW || cmd == F_GETLK ||
172                 cmd == F_DUPFD || cmd == F_DUPFD_CLOEXEC ||
173                 (cmd == F_SETFL && (long_arg & denied_mask) == 0),
174             Allow()).Else(CrashSIGSYS());
175 }
176
177 #if defined(__i386__) || defined(__mips__)
178 ResultExpr RestrictSocketcallCommand() {
179   // Unfortunately, we are unable to restrict the first parameter to
180   // socketpair(2). Whilst initially sounding bad, it's noteworthy that very
181   // few protocols actually support socketpair(2). The scary call that we're
182   // worried about, socket(2), remains blocked.
183   const Arg<int> call(0);
184   return If(call == SYS_SOCKETPAIR || call == SYS_SHUTDOWN ||
185                 call == SYS_RECV || call == SYS_SEND ||
186                 call == SYS_RECVFROM || call == SYS_SENDTO ||
187                 call == SYS_RECVMSG || call == SYS_SENDMSG,
188             Allow()).Else(Error(EPERM));
189 }
190 #endif
191
192 ResultExpr RestrictKillTarget(pid_t target_pid, int sysno) {
193   switch (sysno) {
194     case __NR_kill:
195     case __NR_tgkill: {
196       const Arg<pid_t> pid(0);
197       return If(pid == target_pid, Allow()).Else(CrashSIGSYSKill());
198     }
199     case __NR_tkill:
200       return CrashSIGSYSKill();
201     default:
202       NOTREACHED();
203       return CrashSIGSYS();
204   }
205 }
206
207 ResultExpr RestrictFutex() {
208   // In futex.c, the kernel does "int cmd = op & FUTEX_CMD_MASK;". We need to
209   // make sure that the combination below will cover every way to get
210   // FUTEX_CMP_REQUEUE_PI.
211   const int kBannedFutexBits =
212       ~(FUTEX_CMD_MASK | FUTEX_PRIVATE_FLAG | FUTEX_CLOCK_REALTIME);
213   COMPILE_ASSERT(0 == kBannedFutexBits,
214                  need_to_explicitly_blacklist_more_bits);
215
216   const Arg<int> op(1);
217   return If(op == FUTEX_CMP_REQUEUE_PI || op == FUTEX_CMP_REQUEUE_PI_PRIVATE ||
218                 op == (FUTEX_CMP_REQUEUE_PI | FUTEX_CLOCK_REALTIME) ||
219                 op == (FUTEX_CMP_REQUEUE_PI_PRIVATE | FUTEX_CLOCK_REALTIME),
220             CrashSIGSYSFutex()).Else(Allow());
221 }
222
223 }  // namespace sandbox.