baseline_policy_unittest.cc revision cedac228d2dd51db4b79ea1e72c7f249408ee061
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#include "sandbox/linux/seccomp-bpf-helpers/baseline_policy.h" 6 7#include <errno.h> 8#include <sched.h> 9#include <signal.h> 10#include <string.h> 11#include <sys/socket.h> 12#include <sys/stat.h> 13#include <sys/syscall.h> 14#include <sys/types.h> 15#include <sys/wait.h> 16#include <unistd.h> 17 18#include "base/files/scoped_file.h" 19#include "base/macros.h" 20#include "base/posix/eintr_wrapper.h" 21#include "base/threading/thread.h" 22#include "build/build_config.h" 23#include "sandbox/linux/seccomp-bpf-helpers/sigsys_handlers.h" 24#include "sandbox/linux/seccomp-bpf/bpf_tests.h" 25#include "sandbox/linux/seccomp-bpf/sandbox_bpf.h" 26#include "sandbox/linux/services/linux_syscalls.h" 27#include "sandbox/linux/services/thread_helpers.h" 28#include "sandbox/linux/tests/unit_tests.h" 29 30namespace sandbox { 31 32namespace { 33 34// |pid| is the return value of a fork()-like call. This 35// makes sure that if fork() succeeded the child exits 36// and the parent waits for it. 37void HandlePostForkReturn(pid_t pid) { 38 const int kChildExitCode = 1; 39 if (pid > 0) { 40 int status = 0; 41 PCHECK(pid == HANDLE_EINTR(waitpid(pid, &status, 0))); 42 CHECK(WIFEXITED(status)); 43 CHECK_EQ(kChildExitCode, WEXITSTATUS(status)); 44 } else if (pid == 0) { 45 _exit(kChildExitCode); 46 } 47} 48 49// Check that HandlePostForkReturn works. 50TEST(BaselinePolicy, HandlePostForkReturn) { 51 pid_t pid = fork(); 52 HandlePostForkReturn(pid); 53} 54 55// This also tests that read(), write() and fstat() are allowed. 56void TestPipeOrSocketPair(base::ScopedFD read_end, base::ScopedFD write_end) { 57 BPF_ASSERT_LE(0, read_end.get()); 58 BPF_ASSERT_LE(0, write_end.get()); 59 struct stat stat_buf; 60 int sys_ret = fstat(read_end.get(), &stat_buf); 61 BPF_ASSERT_EQ(0, sys_ret); 62 BPF_ASSERT(S_ISFIFO(stat_buf.st_mode) || S_ISSOCK(stat_buf.st_mode)); 63 64 const ssize_t kTestTransferSize = 4; 65 static const char kTestString[kTestTransferSize] = {'T', 'E', 'S', 'T'}; 66 ssize_t transfered = 0; 67 68 transfered = 69 HANDLE_EINTR(write(write_end.get(), kTestString, kTestTransferSize)); 70 BPF_ASSERT_EQ(kTestTransferSize, transfered); 71 char read_buf[kTestTransferSize + 1] = {0}; 72 transfered = HANDLE_EINTR(read(read_end.get(), read_buf, sizeof(read_buf))); 73 BPF_ASSERT_EQ(kTestTransferSize, transfered); 74 BPF_ASSERT_EQ(0, memcmp(kTestString, read_buf, kTestTransferSize)); 75} 76 77// Test that a few easy-to-test system calls are allowed. 78BPF_TEST_C(BaselinePolicy, BaselinePolicyBasicAllowed, BaselinePolicy) { 79 BPF_ASSERT_EQ(0, sched_yield()); 80 81 int pipefd[2]; 82 int sys_ret = pipe(pipefd); 83 BPF_ASSERT_EQ(0, sys_ret); 84 TestPipeOrSocketPair(base::ScopedFD(pipefd[0]), base::ScopedFD(pipefd[1])); 85 86 BPF_ASSERT_LE(1, getpid()); 87 BPF_ASSERT_LE(0, getuid()); 88} 89 90BPF_TEST_C(BaselinePolicy, FchmodErrno, BaselinePolicy) { 91 int ret = fchmod(-1, 07777); 92 BPF_ASSERT_EQ(-1, ret); 93 // Without the sandbox, this would EBADF instead. 94 BPF_ASSERT_EQ(EPERM, errno); 95} 96 97BPF_TEST_C(BaselinePolicy, ForkErrno, BaselinePolicy) { 98 errno = 0; 99 pid_t pid = fork(); 100 const int fork_errno = errno; 101 HandlePostForkReturn(pid); 102 103 BPF_ASSERT_EQ(-1, pid); 104 BPF_ASSERT_EQ(EPERM, fork_errno); 105} 106 107pid_t ForkX86Glibc() { 108 return syscall(__NR_clone, CLONE_PARENT_SETTID | SIGCHLD); 109} 110 111BPF_TEST_C(BaselinePolicy, ForkX86Eperm, BaselinePolicy) { 112 errno = 0; 113 pid_t pid = ForkX86Glibc(); 114 const int fork_errno = errno; 115 HandlePostForkReturn(pid); 116 117 BPF_ASSERT_EQ(-1, pid); 118 BPF_ASSERT_EQ(EPERM, fork_errno); 119} 120 121pid_t ForkARMGlibc() { 122 return syscall(__NR_clone, 123 CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID | SIGCHLD); 124} 125 126BPF_TEST_C(BaselinePolicy, ForkArmEperm, BaselinePolicy) { 127 errno = 0; 128 pid_t pid = ForkARMGlibc(); 129 const int fork_errno = errno; 130 HandlePostForkReturn(pid); 131 132 BPF_ASSERT_EQ(-1, pid); 133 BPF_ASSERT_EQ(EPERM, fork_errno); 134} 135 136BPF_TEST_C(BaselinePolicy, CreateThread, BaselinePolicy) { 137 base::Thread thread("sandbox_tests"); 138 BPF_ASSERT(thread.Start()); 139} 140 141BPF_DEATH_TEST_C(BaselinePolicy, 142 DisallowedCloneFlagCrashes, 143 DEATH_MESSAGE(GetCloneErrorMessageContentForTests()), 144 BaselinePolicy) { 145 pid_t pid = syscall(__NR_clone, CLONE_THREAD | SIGCHLD); 146 HandlePostForkReturn(pid); 147} 148 149BPF_DEATH_TEST_C(BaselinePolicy, 150 DisallowedKillCrashes, 151 DEATH_MESSAGE(GetKillErrorMessageContentForTests()), 152 BaselinePolicy) { 153 BPF_ASSERT_NE(1, getpid()); 154 kill(1, 0); 155 _exit(1); 156} 157 158BPF_TEST_C(BaselinePolicy, CanKillSelf, BaselinePolicy) { 159 int sys_ret = kill(getpid(), 0); 160 BPF_ASSERT_EQ(0, sys_ret); 161} 162 163BPF_TEST_C(BaselinePolicy, Socketpair, BaselinePolicy) { 164 int sv[2]; 165 int sys_ret = socketpair(AF_UNIX, SOCK_DGRAM, 0, sv); 166 BPF_ASSERT_EQ(0, sys_ret); 167 TestPipeOrSocketPair(base::ScopedFD(sv[0]), base::ScopedFD(sv[1])); 168 169 sys_ret = socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sv); 170 BPF_ASSERT_EQ(0, sys_ret); 171 TestPipeOrSocketPair(base::ScopedFD(sv[0]), base::ScopedFD(sv[1])); 172} 173 174// Not all architectures can restrict the domain for socketpair(). 175#if defined(__x86_64__) || defined(__arm__) 176BPF_DEATH_TEST_C(BaselinePolicy, 177 SocketpairWrongDomain, 178 DEATH_MESSAGE(GetErrorMessageContentForTests()), 179 BaselinePolicy) { 180 int sv[2]; 181 ignore_result(socketpair(AF_INET, SOCK_STREAM, 0, sv)); 182 _exit(1); 183} 184#endif // defined(__x86_64__) || defined(__arm__) 185 186BPF_TEST_C(BaselinePolicy, EPERM_open, BaselinePolicy) { 187 errno = 0; 188 int sys_ret = open("/proc/cpuinfo", O_RDONLY); 189 BPF_ASSERT_EQ(-1, sys_ret); 190 BPF_ASSERT_EQ(EPERM, errno); 191} 192 193BPF_TEST_C(BaselinePolicy, EPERM_access, BaselinePolicy) { 194 errno = 0; 195 int sys_ret = access("/proc/cpuinfo", R_OK); 196 BPF_ASSERT_EQ(-1, sys_ret); 197 BPF_ASSERT_EQ(EPERM, errno); 198} 199 200BPF_TEST_C(BaselinePolicy, EPERM_getcwd, BaselinePolicy) { 201 errno = 0; 202 char buf[1024]; 203 char* cwd = getcwd(buf, sizeof(buf)); 204 BPF_ASSERT_EQ(NULL, cwd); 205 BPF_ASSERT_EQ(EPERM, errno); 206} 207 208// A failing test using this macro could be problematic since we perform 209// system calls by passing "0" as every argument. 210// The kernel could SIGSEGV the process or the system call itself could reboot 211// the machine. Some thoughts have been given when hand-picking the system 212// calls below to limit any potential side effects outside of the current 213// process. 214#define TEST_BASELINE_SIGSYS(sysno) \ 215 BPF_DEATH_TEST_C(BaselinePolicy, \ 216 SIGSYS_##sysno, \ 217 DEATH_MESSAGE(GetErrorMessageContentForTests()), \ 218 BaselinePolicy) { \ 219 syscall(sysno, 0, 0, 0, 0, 0, 0); \ 220 _exit(1); \ 221 } 222 223TEST_BASELINE_SIGSYS(__NR_syslog); 224TEST_BASELINE_SIGSYS(__NR_sched_setaffinity); 225TEST_BASELINE_SIGSYS(__NR_timer_create); 226TEST_BASELINE_SIGSYS(__NR_io_cancel); 227TEST_BASELINE_SIGSYS(__NR_ptrace); 228TEST_BASELINE_SIGSYS(__NR_eventfd); 229TEST_BASELINE_SIGSYS(__NR_fgetxattr); 230TEST_BASELINE_SIGSYS(__NR_fanotify_init); 231TEST_BASELINE_SIGSYS(__NR_swapon); 232TEST_BASELINE_SIGSYS(__NR_chroot); 233TEST_BASELINE_SIGSYS(__NR_acct); 234TEST_BASELINE_SIGSYS(__NR_sysinfo); 235TEST_BASELINE_SIGSYS(__NR_inotify_init); 236TEST_BASELINE_SIGSYS(__NR_init_module); 237TEST_BASELINE_SIGSYS(__NR_keyctl); 238TEST_BASELINE_SIGSYS(__NR_mq_open); 239TEST_BASELINE_SIGSYS(__NR_vserver); 240TEST_BASELINE_SIGSYS(__NR_getcpu); 241TEST_BASELINE_SIGSYS(__NR_setpgid); 242TEST_BASELINE_SIGSYS(__NR_getitimer); 243 244} // namespace 245 246} // namespace sandbox 247