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