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/baseline_policy.h"
      6 
      7 #include <errno.h>
      8 #include <sys/mman.h>
      9 #include <sys/socket.h>
     10 #include <sys/syscall.h>
     11 #include <sys/types.h>
     12 #include <unistd.h>
     13 
     14 #include "base/logging.h"
     15 #include "build/build_config.h"
     16 #include "sandbox/linux/bpf_dsl/bpf_dsl.h"
     17 #include "sandbox/linux/seccomp-bpf-helpers/sigsys_handlers.h"
     18 #include "sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.h"
     19 #include "sandbox/linux/seccomp-bpf-helpers/syscall_sets.h"
     20 #include "sandbox/linux/seccomp-bpf/sandbox_bpf.h"
     21 #include "sandbox/linux/services/syscall_wrappers.h"
     22 #include "sandbox/linux/system_headers/linux_syscalls.h"
     23 
     24 #if !defined(SO_PEEK_OFF)
     25 #define SO_PEEK_OFF 42
     26 #endif
     27 
     28 // Changing this implementation will have an effect on *all* policies.
     29 // Currently this means: Renderer/Worker, GPU, Flash and NaCl.
     30 
     31 using sandbox::bpf_dsl::Allow;
     32 using sandbox::bpf_dsl::Arg;
     33 using sandbox::bpf_dsl::Error;
     34 using sandbox::bpf_dsl::If;
     35 using sandbox::bpf_dsl::ResultExpr;
     36 
     37 namespace sandbox {
     38 
     39 namespace {
     40 
     41 bool IsBaselinePolicyAllowed(int sysno) {
     42   return SyscallSets::IsAllowedAddressSpaceAccess(sysno) ||
     43          SyscallSets::IsAllowedBasicScheduler(sysno) ||
     44          SyscallSets::IsAllowedEpoll(sysno) ||
     45          SyscallSets::IsAllowedFileSystemAccessViaFd(sysno) ||
     46          SyscallSets::IsAllowedFutex(sysno) ||
     47          SyscallSets::IsAllowedGeneralIo(sysno) ||
     48          SyscallSets::IsAllowedGetOrModifySocket(sysno) ||
     49          SyscallSets::IsAllowedGettime(sysno) ||
     50          SyscallSets::IsAllowedProcessStartOrDeath(sysno) ||
     51          SyscallSets::IsAllowedSignalHandling(sysno) ||
     52          SyscallSets::IsGetSimpleId(sysno) ||
     53          SyscallSets::IsKernelInternalApi(sysno) ||
     54 #if defined(__arm__)
     55          SyscallSets::IsArmPrivate(sysno) ||
     56 #endif
     57 #if defined(__mips__)
     58          SyscallSets::IsMipsPrivate(sysno) ||
     59 #endif
     60          SyscallSets::IsAllowedOperationOnFd(sysno);
     61 }
     62 
     63 // System calls that will trigger the crashing SIGSYS handler.
     64 bool IsBaselinePolicyWatched(int sysno) {
     65   return SyscallSets::IsAdminOperation(sysno) ||
     66          SyscallSets::IsAdvancedScheduler(sysno) ||
     67          SyscallSets::IsAdvancedTimer(sysno) ||
     68          SyscallSets::IsAsyncIo(sysno) ||
     69          SyscallSets::IsDebug(sysno) ||
     70          SyscallSets::IsEventFd(sysno) ||
     71          SyscallSets::IsExtendedAttributes(sysno) ||
     72          SyscallSets::IsFaNotify(sysno) ||
     73          SyscallSets::IsFsControl(sysno) ||
     74          SyscallSets::IsGlobalFSViewChange(sysno) ||
     75          SyscallSets::IsGlobalProcessEnvironment(sysno) ||
     76          SyscallSets::IsGlobalSystemStatus(sysno) ||
     77          SyscallSets::IsInotify(sysno) ||
     78          SyscallSets::IsKernelModule(sysno) ||
     79          SyscallSets::IsKeyManagement(sysno) ||
     80          SyscallSets::IsKill(sysno) ||
     81          SyscallSets::IsMessageQueue(sysno) ||
     82          SyscallSets::IsMisc(sysno) ||
     83 #if defined(__x86_64__)
     84          SyscallSets::IsNetworkSocketInformation(sysno) ||
     85 #endif
     86          SyscallSets::IsNuma(sysno) ||
     87          SyscallSets::IsPrctl(sysno) ||
     88          SyscallSets::IsProcessGroupOrSession(sysno) ||
     89 #if defined(__i386__) || defined(__mips__)
     90          SyscallSets::IsSocketCall(sysno) ||
     91 #endif
     92 #if defined(__arm__)
     93          SyscallSets::IsArmPciConfig(sysno) ||
     94 #endif
     95 #if defined(__mips__)
     96          SyscallSets::IsMipsMisc(sysno) ||
     97 #endif
     98          SyscallSets::IsTimer(sysno);
     99 }
    100 
    101 // |fs_denied_errno| is the errno return for denied filesystem access.
    102 ResultExpr EvaluateSyscallImpl(int fs_denied_errno,
    103                                pid_t current_pid,
    104                                int sysno) {
    105 #if defined(ADDRESS_SANITIZER) || defined(THREAD_SANITIZER) || \
    106     defined(MEMORY_SANITIZER)
    107   // TCGETS is required by the sanitizers on failure.
    108   if (sysno == __NR_ioctl) {
    109     return RestrictIoctl();
    110   }
    111 
    112   if (sysno == __NR_sched_getaffinity) {
    113     return Allow();
    114   }
    115 
    116   // Used when RSS limiting is enabled in sanitizers.
    117   if (sysno == __NR_getrusage) {
    118     return RestrictGetrusage();
    119   }
    120 
    121   if (sysno == __NR_sigaltstack) {
    122     // Required for better stack overflow detection in ASan. Disallowed in
    123     // non-ASan builds.
    124     return Allow();
    125   }
    126 #endif  // defined(ADDRESS_SANITIZER) || defined(THREAD_SANITIZER) ||
    127         // defined(MEMORY_SANITIZER)
    128 
    129   if (IsBaselinePolicyAllowed(sysno)) {
    130     return Allow();
    131   }
    132 
    133 #if defined(OS_ANDROID)
    134   // Needed for thread creation.
    135   if (sysno == __NR_sigaltstack)
    136     return Allow();
    137 #endif
    138 
    139   if (sysno == __NR_clock_gettime) {
    140     return RestrictClockID();
    141   }
    142 
    143   if (sysno == __NR_clone) {
    144     return RestrictCloneToThreadsAndEPERMFork();
    145   }
    146 
    147   if (sysno == __NR_fcntl)
    148     return RestrictFcntlCommands();
    149 
    150 #if defined(__i386__) || defined(__arm__) || defined(__mips__)
    151   if (sysno == __NR_fcntl64)
    152     return RestrictFcntlCommands();
    153 #endif
    154 
    155 #if !defined(__aarch64__)
    156   // fork() is never used as a system call (clone() is used instead), but we
    157   // have seen it in fallback code on Android.
    158   if (sysno == __NR_fork) {
    159     return Error(EPERM);
    160   }
    161 #endif
    162 
    163   if (sysno == __NR_futex)
    164     return RestrictFutex();
    165 
    166   if (sysno == __NR_set_robust_list)
    167     return Error(EPERM);
    168 
    169   if (sysno == __NR_getpriority || sysno ==__NR_setpriority)
    170     return RestrictGetSetpriority(current_pid);
    171 
    172   if (sysno == __NR_madvise) {
    173     // Only allow MADV_DONTNEED (aka MADV_FREE).
    174     const Arg<int> advice(2);
    175     return If(advice == MADV_DONTNEED, Allow()).Else(Error(EPERM));
    176   }
    177 
    178 #if defined(__i386__) || defined(__x86_64__) || defined(__mips__) || \
    179     defined(__aarch64__)
    180   if (sysno == __NR_mmap)
    181     return RestrictMmapFlags();
    182 #endif
    183 
    184 #if defined(__i386__) || defined(__arm__) || defined(__mips__)
    185   if (sysno == __NR_mmap2)
    186     return RestrictMmapFlags();
    187 #endif
    188 
    189   if (sysno == __NR_mprotect)
    190     return RestrictMprotectFlags();
    191 
    192   if (sysno == __NR_prctl)
    193     return RestrictPrctl();
    194 
    195 #if defined(__x86_64__) || defined(__arm__) || defined(__mips__) || \
    196     defined(__aarch64__)
    197   if (sysno == __NR_socketpair) {
    198     // Only allow AF_UNIX, PF_UNIX. Crash if anything else is seen.
    199     static_assert(AF_UNIX == PF_UNIX,
    200                   "af_unix and pf_unix should not be different");
    201     const Arg<int> domain(0);
    202     return If(domain == AF_UNIX, Allow()).Else(CrashSIGSYS());
    203   }
    204 #endif
    205 
    206   if (SyscallSets::IsKill(sysno)) {
    207     return RestrictKillTarget(current_pid, sysno);
    208   }
    209 
    210   if (SyscallSets::IsFileSystem(sysno) ||
    211       SyscallSets::IsCurrentDirectory(sysno)) {
    212     return Error(fs_denied_errno);
    213   }
    214 
    215   if (SyscallSets::IsSeccomp(sysno))
    216     return Error(EPERM);
    217 
    218   if (SyscallSets::IsAnySystemV(sysno)) {
    219     return Error(EPERM);
    220   }
    221 
    222   if (SyscallSets::IsUmask(sysno) ||
    223       SyscallSets::IsDeniedFileSystemAccessViaFd(sysno) ||
    224       SyscallSets::IsDeniedGetOrModifySocket(sysno) ||
    225       SyscallSets::IsProcessPrivilegeChange(sysno)) {
    226     return Error(EPERM);
    227   }
    228 
    229 #if defined(__i386__) || defined(__mips__)
    230   if (SyscallSets::IsSocketCall(sysno))
    231     return RestrictSocketcallCommand();
    232 #endif
    233 
    234 #if !defined(__i386__)
    235   if (sysno == __NR_getsockopt || sysno ==__NR_setsockopt) {
    236     // Used by Mojo EDK to catch a message pipe being sent over itself.
    237     const Arg<int> level(1);
    238     const Arg<int> optname(2);
    239     return If(AllOf(level == SOL_SOCKET, optname == SO_PEEK_OFF), Allow())
    240         .Else(CrashSIGSYS());
    241   }
    242 #endif
    243 
    244   if (IsBaselinePolicyWatched(sysno)) {
    245     // Previously unseen syscalls. TODO(jln): some of these should
    246     // be denied gracefully right away.
    247     return CrashSIGSYS();
    248   }
    249 
    250   // In any other case crash the program with our SIGSYS handler.
    251   return CrashSIGSYS();
    252 }
    253 
    254 }  // namespace.
    255 
    256 // Unfortunately C++03 doesn't allow delegated constructors.
    257 // Call other constructor when C++11 lands.
    258 BaselinePolicy::BaselinePolicy() : BaselinePolicy(EPERM) {}
    259 
    260 BaselinePolicy::BaselinePolicy(int fs_denied_errno)
    261     : fs_denied_errno_(fs_denied_errno), policy_pid_(sys_getpid()) {
    262 }
    263 
    264 BaselinePolicy::~BaselinePolicy() {
    265   // Make sure that this policy is created, used and destroyed by a single
    266   // process.
    267   DCHECK_EQ(sys_getpid(), policy_pid_);
    268 }
    269 
    270 ResultExpr BaselinePolicy::EvaluateSyscall(int sysno) const {
    271   // Sanity check that we're only called with valid syscall numbers.
    272   DCHECK(SandboxBPF::IsValidSyscallNumber(sysno));
    273   // Make sure that this policy is used in the creating process.
    274   if (1 == sysno) {
    275     DCHECK_EQ(sys_getpid(), policy_pid_);
    276   }
    277   return EvaluateSyscallImpl(fs_denied_errno_, policy_pid_, sysno);
    278 }
    279 
    280 ResultExpr BaselinePolicy::InvalidSyscall() const {
    281   return CrashSIGSYS();
    282 }
    283 
    284 }  // namespace sandbox.
    285