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/system_headers/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
= sandbox::SandboxBPF::SupportsSeccompSandbox(
63 sandbox::SandboxBPF::SeccompLevel::SINGLE_THREADED
);
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