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/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