Home | History | Annotate | Download | only in bpf_dsl
      1 // Copyright (c) 2012 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/bpf_dsl/syscall_set.h"
      6 
      7 #include <stdint.h>
      8 
      9 #include "base/logging.h"
     10 #include "base/macros.h"
     11 #include "sandbox/linux/bpf_dsl/linux_syscall_ranges.h"
     12 
     13 namespace sandbox {
     14 
     15 namespace {
     16 
     17 #if defined(__mips__) && (_MIPS_SIM == _MIPS_SIM_ABI32)
     18 // This is true for Mips O32 ABI.
     19 static_assert(MIN_SYSCALL == __NR_Linux, "min syscall number should be 4000");
     20 #else
     21 // This true for supported architectures (Intel and ARM EABI).
     22 static_assert(MIN_SYSCALL == 0u,
     23               "min syscall should always be zero");
     24 #endif
     25 
     26 // SyscallRange represents an inclusive range of system call numbers.
     27 struct SyscallRange {
     28   uint32_t first;
     29   uint32_t last;
     30 };
     31 
     32 const SyscallRange kValidSyscallRanges[] = {
     33     // First we iterate up to MAX_PUBLIC_SYSCALL, which is equal to MAX_SYSCALL
     34     // on Intel architectures, but leaves room for private syscalls on ARM.
     35     {MIN_SYSCALL, MAX_PUBLIC_SYSCALL},
     36 #if defined(__arm__)
     37     // ARM EABI includes "ARM private" system calls starting at
     38     // MIN_PRIVATE_SYSCALL, and a "ghost syscall private to the kernel" at
     39     // MIN_GHOST_SYSCALL.
     40     {MIN_PRIVATE_SYSCALL, MAX_PRIVATE_SYSCALL},
     41     {MIN_GHOST_SYSCALL, MAX_SYSCALL},
     42 #endif
     43 };
     44 
     45 }  // namespace
     46 
     47 SyscallSet::Iterator SyscallSet::begin() const {
     48   return Iterator(set_, false);
     49 }
     50 
     51 SyscallSet::Iterator SyscallSet::end() const {
     52   return Iterator(set_, true);
     53 }
     54 
     55 bool SyscallSet::IsValid(uint32_t num) {
     56   for (const SyscallRange& range : kValidSyscallRanges) {
     57     if (num >= range.first && num <= range.last) {
     58       return true;
     59     }
     60   }
     61   return false;
     62 }
     63 
     64 bool operator==(const SyscallSet& lhs, const SyscallSet& rhs) {
     65   return (lhs.set_ == rhs.set_);
     66 }
     67 
     68 SyscallSet::Iterator::Iterator(Set set, bool done)
     69     : set_(set), done_(done), num_(0) {
     70   // If the set doesn't contain 0, we need to skip to the next element.
     71   if (!done && set_ == (IsValid(num_) ? Set::INVALID_ONLY : Set::VALID_ONLY)) {
     72     ++*this;
     73   }
     74 }
     75 
     76 uint32_t SyscallSet::Iterator::operator*() const {
     77   DCHECK(!done_);
     78   return num_;
     79 }
     80 
     81 SyscallSet::Iterator& SyscallSet::Iterator::operator++() {
     82   DCHECK(!done_);
     83 
     84   num_ = NextSyscall();
     85   if (num_ == 0) {
     86     done_ = true;
     87   }
     88 
     89   return *this;
     90 }
     91 
     92 // NextSyscall returns the next system call in the iterated system
     93 // call set after |num_|, or 0 if no such system call exists.
     94 uint32_t SyscallSet::Iterator::NextSyscall() const {
     95   const bool want_valid = (set_ != Set::INVALID_ONLY);
     96   const bool want_invalid = (set_ != Set::VALID_ONLY);
     97 
     98   for (const SyscallRange& range : kValidSyscallRanges) {
     99     if (want_invalid && range.first > 0 && num_ < range.first - 1) {
    100       // Even when iterating invalid syscalls, we only include the end points;
    101       // so skip directly to just before the next (valid) range.
    102       return range.first - 1;
    103     }
    104     if (want_valid && num_ < range.first) {
    105       return range.first;
    106     }
    107     if (want_valid && num_ < range.last) {
    108       return num_ + 1;
    109     }
    110     if (want_invalid && num_ <= range.last) {
    111       return range.last + 1;
    112     }
    113   }
    114 
    115   if (want_invalid) {
    116     // BPF programs only ever operate on unsigned quantities. So,
    117     // that's how we iterate; we return values from
    118     // 0..0xFFFFFFFFu. But there are places, where the kernel might
    119     // interpret system call numbers as signed quantities, so the
    120     // boundaries between signed and unsigned values are potential
    121     // problem cases. We want to explicitly return these values from
    122     // our iterator.
    123     if (num_ < 0x7FFFFFFFu)
    124       return 0x7FFFFFFFu;
    125     if (num_ < 0x80000000u)
    126       return 0x80000000u;
    127 
    128     if (num_ < 0xFFFFFFFFu)
    129       return 0xFFFFFFFFu;
    130   }
    131 
    132   return 0;
    133 }
    134 
    135 bool operator==(const SyscallSet::Iterator& lhs,
    136                 const SyscallSet::Iterator& rhs) {
    137   DCHECK(lhs.set_ == rhs.set_);
    138   return (lhs.done_ == rhs.done_) && (lhs.num_ == rhs.num_);
    139 }
    140 
    141 bool operator!=(const SyscallSet::Iterator& lhs,
    142                 const SyscallSet::Iterator& rhs) {
    143   return !(lhs == rhs);
    144 }
    145 
    146 }  // namespace sandbox
    147