• 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/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/seccomp-bpf-helpers/sigsys_handlers.h"
17 #include "sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.h"
18 #include "sandbox/linux/seccomp-bpf-helpers/syscall_sets.h"
19 #include "sandbox/linux/seccomp-bpf/sandbox_bpf.h"
20 #include "sandbox/linux/seccomp-bpf/sandbox_bpf_policy.h"
21 #include "sandbox/linux/services/linux_syscalls.h"
22 
23 // Changing this implementation will have an effect on *all* policies.
24 // Currently this means: Renderer/Worker, GPU, Flash and NaCl.
25 
26 namespace sandbox {
27 
28 namespace {
29 
IsBaselinePolicyAllowed(int sysno)30 bool IsBaselinePolicyAllowed(int sysno) {
31   return SyscallSets::IsAllowedAddressSpaceAccess(sysno) ||
32          SyscallSets::IsAllowedBasicScheduler(sysno) ||
33          SyscallSets::IsAllowedEpoll(sysno) ||
34          SyscallSets::IsAllowedFileSystemAccessViaFd(sysno) ||
35          SyscallSets::IsAllowedFutex(sysno) ||
36          SyscallSets::IsAllowedGeneralIo(sysno) ||
37          SyscallSets::IsAllowedGetOrModifySocket(sysno) ||
38          SyscallSets::IsAllowedGettime(sysno) ||
39          SyscallSets::IsAllowedProcessStartOrDeath(sysno) ||
40          SyscallSets::IsAllowedSignalHandling(sysno) ||
41          SyscallSets::IsGetSimpleId(sysno) ||
42          SyscallSets::IsKernelInternalApi(sysno) ||
43 #if defined(__arm__)
44          SyscallSets::IsArmPrivate(sysno) ||
45 #endif
46          SyscallSets::IsAllowedOperationOnFd(sysno);
47 }
48 
49 // System calls that will trigger the crashing SIGSYS handler.
IsBaselinePolicyWatched(int sysno)50 bool IsBaselinePolicyWatched(int sysno) {
51   return SyscallSets::IsAdminOperation(sysno) ||
52          SyscallSets::IsAdvancedScheduler(sysno) ||
53          SyscallSets::IsAdvancedTimer(sysno) ||
54          SyscallSets::IsAsyncIo(sysno) ||
55          SyscallSets::IsDebug(sysno) ||
56          SyscallSets::IsEventFd(sysno) ||
57          SyscallSets::IsExtendedAttributes(sysno) ||
58          SyscallSets::IsFaNotify(sysno) ||
59          SyscallSets::IsFsControl(sysno) ||
60          SyscallSets::IsGlobalFSViewChange(sysno) ||
61          SyscallSets::IsGlobalProcessEnvironment(sysno) ||
62          SyscallSets::IsGlobalSystemStatus(sysno) ||
63          SyscallSets::IsInotify(sysno) ||
64          SyscallSets::IsKernelModule(sysno) ||
65          SyscallSets::IsKeyManagement(sysno) ||
66          SyscallSets::IsKill(sysno) ||
67          SyscallSets::IsMessageQueue(sysno) ||
68          SyscallSets::IsMisc(sysno) ||
69 #if defined(__x86_64__)
70          SyscallSets::IsNetworkSocketInformation(sysno) ||
71 #endif
72          SyscallSets::IsNuma(sysno) ||
73          SyscallSets::IsPrctl(sysno) ||
74          SyscallSets::IsProcessGroupOrSession(sysno) ||
75 #if defined(__i386__)
76          SyscallSets::IsSocketCall(sysno) ||
77 #endif
78 #if defined(__arm__)
79          SyscallSets::IsArmPciConfig(sysno) ||
80 #endif
81          SyscallSets::IsTimer(sysno);
82 }
83 
84 // |fs_denied_errno| is the errno return for denied filesystem access.
EvaluateSyscallImpl(int fs_denied_errno,pid_t current_pid,SandboxBPF * sandbox,int sysno)85 ErrorCode EvaluateSyscallImpl(int fs_denied_errno,
86                               pid_t current_pid,
87                               SandboxBPF* sandbox,
88                               int sysno) {
89 #if defined(ADDRESS_SANITIZER) || defined(THREAD_SANITIZER) || \
90     defined(MEMORY_SANITIZER)
91   // TCGETS is required by the sanitizers on failure.
92   if (sysno == __NR_ioctl) {
93     return RestrictIoctl(sandbox);
94   }
95 
96   if (sysno == __NR_sched_getaffinity) {
97     return ErrorCode(ErrorCode::ERR_ALLOWED);
98   }
99 
100   if (sysno == __NR_sigaltstack) {
101     // Required for better stack overflow detection in ASan. Disallowed in
102     // non-ASan builds.
103     return ErrorCode(ErrorCode::ERR_ALLOWED);
104   }
105 #endif  // defined(ADDRESS_SANITIZER) || defined(THREAD_SANITIZER) ||
106         // defined(MEMORY_SANITIZER)
107 
108   if (IsBaselinePolicyAllowed(sysno)) {
109     return ErrorCode(ErrorCode::ERR_ALLOWED);
110   }
111 
112   if (sysno == __NR_clone) {
113     return RestrictCloneToThreadsAndEPERMFork(sandbox);
114   }
115 
116   if (sysno == __NR_fcntl)
117     return RestrictFcntlCommands(sandbox);
118 
119 #if defined(__i386__) || defined(__arm__)
120   if (sysno == __NR_fcntl64)
121     return RestrictFcntlCommands(sandbox);
122 #endif
123 
124   if (sysno == __NR_futex)
125     return RestrictFutex(sandbox);
126 
127   if (sysno == __NR_madvise) {
128     // Only allow MADV_DONTNEED (aka MADV_FREE).
129     return sandbox->Cond(2, ErrorCode::TP_32BIT,
130                          ErrorCode::OP_EQUAL, MADV_DONTNEED,
131                          ErrorCode(ErrorCode::ERR_ALLOWED),
132                          ErrorCode(EPERM));
133   }
134 
135 #if defined(__i386__) || defined(__x86_64__)
136   if (sysno == __NR_mmap)
137     return RestrictMmapFlags(sandbox);
138 #endif
139 
140 #if defined(__i386__) || defined(__arm__)
141   if (sysno == __NR_mmap2)
142     return RestrictMmapFlags(sandbox);
143 #endif
144 
145   if (sysno == __NR_mprotect)
146     return RestrictMprotectFlags(sandbox);
147 
148   if (sysno == __NR_prctl)
149     return sandbox::RestrictPrctl(sandbox);
150 
151 #if defined(__x86_64__) || defined(__arm__)
152   if (sysno == __NR_socketpair) {
153     // Only allow AF_UNIX, PF_UNIX. Crash if anything else is seen.
154     COMPILE_ASSERT(AF_UNIX == PF_UNIX, af_unix_pf_unix_different);
155     return sandbox->Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL, AF_UNIX,
156                          ErrorCode(ErrorCode::ERR_ALLOWED),
157                          sandbox->Trap(CrashSIGSYS_Handler, NULL));
158   }
159 #endif
160 
161   if (SyscallSets::IsKill(sysno)) {
162     return RestrictKillTarget(current_pid, sandbox, sysno);
163   }
164 
165   if (SyscallSets::IsFileSystem(sysno) ||
166       SyscallSets::IsCurrentDirectory(sysno)) {
167     return ErrorCode(fs_denied_errno);
168   }
169 
170   if (SyscallSets::IsAnySystemV(sysno)) {
171     return ErrorCode(EPERM);
172   }
173 
174   if (SyscallSets::IsUmask(sysno) ||
175       SyscallSets::IsDeniedFileSystemAccessViaFd(sysno) ||
176       SyscallSets::IsDeniedGetOrModifySocket(sysno) ||
177       SyscallSets::IsProcessPrivilegeChange(sysno)) {
178     return ErrorCode(EPERM);
179   }
180 
181 #if defined(__i386__)
182   if (SyscallSets::IsSocketCall(sysno))
183     return RestrictSocketcallCommand(sandbox);
184 #endif
185 
186   if (IsBaselinePolicyWatched(sysno)) {
187     // Previously unseen syscalls. TODO(jln): some of these should
188     // be denied gracefully right away.
189     return sandbox->Trap(CrashSIGSYS_Handler, NULL);
190   }
191 
192   // In any other case crash the program with our SIGSYS handler.
193   return sandbox->Trap(CrashSIGSYS_Handler, NULL);
194 }
195 
196 }  // namespace.
197 
198 // Unfortunately C++03 doesn't allow delegated constructors.
199 // Call other constructor when C++11 lands.
BaselinePolicy()200 BaselinePolicy::BaselinePolicy()
201     : fs_denied_errno_(EPERM), current_pid_(syscall(__NR_getpid)) {}
202 
BaselinePolicy(int fs_denied_errno)203 BaselinePolicy::BaselinePolicy(int fs_denied_errno)
204     : fs_denied_errno_(fs_denied_errno), current_pid_(syscall(__NR_getpid)) {}
205 
~BaselinePolicy()206 BaselinePolicy::~BaselinePolicy() {
207   // Make sure that this policy is created, used and destroyed by a single
208   // process.
209   DCHECK_EQ(syscall(__NR_getpid), current_pid_);
210 }
211 
EvaluateSyscall(SandboxBPF * sandbox,int sysno) const212 ErrorCode BaselinePolicy::EvaluateSyscall(SandboxBPF* sandbox,
213                                           int sysno) const {
214   // Make sure that this policy is used in the creating process.
215   if (1 == sysno) {
216     DCHECK_EQ(syscall(__NR_getpid), current_pid_);
217   }
218   return EvaluateSyscallImpl(fs_denied_errno_, current_pid_, sandbox, sysno);
219 }
220 
221 }  // namespace sandbox.
222