OLD | NEW |
(Empty) | |
| 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 <fcntl.h> |
| 9 #include <linux/futex.h> |
| 10 #include <sched.h> |
| 11 #include <signal.h> |
| 12 #include <string.h> |
| 13 #include <sys/prctl.h> |
| 14 #include <sys/resource.h> |
| 15 #include <sys/socket.h> |
| 16 #include <sys/stat.h> |
| 17 #include <sys/syscall.h> |
| 18 #include <sys/time.h> |
| 19 #include <sys/types.h> |
| 20 #include <sys/wait.h> |
| 21 #include <time.h> |
| 22 #include <unistd.h> |
| 23 |
| 24 #include "base/files/scoped_file.h" |
| 25 #include "base/macros.h" |
| 26 #include "base/posix/eintr_wrapper.h" |
| 27 #include "base/threading/thread.h" |
| 28 #include "build/build_config.h" |
| 29 #include "sandbox/linux/seccomp-bpf-helpers/sigsys_handlers.h" |
| 30 #include "sandbox/linux/seccomp-bpf/bpf_tests.h" |
| 31 #include "sandbox/linux/seccomp-bpf/sandbox_bpf.h" |
| 32 #include "sandbox/linux/seccomp-bpf/syscall.h" |
| 33 #include "sandbox/linux/services/android_futex.h" |
| 34 #include "sandbox/linux/services/linux_syscalls.h" |
| 35 #include "sandbox/linux/services/thread_helpers.h" |
| 36 #include "sandbox/linux/tests/unit_tests.h" |
| 37 |
| 38 namespace sandbox { |
| 39 |
| 40 namespace { |
| 41 |
| 42 // |pid| is the return value of a fork()-like call. This |
| 43 // makes sure that if fork() succeeded the child exits |
| 44 // and the parent waits for it. |
| 45 void HandlePostForkReturn(pid_t pid) { |
| 46 const int kChildExitCode = 1; |
| 47 if (pid > 0) { |
| 48 int status = 0; |
| 49 PCHECK(pid == HANDLE_EINTR(waitpid(pid, &status, 0))); |
| 50 CHECK(WIFEXITED(status)); |
| 51 CHECK_EQ(kChildExitCode, WEXITSTATUS(status)); |
| 52 } else if (pid == 0) { |
| 53 _exit(kChildExitCode); |
| 54 } |
| 55 } |
| 56 |
| 57 // Check that HandlePostForkReturn works. |
| 58 TEST(BaselinePolicy, HandlePostForkReturn) { |
| 59 pid_t pid = fork(); |
| 60 HandlePostForkReturn(pid); |
| 61 } |
| 62 |
| 63 // This also tests that read(), write() and fstat() are allowed. |
| 64 void TestPipeOrSocketPair(base::ScopedFD read_end, base::ScopedFD write_end) { |
| 65 BPF_ASSERT_LE(0, read_end.get()); |
| 66 BPF_ASSERT_LE(0, write_end.get()); |
| 67 struct stat stat_buf; |
| 68 int sys_ret = fstat(read_end.get(), &stat_buf); |
| 69 BPF_ASSERT_EQ(0, sys_ret); |
| 70 BPF_ASSERT(S_ISFIFO(stat_buf.st_mode) || S_ISSOCK(stat_buf.st_mode)); |
| 71 |
| 72 const ssize_t kTestTransferSize = 4; |
| 73 static const char kTestString[kTestTransferSize] = {'T', 'E', 'S', 'T'}; |
| 74 ssize_t transfered = 0; |
| 75 |
| 76 transfered = |
| 77 HANDLE_EINTR(write(write_end.get(), kTestString, kTestTransferSize)); |
| 78 BPF_ASSERT_EQ(kTestTransferSize, transfered); |
| 79 char read_buf[kTestTransferSize + 1] = {0}; |
| 80 transfered = HANDLE_EINTR(read(read_end.get(), read_buf, sizeof(read_buf))); |
| 81 BPF_ASSERT_EQ(kTestTransferSize, transfered); |
| 82 BPF_ASSERT_EQ(0, memcmp(kTestString, read_buf, kTestTransferSize)); |
| 83 } |
| 84 |
| 85 // Test that a few easy-to-test system calls are allowed. |
| 86 BPF_TEST_C(BaselinePolicy, BaselinePolicyBasicAllowed, BaselinePolicy) { |
| 87 BPF_ASSERT_EQ(0, sched_yield()); |
| 88 |
| 89 int pipefd[2]; |
| 90 int sys_ret = pipe(pipefd); |
| 91 BPF_ASSERT_EQ(0, sys_ret); |
| 92 TestPipeOrSocketPair(base::ScopedFD(pipefd[0]), base::ScopedFD(pipefd[1])); |
| 93 |
| 94 BPF_ASSERT_LE(1, getpid()); |
| 95 BPF_ASSERT_LE(0, getuid()); |
| 96 } |
| 97 |
| 98 BPF_TEST_C(BaselinePolicy, FchmodErrno, BaselinePolicy) { |
| 99 int ret = fchmod(-1, 07777); |
| 100 BPF_ASSERT_EQ(-1, ret); |
| 101 // Without the sandbox, this would EBADF instead. |
| 102 BPF_ASSERT_EQ(EPERM, errno); |
| 103 } |
| 104 |
| 105 BPF_TEST_C(BaselinePolicy, ForkErrno, BaselinePolicy) { |
| 106 errno = 0; |
| 107 pid_t pid = fork(); |
| 108 const int fork_errno = errno; |
| 109 HandlePostForkReturn(pid); |
| 110 |
| 111 BPF_ASSERT_EQ(-1, pid); |
| 112 BPF_ASSERT_EQ(EPERM, fork_errno); |
| 113 } |
| 114 |
| 115 pid_t ForkX86Glibc() { |
| 116 return syscall(__NR_clone, CLONE_PARENT_SETTID | SIGCHLD); |
| 117 } |
| 118 |
| 119 BPF_TEST_C(BaselinePolicy, ForkX86Eperm, BaselinePolicy) { |
| 120 errno = 0; |
| 121 pid_t pid = ForkX86Glibc(); |
| 122 const int fork_errno = errno; |
| 123 HandlePostForkReturn(pid); |
| 124 |
| 125 BPF_ASSERT_EQ(-1, pid); |
| 126 BPF_ASSERT_EQ(EPERM, fork_errno); |
| 127 } |
| 128 |
| 129 pid_t ForkARMGlibc() { |
| 130 return syscall(__NR_clone, |
| 131 CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID | SIGCHLD); |
| 132 } |
| 133 |
| 134 BPF_TEST_C(BaselinePolicy, ForkArmEperm, BaselinePolicy) { |
| 135 errno = 0; |
| 136 pid_t pid = ForkARMGlibc(); |
| 137 const int fork_errno = errno; |
| 138 HandlePostForkReturn(pid); |
| 139 |
| 140 BPF_ASSERT_EQ(-1, pid); |
| 141 BPF_ASSERT_EQ(EPERM, fork_errno); |
| 142 } |
| 143 |
| 144 BPF_TEST_C(BaselinePolicy, CreateThread, BaselinePolicy) { |
| 145 base::Thread thread("sandbox_tests"); |
| 146 BPF_ASSERT(thread.Start()); |
| 147 } |
| 148 |
| 149 BPF_DEATH_TEST_C(BaselinePolicy, |
| 150 DisallowedCloneFlagCrashes, |
| 151 DEATH_SEGV_MESSAGE(GetCloneErrorMessageContentForTests()), |
| 152 BaselinePolicy) { |
| 153 pid_t pid = syscall(__NR_clone, CLONE_THREAD | SIGCHLD); |
| 154 HandlePostForkReturn(pid); |
| 155 } |
| 156 |
| 157 BPF_DEATH_TEST_C(BaselinePolicy, |
| 158 DisallowedKillCrashes, |
| 159 DEATH_SEGV_MESSAGE(GetKillErrorMessageContentForTests()), |
| 160 BaselinePolicy) { |
| 161 BPF_ASSERT_NE(1, getpid()); |
| 162 kill(1, 0); |
| 163 _exit(0); |
| 164 } |
| 165 |
| 166 BPF_TEST_C(BaselinePolicy, CanKillSelf, BaselinePolicy) { |
| 167 int sys_ret = kill(getpid(), 0); |
| 168 BPF_ASSERT_EQ(0, sys_ret); |
| 169 } |
| 170 |
| 171 BPF_TEST_C(BaselinePolicy, Socketpair, BaselinePolicy) { |
| 172 int sv[2]; |
| 173 int sys_ret = socketpair(AF_UNIX, SOCK_DGRAM, 0, sv); |
| 174 BPF_ASSERT_EQ(0, sys_ret); |
| 175 TestPipeOrSocketPair(base::ScopedFD(sv[0]), base::ScopedFD(sv[1])); |
| 176 |
| 177 sys_ret = socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sv); |
| 178 BPF_ASSERT_EQ(0, sys_ret); |
| 179 TestPipeOrSocketPair(base::ScopedFD(sv[0]), base::ScopedFD(sv[1])); |
| 180 } |
| 181 |
| 182 // Not all architectures can restrict the domain for socketpair(). |
| 183 #if defined(__x86_64__) || defined(__arm__) || defined(__aarch64__) |
| 184 BPF_DEATH_TEST_C(BaselinePolicy, |
| 185 SocketpairWrongDomain, |
| 186 DEATH_SEGV_MESSAGE(GetErrorMessageContentForTests()), |
| 187 BaselinePolicy) { |
| 188 int sv[2]; |
| 189 ignore_result(socketpair(AF_INET, SOCK_STREAM, 0, sv)); |
| 190 _exit(1); |
| 191 } |
| 192 #endif // defined(__x86_64__) || defined(__arm__) || defined(__aarch64__) |
| 193 |
| 194 BPF_TEST_C(BaselinePolicy, EPERM_open, BaselinePolicy) { |
| 195 errno = 0; |
| 196 int sys_ret = open("/proc/cpuinfo", O_RDONLY); |
| 197 BPF_ASSERT_EQ(-1, sys_ret); |
| 198 BPF_ASSERT_EQ(EPERM, errno); |
| 199 } |
| 200 |
| 201 BPF_TEST_C(BaselinePolicy, EPERM_access, BaselinePolicy) { |
| 202 errno = 0; |
| 203 int sys_ret = access("/proc/cpuinfo", R_OK); |
| 204 BPF_ASSERT_EQ(-1, sys_ret); |
| 205 BPF_ASSERT_EQ(EPERM, errno); |
| 206 } |
| 207 |
| 208 BPF_TEST_C(BaselinePolicy, EPERM_getcwd, BaselinePolicy) { |
| 209 errno = 0; |
| 210 char buf[1024]; |
| 211 char* cwd = getcwd(buf, sizeof(buf)); |
| 212 BPF_ASSERT_EQ(NULL, cwd); |
| 213 BPF_ASSERT_EQ(EPERM, errno); |
| 214 } |
| 215 |
| 216 BPF_DEATH_TEST_C(BaselinePolicy, |
| 217 SIGSYS_InvalidSyscall, |
| 218 DEATH_SEGV_MESSAGE(GetErrorMessageContentForTests()), |
| 219 BaselinePolicy) { |
| 220 Syscall::InvalidCall(); |
| 221 } |
| 222 |
| 223 // A failing test using this macro could be problematic since we perform |
| 224 // system calls by passing "0" as every argument. |
| 225 // The kernel could SIGSEGV the process or the system call itself could reboot |
| 226 // the machine. Some thoughts have been given when hand-picking the system |
| 227 // calls below to limit any potential side effects outside of the current |
| 228 // process. |
| 229 #define TEST_BASELINE_SIGSYS(sysno) \ |
| 230 BPF_DEATH_TEST_C(BaselinePolicy, \ |
| 231 SIGSYS_##sysno, \ |
| 232 DEATH_SEGV_MESSAGE(GetErrorMessageContentForTests()), \ |
| 233 BaselinePolicy) { \ |
| 234 syscall(sysno, 0, 0, 0, 0, 0, 0); \ |
| 235 _exit(1); \ |
| 236 } |
| 237 |
| 238 TEST_BASELINE_SIGSYS(__NR_acct); |
| 239 TEST_BASELINE_SIGSYS(__NR_chroot); |
| 240 TEST_BASELINE_SIGSYS(__NR_fanotify_init); |
| 241 TEST_BASELINE_SIGSYS(__NR_fgetxattr); |
| 242 TEST_BASELINE_SIGSYS(__NR_getcpu); |
| 243 TEST_BASELINE_SIGSYS(__NR_getitimer); |
| 244 TEST_BASELINE_SIGSYS(__NR_init_module); |
| 245 TEST_BASELINE_SIGSYS(__NR_io_cancel); |
| 246 TEST_BASELINE_SIGSYS(__NR_keyctl); |
| 247 TEST_BASELINE_SIGSYS(__NR_mq_open); |
| 248 TEST_BASELINE_SIGSYS(__NR_ptrace); |
| 249 TEST_BASELINE_SIGSYS(__NR_sched_setaffinity); |
| 250 TEST_BASELINE_SIGSYS(__NR_setpgid); |
| 251 TEST_BASELINE_SIGSYS(__NR_swapon); |
| 252 TEST_BASELINE_SIGSYS(__NR_sysinfo); |
| 253 TEST_BASELINE_SIGSYS(__NR_syslog); |
| 254 TEST_BASELINE_SIGSYS(__NR_timer_create); |
| 255 |
| 256 #if !defined(__aarch64__) |
| 257 TEST_BASELINE_SIGSYS(__NR_eventfd); |
| 258 TEST_BASELINE_SIGSYS(__NR_inotify_init); |
| 259 TEST_BASELINE_SIGSYS(__NR_vserver); |
| 260 #endif |
| 261 |
| 262 BPF_DEATH_TEST_C(BaselinePolicy, |
| 263 FutexWithRequeuePriorityInheritence, |
| 264 DEATH_SEGV_MESSAGE(GetFutexErrorMessageContentForTests()), |
| 265 BaselinePolicy) { |
| 266 syscall(__NR_futex, NULL, FUTEX_CMP_REQUEUE_PI, 0, NULL, NULL, 0); |
| 267 _exit(1); |
| 268 } |
| 269 |
| 270 BPF_DEATH_TEST_C(BaselinePolicy, |
| 271 FutexWithRequeuePriorityInheritencePrivate, |
| 272 DEATH_SEGV_MESSAGE(GetFutexErrorMessageContentForTests()), |
| 273 BaselinePolicy) { |
| 274 syscall(__NR_futex, NULL, FUTEX_CMP_REQUEUE_PI_PRIVATE, 0, NULL, NULL, 0); |
| 275 _exit(1); |
| 276 } |
| 277 |
| 278 BPF_DEATH_TEST_C(BaselinePolicy, |
| 279 FutexWithUnlockPIPrivate, |
| 280 DEATH_SEGV_MESSAGE(GetFutexErrorMessageContentForTests()), |
| 281 BaselinePolicy) { |
| 282 syscall(__NR_futex, NULL, FUTEX_UNLOCK_PI_PRIVATE, 0, NULL, NULL, 0); |
| 283 _exit(1); |
| 284 } |
| 285 |
| 286 BPF_TEST_C(BaselinePolicy, PrctlDumpable, BaselinePolicy) { |
| 287 const int is_dumpable = prctl(PR_GET_DUMPABLE, 0, 0, 0, 0); |
| 288 BPF_ASSERT(is_dumpable == 1 || is_dumpable == 0); |
| 289 const int prctl_ret = prctl(PR_SET_DUMPABLE, is_dumpable, 0, 0, 0, 0); |
| 290 BPF_ASSERT_EQ(0, prctl_ret); |
| 291 } |
| 292 |
| 293 // Workaround incomplete Android headers. |
| 294 #if !defined(PR_CAPBSET_READ) |
| 295 #define PR_CAPBSET_READ 23 |
| 296 #endif |
| 297 |
| 298 BPF_DEATH_TEST_C(BaselinePolicy, |
| 299 PrctlSigsys, |
| 300 DEATH_SEGV_MESSAGE(GetPrctlErrorMessageContentForTests()), |
| 301 BaselinePolicy) { |
| 302 prctl(PR_CAPBSET_READ, 0, 0, 0, 0); |
| 303 _exit(1); |
| 304 } |
| 305 |
| 306 BPF_TEST_C(BaselinePolicy, GetOrSetPriority, BaselinePolicy) { |
| 307 errno = 0; |
| 308 const int original_prio = getpriority(PRIO_PROCESS, 0); |
| 309 // Check errno instead of the return value since this system call can return |
| 310 // -1 as a valid value. |
| 311 BPF_ASSERT_EQ(0, errno); |
| 312 |
| 313 errno = 0; |
| 314 int rc = getpriority(PRIO_PROCESS, getpid()); |
| 315 BPF_ASSERT_EQ(0, errno); |
| 316 |
| 317 rc = getpriority(PRIO_PROCESS, getpid() + 1); |
| 318 BPF_ASSERT_EQ(-1, rc); |
| 319 BPF_ASSERT_EQ(EPERM, errno); |
| 320 |
| 321 rc = setpriority(PRIO_PROCESS, 0, original_prio); |
| 322 BPF_ASSERT_EQ(0, rc); |
| 323 |
| 324 rc = setpriority(PRIO_PROCESS, getpid(), original_prio); |
| 325 BPF_ASSERT_EQ(0, rc); |
| 326 |
| 327 errno = 0; |
| 328 rc = setpriority(PRIO_PROCESS, getpid() + 1, original_prio); |
| 329 BPF_ASSERT_EQ(-1, rc); |
| 330 BPF_ASSERT_EQ(EPERM, errno); |
| 331 } |
| 332 |
| 333 BPF_DEATH_TEST_C(BaselinePolicy, |
| 334 GetPrioritySigsys, |
| 335 DEATH_SEGV_MESSAGE(GetErrorMessageContentForTests()), |
| 336 BaselinePolicy) { |
| 337 getpriority(PRIO_USER, 0); |
| 338 _exit(1); |
| 339 } |
| 340 |
| 341 BPF_DEATH_TEST_C(BaselinePolicy, |
| 342 ClockGettimeWithDisallowedClockCrashes, |
| 343 DEATH_SEGV_MESSAGE(sandbox::GetErrorMessageContentForTests()), |
| 344 BaselinePolicy) { |
| 345 struct timespec ts; |
| 346 clock_gettime(CLOCK_MONOTONIC_RAW, &ts); |
| 347 } |
| 348 |
| 349 } // namespace |
| 350 |
| 351 } // namespace sandbox |
OLD | NEW |