syscall_parameters_restrictions.cc revision 5f1c94371a64b3196d4be9466099bb892df9b88e
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/stat.h> 18#include <sys/types.h> 19#include <unistd.h> 20 21#include "base/basictypes.h" 22#include "base/logging.h" 23#include "base/macros.h" 24#include "build/build_config.h" 25#include "sandbox/linux/seccomp-bpf-helpers/sigsys_handlers.h" 26#include "sandbox/linux/seccomp-bpf/linux_seccomp.h" 27#include "sandbox/linux/seccomp-bpf/sandbox_bpf.h" 28#include "sandbox/linux/services/android_futex.h" 29 30#if defined(OS_ANDROID) 31#if !defined(F_DUPFD_CLOEXEC) 32#define F_DUPFD_CLOEXEC (F_LINUX_SPECIFIC_BASE + 6) 33#endif 34#endif 35 36#if defined(__arm__) && !defined(MAP_STACK) 37#define MAP_STACK 0x20000 // Daisy build environment has old headers. 38#endif 39 40#if defined(__mips__) && !defined(MAP_STACK) 41#define MAP_STACK 0x40000 42#endif 43namespace { 44 45inline bool IsArchitectureX86_64() { 46#if defined(__x86_64__) 47 return true; 48#else 49 return false; 50#endif 51} 52 53inline bool IsArchitectureI386() { 54#if defined(__i386__) 55 return true; 56#else 57 return false; 58#endif 59} 60 61inline bool IsAndroid() { 62#if defined(OS_ANDROID) 63 return true; 64#else 65 return false; 66#endif 67} 68 69inline bool IsArchitectureMips() { 70#if defined(__mips__) 71 return true; 72#else 73 return false; 74#endif 75} 76 77} // namespace. 78 79using sandbox::bpf_dsl::Allow; 80using sandbox::bpf_dsl::Arg; 81using sandbox::bpf_dsl::BoolExpr; 82using sandbox::bpf_dsl::Error; 83using sandbox::bpf_dsl::If; 84using sandbox::bpf_dsl::ResultExpr; 85 86// TODO(mdempsky): Make BoolExpr a standalone class so these operators can 87// be resolved via argument-dependent lookup. 88using sandbox::bpf_dsl::operator||; 89using sandbox::bpf_dsl::operator&&; 90 91namespace sandbox { 92 93// Allow Glibc's and Android pthread creation flags, crash on any other 94// thread creation attempts and EPERM attempts to use neither 95// CLONE_VM, nor CLONE_THREAD, which includes all fork() implementations. 96ResultExpr RestrictCloneToThreadsAndEPERMFork() { 97 const Arg<unsigned long> flags(0); 98 99 // TODO(mdempsky): Extend DSL to support (flags & ~mask1) == mask2. 100 const uint64_t kAndroidCloneMask = CLONE_VM | CLONE_FS | CLONE_FILES | 101 CLONE_SIGHAND | CLONE_THREAD | 102 CLONE_SYSVSEM; 103 const uint64_t kObsoleteAndroidCloneMask = kAndroidCloneMask | CLONE_DETACHED; 104 const BoolExpr android_test = 105 flags == kAndroidCloneMask || flags == kObsoleteAndroidCloneMask; 106 107 const uint64_t kGlibcPthreadFlags = 108 CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | CLONE_THREAD | 109 CLONE_SYSVSEM | CLONE_SETTLS | CLONE_PARENT_SETTID | CLONE_CHILD_CLEARTID; 110 const BoolExpr glibc_test = flags == kGlibcPthreadFlags; 111 112 return If(IsAndroid() ? android_test : glibc_test, Allow()) 113 .ElseIf((flags & (CLONE_VM | CLONE_THREAD)) == 0, Error(EPERM)) 114 .Else(CrashSIGSYSClone()); 115} 116 117ResultExpr RestrictPrctl() { 118 // Will need to add seccomp compositing in the future. PR_SET_PTRACER is 119 // used by breakpad but not needed anymore. 120 const Arg<int> option(0); 121 return If(option == PR_GET_NAME || option == PR_SET_NAME || 122 option == PR_GET_DUMPABLE || option == PR_SET_DUMPABLE, 123 Allow()).Else(CrashSIGSYSPrctl()); 124} 125 126ResultExpr RestrictIoctl() { 127 const Arg<int> request(1); 128 return If(request == TCGETS || request == FIONREAD, Allow()) 129 .Else(CrashSIGSYSIoctl()); 130} 131 132ResultExpr RestrictMmapFlags() { 133 // The flags you see are actually the allowed ones, and the variable is a 134 // "denied" mask because of the negation operator. 135 // Significantly, we don't permit MAP_HUGETLB, or the newer flags such as 136 // MAP_POPULATE. 137 // TODO(davidung), remove MAP_DENYWRITE with updated Tegra libraries. 138 const uint32_t denied_mask = 139 ~(MAP_SHARED | MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK | MAP_NORESERVE | 140 MAP_FIXED | MAP_DENYWRITE); 141 const Arg<int> flags(3); 142 return If((flags & denied_mask) == 0, Allow()).Else(CrashSIGSYS()); 143} 144 145ResultExpr RestrictMprotectFlags() { 146 // The flags you see are actually the allowed ones, and the variable is a 147 // "denied" mask because of the negation operator. 148 // Significantly, we don't permit weird undocumented flags such as 149 // PROT_GROWSDOWN. 150 const uint32_t denied_mask = ~(PROT_READ | PROT_WRITE | PROT_EXEC); 151 const Arg<int> prot(2); 152 return If((prot & denied_mask) == 0, Allow()).Else(CrashSIGSYS()); 153} 154 155ResultExpr RestrictFcntlCommands() { 156 // We also restrict the flags in F_SETFL. We don't want to permit flags with 157 // a history of trouble such as O_DIRECT. The flags you see are actually the 158 // allowed ones, and the variable is a "denied" mask because of the negation 159 // operator. 160 // Glibc overrides the kernel's O_LARGEFILE value. Account for this. 161 int kOLargeFileFlag = O_LARGEFILE; 162 if (IsArchitectureX86_64() || IsArchitectureI386() || IsArchitectureMips()) 163 kOLargeFileFlag = 0100000; 164 165 const Arg<int> cmd(1); 166 const Arg<long> long_arg(2); 167 168 unsigned long denied_mask = ~(O_ACCMODE | O_APPEND | O_NONBLOCK | O_SYNC | 169 kOLargeFileFlag | O_CLOEXEC | O_NOATIME); 170 return If(cmd == F_GETFL || cmd == F_GETFD || cmd == F_SETFD || 171 cmd == F_SETLK || cmd == F_SETLKW || cmd == F_GETLK || 172 cmd == F_DUPFD || cmd == F_DUPFD_CLOEXEC || 173 (cmd == F_SETFL && (long_arg & denied_mask) == 0), 174 Allow()).Else(CrashSIGSYS()); 175} 176 177#if defined(__i386__) || defined(__mips__) 178ResultExpr RestrictSocketcallCommand() { 179 // Unfortunately, we are unable to restrict the first parameter to 180 // socketpair(2). Whilst initially sounding bad, it's noteworthy that very 181 // few protocols actually support socketpair(2). The scary call that we're 182 // worried about, socket(2), remains blocked. 183 const Arg<int> call(0); 184 return If(call == SYS_SOCKETPAIR || call == SYS_SHUTDOWN || 185 call == SYS_RECV || call == SYS_SEND || 186 call == SYS_RECVFROM || call == SYS_SENDTO || 187 call == SYS_RECVMSG || call == SYS_SENDMSG, 188 Allow()).Else(Error(EPERM)); 189} 190#endif 191 192ResultExpr RestrictKillTarget(pid_t target_pid, int sysno) { 193 switch (sysno) { 194 case __NR_kill: 195 case __NR_tgkill: { 196 const Arg<pid_t> pid(0); 197 return If(pid == target_pid, Allow()).Else(CrashSIGSYSKill()); 198 } 199 case __NR_tkill: 200 return CrashSIGSYSKill(); 201 default: 202 NOTREACHED(); 203 return CrashSIGSYS(); 204 } 205} 206 207ResultExpr RestrictFutex() { 208 // In futex.c, the kernel does "int cmd = op & FUTEX_CMD_MASK;". We need to 209 // make sure that the combination below will cover every way to get 210 // FUTEX_CMP_REQUEUE_PI. 211 const int kBannedFutexBits = 212 ~(FUTEX_CMD_MASK | FUTEX_PRIVATE_FLAG | FUTEX_CLOCK_REALTIME); 213 COMPILE_ASSERT(0 == kBannedFutexBits, 214 need_to_explicitly_blacklist_more_bits); 215 216 const Arg<int> op(1); 217 return If(op == FUTEX_CMP_REQUEUE_PI || op == FUTEX_CMP_REQUEUE_PI_PRIVATE || 218 op == (FUTEX_CMP_REQUEUE_PI | FUTEX_CLOCK_REALTIME) || 219 op == (FUTEX_CMP_REQUEUE_PI_PRIVATE | FUTEX_CLOCK_REALTIME), 220 CrashSIGSYSFutex()).Else(Allow()); 221} 222 223} // namespace sandbox. 224