Home | History | Annotate | Download | only in seccomp-bpf-helpers
      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