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
begin() const47 SyscallSet::Iterator SyscallSet::begin() const {
48 return Iterator(set_, false);
49 }
50
end() const51 SyscallSet::Iterator SyscallSet::end() const {
52 return Iterator(set_, true);
53 }
54
IsValid(uint32_t num)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
operator ==(const SyscallSet & lhs,const SyscallSet & rhs)64 bool operator==(const SyscallSet& lhs, const SyscallSet& rhs) {
65 return (lhs.set_ == rhs.set_);
66 }
67
Iterator(Set set,bool done)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
operator *() const76 uint32_t SyscallSet::Iterator::operator*() const {
77 DCHECK(!done_);
78 return num_;
79 }
80
operator ++()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.
NextSyscall() const94 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
operator ==(const SyscallSet::Iterator & lhs,const SyscallSet::Iterator & rhs)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
operator !=(const SyscallSet::Iterator & lhs,const SyscallSet::Iterator & rhs)141 bool operator!=(const SyscallSet::Iterator& lhs,
142 const SyscallSet::Iterator& rhs) {
143 return !(lhs == rhs);
144 }
145
146 } // namespace sandbox
147