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