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.
4
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)
8
9#include "components/nacl/loader/nonsfi/nonsfi_sandbox.h"
10
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>
28
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
44
45namespace {
46
47void 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]);
52}
53
54void 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]);
59}
60
61TEST(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";
68  }
69}
70
71BPF_DEATH_TEST_C(NaClNonSfiSandboxTest,
72                 invalid_sysno,
73                 DEATH_MESSAGE(sandbox::GetErrorMessageContentForTests()),
74                 nacl::nonsfi::NaClNonSfiBPFSandboxPolicy) {
75  syscall(999);
76}
77
78const int kExpectedValue = 123;
79
80void* SetValueInThread(void* test_val_ptr) {
81  *reinterpret_cast<int*>(test_val_ptr) = kExpectedValue;
82  return NULL;
83}
84
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.
87BPF_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);
96}
97
98int 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;
104}
105
106// The sanity check for DoFork without the sandbox.
107TEST(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));
114}
115
116// Then, try this in the sandbox.
117BPF_DEATH_TEST_C(NaClNonSfiSandboxTest,
118                 clone_for_fork,
119                 DEATH_MESSAGE(sandbox::GetCloneErrorMessageContentForTests()),
120                 nacl::nonsfi::NaClNonSfiBPFSandboxPolicy) {
121  DoFork();
122}
123
124BPF_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);
130}
131
132BPF_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);
137}
138
139BPF_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));
156}
157
158BPF_DEATH_TEST_C(NaClNonSfiSandboxTest,
159                 accept,
160                 DEATH_MESSAGE(sandbox::GetErrorMessageContentForTests()),
161                 nacl::nonsfi::NaClNonSfiBPFSandboxPolicy) {
162  accept(0, NULL, NULL);
163}
164
165BPF_DEATH_TEST_C(NaClNonSfiSandboxTest,
166                 bind,
167                 DEATH_MESSAGE(sandbox::GetErrorMessageContentForTests()),
168                 nacl::nonsfi::NaClNonSfiBPFSandboxPolicy) {
169  bind(0, NULL, 0);
170}
171
172BPF_DEATH_TEST_C(NaClNonSfiSandboxTest,
173                 connect,
174                 DEATH_MESSAGE(sandbox::GetErrorMessageContentForTests()),
175                 nacl::nonsfi::NaClNonSfiBPFSandboxPolicy) {
176  connect(0, NULL, 0);
177}
178
179BPF_DEATH_TEST_C(NaClNonSfiSandboxTest,
180                 getpeername,
181                 DEATH_MESSAGE(sandbox::GetErrorMessageContentForTests()),
182                 nacl::nonsfi::NaClNonSfiBPFSandboxPolicy) {
183  getpeername(0, NULL, NULL);
184}
185
186BPF_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);
193}
194
195BPF_DEATH_TEST_C(NaClNonSfiSandboxTest,
196                 getsockopt,
197                 DEATH_MESSAGE(sandbox::GetErrorMessageContentForTests()),
198                 nacl::nonsfi::NaClNonSfiBPFSandboxPolicy) {
199  getsockopt(0, 0, 0, NULL, NULL);
200}
201
202BPF_DEATH_TEST_C(NaClNonSfiSandboxTest,
203                 listen,
204                 DEATH_MESSAGE(sandbox::GetErrorMessageContentForTests()),
205                 nacl::nonsfi::NaClNonSfiBPFSandboxPolicy) {
206  listen(0, 0);
207}
208
209BPF_DEATH_TEST_C(NaClNonSfiSandboxTest,
210                 recv,
211                 DEATH_MESSAGE(sandbox::GetErrorMessageContentForTests()),
212                 nacl::nonsfi::NaClNonSfiBPFSandboxPolicy) {
213  recv(0, NULL, 0, 0);
214}
215
216BPF_DEATH_TEST_C(NaClNonSfiSandboxTest,
217                 recvfrom,
218                 DEATH_MESSAGE(sandbox::GetErrorMessageContentForTests()),
219                 nacl::nonsfi::NaClNonSfiBPFSandboxPolicy) {
220  recvfrom(0, NULL, 0, 0, NULL, NULL);
221}
222
223BPF_DEATH_TEST_C(NaClNonSfiSandboxTest,
224                 send,
225                 DEATH_MESSAGE(sandbox::GetErrorMessageContentForTests()),
226                 nacl::nonsfi::NaClNonSfiBPFSandboxPolicy) {
227  send(0, NULL, 0, 0);
228}
229
230BPF_DEATH_TEST_C(NaClNonSfiSandboxTest,
231                 sendto,
232                 DEATH_MESSAGE(sandbox::GetErrorMessageContentForTests()),
233                 nacl::nonsfi::NaClNonSfiBPFSandboxPolicy) {
234  sendto(0, NULL, 0, 0, NULL, 0);
235}
236
237BPF_DEATH_TEST_C(NaClNonSfiSandboxTest,
238                 setsockopt,
239                 DEATH_MESSAGE(sandbox::GetErrorMessageContentForTests()),
240                 nacl::nonsfi::NaClNonSfiBPFSandboxPolicy) {
241  setsockopt(0, 0, 0, NULL, 0);
242}
243
244BPF_DEATH_TEST_C(NaClNonSfiSandboxTest,
245                 socket,
246                 DEATH_MESSAGE(sandbox::GetErrorMessageContentForTests()),
247                 nacl::nonsfi::NaClNonSfiBPFSandboxPolicy) {
248  socket(0, 0, 0);
249}
250
251#if defined(__x86_64__) || defined(__arm__)
252BPF_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);
258}
259#endif
260
261BPF_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));
267}
268
269BPF_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);
276}
277
278BPF_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));
287}
288
289BPF_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);
296}
297
298BPF_DEATH_TEST_C(NaClNonSfiSandboxTest,
299                 fcntl_DUPFD,
300                 DEATH_MESSAGE(sandbox::GetErrorMessageContentForTests()),
301                 nacl::nonsfi::NaClNonSfiBPFSandboxPolicy) {
302  fcntl(0, F_DUPFD);
303}
304
305BPF_DEATH_TEST_C(NaClNonSfiSandboxTest,
306                 fcntl_DUPFD_CLOEXEC,
307                 DEATH_MESSAGE(sandbox::GetErrorMessageContentForTests()),
308                 nacl::nonsfi::NaClNonSfiBPFSandboxPolicy) {
309  fcntl(0, F_DUPFD_CLOEXEC);
310}
311
312BPF_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);
318}
319
320BPF_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);
326}
327
328BPF_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.
334}
335
336BPF_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);
342}
343
344void* DoAllowedAnonymousMmap() {
345  return mmap(NULL, getpagesize(), PROT_READ | PROT_WRITE,
346              MAP_ANONYMOUS | MAP_SHARED, -1, 0);
347}
348
349BPF_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()));
355}
356
357BPF_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);
363}
364
365BPF_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);
371}
372
373BPF_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);
378}
379
380BPF_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);
385}
386
387BPF_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);
392}
393
394BPF_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);
400}
401
402BPF_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()));
409}
410
411BPF_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);
421}
422
423BPF_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);
433}
434
435// clockid restrictions are mostly tested in sandbox/ with the
436// RestrictClockID() unittests. Some basic tests are duplicated here as
437// a precaution.
438
439void 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);
445}
446
447BPF_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);
454}
455
456BPF_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);
462}
463
464BPF_DEATH_TEST_C(NaClNonSfiSandboxTest,
465                 invalid_syscall_crash,
466                 DEATH_SEGV_MESSAGE(sandbox::GetErrorMessageContentForTests()),
467                 nacl::nonsfi::NaClNonSfiBPFSandboxPolicy) {
468  sandbox::Syscall::InvalidCall();
469}
470
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);                               \
480  }
481
482RESTRICT_SYSCALL_EPERM_TEST(epoll_create);
483#if defined(__i386__) || defined(__arm__)
484RESTRICT_SYSCALL_EPERM_TEST(getegid32);
485RESTRICT_SYSCALL_EPERM_TEST(geteuid32);
486RESTRICT_SYSCALL_EPERM_TEST(getgid32);
487RESTRICT_SYSCALL_EPERM_TEST(getuid32);
488#endif
489RESTRICT_SYSCALL_EPERM_TEST(getegid);
490RESTRICT_SYSCALL_EPERM_TEST(geteuid);
491RESTRICT_SYSCALL_EPERM_TEST(getgid);
492RESTRICT_SYSCALL_EPERM_TEST(getuid);
493RESTRICT_SYSCALL_EPERM_TEST(madvise);
494RESTRICT_SYSCALL_EPERM_TEST(open);
495RESTRICT_SYSCALL_EPERM_TEST(openat);
496RESTRICT_SYSCALL_EPERM_TEST(ptrace);
497RESTRICT_SYSCALL_EPERM_TEST(set_robust_list);
498#if defined(__i386__) || defined(__x86_64__)
499RESTRICT_SYSCALL_EPERM_TEST(time);
500#endif
501
502}  // namespace
503
504#endif  // !ADDRESS_SANITIZER && !THREAD_SANITIZER &&
505        // !MEMORY_SANITIZER && !LEAK_SANITIZER
506