James Robinson | 30d547e | 2014-10-23 18:20:06 -0700 | [diff] [blame] | 1 | // Copyright (c) 2013 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/syscall_parameters_restrictions.h" |
| 6 | |
| 7 | #include <errno.h> |
| 8 | #include <fcntl.h> |
| 9 | #include <fcntl.h> |
James Robinson | 30d547e | 2014-10-23 18:20:06 -0700 | [diff] [blame] | 10 | #include <linux/net.h> |
| 11 | #include <sched.h> |
| 12 | #include <signal.h> |
James Robinson | 0fae000 | 2015-05-05 16:31:51 -0700 | [diff] [blame] | 13 | #include <stdint.h> |
James Robinson | 30d547e | 2014-10-23 18:20:06 -0700 | [diff] [blame] | 14 | #include <sys/mman.h> |
| 15 | #include <sys/prctl.h> |
| 16 | #include <sys/resource.h> |
| 17 | #include <sys/stat.h> |
| 18 | #include <sys/time.h> |
| 19 | #include <sys/types.h> |
| 20 | #include <time.h> |
| 21 | #include <unistd.h> |
| 22 | |
James Robinson | 30d547e | 2014-10-23 18:20:06 -0700 | [diff] [blame] | 23 | #include "base/logging.h" |
| 24 | #include "base/macros.h" |
| 25 | #include "base/time/time.h" |
| 26 | #include "build/build_config.h" |
James Robinson | 6165015 | 2014-10-26 23:24:55 -0700 | [diff] [blame] | 27 | #include "sandbox/linux/bpf_dsl/bpf_dsl.h" |
Etienne Membrives | 386015a | 2015-02-19 17:27:12 +0100 | [diff] [blame] | 28 | #include "sandbox/linux/bpf_dsl/seccomp_macros.h" |
James Robinson | 30d547e | 2014-10-23 18:20:06 -0700 | [diff] [blame] | 29 | #include "sandbox/linux/seccomp-bpf-helpers/sigsys_handlers.h" |
James Robinson | 30d547e | 2014-10-23 18:20:06 -0700 | [diff] [blame] | 30 | #include "sandbox/linux/seccomp-bpf/sandbox_bpf.h" |
James Robinson | 0fae000 | 2015-05-05 16:31:51 -0700 | [diff] [blame] | 31 | #include "sandbox/linux/system_headers/linux_futex.h" |
Etienne Membrives | 386015a | 2015-02-19 17:27:12 +0100 | [diff] [blame] | 32 | #include "sandbox/linux/system_headers/linux_syscalls.h" |
James Robinson | 30d547e | 2014-10-23 18:20:06 -0700 | [diff] [blame] | 33 | |
James Robinson | f19b102 | 2015-05-05 18:12:15 -0700 | [diff] [blame^] | 34 | // PNaCl toolchain does not provide sys/ioctl.h header. |
| 35 | #if !defined(OS_NACL_NONSFI) |
| 36 | #include <sys/ioctl.h> |
| 37 | #endif |
| 38 | |
James Robinson | 30d547e | 2014-10-23 18:20:06 -0700 | [diff] [blame] | 39 | #if defined(OS_ANDROID) |
| 40 | |
James Robinson | 30d547e | 2014-10-23 18:20:06 -0700 | [diff] [blame] | 41 | #if !defined(F_DUPFD_CLOEXEC) |
| 42 | #define F_DUPFD_CLOEXEC (F_LINUX_SPECIFIC_BASE + 6) |
| 43 | #endif |
| 44 | |
James Robinson | 1027bc1 | 2014-12-04 14:51:42 -0800 | [diff] [blame] | 45 | // https://android.googlesource.com/platform/bionic/+/lollipop-release/libc/private/bionic_prctl.h |
| 46 | #if !defined(PR_SET_VMA) |
| 47 | #define PR_SET_VMA 0x53564d41 |
| 48 | #endif |
| 49 | |
| 50 | // https://android.googlesource.com/platform/system/core/+/lollipop-release/libcutils/sched_policy.c |
| 51 | #if !defined(PR_SET_TIMERSLACK_PID) |
| 52 | #define PR_SET_TIMERSLACK_PID 41 |
| 53 | #endif |
| 54 | |
James Robinson | 30d547e | 2014-10-23 18:20:06 -0700 | [diff] [blame] | 55 | #endif // defined(OS_ANDROID) |
| 56 | |
| 57 | #if defined(__arm__) && !defined(MAP_STACK) |
| 58 | #define MAP_STACK 0x20000 // Daisy build environment has old headers. |
| 59 | #endif |
| 60 | |
| 61 | #if defined(__mips__) && !defined(MAP_STACK) |
| 62 | #define MAP_STACK 0x40000 |
| 63 | #endif |
| 64 | namespace { |
| 65 | |
| 66 | inline bool IsArchitectureX86_64() { |
| 67 | #if defined(__x86_64__) |
| 68 | return true; |
| 69 | #else |
| 70 | return false; |
| 71 | #endif |
| 72 | } |
| 73 | |
| 74 | inline bool IsArchitectureI386() { |
| 75 | #if defined(__i386__) |
| 76 | return true; |
| 77 | #else |
| 78 | return false; |
| 79 | #endif |
| 80 | } |
| 81 | |
| 82 | inline bool IsAndroid() { |
| 83 | #if defined(OS_ANDROID) |
| 84 | return true; |
| 85 | #else |
| 86 | return false; |
| 87 | #endif |
| 88 | } |
| 89 | |
| 90 | inline bool IsArchitectureMips() { |
| 91 | #if defined(__mips__) |
| 92 | return true; |
| 93 | #else |
| 94 | return false; |
| 95 | #endif |
| 96 | } |
| 97 | |
| 98 | } // namespace. |
| 99 | |
| 100 | #define CASES SANDBOX_BPF_DSL_CASES |
| 101 | |
| 102 | using sandbox::bpf_dsl::Allow; |
| 103 | using sandbox::bpf_dsl::Arg; |
| 104 | using sandbox::bpf_dsl::BoolExpr; |
| 105 | using sandbox::bpf_dsl::Error; |
| 106 | using sandbox::bpf_dsl::If; |
| 107 | using sandbox::bpf_dsl::ResultExpr; |
| 108 | |
| 109 | namespace sandbox { |
| 110 | |
James Robinson | f19b102 | 2015-05-05 18:12:15 -0700 | [diff] [blame^] | 111 | #if !defined(OS_NACL_NONSFI) |
James Robinson | 30d547e | 2014-10-23 18:20:06 -0700 | [diff] [blame] | 112 | // Allow Glibc's and Android pthread creation flags, crash on any other |
| 113 | // thread creation attempts and EPERM attempts to use neither |
| 114 | // CLONE_VM, nor CLONE_THREAD, which includes all fork() implementations. |
| 115 | ResultExpr RestrictCloneToThreadsAndEPERMFork() { |
| 116 | const Arg<unsigned long> flags(0); |
| 117 | |
| 118 | // TODO(mdempsky): Extend DSL to support (flags & ~mask1) == mask2. |
| 119 | const uint64_t kAndroidCloneMask = CLONE_VM | CLONE_FS | CLONE_FILES | |
| 120 | CLONE_SIGHAND | CLONE_THREAD | |
| 121 | CLONE_SYSVSEM; |
| 122 | const uint64_t kObsoleteAndroidCloneMask = kAndroidCloneMask | CLONE_DETACHED; |
| 123 | |
| 124 | const uint64_t kGlibcPthreadFlags = |
| 125 | CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | CLONE_THREAD | |
| 126 | CLONE_SYSVSEM | CLONE_SETTLS | CLONE_PARENT_SETTID | CLONE_CHILD_CLEARTID; |
| 127 | const BoolExpr glibc_test = flags == kGlibcPthreadFlags; |
| 128 | |
| 129 | const BoolExpr android_test = flags == kAndroidCloneMask || |
| 130 | flags == kObsoleteAndroidCloneMask || |
| 131 | flags == kGlibcPthreadFlags; |
| 132 | |
| 133 | return If(IsAndroid() ? android_test : glibc_test, Allow()) |
| 134 | .ElseIf((flags & (CLONE_VM | CLONE_THREAD)) == 0, Error(EPERM)) |
| 135 | .Else(CrashSIGSYSClone()); |
| 136 | } |
| 137 | |
| 138 | ResultExpr RestrictPrctl() { |
| 139 | // Will need to add seccomp compositing in the future. PR_SET_PTRACER is |
| 140 | // used by breakpad but not needed anymore. |
| 141 | const Arg<int> option(0); |
| 142 | return Switch(option) |
| 143 | .CASES((PR_GET_NAME, PR_SET_NAME, PR_GET_DUMPABLE, PR_SET_DUMPABLE), |
| 144 | Allow()) |
James Robinson | 1027bc1 | 2014-12-04 14:51:42 -0800 | [diff] [blame] | 145 | #if defined(OS_ANDROID) |
| 146 | .CASES((PR_SET_VMA, PR_SET_TIMERSLACK_PID), Allow()) |
| 147 | #endif |
James Robinson | 30d547e | 2014-10-23 18:20:06 -0700 | [diff] [blame] | 148 | .Default(CrashSIGSYSPrctl()); |
| 149 | } |
| 150 | |
| 151 | ResultExpr RestrictIoctl() { |
| 152 | const Arg<int> request(1); |
| 153 | return Switch(request).CASES((TCGETS, FIONREAD), Allow()).Default( |
| 154 | CrashSIGSYSIoctl()); |
| 155 | } |
| 156 | |
| 157 | ResultExpr RestrictMmapFlags() { |
| 158 | // The flags you see are actually the allowed ones, and the variable is a |
| 159 | // "denied" mask because of the negation operator. |
| 160 | // Significantly, we don't permit MAP_HUGETLB, or the newer flags such as |
| 161 | // MAP_POPULATE. |
| 162 | // TODO(davidung), remove MAP_DENYWRITE with updated Tegra libraries. |
| 163 | const uint64_t kAllowedMask = MAP_SHARED | MAP_PRIVATE | MAP_ANONYMOUS | |
| 164 | MAP_STACK | MAP_NORESERVE | MAP_FIXED | |
| 165 | MAP_DENYWRITE; |
| 166 | const Arg<int> flags(3); |
| 167 | return If((flags & ~kAllowedMask) == 0, Allow()).Else(CrashSIGSYS()); |
| 168 | } |
| 169 | |
| 170 | ResultExpr RestrictMprotectFlags() { |
| 171 | // The flags you see are actually the allowed ones, and the variable is a |
| 172 | // "denied" mask because of the negation operator. |
| 173 | // Significantly, we don't permit weird undocumented flags such as |
| 174 | // PROT_GROWSDOWN. |
| 175 | const uint64_t kAllowedMask = PROT_READ | PROT_WRITE | PROT_EXEC; |
| 176 | const Arg<int> prot(2); |
| 177 | return If((prot & ~kAllowedMask) == 0, Allow()).Else(CrashSIGSYS()); |
| 178 | } |
| 179 | |
| 180 | ResultExpr RestrictFcntlCommands() { |
| 181 | // We also restrict the flags in F_SETFL. We don't want to permit flags with |
| 182 | // a history of trouble such as O_DIRECT. The flags you see are actually the |
| 183 | // allowed ones, and the variable is a "denied" mask because of the negation |
| 184 | // operator. |
| 185 | // Glibc overrides the kernel's O_LARGEFILE value. Account for this. |
| 186 | uint64_t kOLargeFileFlag = O_LARGEFILE; |
| 187 | if (IsArchitectureX86_64() || IsArchitectureI386() || IsArchitectureMips()) |
| 188 | kOLargeFileFlag = 0100000; |
| 189 | |
| 190 | const Arg<int> cmd(1); |
| 191 | const Arg<long> long_arg(2); |
| 192 | |
| 193 | const uint64_t kAllowedMask = O_ACCMODE | O_APPEND | O_NONBLOCK | O_SYNC | |
| 194 | kOLargeFileFlag | O_CLOEXEC | O_NOATIME; |
| 195 | return Switch(cmd) |
| 196 | .CASES((F_GETFL, |
| 197 | F_GETFD, |
| 198 | F_SETFD, |
| 199 | F_SETLK, |
| 200 | F_SETLKW, |
| 201 | F_GETLK, |
| 202 | F_DUPFD, |
| 203 | F_DUPFD_CLOEXEC), |
| 204 | Allow()) |
| 205 | .Case(F_SETFL, |
| 206 | If((long_arg & ~kAllowedMask) == 0, Allow()).Else(CrashSIGSYS())) |
| 207 | .Default(CrashSIGSYS()); |
| 208 | } |
| 209 | |
| 210 | #if defined(__i386__) || defined(__mips__) |
| 211 | ResultExpr RestrictSocketcallCommand() { |
| 212 | // Unfortunately, we are unable to restrict the first parameter to |
| 213 | // socketpair(2). Whilst initially sounding bad, it's noteworthy that very |
| 214 | // few protocols actually support socketpair(2). The scary call that we're |
| 215 | // worried about, socket(2), remains blocked. |
| 216 | const Arg<int> call(0); |
| 217 | return Switch(call) |
| 218 | .CASES((SYS_SOCKETPAIR, |
| 219 | SYS_SHUTDOWN, |
| 220 | SYS_RECV, |
| 221 | SYS_SEND, |
| 222 | SYS_RECVFROM, |
| 223 | SYS_SENDTO, |
| 224 | SYS_RECVMSG, |
| 225 | SYS_SENDMSG), |
| 226 | Allow()) |
| 227 | .Default(Error(EPERM)); |
| 228 | } |
| 229 | #endif |
| 230 | |
| 231 | ResultExpr RestrictKillTarget(pid_t target_pid, int sysno) { |
| 232 | switch (sysno) { |
| 233 | case __NR_kill: |
| 234 | case __NR_tgkill: { |
| 235 | const Arg<pid_t> pid(0); |
| 236 | return If(pid == target_pid, Allow()).Else(CrashSIGSYSKill()); |
| 237 | } |
| 238 | case __NR_tkill: |
| 239 | return CrashSIGSYSKill(); |
| 240 | default: |
| 241 | NOTREACHED(); |
| 242 | return CrashSIGSYS(); |
| 243 | } |
| 244 | } |
| 245 | |
| 246 | ResultExpr RestrictFutex() { |
| 247 | const uint64_t kAllowedFutexFlags = FUTEX_PRIVATE_FLAG | FUTEX_CLOCK_REALTIME; |
| 248 | const Arg<int> op(1); |
| 249 | return Switch(op & ~kAllowedFutexFlags) |
| 250 | .CASES((FUTEX_WAIT, |
| 251 | FUTEX_WAKE, |
| 252 | FUTEX_REQUEUE, |
| 253 | FUTEX_CMP_REQUEUE, |
| 254 | FUTEX_WAKE_OP, |
| 255 | FUTEX_WAIT_BITSET, |
| 256 | FUTEX_WAKE_BITSET), |
| 257 | Allow()) |
| 258 | .Default(CrashSIGSYSFutex()); |
| 259 | } |
| 260 | |
| 261 | ResultExpr RestrictGetSetpriority(pid_t target_pid) { |
| 262 | const Arg<int> which(0); |
| 263 | const Arg<int> who(1); |
| 264 | return If(which == PRIO_PROCESS, |
| 265 | If(who == 0 || who == target_pid, Allow()).Else(Error(EPERM))) |
| 266 | .Else(CrashSIGSYS()); |
| 267 | } |
| 268 | |
James Robinson | 30d547e | 2014-10-23 18:20:06 -0700 | [diff] [blame] | 269 | ResultExpr RestrictSchedTarget(pid_t target_pid, int sysno) { |
| 270 | switch (sysno) { |
| 271 | case __NR_sched_getaffinity: |
| 272 | case __NR_sched_getattr: |
| 273 | case __NR_sched_getparam: |
| 274 | case __NR_sched_getscheduler: |
| 275 | case __NR_sched_rr_get_interval: |
| 276 | case __NR_sched_setaffinity: |
| 277 | case __NR_sched_setattr: |
| 278 | case __NR_sched_setparam: |
| 279 | case __NR_sched_setscheduler: { |
| 280 | const Arg<pid_t> pid(0); |
| 281 | return If(pid == 0 || pid == target_pid, Allow()) |
| 282 | .Else(RewriteSchedSIGSYS()); |
| 283 | } |
| 284 | default: |
| 285 | NOTREACHED(); |
| 286 | return CrashSIGSYS(); |
| 287 | } |
| 288 | } |
| 289 | |
James Robinson | c4c1c59 | 2014-11-21 18:27:04 -0800 | [diff] [blame] | 290 | ResultExpr RestrictPrlimit64(pid_t target_pid) { |
| 291 | const Arg<pid_t> pid(0); |
| 292 | return If(pid == 0 || pid == target_pid, Allow()).Else(CrashSIGSYS()); |
| 293 | } |
James Robinson | 30d547e | 2014-10-23 18:20:06 -0700 | [diff] [blame] | 294 | |
Benjamin Lerman | cdfc88d | 2015-02-03 14:35:12 +0100 | [diff] [blame] | 295 | ResultExpr RestrictGetrusage() { |
| 296 | const Arg<int> who(0); |
| 297 | return If(who == RUSAGE_SELF, Allow()).Else(CrashSIGSYS()); |
| 298 | } |
James Robinson | f19b102 | 2015-05-05 18:12:15 -0700 | [diff] [blame^] | 299 | #endif // !defined(OS_NACL_NONSFI) |
| 300 | |
| 301 | ResultExpr RestrictClockID() { |
| 302 | static_assert(4 == sizeof(clockid_t), "clockid_t is not 32bit"); |
| 303 | const Arg<clockid_t> clockid(0); |
| 304 | return If( |
| 305 | #if defined(OS_CHROMEOS) |
| 306 | // Allow the special clock for Chrome OS used by Chrome tracing. |
| 307 | clockid == base::TimeTicks::kClockSystemTrace || |
| 308 | #endif |
| 309 | clockid == CLOCK_MONOTONIC || |
| 310 | clockid == CLOCK_PROCESS_CPUTIME_ID || |
| 311 | clockid == CLOCK_REALTIME || |
| 312 | clockid == CLOCK_THREAD_CPUTIME_ID, |
| 313 | Allow()).Else(CrashSIGSYS()); |
| 314 | } |
Benjamin Lerman | cdfc88d | 2015-02-03 14:35:12 +0100 | [diff] [blame] | 315 | |
James Robinson | 30d547e | 2014-10-23 18:20:06 -0700 | [diff] [blame] | 316 | } // namespace sandbox. |