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> 10 #include <linux/net.h> 11 #include <sched.h> 12 #include <signal.h> 13 #include <stdint.h> 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 23 #include "base/logging.h" 24 #include "base/macros.h" 25 #include "build/build_config.h" 26 #include "sandbox/linux/bpf_dsl/bpf_dsl.h" 27 #include "sandbox/linux/bpf_dsl/seccomp_macros.h" 28 #include "sandbox/linux/seccomp-bpf-helpers/sigsys_handlers.h" 29 #include "sandbox/linux/seccomp-bpf/sandbox_bpf.h" 30 #include "sandbox/linux/system_headers/linux_futex.h" 31 #include "sandbox/linux/system_headers/linux_syscalls.h" 32 #include "sandbox/linux/system_headers/linux_time.h" 33 34 // PNaCl toolchain does not provide sys/ioctl.h header. 35 #if !defined(OS_NACL_NONSFI) 36 #include <sys/ioctl.h> 37 #endif 38 39 #if defined(OS_ANDROID) 40 41 #if !defined(F_DUPFD_CLOEXEC) 42 #define F_DUPFD_CLOEXEC (F_LINUX_SPECIFIC_BASE + 6) 43 #endif 44 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 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 111 #if !defined(OS_NACL_NONSFI) 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 = 130 AnyOf(flags == kAndroidCloneMask, 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 #if defined(OS_ANDROID) 145 , 146 PR_SET_VMA, PR_SET_TIMERSLACK_PID 147 #endif 148 ), 149 Allow()) 150 .Default(CrashSIGSYSPrctl()); 151 } 152 153 ResultExpr RestrictIoctl() { 154 const Arg<int> request(1); 155 return Switch(request).CASES((TCGETS, FIONREAD), Allow()).Default( 156 CrashSIGSYSIoctl()); 157 } 158 159 ResultExpr RestrictMmapFlags() { 160 // The flags you see are actually the allowed ones, and the variable is a 161 // "denied" mask because of the negation operator. 162 // Significantly, we don't permit MAP_HUGETLB, or the newer flags such as 163 // MAP_POPULATE. 164 // TODO(davidung), remove MAP_DENYWRITE with updated Tegra libraries. 165 const uint64_t kAllowedMask = MAP_SHARED | MAP_PRIVATE | MAP_ANONYMOUS | 166 MAP_STACK | MAP_NORESERVE | MAP_FIXED | 167 MAP_DENYWRITE; 168 const Arg<int> flags(3); 169 return If((flags & ~kAllowedMask) == 0, Allow()).Else(CrashSIGSYS()); 170 } 171 172 ResultExpr RestrictMprotectFlags() { 173 // The flags you see are actually the allowed ones, and the variable is a 174 // "denied" mask because of the negation operator. 175 // Significantly, we don't permit weird undocumented flags such as 176 // PROT_GROWSDOWN. 177 const uint64_t kAllowedMask = PROT_READ | PROT_WRITE | PROT_EXEC; 178 const Arg<int> prot(2); 179 return If((prot & ~kAllowedMask) == 0, Allow()).Else(CrashSIGSYS()); 180 } 181 182 ResultExpr RestrictFcntlCommands() { 183 // We also restrict the flags in F_SETFL. We don't want to permit flags with 184 // a history of trouble such as O_DIRECT. The flags you see are actually the 185 // allowed ones, and the variable is a "denied" mask because of the negation 186 // operator. 187 // Glibc overrides the kernel's O_LARGEFILE value. Account for this. 188 uint64_t kOLargeFileFlag = O_LARGEFILE; 189 if (IsArchitectureX86_64() || IsArchitectureI386() || IsArchitectureMips()) 190 kOLargeFileFlag = 0100000; 191 192 const Arg<int> cmd(1); 193 const Arg<long> long_arg(2); 194 195 const uint64_t kAllowedMask = O_ACCMODE | O_APPEND | O_NONBLOCK | O_SYNC | 196 kOLargeFileFlag | O_CLOEXEC | O_NOATIME; 197 return Switch(cmd) 198 .CASES((F_GETFL, 199 F_GETFD, 200 F_SETFD, 201 F_SETLK, 202 F_SETLKW, 203 F_GETLK, 204 F_DUPFD, 205 F_DUPFD_CLOEXEC), 206 Allow()) 207 .Case(F_SETFL, 208 If((long_arg & ~kAllowedMask) == 0, Allow()).Else(CrashSIGSYS())) 209 .Default(CrashSIGSYS()); 210 } 211 212 #if defined(__i386__) || defined(__mips__) 213 ResultExpr RestrictSocketcallCommand() { 214 // Unfortunately, we are unable to restrict the first parameter to 215 // socketpair(2). Whilst initially sounding bad, it's noteworthy that very 216 // few protocols actually support socketpair(2). The scary call that we're 217 // worried about, socket(2), remains blocked. 218 const Arg<int> call(0); 219 return Switch(call) 220 .CASES((SYS_SOCKETPAIR, 221 SYS_SHUTDOWN, 222 SYS_RECV, 223 SYS_SEND, 224 SYS_RECVFROM, 225 SYS_SENDTO, 226 SYS_RECVMSG, 227 SYS_SENDMSG), 228 Allow()) 229 .Default(Error(EPERM)); 230 } 231 #endif 232 233 ResultExpr RestrictKillTarget(pid_t target_pid, int sysno) { 234 switch (sysno) { 235 case __NR_kill: 236 case __NR_tgkill: { 237 const Arg<pid_t> pid(0); 238 return If(pid == target_pid, Allow()).Else(CrashSIGSYSKill()); 239 } 240 case __NR_tkill: 241 return CrashSIGSYSKill(); 242 default: 243 NOTREACHED(); 244 return CrashSIGSYS(); 245 } 246 } 247 248 ResultExpr RestrictFutex() { 249 const uint64_t kAllowedFutexFlags = FUTEX_PRIVATE_FLAG | FUTEX_CLOCK_REALTIME; 250 const Arg<int> op(1); 251 return Switch(op & ~kAllowedFutexFlags) 252 .CASES((FUTEX_WAIT, 253 FUTEX_WAKE, 254 FUTEX_REQUEUE, 255 FUTEX_CMP_REQUEUE, 256 FUTEX_WAKE_OP, 257 FUTEX_WAIT_BITSET, 258 FUTEX_WAKE_BITSET), 259 Allow()) 260 .Default(CrashSIGSYSFutex()); 261 } 262 263 ResultExpr RestrictGetSetpriority(pid_t target_pid) { 264 const Arg<int> which(0); 265 const Arg<int> who(1); 266 return If(which == PRIO_PROCESS, 267 Switch(who).CASES((0, target_pid), Allow()).Default(Error(EPERM))) 268 .Else(CrashSIGSYS()); 269 } 270 271 ResultExpr RestrictSchedTarget(pid_t target_pid, int sysno) { 272 switch (sysno) { 273 case __NR_sched_getaffinity: 274 case __NR_sched_getattr: 275 case __NR_sched_getparam: 276 case __NR_sched_getscheduler: 277 case __NR_sched_rr_get_interval: 278 case __NR_sched_setaffinity: 279 case __NR_sched_setattr: 280 case __NR_sched_setparam: 281 case __NR_sched_setscheduler: { 282 const Arg<pid_t> pid(0); 283 return Switch(pid) 284 .CASES((0, target_pid), Allow()) 285 .Default(RewriteSchedSIGSYS()); 286 } 287 default: 288 NOTREACHED(); 289 return CrashSIGSYS(); 290 } 291 } 292 293 ResultExpr RestrictPrlimit64(pid_t target_pid) { 294 const Arg<pid_t> pid(0); 295 return Switch(pid).CASES((0, target_pid), Allow()).Default(CrashSIGSYS()); 296 } 297 298 ResultExpr RestrictGetrusage() { 299 const Arg<int> who(0); 300 return If(who == RUSAGE_SELF, Allow()).Else(CrashSIGSYS()); 301 } 302 #endif // !defined(OS_NACL_NONSFI) 303 304 ResultExpr RestrictClockID() { 305 static_assert(4 == sizeof(clockid_t), "clockid_t is not 32bit"); 306 const Arg<clockid_t> clockid(0); 307 return Switch(clockid) 308 .CASES((CLOCK_MONOTONIC, CLOCK_MONOTONIC_COARSE, CLOCK_PROCESS_CPUTIME_ID, 309 CLOCK_REALTIME, CLOCK_REALTIME_COARSE, CLOCK_THREAD_CPUTIME_ID), 310 Allow()) 311 .Default(CrashSIGSYS()); 312 } 313 314 } // namespace sandbox. 315