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 #ifndef PR_SET_PTRACER 51 #define PR_SET_PTRACER 0x59616d61 52 #endif 53 54 #endif // defined(OS_ANDROID) 55 56 #if defined(__arm__) && !defined(MAP_STACK) 57 #define MAP_STACK 0x20000 // Daisy build environment has old headers. 58 #endif 59 60 #if defined(__mips__) && !defined(MAP_STACK) 61 #define MAP_STACK 0x40000 62 #endif 63 namespace { 64 65 inline bool IsArchitectureX86_64() { 66 #if defined(__x86_64__) 67 return true; 68 #else 69 return false; 70 #endif 71 } 72 73 inline bool IsArchitectureI386() { 74 #if defined(__i386__) 75 return true; 76 #else 77 return false; 78 #endif 79 } 80 81 inline bool IsAndroid() { 82 #if defined(OS_ANDROID) 83 return true; 84 #else 85 return false; 86 #endif 87 } 88 89 inline bool IsArchitectureMips() { 90 #if defined(__mips__) 91 return true; 92 #else 93 return false; 94 #endif 95 } 96 97 // Ubuntu's version of glibc has a race condition in sem_post that can cause 98 // it to call futex(2) with bogus op arguments. To workaround this, we need 99 // to allow those futex(2) calls to fail with EINVAL, instead of crashing the 100 // process. See crbug.com/598471. 101 inline bool IsBuggyGlibcSemPost() { 102 #if defined(LIBC_GLIBC) && !defined(OS_CHROMEOS) 103 return true; 104 #else 105 return false; 106 #endif 107 } 108 109 } // namespace. 110 111 #define CASES SANDBOX_BPF_DSL_CASES 112 113 using sandbox::bpf_dsl::Allow; 114 using sandbox::bpf_dsl::Arg; 115 using sandbox::bpf_dsl::BoolExpr; 116 using sandbox::bpf_dsl::Error; 117 using sandbox::bpf_dsl::If; 118 using sandbox::bpf_dsl::ResultExpr; 119 120 namespace sandbox { 121 122 #if !defined(OS_NACL_NONSFI) 123 // Allow Glibc's and Android pthread creation flags, crash on any other 124 // thread creation attempts and EPERM attempts to use neither 125 // CLONE_VM, nor CLONE_THREAD, which includes all fork() implementations. 126 ResultExpr RestrictCloneToThreadsAndEPERMFork() { 127 const Arg<unsigned long> flags(0); 128 129 // TODO(mdempsky): Extend DSL to support (flags & ~mask1) == mask2. 130 const uint64_t kAndroidCloneMask = CLONE_VM | CLONE_FS | CLONE_FILES | 131 CLONE_SIGHAND | CLONE_THREAD | 132 CLONE_SYSVSEM; 133 const uint64_t kObsoleteAndroidCloneMask = kAndroidCloneMask | CLONE_DETACHED; 134 135 const uint64_t kGlibcPthreadFlags = 136 CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | CLONE_THREAD | 137 CLONE_SYSVSEM | CLONE_SETTLS | CLONE_PARENT_SETTID | CLONE_CHILD_CLEARTID; 138 const BoolExpr glibc_test = flags == kGlibcPthreadFlags; 139 140 const BoolExpr android_test = 141 AnyOf(flags == kAndroidCloneMask, flags == kObsoleteAndroidCloneMask, 142 flags == kGlibcPthreadFlags); 143 144 return If(IsAndroid() ? android_test : glibc_test, Allow()) 145 .ElseIf((flags & (CLONE_VM | CLONE_THREAD)) == 0, Error(EPERM)) 146 .Else(CrashSIGSYSClone()); 147 } 148 149 ResultExpr RestrictPrctl() { 150 // Will need to add seccomp compositing in the future. PR_SET_PTRACER is 151 // used by breakpad but not needed anymore. 152 const Arg<int> option(0); 153 return Switch(option) 154 .CASES((PR_GET_NAME, PR_SET_NAME, PR_GET_DUMPABLE, PR_SET_DUMPABLE 155 #if defined(OS_ANDROID) 156 , PR_SET_VMA, PR_SET_PTRACER 157 158 // Enable PR_SET_TIMERSLACK_PID, an Android custom prctl which is used in: 159 // https://android.googlesource.com/platform/system/core/+/lollipop-release/libcutils/sched_policy.c. 160 // Depending on the Android kernel version, this prctl may have different 161 // values. Since we don't know the correct value for the running kernel, we must 162 // allow them all. 163 // 164 // The effect is: 165 // On 3.14 kernels, this allows PR_SET_TIMERSLACK_PID and 43 and 127 (invalid 166 // prctls which will return EINVAL) 167 // On 3.18 kernels, this allows PR_SET_TIMERSLACK_PID, PR_SET_THP_DISABLE, and 168 // 127 (invalid). 169 // On 4.1 kernels and up, this allows PR_SET_TIMERSLACK_PID, PR_SET_THP_DISABLE, 170 // and PR_MPX_ENABLE_MANAGEMENT. 171 172 // https://android.googlesource.com/kernel/common/+/android-3.14/include/uapi/linux/prctl.h 173 #define PR_SET_TIMERSLACK_PID_1 41 174 175 // https://android.googlesource.com/kernel/common/+/android-3.18/include/uapi/linux/prctl.h 176 #define PR_SET_TIMERSLACK_PID_2 43 177 178 // https://android.googlesource.com/kernel/common/+/android-4.1/include/uapi/linux/prctl.h and up 179 #define PR_SET_TIMERSLACK_PID_3 127 180 181 , PR_SET_TIMERSLACK_PID_1 182 , PR_SET_TIMERSLACK_PID_2 183 , PR_SET_TIMERSLACK_PID_3 184 #endif // defined(OS_ANDROID) 185 ), 186 Allow()) 187 .Default(CrashSIGSYSPrctl()); 188 } 189 190 ResultExpr RestrictIoctl() { 191 const Arg<int> request(1); 192 return Switch(request).CASES((TCGETS, FIONREAD), Allow()).Default( 193 CrashSIGSYSIoctl()); 194 } 195 196 ResultExpr RestrictMmapFlags() { 197 // The flags you see are actually the allowed ones, and the variable is a 198 // "denied" mask because of the negation operator. 199 // Significantly, we don't permit MAP_HUGETLB, or the newer flags such as 200 // MAP_POPULATE. 201 // TODO(davidung), remove MAP_DENYWRITE with updated Tegra libraries. 202 const uint64_t kAllowedMask = MAP_SHARED | MAP_PRIVATE | MAP_ANONYMOUS | 203 MAP_STACK | MAP_NORESERVE | MAP_FIXED | 204 MAP_DENYWRITE; 205 const Arg<int> flags(3); 206 return If((flags & ~kAllowedMask) == 0, Allow()).Else(CrashSIGSYS()); 207 } 208 209 ResultExpr RestrictMprotectFlags() { 210 // The flags you see are actually the allowed ones, and the variable is a 211 // "denied" mask because of the negation operator. 212 // Significantly, we don't permit weird undocumented flags such as 213 // PROT_GROWSDOWN. 214 const uint64_t kAllowedMask = PROT_READ | PROT_WRITE | PROT_EXEC; 215 const Arg<int> prot(2); 216 return If((prot & ~kAllowedMask) == 0, Allow()).Else(CrashSIGSYS()); 217 } 218 219 ResultExpr RestrictFcntlCommands() { 220 // We also restrict the flags in F_SETFL. We don't want to permit flags with 221 // a history of trouble such as O_DIRECT. The flags you see are actually the 222 // allowed ones, and the variable is a "denied" mask because of the negation 223 // operator. 224 // Glibc overrides the kernel's O_LARGEFILE value. Account for this. 225 uint64_t kOLargeFileFlag = O_LARGEFILE; 226 if (IsArchitectureX86_64() || IsArchitectureI386() || IsArchitectureMips()) 227 kOLargeFileFlag = 0100000; 228 229 const Arg<int> cmd(1); 230 const Arg<long> long_arg(2); 231 232 const uint64_t kAllowedMask = O_ACCMODE | O_APPEND | O_NONBLOCK | O_SYNC | 233 kOLargeFileFlag | O_CLOEXEC | O_NOATIME; 234 return Switch(cmd) 235 .CASES((F_GETFL, 236 F_GETFD, 237 F_SETFD, 238 F_SETLK, 239 F_SETLKW, 240 F_GETLK, 241 F_DUPFD, 242 F_DUPFD_CLOEXEC), 243 Allow()) 244 .Case(F_SETFL, 245 If((long_arg & ~kAllowedMask) == 0, Allow()).Else(CrashSIGSYS())) 246 .Default(CrashSIGSYS()); 247 } 248 249 #if defined(__i386__) || defined(__mips__) 250 ResultExpr RestrictSocketcallCommand() { 251 // Unfortunately, we are unable to restrict the first parameter to 252 // socketpair(2). Whilst initially sounding bad, it's noteworthy that very 253 // few protocols actually support socketpair(2). The scary call that we're 254 // worried about, socket(2), remains blocked. 255 const Arg<int> call(0); 256 return Switch(call) 257 .CASES((SYS_SOCKETPAIR, 258 SYS_SHUTDOWN, 259 SYS_RECV, 260 SYS_SEND, 261 SYS_RECVFROM, 262 SYS_SENDTO, 263 SYS_RECVMSG, 264 SYS_SENDMSG), 265 Allow()) 266 .Default(Error(EPERM)); 267 } 268 #endif 269 270 ResultExpr RestrictKillTarget(pid_t target_pid, int sysno) { 271 switch (sysno) { 272 case __NR_kill: 273 case __NR_tgkill: { 274 const Arg<pid_t> pid(0); 275 return If(pid == target_pid, Allow()).Else(CrashSIGSYSKill()); 276 } 277 case __NR_tkill: 278 return CrashSIGSYSKill(); 279 default: 280 NOTREACHED(); 281 return CrashSIGSYS(); 282 } 283 } 284 285 ResultExpr RestrictFutex() { 286 const uint64_t kAllowedFutexFlags = FUTEX_PRIVATE_FLAG | FUTEX_CLOCK_REALTIME; 287 const Arg<int> op(1); 288 return Switch(op & ~kAllowedFutexFlags) 289 .CASES((FUTEX_WAIT, FUTEX_WAKE, FUTEX_REQUEUE, FUTEX_CMP_REQUEUE, 290 FUTEX_WAKE_OP, FUTEX_WAIT_BITSET, FUTEX_WAKE_BITSET), 291 Allow()) 292 .Default(IsBuggyGlibcSemPost() ? Error(EINVAL) : CrashSIGSYSFutex()); 293 } 294 295 ResultExpr RestrictGetSetpriority(pid_t target_pid) { 296 const Arg<int> which(0); 297 const Arg<int> who(1); 298 return If(which == PRIO_PROCESS, 299 Switch(who).CASES((0, target_pid), Allow()).Default(Error(EPERM))) 300 .Else(CrashSIGSYS()); 301 } 302 303 ResultExpr RestrictSchedTarget(pid_t target_pid, int sysno) { 304 switch (sysno) { 305 case __NR_sched_getaffinity: 306 case __NR_sched_getattr: 307 case __NR_sched_getparam: 308 case __NR_sched_getscheduler: 309 case __NR_sched_rr_get_interval: 310 case __NR_sched_setaffinity: 311 case __NR_sched_setattr: 312 case __NR_sched_setparam: 313 case __NR_sched_setscheduler: { 314 const Arg<pid_t> pid(0); 315 return Switch(pid) 316 .CASES((0, target_pid), Allow()) 317 .Default(RewriteSchedSIGSYS()); 318 } 319 default: 320 NOTREACHED(); 321 return CrashSIGSYS(); 322 } 323 } 324 325 ResultExpr RestrictPrlimit64(pid_t target_pid) { 326 const Arg<pid_t> pid(0); 327 return Switch(pid).CASES((0, target_pid), Allow()).Default(CrashSIGSYS()); 328 } 329 330 ResultExpr RestrictGetrusage() { 331 const Arg<int> who(0); 332 return If(who == RUSAGE_SELF, Allow()).Else(CrashSIGSYS()); 333 } 334 #endif // !defined(OS_NACL_NONSFI) 335 336 ResultExpr RestrictClockID() { 337 static_assert(4 == sizeof(clockid_t), "clockid_t is not 32bit"); 338 const Arg<clockid_t> clockid(0); 339 return Switch(clockid) 340 .CASES(( 341 #if defined(OS_ANDROID) 342 CLOCK_BOOTTIME, 343 #endif 344 CLOCK_MONOTONIC, 345 CLOCK_MONOTONIC_COARSE, 346 CLOCK_PROCESS_CPUTIME_ID, 347 CLOCK_REALTIME, 348 CLOCK_REALTIME_COARSE, 349 CLOCK_THREAD_CPUTIME_ID), 350 Allow()) 351 .Default(CrashSIGSYS()); 352 } 353 354 } // namespace sandbox. 355