| // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "sandbox/linux/bpf_dsl/syscall_set.h" |
| |
| #include "base/logging.h" |
| #include "base/macros.h" |
| #include "sandbox/linux/bpf_dsl/linux_syscall_ranges.h" |
| |
| namespace sandbox { |
| |
| namespace { |
| |
| #if defined(__mips__) && (_MIPS_SIM == _MIPS_SIM_ABI32) |
| // This is true for Mips O32 ABI. |
| static_assert(MIN_SYSCALL == __NR_Linux, "min syscall number should be 4000"); |
| #else |
| // This true for supported architectures (Intel and ARM EABI). |
| static_assert(MIN_SYSCALL == 0u, |
| "min syscall should always be zero"); |
| #endif |
| |
| // SyscallRange represents an inclusive range of system call numbers. |
| struct SyscallRange { |
| uint32_t first; |
| uint32_t last; |
| }; |
| |
| const SyscallRange kValidSyscallRanges[] = { |
| // First we iterate up to MAX_PUBLIC_SYSCALL, which is equal to MAX_SYSCALL |
| // on Intel architectures, but leaves room for private syscalls on ARM. |
| {MIN_SYSCALL, MAX_PUBLIC_SYSCALL}, |
| #if defined(__arm__) |
| // ARM EABI includes "ARM private" system calls starting at |
| // MIN_PRIVATE_SYSCALL, and a "ghost syscall private to the kernel" at |
| // MIN_GHOST_SYSCALL. |
| {MIN_PRIVATE_SYSCALL, MAX_PRIVATE_SYSCALL}, |
| {MIN_GHOST_SYSCALL, MAX_SYSCALL}, |
| #endif |
| }; |
| |
| } // namespace |
| |
| SyscallSet::Iterator SyscallSet::begin() const { |
| return Iterator(set_, false); |
| } |
| |
| SyscallSet::Iterator SyscallSet::end() const { |
| return Iterator(set_, true); |
| } |
| |
| bool SyscallSet::IsValid(uint32_t num) { |
| for (const SyscallRange& range : kValidSyscallRanges) { |
| if (num >= range.first && num <= range.last) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| bool operator==(const SyscallSet& lhs, const SyscallSet& rhs) { |
| return (lhs.set_ == rhs.set_); |
| } |
| |
| SyscallSet::Iterator::Iterator(Set set, bool done) |
| : set_(set), done_(done), num_(0) { |
| // If the set doesn't contain 0, we need to skip to the next element. |
| if (!done && set_ == (IsValid(num_) ? Set::INVALID_ONLY : Set::VALID_ONLY)) { |
| ++*this; |
| } |
| } |
| |
| uint32_t SyscallSet::Iterator::operator*() const { |
| DCHECK(!done_); |
| return num_; |
| } |
| |
| SyscallSet::Iterator& SyscallSet::Iterator::operator++() { |
| DCHECK(!done_); |
| |
| num_ = NextSyscall(); |
| if (num_ == 0) { |
| done_ = true; |
| } |
| |
| return *this; |
| } |
| |
| // NextSyscall returns the next system call in the iterated system |
| // call set after |num_|, or 0 if no such system call exists. |
| uint32_t SyscallSet::Iterator::NextSyscall() const { |
| const bool want_valid = (set_ != Set::INVALID_ONLY); |
| const bool want_invalid = (set_ != Set::VALID_ONLY); |
| |
| for (const SyscallRange& range : kValidSyscallRanges) { |
| if (want_invalid && range.first > 0 && num_ < range.first - 1) { |
| // Even when iterating invalid syscalls, we only include the end points; |
| // so skip directly to just before the next (valid) range. |
| return range.first - 1; |
| } |
| if (want_valid && num_ < range.first) { |
| return range.first; |
| } |
| if (want_valid && num_ < range.last) { |
| return num_ + 1; |
| } |
| if (want_invalid && num_ <= range.last) { |
| return range.last + 1; |
| } |
| } |
| |
| if (want_invalid) { |
| // BPF programs only ever operate on unsigned quantities. So, |
| // that's how we iterate; we return values from |
| // 0..0xFFFFFFFFu. But there are places, where the kernel might |
| // interpret system call numbers as signed quantities, so the |
| // boundaries between signed and unsigned values are potential |
| // problem cases. We want to explicitly return these values from |
| // our iterator. |
| if (num_ < 0x7FFFFFFFu) |
| return 0x7FFFFFFFu; |
| if (num_ < 0x80000000u) |
| return 0x80000000u; |
| |
| if (num_ < 0xFFFFFFFFu) |
| return 0xFFFFFFFFu; |
| } |
| |
| return 0; |
| } |
| |
| bool operator==(const SyscallSet::Iterator& lhs, |
| const SyscallSet::Iterator& rhs) { |
| DCHECK(lhs.set_ == rhs.set_); |
| return (lhs.done_ == rhs.done_) && (lhs.num_ == rhs.num_); |
| } |
| |
| bool operator!=(const SyscallSet::Iterator& lhs, |
| const SyscallSet::Iterator& rhs) { |
| return !(lhs == rhs); |
| } |
| |
| } // namespace sandbox |