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