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/baseline_policy.h"
6
7#include <errno.h>
8#include <sys/mman.h>
9#include <sys/socket.h>
10#include <sys/syscall.h>
11#include <sys/types.h>
12#include <unistd.h>
13
14#include "base/logging.h"
15#include "build/build_config.h"
16#include "sandbox/linux/bpf_dsl/bpf_dsl.h"
17#include "sandbox/linux/seccomp-bpf-helpers/sigsys_handlers.h"
18#include "sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.h"
19#include "sandbox/linux/seccomp-bpf-helpers/syscall_sets.h"
20#include "sandbox/linux/seccomp-bpf/sandbox_bpf.h"
21#include "sandbox/linux/services/syscall_wrappers.h"
22#include "sandbox/linux/system_headers/linux_syscalls.h"
23
24#if !defined(SO_PEEK_OFF)
25#define SO_PEEK_OFF 42
26#endif
27
28// Changing this implementation will have an effect on *all* policies.
29// Currently this means: Renderer/Worker, GPU, Flash and NaCl.
30
31using sandbox::bpf_dsl::Allow;
32using sandbox::bpf_dsl::Arg;
33using sandbox::bpf_dsl::Error;
34using sandbox::bpf_dsl::If;
35using sandbox::bpf_dsl::ResultExpr;
36
37namespace sandbox {
38
39namespace {
40
41bool IsBaselinePolicyAllowed(int sysno) {
42  return SyscallSets::IsAllowedAddressSpaceAccess(sysno) ||
43         SyscallSets::IsAllowedBasicScheduler(sysno) ||
44         SyscallSets::IsAllowedEpoll(sysno) ||
45         SyscallSets::IsAllowedFileSystemAccessViaFd(sysno) ||
46         SyscallSets::IsAllowedFutex(sysno) ||
47         SyscallSets::IsAllowedGeneralIo(sysno) ||
48         SyscallSets::IsAllowedGetOrModifySocket(sysno) ||
49         SyscallSets::IsAllowedGettime(sysno) ||
50         SyscallSets::IsAllowedProcessStartOrDeath(sysno) ||
51         SyscallSets::IsAllowedSignalHandling(sysno) ||
52         SyscallSets::IsGetSimpleId(sysno) ||
53         SyscallSets::IsKernelInternalApi(sysno) ||
54#if defined(__arm__)
55         SyscallSets::IsArmPrivate(sysno) ||
56#endif
57#if defined(__mips__)
58         SyscallSets::IsMipsPrivate(sysno) ||
59#endif
60         SyscallSets::IsAllowedOperationOnFd(sysno);
61}
62
63// System calls that will trigger the crashing SIGSYS handler.
64bool IsBaselinePolicyWatched(int sysno) {
65  return SyscallSets::IsAdminOperation(sysno) ||
66         SyscallSets::IsAdvancedScheduler(sysno) ||
67         SyscallSets::IsAdvancedTimer(sysno) ||
68         SyscallSets::IsAsyncIo(sysno) ||
69         SyscallSets::IsDebug(sysno) ||
70         SyscallSets::IsEventFd(sysno) ||
71         SyscallSets::IsExtendedAttributes(sysno) ||
72         SyscallSets::IsFaNotify(sysno) ||
73         SyscallSets::IsFsControl(sysno) ||
74         SyscallSets::IsGlobalFSViewChange(sysno) ||
75         SyscallSets::IsGlobalProcessEnvironment(sysno) ||
76         SyscallSets::IsGlobalSystemStatus(sysno) ||
77         SyscallSets::IsInotify(sysno) ||
78         SyscallSets::IsKernelModule(sysno) ||
79         SyscallSets::IsKeyManagement(sysno) ||
80         SyscallSets::IsKill(sysno) ||
81         SyscallSets::IsMessageQueue(sysno) ||
82         SyscallSets::IsMisc(sysno) ||
83#if defined(__x86_64__)
84         SyscallSets::IsNetworkSocketInformation(sysno) ||
85#endif
86         SyscallSets::IsNuma(sysno) ||
87         SyscallSets::IsPrctl(sysno) ||
88         SyscallSets::IsProcessGroupOrSession(sysno) ||
89#if defined(__i386__) || defined(__mips__)
90         SyscallSets::IsSocketCall(sysno) ||
91#endif
92#if defined(__arm__)
93         SyscallSets::IsArmPciConfig(sysno) ||
94#endif
95#if defined(__mips__)
96         SyscallSets::IsMipsMisc(sysno) ||
97#endif
98         SyscallSets::IsTimer(sysno);
99}
100
101// |fs_denied_errno| is the errno return for denied filesystem access.
102ResultExpr EvaluateSyscallImpl(int fs_denied_errno,
103                               pid_t current_pid,
104                               int sysno) {
105#if defined(ADDRESS_SANITIZER) || defined(THREAD_SANITIZER) || \
106    defined(MEMORY_SANITIZER)
107  // TCGETS is required by the sanitizers on failure.
108  if (sysno == __NR_ioctl) {
109    return RestrictIoctl();
110  }
111
112  if (sysno == __NR_sched_getaffinity) {
113    return Allow();
114  }
115
116  // Used when RSS limiting is enabled in sanitizers.
117  if (sysno == __NR_getrusage) {
118    return RestrictGetrusage();
119  }
120
121  if (sysno == __NR_sigaltstack) {
122    // Required for better stack overflow detection in ASan. Disallowed in
123    // non-ASan builds.
124    return Allow();
125  }
126#endif  // defined(ADDRESS_SANITIZER) || defined(THREAD_SANITIZER) ||
127        // defined(MEMORY_SANITIZER)
128
129  if (IsBaselinePolicyAllowed(sysno)) {
130    return Allow();
131  }
132
133#if defined(OS_ANDROID)
134  // Needed for thread creation.
135  if (sysno == __NR_sigaltstack)
136    return Allow();
137#endif
138
139  if (sysno == __NR_clock_gettime) {
140    return RestrictClockID();
141  }
142
143  if (sysno == __NR_clone) {
144    return RestrictCloneToThreadsAndEPERMFork();
145  }
146
147  if (sysno == __NR_fcntl)
148    return RestrictFcntlCommands();
149
150#if defined(__i386__) || defined(__arm__) || defined(__mips__)
151  if (sysno == __NR_fcntl64)
152    return RestrictFcntlCommands();
153#endif
154
155#if !defined(__aarch64__)
156  // fork() is never used as a system call (clone() is used instead), but we
157  // have seen it in fallback code on Android.
158  if (sysno == __NR_fork) {
159    return Error(EPERM);
160  }
161#endif
162
163  if (sysno == __NR_futex)
164    return RestrictFutex();
165
166  if (sysno == __NR_set_robust_list)
167    return Error(EPERM);
168
169  if (sysno == __NR_getpriority || sysno ==__NR_setpriority)
170    return RestrictGetSetpriority(current_pid);
171
172  if (sysno == __NR_madvise) {
173    // Only allow MADV_DONTNEED (aka MADV_FREE).
174    const Arg<int> advice(2);
175    return If(advice == MADV_DONTNEED, Allow()).Else(Error(EPERM));
176  }
177
178#if defined(__i386__) || defined(__x86_64__) || defined(__mips__) || \
179    defined(__aarch64__)
180  if (sysno == __NR_mmap)
181    return RestrictMmapFlags();
182#endif
183
184#if defined(__i386__) || defined(__arm__) || defined(__mips__)
185  if (sysno == __NR_mmap2)
186    return RestrictMmapFlags();
187#endif
188
189  if (sysno == __NR_mprotect)
190    return RestrictMprotectFlags();
191
192  if (sysno == __NR_prctl)
193    return RestrictPrctl();
194
195#if defined(__x86_64__) || defined(__arm__) || defined(__mips__) || \
196    defined(__aarch64__)
197  if (sysno == __NR_socketpair) {
198    // Only allow AF_UNIX, PF_UNIX. Crash if anything else is seen.
199    static_assert(AF_UNIX == PF_UNIX,
200                  "af_unix and pf_unix should not be different");
201    const Arg<int> domain(0);
202    return If(domain == AF_UNIX, Allow()).Else(CrashSIGSYS());
203  }
204#endif
205
206  if (SyscallSets::IsKill(sysno)) {
207    return RestrictKillTarget(current_pid, sysno);
208  }
209
210  if (SyscallSets::IsFileSystem(sysno) ||
211      SyscallSets::IsCurrentDirectory(sysno)) {
212    return Error(fs_denied_errno);
213  }
214
215  if (SyscallSets::IsSeccomp(sysno))
216    return Error(EPERM);
217
218  if (SyscallSets::IsAnySystemV(sysno)) {
219    return Error(EPERM);
220  }
221
222  if (SyscallSets::IsUmask(sysno) ||
223      SyscallSets::IsDeniedFileSystemAccessViaFd(sysno) ||
224      SyscallSets::IsDeniedGetOrModifySocket(sysno) ||
225      SyscallSets::IsProcessPrivilegeChange(sysno)) {
226    return Error(EPERM);
227  }
228
229#if defined(__i386__) || defined(__mips__)
230  if (SyscallSets::IsSocketCall(sysno))
231    return RestrictSocketcallCommand();
232#endif
233
234#if !defined(__i386__)
235  if (sysno == __NR_getsockopt || sysno ==__NR_setsockopt) {
236    // Used by Mojo EDK to catch a message pipe being sent over itself.
237    const Arg<int> level(1);
238    const Arg<int> optname(2);
239    return If(AllOf(level == SOL_SOCKET, optname == SO_PEEK_OFF), Allow())
240        .Else(CrashSIGSYS());
241  }
242#endif
243
244  if (IsBaselinePolicyWatched(sysno)) {
245    // Previously unseen syscalls. TODO(jln): some of these should
246    // be denied gracefully right away.
247    return CrashSIGSYS();
248  }
249
250  // In any other case crash the program with our SIGSYS handler.
251  return CrashSIGSYS();
252}
253
254}  // namespace.
255
256// Unfortunately C++03 doesn't allow delegated constructors.
257// Call other constructor when C++11 lands.
258BaselinePolicy::BaselinePolicy() : BaselinePolicy(EPERM) {}
259
260BaselinePolicy::BaselinePolicy(int fs_denied_errno)
261    : fs_denied_errno_(fs_denied_errno), policy_pid_(sys_getpid()) {
262}
263
264BaselinePolicy::~BaselinePolicy() {
265  // Make sure that this policy is created, used and destroyed by a single
266  // process.
267  DCHECK_EQ(sys_getpid(), policy_pid_);
268}
269
270ResultExpr BaselinePolicy::EvaluateSyscall(int sysno) const {
271  // Sanity check that we're only called with valid syscall numbers.
272  DCHECK(SandboxBPF::IsValidSyscallNumber(sysno));
273  // Make sure that this policy is used in the creating process.
274  if (1 == sysno) {
275    DCHECK_EQ(sys_getpid(), policy_pid_);
276  }
277  return EvaluateSyscallImpl(fs_denied_errno_, policy_pid_, sysno);
278}
279
280ResultExpr BaselinePolicy::InvalidSyscall() const {
281  return CrashSIGSYS();
282}
283
284}  // namespace sandbox.
285