syscall_parameters_restrictions.cc revision 5f1c94371a64b3196d4be9466099bb892df9b88e
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
43namespace {
44
45inline bool IsArchitectureX86_64() {
46#if defined(__x86_64__)
47  return true;
48#else
49  return false;
50#endif
51}
52
53inline bool IsArchitectureI386() {
54#if defined(__i386__)
55  return true;
56#else
57  return false;
58#endif
59}
60
61inline bool IsAndroid() {
62#if defined(OS_ANDROID)
63  return true;
64#else
65  return false;
66#endif
67}
68
69inline bool IsArchitectureMips() {
70#if defined(__mips__)
71  return true;
72#else
73  return false;
74#endif
75}
76
77}  // namespace.
78
79using sandbox::bpf_dsl::Allow;
80using sandbox::bpf_dsl::Arg;
81using sandbox::bpf_dsl::BoolExpr;
82using sandbox::bpf_dsl::Error;
83using sandbox::bpf_dsl::If;
84using sandbox::bpf_dsl::ResultExpr;
85
86// TODO(mdempsky): Make BoolExpr a standalone class so these operators can
87// be resolved via argument-dependent lookup.
88using sandbox::bpf_dsl::operator||;
89using sandbox::bpf_dsl::operator&&;
90
91namespace 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.
96ResultExpr 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
117ResultExpr 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
126ResultExpr RestrictIoctl() {
127  const Arg<int> request(1);
128  return If(request == TCGETS || request == FIONREAD, Allow())
129      .Else(CrashSIGSYSIoctl());
130}
131
132ResultExpr 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
145ResultExpr 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
155ResultExpr 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__)
178ResultExpr 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
192ResultExpr 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
207ResultExpr 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.
224