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"
13 #include <linux/futex.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>
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
47 void DoPipe(base::ScopedFD* fds) {
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) {
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,
73 DEATH_MESSAGE(sandbox::GetErrorMessageContentForTests()),
74 nacl::nonsfi::NaClNonSfiBPFSandboxPolicy) {
78 const int kExpectedValue = 123;
80 void* SetValueInThread(void* test_val_ptr) {
81 *reinterpret_cast<int*>(test_val_ptr) = kExpectedValue;
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.
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);
99 // Call clone() to do a fork().
100 const int pid = syscall(__NR_clone, SIGCHLD, NULL);
106 // The sanity check for DoFork without the sandbox.
107 TEST(NaClNonSfiSandboxTest, DoFork) {
108 const int pid = DoFork();
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,
119 DEATH_MESSAGE(sandbox::GetCloneErrorMessageContentForTests()),
120 nacl::nonsfi::NaClNonSfiBPFSandboxPolicy) {
124 BPF_TEST_C(NaClNonSfiSandboxTest,
126 nacl::nonsfi::NaClNonSfiBPFSandboxPolicy) {
128 BPF_ASSERT_EQ(-1, syscall(__NR_prctl, PR_SET_NAME, "foo"));
129 BPF_ASSERT_EQ(EPERM, errno);
132 BPF_DEATH_TEST_C(NaClNonSfiSandboxTest,
134 DEATH_MESSAGE(sandbox::GetPrctlErrorMessageContentForTests()),
135 nacl::nonsfi::NaClNonSfiBPFSandboxPolicy) {
136 syscall(__NR_prctl, PR_SET_DUMPABLE, 1UL);
139 BPF_TEST_C(NaClNonSfiSandboxTest,
141 nacl::nonsfi::NaClNonSfiBPFSandboxPolicy) {
142 base::ScopedFD fds[2];
143 struct msghdr msg = {};
145 std::string payload("foo");
146 iov.iov_base = &payload[0];
147 iov.iov_len = payload.size();
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,
160 DEATH_MESSAGE(sandbox::GetErrorMessageContentForTests()),
161 nacl::nonsfi::NaClNonSfiBPFSandboxPolicy) {
162 accept(0, NULL, NULL);
165 BPF_DEATH_TEST_C(NaClNonSfiSandboxTest,
167 DEATH_MESSAGE(sandbox::GetErrorMessageContentForTests()),
168 nacl::nonsfi::NaClNonSfiBPFSandboxPolicy) {
172 BPF_DEATH_TEST_C(NaClNonSfiSandboxTest,
174 DEATH_MESSAGE(sandbox::GetErrorMessageContentForTests()),
175 nacl::nonsfi::NaClNonSfiBPFSandboxPolicy) {
179 BPF_DEATH_TEST_C(NaClNonSfiSandboxTest,
181 DEATH_MESSAGE(sandbox::GetErrorMessageContentForTests()),
182 nacl::nonsfi::NaClNonSfiBPFSandboxPolicy) {
183 getpeername(0, NULL, NULL);
186 BPF_DEATH_TEST_C(NaClNonSfiSandboxTest,
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,
197 DEATH_MESSAGE(sandbox::GetErrorMessageContentForTests()),
198 nacl::nonsfi::NaClNonSfiBPFSandboxPolicy) {
199 getsockopt(0, 0, 0, NULL, NULL);
202 BPF_DEATH_TEST_C(NaClNonSfiSandboxTest,
204 DEATH_MESSAGE(sandbox::GetErrorMessageContentForTests()),
205 nacl::nonsfi::NaClNonSfiBPFSandboxPolicy) {
209 BPF_DEATH_TEST_C(NaClNonSfiSandboxTest,
211 DEATH_MESSAGE(sandbox::GetErrorMessageContentForTests()),
212 nacl::nonsfi::NaClNonSfiBPFSandboxPolicy) {
216 BPF_DEATH_TEST_C(NaClNonSfiSandboxTest,
218 DEATH_MESSAGE(sandbox::GetErrorMessageContentForTests()),
219 nacl::nonsfi::NaClNonSfiBPFSandboxPolicy) {
220 recvfrom(0, NULL, 0, 0, NULL, NULL);
223 BPF_DEATH_TEST_C(NaClNonSfiSandboxTest,
225 DEATH_MESSAGE(sandbox::GetErrorMessageContentForTests()),
226 nacl::nonsfi::NaClNonSfiBPFSandboxPolicy) {
230 BPF_DEATH_TEST_C(NaClNonSfiSandboxTest,
232 DEATH_MESSAGE(sandbox::GetErrorMessageContentForTests()),
233 nacl::nonsfi::NaClNonSfiBPFSandboxPolicy) {
234 sendto(0, NULL, 0, 0, NULL, 0);
237 BPF_DEATH_TEST_C(NaClNonSfiSandboxTest,
239 DEATH_MESSAGE(sandbox::GetErrorMessageContentForTests()),
240 nacl::nonsfi::NaClNonSfiBPFSandboxPolicy) {
241 setsockopt(0, 0, 0, NULL, 0);
244 BPF_DEATH_TEST_C(NaClNonSfiSandboxTest,
246 DEATH_MESSAGE(sandbox::GetErrorMessageContentForTests()),
247 nacl::nonsfi::NaClNonSfiBPFSandboxPolicy) {
251 #if defined(__x86_64__) || defined(__arm__)
252 BPF_DEATH_TEST_C(NaClNonSfiSandboxTest,
254 DEATH_MESSAGE(sandbox::GetErrorMessageContentForTests()),
255 nacl::nonsfi::NaClNonSfiBPFSandboxPolicy) {
257 socketpair(AF_INET, SOCK_STREAM, 0, fds);
261 BPF_TEST_C(NaClNonSfiSandboxTest,
263 nacl::nonsfi::NaClNonSfiBPFSandboxPolicy) {
264 base::ScopedFD fds[2];
266 BPF_ASSERT_EQ(0, fcntl(fds[0].get(), F_SETFD, FD_CLOEXEC));
269 BPF_DEATH_TEST_C(NaClNonSfiSandboxTest,
271 DEATH_MESSAGE(sandbox::GetErrorMessageContentForTests()),
272 nacl::nonsfi::NaClNonSfiBPFSandboxPolicy) {
273 base::ScopedFD fds[2];
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];
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,
291 DEATH_MESSAGE(sandbox::GetErrorMessageContentForTests()),
292 nacl::nonsfi::NaClNonSfiBPFSandboxPolicy) {
293 base::ScopedFD fds[2];
295 fcntl(fds[0].get(), F_SETFL, O_APPEND);
298 BPF_DEATH_TEST_C(NaClNonSfiSandboxTest,
300 DEATH_MESSAGE(sandbox::GetErrorMessageContentForTests()),
301 nacl::nonsfi::NaClNonSfiBPFSandboxPolicy) {
305 BPF_DEATH_TEST_C(NaClNonSfiSandboxTest,
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);
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);
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);
344 void* DoAllowedAnonymousMmap() {
345 return mmap(NULL, getpagesize(), PROT_READ | PROT_WRITE,
346 MAP_ANONYMOUS | MAP_SHARED, -1, 0);
349 BPF_TEST_C(NaClNonSfiSandboxTest,
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,
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,
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,
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,
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,
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,
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,
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.
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
439 void CheckClock(clockid_t clockid) {
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) {
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
473 #define RESTRICT_SYSCALL_EPERM_TEST(name) \
474 BPF_TEST_C(NaClNonSfiSandboxTest, \
476 nacl::nonsfi::NaClNonSfiBPFSandboxPolicy) { \
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);
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);
504 #endif // !ADDRESS_SANITIZER && !THREAD_SANITIZER &&
505 // !MEMORY_SANITIZER && !LEAK_SANITIZER