Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1421)

Side by Side Diff: components/nacl/loader/nacl_sandbox_linux.cc

Issue 196793023: Add seccomp sandbox for non-SFI NaCl (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 6 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "components/nacl/loader/nacl_sandbox_linux.h" 5 #include "components/nacl/loader/nacl_sandbox_linux.h"
6 6
7 #include <errno.h> 7 #include <errno.h>
8 #include <fcntl.h>
9 #include <linux/net.h>
8 #include <signal.h> 10 #include <signal.h>
11 #include <sys/prctl.h>
9 #include <sys/ptrace.h> 12 #include <sys/ptrace.h>
13 #include <sys/mman.h>
14 #include <sys/socket.h>
15 #include <sys/syscall.h>
10 16
11 #include "base/basictypes.h" 17 #include "base/basictypes.h"
12 #include "base/callback.h" 18 #include "base/callback.h"
13 #include "base/compiler_specific.h" 19 #include "base/compiler_specific.h"
14 #include "base/logging.h" 20 #include "base/logging.h"
15 #include "build/build_config.h" 21 #include "build/build_config.h"
16 22
17 #if defined(USE_SECCOMP_BPF) 23 #if defined(USE_SECCOMP_BPF)
18 #include "content/public/common/sandbox_init.h" 24 #include "content/public/common/sandbox_init.h"
25 #include "sandbox/linux/seccomp-bpf-helpers/sigsys_handlers.h"
19 #include "sandbox/linux/seccomp-bpf/sandbox_bpf.h" 26 #include "sandbox/linux/seccomp-bpf/sandbox_bpf.h"
20 #include "sandbox/linux/seccomp-bpf/sandbox_bpf_policy.h" 27 #include "sandbox/linux/seccomp-bpf/sandbox_bpf_policy.h"
28 #include "sandbox/linux/seccomp-bpf/trap.h"
21 #include "sandbox/linux/services/linux_syscalls.h" 29 #include "sandbox/linux/services/linux_syscalls.h"
22 30
31 #if defined(__arm__) && !defined(MAP_STACK)
32 #define MAP_STACK 0x20000 // Daisy build environment has old headers.
33 #endif
34
23 using sandbox::ErrorCode; 35 using sandbox::ErrorCode;
24 using sandbox::SandboxBPF; 36 using sandbox::SandboxBPF;
25 using sandbox::SandboxBPFPolicy; 37 using sandbox::SandboxBPFPolicy;
26 38
27 namespace { 39 namespace {
28 40
29 // On ARM and x86_64, System V shared memory calls have each their own system 41 // On ARM and x86_64, System V shared memory calls have each their own system
30 // call, while on i386 they are multiplexed. 42 // call, while on i386 they are multiplexed.
31 #if defined(__x86_64__) || defined(__arm__) 43 #if defined(__x86_64__) || defined(__arm__)
32 bool IsSystemVSharedMemory(int sysno) { 44 bool IsSystemVSharedMemory(int sysno) {
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after
115 case __NR_sched_setscheduler: 127 case __NR_sched_setscheduler:
116 case __NR_setpriority: 128 case __NR_setpriority:
117 case __NR_sysinfo: 129 case __NR_sysinfo:
118 // __NR_times needed as clock() is called by CommandBufferHelper, which is 130 // __NR_times needed as clock() is called by CommandBufferHelper, which is
119 // used by NaCl applications that use Pepper's 3D interfaces. 131 // used by NaCl applications that use Pepper's 3D interfaces.
120 // See crbug.com/264856 for details. 132 // See crbug.com/264856 for details.
121 case __NR_times: 133 case __NR_times:
122 case __NR_uname: 134 case __NR_uname:
123 return ErrorCode(ErrorCode::ERR_ALLOWED); 135 return ErrorCode(ErrorCode::ERR_ALLOWED);
124 case __NR_ptrace: 136 case __NR_ptrace:
137 // For RunSandboxSanityChecks().
125 return ErrorCode(EPERM); 138 return ErrorCode(EPERM);
126 default: 139 default:
127 // TODO(jln): look into getting rid of System V shared memory: 140 // TODO(jln): look into getting rid of System V shared memory:
128 // platform_qualify/linux/sysv_shm_and_mmap.c makes it a requirement, but 141 // platform_qualify/linux/sysv_shm_and_mmap.c makes it a requirement, but
129 // it may not be needed in all cases. Chromium renderers don't need 142 // it may not be needed in all cases. Chromium renderers don't need
130 // System V shared memory on Aura. 143 // System V shared memory on Aura.
131 #if defined(__x86_64__) || defined(__arm__) 144 #if defined(__x86_64__) || defined(__arm__)
132 if (IsSystemVSharedMemory(sysno)) 145 if (IsSystemVSharedMemory(sysno))
133 return ErrorCode(ErrorCode::ERR_ALLOWED); 146 return ErrorCode(ErrorCode::ERR_ALLOWED);
134 #elif defined(__i386__) 147 #elif defined(__i386__)
135 if (IsSystemVIpc(sysno)) 148 if (IsSystemVIpc(sysno))
136 return ErrorCode(ErrorCode::ERR_ALLOWED); 149 return ErrorCode(ErrorCode::ERR_ALLOWED);
137 #endif 150 #endif
138 return baseline_policy_->EvaluateSyscall(sb, sysno); 151 return baseline_policy_->EvaluateSyscall(sb, sysno);
139 } 152 }
140 NOTREACHED(); 153 NOTREACHED();
141 // GCC wants this. 154 // GCC wants this.
142 return ErrorCode(EPERM); 155 return ErrorCode(EPERM);
143 } 156 }
144 157
158 ErrorCode RestrictFcntlCommandsForNonSfiNaCl(SandboxBPF* sb) {
159 ErrorCode::ArgType mask_long_type;
160 if (sizeof(long) == 8)
161 mask_long_type = ErrorCode::TP_64BIT;
162 else if (sizeof(long) == 4)
163 mask_long_type = ErrorCode::TP_32BIT;
164 else
165 NOTREACHED();
166 // We allow following cases:
167 // 1. F_SETFD + FD_CLOEXEC: libevent's epoll_init uses this.
168 // 2. F_GETFL: Used by SetNonBlocking in
169 // message_pump_libevent.cc and Channel::ChannelImpl::CreatePipe
170 // in ipc_channel_posix.cc. Note that the latter does not work
171 // with EPERM.
172 // 3. F_SETFL: Used by evutil_make_socket_nonblocking in
173 // libevent and SetNonBlocking. As the latter mix O_NONBLOCK to
174 // the return value of F_GETFL, so we need to allow O_ACCMODE in
175 // addition to O_NONBLOCK.
176 unsigned long denied_mask = ~(O_ACCMODE | O_NONBLOCK);
177 return sb->Cond(1, ErrorCode::TP_32BIT,
178 ErrorCode::OP_EQUAL, F_SETFD,
179 sb->Cond(2, mask_long_type,
180 ErrorCode::OP_EQUAL, FD_CLOEXEC,
181 ErrorCode(ErrorCode::ERR_ALLOWED),
182 sb->Trap(sandbox::CrashSIGSYS_Handler, NULL)),
183 sb->Cond(1, ErrorCode::TP_32BIT,
184 ErrorCode::OP_EQUAL, F_GETFL,
185 ErrorCode(ErrorCode::ERR_ALLOWED),
186 sb->Cond(1, ErrorCode::TP_32BIT,
187 ErrorCode::OP_EQUAL, F_SETFL,
188 sb->Cond(2, mask_long_type,
189 ErrorCode::OP_HAS_ANY_BITS, denied_mask,
190 sb->Trap(sandbox::CrashSIGSYS_Handler, NULL),
191 ErrorCode(ErrorCode::ERR_ALLOWED)),
192 sb->Trap(sandbox::CrashSIGSYS_Handler, NULL))));
193 }
194
195 // The seccomp sandbox policy for NaCl non-SFI mode. Note that this
196 // policy must be as strong as possible, as non-SFI mode heavily
197 // depends on seccomp sandbox.
198 class NonSfiNaClBPFSandboxPolicy : public SandboxBPFPolicy {
Mark Seaborn 2014/03/28 01:38:25 Can we put the Non-SFI Mode sandbox policy in a se
hamaji 2014/03/28 12:06:10 Thanks, will do!
199 public:
200 explicit NonSfiNaClBPFSandboxPolicy() {
201 }
202 virtual ~NonSfiNaClBPFSandboxPolicy() {}
203
204 virtual ErrorCode EvaluateSyscall(SandboxBPF* sandbox_compiler,
205 int system_call_number) const OVERRIDE;
206
207 private:
208 DISALLOW_COPY_AND_ASSIGN(NonSfiNaClBPFSandboxPolicy);
209 };
210
211 ErrorCode NonSfiNaClBPFSandboxPolicy::EvaluateSyscall(
212 sandbox::SandboxBPF* sb, int sysno) const {
213 ErrorCode ret = sb->Trap(sandbox::CrashSIGSYS_Handler, NULL);
214 switch (sysno) {
215 // Allowed syscalls.
hamaji 2014/03/24 15:56:37 I have a question about sigaction and sigaltstack.
216 case __NR__llseek:
217 case __NR_clock_gettime:
218 case __NR_close:
219 case __NR_dup:
220 case __NR_dup2:
221 case __NR_epoll_create:
222 case __NR_epoll_ctl:
hamaji 2014/03/24 15:56:37 Would it be better to check the operation type is
223 case __NR_epoll_wait:
224 case __NR_exit:
225 case __NR_exit_group:
226 case __NR_fstat64:
227 case __NR_futex:
hamaji 2014/03/24 16:25:43 Maybe better to restrict the operation of futex?
228 case __NR_gettid:
229 case __NR_gettimeofday:
230 case __NR_munmap:
231 case __NR_nanosleep:
232 case __NR_pipe:
233 case __NR_read:
234 case __NR_restart_syscall:
235 case __NR_sched_yield:
236 case __NR_write:
237 #if defined(__arm__)
238 case __ARM_NR_cacheflush:
239 #endif
240 ret = ErrorCode(ErrorCode::ERR_ALLOWED);
241 break;
242
243 // __NR_times needed as clock() is called by CommandBufferHelper, which is
244 // used by NaCl applications that use Pepper's 3D interfaces.
245 // See crbug.com/264856 for details.
246 case __NR_times:
247 // NaCl runtime exposes clock_getres to untrusted code.
248 case __NR_clock_getres:
hamaji 2014/03/24 16:25:43 Do we need to restrict clk_id for gettime and getr
249 ret = ErrorCode(ErrorCode::ERR_ALLOWED);
250 break;
251
252 // Conditionally allowed syscalls:
253 case __NR_clone: {
254 // We allow clone only for new thread creation.
255 ret = sb->Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL,
256 CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND |
257 CLONE_THREAD | CLONE_SYSVSEM | CLONE_SETTLS |
258 CLONE_PARENT_SETTID | CLONE_CHILD_CLEARTID,
259 ErrorCode(ErrorCode::ERR_ALLOWED),
260 sb->Trap(sandbox::SIGSYSCloneFailure, NULL));
261 break;
262 }
263 case __NR_prctl:
264 // base::PlatformThread::SetName() uses PR_SET_NAME so we return
265 // EPERM for it. Otherwise, we will raise SIGSYS.
266 ret = sb->Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL,
267 PR_SET_NAME, ErrorCode(EPERM),
268 sb->Trap(sandbox::SIGSYSPrctlFailure, NULL));
269
270 #if defined(__i386__)
271 case __NR_socketcall: {
272 // We only allow socketpair, sendmsg, and recvmsg.
273 ret = sb->Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL,
274 SYS_SOCKETPAIR, ErrorCode(ErrorCode::ERR_ALLOWED),
275 sb->Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL,
276 SYS_SENDMSG, ErrorCode(ErrorCode::ERR_ALLOWED),
277 sb->Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL,
278 SYS_RECVMSG, ErrorCode(ErrorCode::ERR_ALLOWED),
279 ErrorCode(EPERM))));
280 break;
281 }
282 #endif
283 #if defined(__x86_64__) || defined(__arm__)
284 case __NR_recvmsg:
285 case __NR_sendmsg:
286 ret = ErrorCode(ErrorCode::ERR_ALLOWED);
287 break;
288
289 case __NR_socketpair:
290 // Only allow AF_UNIX, PF_UNIX. Crash if anything else is seen.
291 COMPILE_ASSERT(AF_UNIX == PF_UNIX, af_unix_pf_unix_different);
292 return sb->Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL, AF_UNIX,
293 ErrorCode(ErrorCode::ERR_ALLOWED),
294 sb->Trap(sandbox::CrashSIGSYS_Handler, NULL));
295 break;
296 #endif
297
298 // It is allowed to call the following syscalls, but they just
299 // return EPERM.
300 case __NR_ptrace:
301 // For RunSandboxSanityChecks().
302 ret = ErrorCode(EPERM);
303 break;
304 case __NR_set_robust_list:
305 // glibc uses this for its pthread implementation. If we return
306 // EPERM for this, glibc will stop using this.
307 // TODO(hamaji): newlib does not use this. Make this SIGTRAP once
308 // we have switched to newlib.
309 ret = ErrorCode(EPERM);
310 break;
311 #if !defined(__x86_64__)
312 case __NR_getegid32:
313 case __NR_geteuid32:
314 case __NR_getgid32:
315 case __NR_getuid32:
316 #endif
317 // third_party/libevent uses them, but we can just return -1 from
318 // them as it is just checking getuid() != geteuid() and
319 // getgid() != getegid()
320 ret = ErrorCode(EPERM);
321 break;
322 #if defined(__i386__) || defined(__x86_64__)
323 case __NR_time:
324 // This is obsolete in ARM EABI, but x86 glibc indirectly calls
325 // this in sysconf.
326 ret = ErrorCode(EPERM);
327 break;
328 #endif
329
330 #if defined(__x86_64__)
331 case __NR_fcntl:
332 #endif
333 #if defined(__i386__) || defined(__arm__)
334 case __NR_fcntl64:
335 #endif
336 ret = RestrictFcntlCommandsForNonSfiNaCl(sb);
337 break;
338
339 #if defined(__x86_64__)
340 case __NR_mmap:
341 #endif
342 #if defined(__i386__) || defined(__arm__)
343 case __NR_mmap2:
344 #endif
345 {
346 uint32_t denied_flag_mask = ~(MAP_SHARED | MAP_PRIVATE | MAP_ANONYMOUS |
347 MAP_STACK | MAP_FIXED);
348 // switch to newlib. Currently, it is used by glibc's pthread_create.
349 // TODO(jln, keescook, drewry): Limit the use of mmap by adding
350 // some features to linux kernel.
351 uint32_t denied_prot_mask = ~(PROT_READ | PROT_WRITE | PROT_EXEC);
352 return sb->Cond(3, ErrorCode::TP_32BIT, ErrorCode::OP_HAS_ANY_BITS,
353 denied_flag_mask,
354 sb->Trap(sandbox::CrashSIGSYS_Handler, NULL),
355 sb->Cond(2, ErrorCode::TP_32BIT, ErrorCode::OP_HAS_ANY_BITS,
356 denied_prot_mask,
357 sb->Trap(sandbox::CrashSIGSYS_Handler, NULL),
358 ErrorCode(ErrorCode::ERR_ALLOWED)));
359 break;
360 }
361
362 case __NR_mprotect: {
363 // TODO(jln, keescook, drewry): Limit the use of mmap by adding
364 // some features to linux kernel.
365 uint32_t denied_mask = ~(PROT_READ | PROT_WRITE | PROT_EXEC);
366 return sb->Cond(2, ErrorCode::TP_32BIT, ErrorCode::OP_HAS_ANY_BITS,
367 denied_mask,
368 sb->Trap(sandbox::CrashSIGSYS_Handler, NULL),
369 ErrorCode(ErrorCode::ERR_ALLOWED));
370 break;
371 }
372
373 case __NR_open:
374 // EPERM instead of SIGSYS as glibc tries to open files in /proc.
375 // TODO(hamaji): Remove this when we switch to newlib.
376 ret = ErrorCode(EPERM);
377 break;
378
379 case __NR_brk:
380 // tcmalloc uses brk because HAVE_SBRK is set in
381 // third_party/tcmalloc/chromium/src/config_linux.h
382 // TODO(hamaji): We can get rid of this when we stop using
383 // tcmalloc for non-SFI nacl_helper.
384 ret = ErrorCode(ErrorCode::ERR_ALLOWED);
385 break;
386
387 case __NR_madvise:
388 // tcmalloc calls madvise in TCMalloc_SystemRelease.
389 // TODO(hamaji): We can get rid of this when we stop using
390 // tcmalloc for non-SFI nacl_helper.
391 ret = ErrorCode(EPERM);
392 break;
393
394 default:
395 ret = sb->Trap(sandbox::CrashSIGSYS_Handler, NULL);
396 break;
397 }
398 return ret;
399 }
400
145 void RunSandboxSanityChecks() { 401 void RunSandboxSanityChecks() {
146 errno = 0; 402 errno = 0;
147 // Make a ptrace request with an invalid PID. 403 // Make a ptrace request with an invalid PID.
148 long ptrace_ret = ptrace(PTRACE_PEEKUSER, -1 /* pid */, NULL, NULL); 404 long ptrace_ret = ptrace(PTRACE_PEEKUSER, -1 /* pid */, NULL, NULL);
149 CHECK_EQ(-1, ptrace_ret); 405 CHECK_EQ(-1, ptrace_ret);
150 // Without the sandbox on, this ptrace call would ESRCH instead. 406 // Without the sandbox on, this ptrace call would ESRCH instead.
151 CHECK_EQ(EPERM, errno); 407 CHECK_EQ(EPERM, errno);
152 } 408 }
153 409
154 } // namespace 410 } // namespace
(...skipping 10 matching lines...) Expand all
165 #if defined(USE_SECCOMP_BPF) 421 #if defined(USE_SECCOMP_BPF)
166 bool sandbox_is_initialized = content::InitializeSandbox( 422 bool sandbox_is_initialized = content::InitializeSandbox(
167 scoped_ptr<SandboxBPFPolicy>(new NaClBPFSandboxPolicy())); 423 scoped_ptr<SandboxBPFPolicy>(new NaClBPFSandboxPolicy()));
168 if (sandbox_is_initialized) { 424 if (sandbox_is_initialized) {
169 RunSandboxSanityChecks(); 425 RunSandboxSanityChecks();
170 return true; 426 return true;
171 } 427 }
172 #endif // defined(USE_SECCOMP_BPF) 428 #endif // defined(USE_SECCOMP_BPF)
173 return false; 429 return false;
174 } 430 }
431
432 bool InitializeBPFSandboxForNonSfi() {
433 #if defined(USE_SECCOMP_BPF)
434 bool sandbox_is_initialized = content::InitializeSandbox(
435 scoped_ptr<SandboxBPFPolicy>(new NonSfiNaClBPFSandboxPolicy()));
436 if (sandbox_is_initialized) {
437 RunSandboxSanityChecks();
438 return true;
439 }
440 #endif // defined(USE_SECCOMP_BPF)
441 LOG(FATAL) << "InitializeBPFSandboxForNonSfi failed";
442 return false;
443 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698