sandbox: Convert remaining legacy tests to use policy classes
[chromium-blink-merge.git] / components / nacl / loader / nonsfi / nonsfi_sandbox_unittest.cc
blob0ed17e2118793e428cf9d924b4e32834c863fe65
1 // Copyright 2014 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.
5 // Sanitizers internally use some syscalls which non-SFI NaCl disallows.
6 #if !defined(ADDRESS_SANITIZER) && !defined(THREAD_SANITIZER) && \
7 !defined(MEMORY_SANITIZER) && !defined(LEAK_SANITIZER)
9 #include "components/nacl/loader/nonsfi/nonsfi_sandbox.h"
11 #include <errno.h>
12 #include <fcntl.h>
13 #include <linux/futex.h>
14 #include <pthread.h>
15 #include <sched.h>
16 #include <signal.h>
17 #include <stdlib.h>
18 #include <string.h>
19 #include <sys/mman.h>
20 #include <sys/prctl.h>
21 #include <sys/ptrace.h>
22 #include <sys/socket.h>
23 #include <sys/syscall.h>
24 #include <sys/types.h>
25 #include <sys/wait.h>
26 #include <time.h>
27 #include <unistd.h>
29 #include "base/bind.h"
30 #include "base/callback.h"
31 #include "base/compiler_specific.h"
32 #include "base/files/scoped_file.h"
33 #include "base/logging.h"
34 #include "base/posix/eintr_wrapper.h"
35 #include "base/sys_info.h"
36 #include "base/threading/thread.h"
37 #include "base/time/time.h"
38 #include "sandbox/linux/seccomp-bpf-helpers/sigsys_handlers.h"
39 #include "sandbox/linux/seccomp-bpf/bpf_tests.h"
40 #include "sandbox/linux/seccomp-bpf/sandbox_bpf.h"
41 #include "sandbox/linux/seccomp-bpf/syscall.h"
42 #include "sandbox/linux/services/linux_syscalls.h"
43 #include "third_party/lss/linux_syscall_support.h" // for MAKE_PROCESS_CPUCLOCK
45 namespace {
47 void DoPipe(base::ScopedFD* fds) {
48 int tmp_fds[2];
49 BPF_ASSERT_EQ(0, pipe(tmp_fds));
50 fds[0].reset(tmp_fds[0]);
51 fds[1].reset(tmp_fds[1]);
54 void DoSocketpair(base::ScopedFD* fds) {
55 int tmp_fds[2];
56 BPF_ASSERT_EQ(0, socketpair(AF_UNIX, SOCK_STREAM, 0, tmp_fds));
57 fds[0].reset(tmp_fds[0]);
58 fds[1].reset(tmp_fds[1]);
61 TEST(NaClNonSfiSandboxTest, BPFIsSupported) {
62 bool seccomp_bpf_supported = (
63 sandbox::SandboxBPF::SupportsSeccompSandbox(-1) ==
64 sandbox::SandboxBPF::STATUS_AVAILABLE);
65 if (!seccomp_bpf_supported) {
66 LOG(ERROR) << "Seccomp BPF is not supported, these tests "
67 << "will pass without running";
71 BPF_DEATH_TEST_C(NaClNonSfiSandboxTest,
72 invalid_sysno,
73 DEATH_MESSAGE(sandbox::GetErrorMessageContentForTests()),
74 nacl::nonsfi::NaClNonSfiBPFSandboxPolicy) {
75 syscall(999);
78 const int kExpectedValue = 123;
80 void* SetValueInThread(void* test_val_ptr) {
81 *reinterpret_cast<int*>(test_val_ptr) = kExpectedValue;
82 return NULL;
85 // To make this test pass, we need to allow sched_getaffinity and
86 // mmap. We just disable this test not to complicate the sandbox.
87 BPF_TEST_C(NaClNonSfiSandboxTest,
88 clone_by_pthread_create,
89 nacl::nonsfi::NaClNonSfiBPFSandboxPolicy) {
90 // clone call for thread creation is allowed.
91 pthread_t th;
92 int test_val = 42;
93 BPF_ASSERT_EQ(0, pthread_create(&th, NULL, &SetValueInThread, &test_val));
94 BPF_ASSERT_EQ(0, pthread_join(th, NULL));
95 BPF_ASSERT_EQ(kExpectedValue, test_val);
98 int DoFork() {
99 // Call clone() to do a fork().
100 const int pid = syscall(__NR_clone, SIGCHLD, NULL);
101 if (pid == 0)
102 _exit(0);
103 return pid;
106 // The sanity check for DoFork without the sandbox.
107 TEST(NaClNonSfiSandboxTest, DoFork) {
108 const int pid = DoFork();
109 ASSERT_LT(0, pid);
110 int status;
111 ASSERT_EQ(pid, HANDLE_EINTR(waitpid(pid, &status, 0)));
112 ASSERT_TRUE(WIFEXITED(status));
113 ASSERT_EQ(0, WEXITSTATUS(status));
116 // Then, try this in the sandbox.
117 BPF_DEATH_TEST_C(NaClNonSfiSandboxTest,
118 clone_for_fork,
119 DEATH_MESSAGE(sandbox::GetCloneErrorMessageContentForTests()),
120 nacl::nonsfi::NaClNonSfiBPFSandboxPolicy) {
121 DoFork();
124 BPF_TEST_C(NaClNonSfiSandboxTest,
125 prctl_SET_NAME,
126 nacl::nonsfi::NaClNonSfiBPFSandboxPolicy) {
127 errno = 0;
128 BPF_ASSERT_EQ(-1, syscall(__NR_prctl, PR_SET_NAME, "foo"));
129 BPF_ASSERT_EQ(EPERM, errno);
132 BPF_DEATH_TEST_C(NaClNonSfiSandboxTest,
133 prctl_SET_DUMPABLE,
134 DEATH_MESSAGE(sandbox::GetPrctlErrorMessageContentForTests()),
135 nacl::nonsfi::NaClNonSfiBPFSandboxPolicy) {
136 syscall(__NR_prctl, PR_SET_DUMPABLE, 1UL);
139 BPF_TEST_C(NaClNonSfiSandboxTest,
140 socketcall_allowed,
141 nacl::nonsfi::NaClNonSfiBPFSandboxPolicy) {
142 base::ScopedFD fds[2];
143 struct msghdr msg = {};
144 struct iovec iov;
145 std::string payload("foo");
146 iov.iov_base = &payload[0];
147 iov.iov_len = payload.size();
148 msg.msg_iov = &iov;
149 msg.msg_iovlen = 1;
150 DoSocketpair(fds);
151 BPF_ASSERT_EQ(static_cast<int>(payload.size()),
152 HANDLE_EINTR(sendmsg(fds[1].get(), &msg, 0)));
153 BPF_ASSERT_EQ(static_cast<int>(payload.size()),
154 HANDLE_EINTR(recvmsg(fds[0].get(), &msg, 0)));
155 BPF_ASSERT_EQ(0, shutdown(fds[0].get(), SHUT_RDWR));
158 BPF_DEATH_TEST_C(NaClNonSfiSandboxTest,
159 accept,
160 DEATH_MESSAGE(sandbox::GetErrorMessageContentForTests()),
161 nacl::nonsfi::NaClNonSfiBPFSandboxPolicy) {
162 accept(0, NULL, NULL);
165 BPF_DEATH_TEST_C(NaClNonSfiSandboxTest,
166 bind,
167 DEATH_MESSAGE(sandbox::GetErrorMessageContentForTests()),
168 nacl::nonsfi::NaClNonSfiBPFSandboxPolicy) {
169 bind(0, NULL, 0);
172 BPF_DEATH_TEST_C(NaClNonSfiSandboxTest,
173 connect,
174 DEATH_MESSAGE(sandbox::GetErrorMessageContentForTests()),
175 nacl::nonsfi::NaClNonSfiBPFSandboxPolicy) {
176 connect(0, NULL, 0);
179 BPF_DEATH_TEST_C(NaClNonSfiSandboxTest,
180 getpeername,
181 DEATH_MESSAGE(sandbox::GetErrorMessageContentForTests()),
182 nacl::nonsfi::NaClNonSfiBPFSandboxPolicy) {
183 getpeername(0, NULL, NULL);
186 BPF_DEATH_TEST_C(NaClNonSfiSandboxTest,
187 getsockname,
188 DEATH_MESSAGE(sandbox::GetErrorMessageContentForTests()),
189 nacl::nonsfi::NaClNonSfiBPFSandboxPolicy) {
190 struct sockaddr addr;
191 socklen_t addrlen = 0;
192 getsockname(0, &addr, &addrlen);
195 BPF_DEATH_TEST_C(NaClNonSfiSandboxTest,
196 getsockopt,
197 DEATH_MESSAGE(sandbox::GetErrorMessageContentForTests()),
198 nacl::nonsfi::NaClNonSfiBPFSandboxPolicy) {
199 getsockopt(0, 0, 0, NULL, NULL);
202 BPF_DEATH_TEST_C(NaClNonSfiSandboxTest,
203 listen,
204 DEATH_MESSAGE(sandbox::GetErrorMessageContentForTests()),
205 nacl::nonsfi::NaClNonSfiBPFSandboxPolicy) {
206 listen(0, 0);
209 BPF_DEATH_TEST_C(NaClNonSfiSandboxTest,
210 recv,
211 DEATH_MESSAGE(sandbox::GetErrorMessageContentForTests()),
212 nacl::nonsfi::NaClNonSfiBPFSandboxPolicy) {
213 recv(0, NULL, 0, 0);
216 BPF_DEATH_TEST_C(NaClNonSfiSandboxTest,
217 recvfrom,
218 DEATH_MESSAGE(sandbox::GetErrorMessageContentForTests()),
219 nacl::nonsfi::NaClNonSfiBPFSandboxPolicy) {
220 recvfrom(0, NULL, 0, 0, NULL, NULL);
223 BPF_DEATH_TEST_C(NaClNonSfiSandboxTest,
224 send,
225 DEATH_MESSAGE(sandbox::GetErrorMessageContentForTests()),
226 nacl::nonsfi::NaClNonSfiBPFSandboxPolicy) {
227 send(0, NULL, 0, 0);
230 BPF_DEATH_TEST_C(NaClNonSfiSandboxTest,
231 sendto,
232 DEATH_MESSAGE(sandbox::GetErrorMessageContentForTests()),
233 nacl::nonsfi::NaClNonSfiBPFSandboxPolicy) {
234 sendto(0, NULL, 0, 0, NULL, 0);
237 BPF_DEATH_TEST_C(NaClNonSfiSandboxTest,
238 setsockopt,
239 DEATH_MESSAGE(sandbox::GetErrorMessageContentForTests()),
240 nacl::nonsfi::NaClNonSfiBPFSandboxPolicy) {
241 setsockopt(0, 0, 0, NULL, 0);
244 BPF_DEATH_TEST_C(NaClNonSfiSandboxTest,
245 socket,
246 DEATH_MESSAGE(sandbox::GetErrorMessageContentForTests()),
247 nacl::nonsfi::NaClNonSfiBPFSandboxPolicy) {
248 socket(0, 0, 0);
251 #if defined(__x86_64__) || defined(__arm__)
252 BPF_DEATH_TEST_C(NaClNonSfiSandboxTest,
253 socketpair,
254 DEATH_MESSAGE(sandbox::GetErrorMessageContentForTests()),
255 nacl::nonsfi::NaClNonSfiBPFSandboxPolicy) {
256 int fds[2];
257 socketpair(AF_INET, SOCK_STREAM, 0, fds);
259 #endif
261 BPF_TEST_C(NaClNonSfiSandboxTest,
262 fcntl_SETFD_allowed,
263 nacl::nonsfi::NaClNonSfiBPFSandboxPolicy) {
264 base::ScopedFD fds[2];
265 DoSocketpair(fds);
266 BPF_ASSERT_EQ(0, fcntl(fds[0].get(), F_SETFD, FD_CLOEXEC));
269 BPF_DEATH_TEST_C(NaClNonSfiSandboxTest,
270 fcntl_SETFD,
271 DEATH_MESSAGE(sandbox::GetErrorMessageContentForTests()),
272 nacl::nonsfi::NaClNonSfiBPFSandboxPolicy) {
273 base::ScopedFD fds[2];
274 DoSocketpair(fds);
275 fcntl(fds[0].get(), F_SETFD, 99);
278 BPF_TEST_C(NaClNonSfiSandboxTest,
279 fcntl_GETFL_SETFL_allowed,
280 nacl::nonsfi::NaClNonSfiBPFSandboxPolicy) {
281 base::ScopedFD fds[2];
282 DoPipe(fds);
283 const int fd = fds[0].get();
284 BPF_ASSERT_EQ(0, fcntl(fd, F_GETFL));
285 BPF_ASSERT_EQ(0, fcntl(fd, F_SETFL, O_RDWR | O_NONBLOCK));
286 BPF_ASSERT_EQ(O_NONBLOCK, fcntl(fd, F_GETFL));
289 BPF_DEATH_TEST_C(NaClNonSfiSandboxTest,
290 fcntl_GETFL_SETFL,
291 DEATH_MESSAGE(sandbox::GetErrorMessageContentForTests()),
292 nacl::nonsfi::NaClNonSfiBPFSandboxPolicy) {
293 base::ScopedFD fds[2];
294 DoSocketpair(fds);
295 fcntl(fds[0].get(), F_SETFL, O_APPEND);
298 BPF_DEATH_TEST_C(NaClNonSfiSandboxTest,
299 fcntl_DUPFD,
300 DEATH_MESSAGE(sandbox::GetErrorMessageContentForTests()),
301 nacl::nonsfi::NaClNonSfiBPFSandboxPolicy) {
302 fcntl(0, F_DUPFD);
305 BPF_DEATH_TEST_C(NaClNonSfiSandboxTest,
306 fcntl_DUPFD_CLOEXEC,
307 DEATH_MESSAGE(sandbox::GetErrorMessageContentForTests()),
308 nacl::nonsfi::NaClNonSfiBPFSandboxPolicy) {
309 fcntl(0, F_DUPFD_CLOEXEC);
312 BPF_DEATH_TEST_C(NaClNonSfiSandboxTest,
313 FutexWithRequeuePriorityInheritence,
314 DEATH_MESSAGE(sandbox::GetFutexErrorMessageContentForTests()),
315 nacl::nonsfi::NaClNonSfiBPFSandboxPolicy) {
316 syscall(__NR_futex, NULL, FUTEX_CMP_REQUEUE_PI, 0, NULL, NULL, 0);
317 _exit(1);
320 BPF_DEATH_TEST_C(NaClNonSfiSandboxTest,
321 FutexWithRequeuePriorityInheritencePrivate,
322 DEATH_MESSAGE(sandbox::GetFutexErrorMessageContentForTests()),
323 nacl::nonsfi::NaClNonSfiBPFSandboxPolicy) {
324 syscall(__NR_futex, NULL, FUTEX_CMP_REQUEUE_PI_PRIVATE, 0, NULL, NULL, 0);
325 _exit(1);
328 BPF_TEST_C(NaClNonSfiSandboxTest,
329 StartingAndJoiningThreadWorks,
330 nacl::nonsfi::NaClNonSfiBPFSandboxPolicy) {
331 base::Thread thread("sandbox_tests");
332 BPF_ASSERT(thread.Start());
333 // |thread|'s destructor will join the thread.
336 BPF_DEATH_TEST_C(NaClNonSfiSandboxTest,
337 FutexWithUnlockPIPrivate,
338 DEATH_MESSAGE(sandbox::GetFutexErrorMessageContentForTests()),
339 nacl::nonsfi::NaClNonSfiBPFSandboxPolicy) {
340 syscall(__NR_futex, NULL, FUTEX_UNLOCK_PI_PRIVATE, 0, NULL, NULL, 0);
341 _exit(1);
344 void* DoAllowedAnonymousMmap() {
345 return mmap(NULL, getpagesize(), PROT_READ | PROT_WRITE,
346 MAP_ANONYMOUS | MAP_SHARED, -1, 0);
349 BPF_TEST_C(NaClNonSfiSandboxTest,
350 mmap_allowed,
351 nacl::nonsfi::NaClNonSfiBPFSandboxPolicy) {
352 void* ptr = DoAllowedAnonymousMmap();
353 BPF_ASSERT_NE(MAP_FAILED, ptr);
354 BPF_ASSERT_EQ(0, munmap(ptr, getpagesize()));
357 BPF_DEATH_TEST_C(NaClNonSfiSandboxTest,
358 mmap_unallowed_flag,
359 DEATH_MESSAGE(sandbox::GetErrorMessageContentForTests()),
360 nacl::nonsfi::NaClNonSfiBPFSandboxPolicy) {
361 mmap(NULL, getpagesize(), PROT_READ | PROT_WRITE,
362 MAP_ANONYMOUS | MAP_POPULATE, -1, 0);
365 BPF_DEATH_TEST_C(NaClNonSfiSandboxTest,
366 mmap_unallowed_prot,
367 DEATH_MESSAGE(sandbox::GetErrorMessageContentForTests()),
368 nacl::nonsfi::NaClNonSfiBPFSandboxPolicy) {
369 mmap(NULL, getpagesize(), PROT_READ | PROT_GROWSDOWN,
370 MAP_ANONYMOUS, -1, 0);
373 BPF_DEATH_TEST_C(NaClNonSfiSandboxTest,
374 mmap_exec,
375 DEATH_MESSAGE(sandbox::GetErrorMessageContentForTests()),
376 nacl::nonsfi::NaClNonSfiBPFSandboxPolicy) {
377 mmap(NULL, getpagesize(), PROT_EXEC, MAP_ANONYMOUS, -1, 0);
380 BPF_DEATH_TEST_C(NaClNonSfiSandboxTest,
381 mmap_read_exec,
382 DEATH_MESSAGE(sandbox::GetErrorMessageContentForTests()),
383 nacl::nonsfi::NaClNonSfiBPFSandboxPolicy) {
384 mmap(NULL, getpagesize(), PROT_READ | PROT_EXEC, MAP_ANONYMOUS, -1, 0);
387 BPF_DEATH_TEST_C(NaClNonSfiSandboxTest,
388 mmap_write_exec,
389 DEATH_MESSAGE(sandbox::GetErrorMessageContentForTests()),
390 nacl::nonsfi::NaClNonSfiBPFSandboxPolicy) {
391 mmap(NULL, getpagesize(), PROT_WRITE | PROT_EXEC, MAP_ANONYMOUS, -1, 0);
394 BPF_DEATH_TEST_C(NaClNonSfiSandboxTest,
395 mmap_read_write_exec,
396 DEATH_MESSAGE(sandbox::GetErrorMessageContentForTests()),
397 nacl::nonsfi::NaClNonSfiBPFSandboxPolicy) {
398 mmap(NULL, getpagesize(), PROT_READ | PROT_WRITE | PROT_EXEC,
399 MAP_ANONYMOUS, -1, 0);
402 BPF_TEST_C(NaClNonSfiSandboxTest,
403 mprotect_allowed,
404 nacl::nonsfi::NaClNonSfiBPFSandboxPolicy) {
405 void* ptr = DoAllowedAnonymousMmap();
406 BPF_ASSERT_NE(MAP_FAILED, ptr);
407 BPF_ASSERT_EQ(0, mprotect(ptr, getpagesize(), PROT_READ));
408 BPF_ASSERT_EQ(0, munmap(ptr, getpagesize()));
411 BPF_DEATH_TEST_C(NaClNonSfiSandboxTest,
412 mprotect_unallowed_prot,
413 DEATH_MESSAGE(sandbox::GetErrorMessageContentForTests()),
414 nacl::nonsfi::NaClNonSfiBPFSandboxPolicy) {
415 // We have tested DoAllowedAnonymousMmap is allowed in
416 // mmap_allowed, so we can make sure the following mprotect call
417 // kills the process.
418 void* ptr = DoAllowedAnonymousMmap();
419 BPF_ASSERT_NE(MAP_FAILED, ptr);
420 mprotect(ptr, getpagesize(), PROT_READ | PROT_GROWSDOWN);
423 BPF_TEST_C(NaClNonSfiSandboxTest,
424 brk,
425 nacl::nonsfi::NaClNonSfiBPFSandboxPolicy) {
426 char* next_brk = static_cast<char*>(sbrk(0)) + getpagesize();
427 // The kernel interface must return zero for brk.
428 BPF_ASSERT_EQ(0, syscall(__NR_brk, next_brk));
429 // The libc wrapper translates it to ENOMEM.
430 errno = 0;
431 BPF_ASSERT_EQ(-1, brk(next_brk));
432 BPF_ASSERT_EQ(ENOMEM, errno);
435 // clockid restrictions are mostly tested in sandbox/ with the
436 // RestrictClockID() unittests. Some basic tests are duplicated here as
437 // a precaution.
439 void CheckClock(clockid_t clockid) {
440 struct timespec ts;
441 ts.tv_sec = ts.tv_nsec = -1;
442 BPF_ASSERT_EQ(0, clock_gettime(clockid, &ts));
443 BPF_ASSERT_LE(0, ts.tv_sec);
444 BPF_ASSERT_LE(0, ts.tv_nsec);
447 BPF_TEST_C(NaClNonSfiSandboxTest,
448 clock_gettime_allowed,
449 nacl::nonsfi::NaClNonSfiBPFSandboxPolicy) {
450 CheckClock(CLOCK_MONOTONIC);
451 CheckClock(CLOCK_PROCESS_CPUTIME_ID);
452 CheckClock(CLOCK_REALTIME);
453 CheckClock(CLOCK_THREAD_CPUTIME_ID);
456 BPF_DEATH_TEST_C(NaClNonSfiSandboxTest,
457 clock_gettime_crash_monotonic_raw,
458 DEATH_MESSAGE(sandbox::GetErrorMessageContentForTests()),
459 nacl::nonsfi::NaClNonSfiBPFSandboxPolicy) {
460 struct timespec ts;
461 clock_gettime(CLOCK_MONOTONIC_RAW, &ts);
464 BPF_DEATH_TEST_C(NaClNonSfiSandboxTest,
465 invalid_syscall_crash,
466 DEATH_SEGV_MESSAGE(sandbox::GetErrorMessageContentForTests()),
467 nacl::nonsfi::NaClNonSfiBPFSandboxPolicy) {
468 sandbox::Syscall::InvalidCall();
471 // The following test cases check if syscalls return EPERM regardless
472 // of arguments.
473 #define RESTRICT_SYSCALL_EPERM_TEST(name) \
474 BPF_TEST_C(NaClNonSfiSandboxTest, \
475 name##_EPERM, \
476 nacl::nonsfi::NaClNonSfiBPFSandboxPolicy) { \
477 errno = 0; \
478 BPF_ASSERT_EQ(-1, syscall(__NR_##name, 0, 0, 0, 0, 0, 0)); \
479 BPF_ASSERT_EQ(EPERM, errno); \
482 RESTRICT_SYSCALL_EPERM_TEST(epoll_create);
483 #if defined(__i386__) || defined(__arm__)
484 RESTRICT_SYSCALL_EPERM_TEST(getegid32);
485 RESTRICT_SYSCALL_EPERM_TEST(geteuid32);
486 RESTRICT_SYSCALL_EPERM_TEST(getgid32);
487 RESTRICT_SYSCALL_EPERM_TEST(getuid32);
488 #endif
489 RESTRICT_SYSCALL_EPERM_TEST(getegid);
490 RESTRICT_SYSCALL_EPERM_TEST(geteuid);
491 RESTRICT_SYSCALL_EPERM_TEST(getgid);
492 RESTRICT_SYSCALL_EPERM_TEST(getuid);
493 RESTRICT_SYSCALL_EPERM_TEST(madvise);
494 RESTRICT_SYSCALL_EPERM_TEST(open);
495 RESTRICT_SYSCALL_EPERM_TEST(openat);
496 RESTRICT_SYSCALL_EPERM_TEST(ptrace);
497 RESTRICT_SYSCALL_EPERM_TEST(set_robust_list);
498 #if defined(__i386__) || defined(__x86_64__)
499 RESTRICT_SYSCALL_EPERM_TEST(time);
500 #endif
502 } // namespace
504 #endif // !ADDRESS_SANITIZER && !THREAD_SANITIZER &&
505 // !MEMORY_SANITIZER && !LEAK_SANITIZER