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