summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormdempsky <mdempsky@chromium.org>2014-10-21 21:45:57 -0700
committerCommit bot <commit-bot@chromium.org>2014-10-22 04:46:13 +0000
commit2e58094a81b0291aa2b6f12c99cb2653c361d8a0 (patch)
tree678c96746789adb556533667be65176d01a2f762
parent558a1c9d789332e0151c989963f6517b29455f4b (diff)
downloadchromium_src-2e58094a81b0291aa2b6f12c99cb2653c361d8a0.zip
chromium_src-2e58094a81b0291aa2b6f12c99cb2653c361d8a0.tar.gz
chromium_src-2e58094a81b0291aa2b6f12c99cb2653c361d8a0.tar.bz2
SyscallIterator: support C++11 range-based for loops
Also remove the superfluous "to" field in PolicyCompiler::Range, and fix the next-syscall-number calculation so we can remove the loop in SyscallIterator::operator++() (nee SyscallIterator::Next()). BUG=414363 Review URL: https://codereview.chromium.org/659723002 Cr-Commit-Position: refs/heads/master@{#300633}
-rw-r--r--sandbox/linux/bpf_dsl/policy_compiler.cc21
-rw-r--r--sandbox/linux/seccomp-bpf/sandbox_bpf.cc2
-rw-r--r--sandbox/linux/seccomp-bpf/syscall_iterator.cc68
-rw-r--r--sandbox/linux/seccomp-bpf/syscall_iterator.h72
-rw-r--r--sandbox/linux/seccomp-bpf/syscall_iterator_unittest.cc29
-rw-r--r--sandbox/linux/seccomp-bpf/verifier.cc5
6 files changed, 139 insertions, 58 deletions
diff --git a/sandbox/linux/bpf_dsl/policy_compiler.cc b/sandbox/linux/bpf_dsl/policy_compiler.cc
index ad100f9..0eb85ca 100644
--- a/sandbox/linux/bpf_dsl/policy_compiler.cc
+++ b/sandbox/linux/bpf_dsl/policy_compiler.cc
@@ -76,9 +76,8 @@ intptr_t BPFFailure(const struct arch_seccomp_data&, void* aux) {
}
bool HasUnsafeTraps(const SandboxBPFDSLPolicy* policy) {
- for (SyscallIterator iter(false); !iter.Done();) {
- uint32_t sysnum = iter.Next();
- if (SyscallIterator::IsValid(sysnum) &&
+ for (uint32_t sysnum : SyscallSet::All()) {
+ if (SyscallSet::IsValid(sysnum) &&
policy->EvaluateSyscall(sysnum)->HasUnsafeTraps()) {
return true;
}
@@ -89,8 +88,8 @@ bool HasUnsafeTraps(const SandboxBPFDSLPolicy* policy) {
} // namespace
struct PolicyCompiler::Range {
- Range(uint32_t f, uint32_t t, const ErrorCode& e) : from(f), to(t), err(e) {}
- uint32_t from, to;
+ Range(uint32_t f, const ErrorCode& e) : from(f), err(e) {}
+ uint32_t from;
ErrorCode err;
};
@@ -252,22 +251,22 @@ void PolicyCompiler::FindRanges(Ranges* ranges) {
// negative) all return the same ErrorCode.
const ErrorCode invalid_err = policy_->InvalidSyscall()->Compile(this);
uint32_t old_sysnum = 0;
- ErrorCode old_err = SyscallIterator::IsValid(old_sysnum)
+ ErrorCode old_err = SyscallSet::IsValid(old_sysnum)
? policy_->EvaluateSyscall(old_sysnum)->Compile(this)
: invalid_err;
- for (SyscallIterator iter(false); !iter.Done();) {
- uint32_t sysnum = iter.Next();
+ for (uint32_t sysnum : SyscallSet::All()) {
ErrorCode err =
- SyscallIterator::IsValid(sysnum)
+ SyscallSet::IsValid(sysnum)
? policy_->EvaluateSyscall(static_cast<int>(sysnum))->Compile(this)
: invalid_err;
- if (!err.Equals(old_err) || iter.Done()) {
- ranges->push_back(Range(old_sysnum, sysnum - 1, old_err));
+ if (!err.Equals(old_err)) {
+ ranges->push_back(Range(old_sysnum, old_err));
old_sysnum = sysnum;
old_err = err;
}
}
+ ranges->push_back(Range(old_sysnum, old_err));
}
Instruction* PolicyCompiler::AssembleJumpTable(Ranges::const_iterator start,
diff --git a/sandbox/linux/seccomp-bpf/sandbox_bpf.cc b/sandbox/linux/seccomp-bpf/sandbox_bpf.cc
index f1073c1..8a9b3f7 100644
--- a/sandbox/linux/seccomp-bpf/sandbox_bpf.cc
+++ b/sandbox/linux/seccomp-bpf/sandbox_bpf.cc
@@ -150,7 +150,7 @@ SandboxBPF::~SandboxBPF() {
}
bool SandboxBPF::IsValidSyscallNumber(int sysnum) {
- return SyscallIterator::IsValid(sysnum);
+ return SyscallSet::IsValid(sysnum);
}
bool SandboxBPF::RunFunctionInPolicy(
diff --git a/sandbox/linux/seccomp-bpf/syscall_iterator.cc b/sandbox/linux/seccomp-bpf/syscall_iterator.cc
index 6701d50..1b4e0678 100644
--- a/sandbox/linux/seccomp-bpf/syscall_iterator.cc
+++ b/sandbox/linux/seccomp-bpf/syscall_iterator.cc
@@ -4,6 +4,7 @@
#include "sandbox/linux/seccomp-bpf/syscall_iterator.h"
+#include "base/logging.h"
#include "base/macros.h"
#include "sandbox/linux/seccomp-bpf/linux_seccomp.h"
@@ -38,14 +39,16 @@ const SyscallRange kValidSyscallRanges[] = {
#endif
};
+// NextSyscall returns the next system call in the specified system
+// call set after |cur|, or 0 if no such system call exists.
uint32_t NextSyscall(uint32_t cur, bool invalid_only) {
for (const SyscallRange& range : kValidSyscallRanges) {
if (range.first > 0 && cur < range.first - 1) {
return range.first - 1;
}
if (cur <= range.last) {
- if (invalid_only && cur < range.last) {
- return range.last;
+ if (invalid_only) {
+ return range.last + 1;
}
return cur + 1;
}
@@ -62,27 +65,22 @@ uint32_t NextSyscall(uint32_t cur, bool invalid_only) {
if (cur < 0x80000000u)
return 0x80000000u;
- return 0xFFFFFFFFu;
+ if (cur < 0xFFFFFFFFu)
+ return 0xFFFFFFFFu;
+ return 0;
}
} // namespace
-uint32_t SyscallIterator::Next() {
- if (done_) {
- return num_;
- }
-
- uint32_t val;
- do {
- val = num_;
- num_ = NextSyscall(num_, invalid_only_);
- } while (invalid_only_ && IsValid(val));
+SyscallSet::Iterator SyscallSet::begin() const {
+ return Iterator(set_, false);
+}
- done_ |= val == 0xFFFFFFFFu;
- return val;
+SyscallSet::Iterator SyscallSet::end() const {
+ return Iterator(set_, true);
}
-bool SyscallIterator::IsValid(uint32_t num) {
+bool SyscallSet::IsValid(uint32_t num) {
for (const SyscallRange& range : kValidSyscallRanges) {
if (num >= range.first && num <= range.last) {
return true;
@@ -91,4 +89,42 @@ bool SyscallIterator::IsValid(uint32_t num) {
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 (set_ == Set::INVALID_ONLY && !done_ && IsValid(num_)) {
+ ++*this;
+ }
+}
+
+uint32_t SyscallSet::Iterator::operator*() const {
+ DCHECK(!done_);
+ return num_;
+}
+
+SyscallSet::Iterator& SyscallSet::Iterator::operator++() {
+ DCHECK(!done_);
+
+ num_ = NextSyscall(num_, set_ == Set::INVALID_ONLY);
+ if (num_ == 0) {
+ done_ = true;
+ }
+
+ return *this;
+}
+
+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
diff --git a/sandbox/linux/seccomp-bpf/syscall_iterator.h b/sandbox/linux/seccomp-bpf/syscall_iterator.h
index 3796be5..d89b981 100644
--- a/sandbox/linux/seccomp-bpf/syscall_iterator.h
+++ b/sandbox/linux/seccomp-bpf/syscall_iterator.h
@@ -12,6 +12,8 @@
namespace sandbox {
+// TODO(mdempsky): Rename this header to syscall_set.h.
+
// Iterates over the entire system call range from 0..0xFFFFFFFFu. This
// iterator is aware of how system calls look like and will skip quickly
// over ranges that can't contain system calls. It iterates more slowly
@@ -20,35 +22,75 @@ namespace sandbox {
// first invalid value after a valid range of syscalls. It iterates over
// individual values whenever it is in the normal range for system calls
// (typically MIN_SYSCALL..MAX_SYSCALL).
-// If |invalid_only| is true, this iterator will only return invalid
-// syscall numbers, but will still skip quickly over invalid ranges,
-// returning the first invalid value in the range and then skipping
-// to the last invalid value in the range.
//
// Example usage:
-// for (SyscallIterator iter(false); !iter.Done(); ) {
-// uint32_t sysnum = iter.Next();
+// for (uint32_t sysnum : SyscallSet::All()) {
// // Do something with sysnum.
// }
-//
-// TODO(markus): Make this a classic C++ iterator.
-class SANDBOX_EXPORT SyscallIterator {
+class SANDBOX_EXPORT SyscallSet {
public:
- explicit SyscallIterator(bool invalid_only)
- : invalid_only_(invalid_only), done_(false), num_(0) {}
+ class Iterator;
+
+ SyscallSet(const SyscallSet& ss) : set_(ss.set_) {}
+ ~SyscallSet() {}
+
+ Iterator begin() const;
+ Iterator end() const;
+
+ // All returns a SyscallSet that contains both valid and invalid
+ // system call numbers.
+ static SyscallSet All() { return SyscallSet(Set::ALL); }
- bool Done() const { return done_; }
- uint32_t Next();
+ // InvalidOnly returns a SyscallSet that contains only invalid
+ // system call numbers, but still omits numbers in the middle of a
+ // range of invalid system call numbers.
+ static SyscallSet InvalidOnly() { return SyscallSet(Set::INVALID_ONLY); }
+
+ // IsValid returns whether |num| specifies a valid system call
+ // number.
static bool IsValid(uint32_t num);
private:
- bool invalid_only_;
+ enum class Set { ALL, INVALID_ONLY };
+
+ explicit SyscallSet(Set set) : set_(set) {}
+
+ Set set_;
+
+ friend bool operator==(const SyscallSet&, const SyscallSet&);
+ DISALLOW_ASSIGN(SyscallSet);
+};
+
+SANDBOX_EXPORT bool operator==(const SyscallSet& lhs, const SyscallSet& rhs);
+
+// Iterator provides C++ input iterator semantics for traversing a
+// SyscallSet.
+class SyscallSet::Iterator {
+ public:
+ Iterator(const Iterator& it)
+ : set_(it.set_), done_(it.done_), num_(it.num_) {}
+ ~Iterator() {}
+
+ uint32_t operator*() const;
+ Iterator& operator++();
+
+ private:
+ Iterator(Set set, bool done);
+
+ Set set_;
bool done_;
uint32_t num_;
- DISALLOW_IMPLICIT_CONSTRUCTORS(SyscallIterator);
+ friend SyscallSet;
+ friend bool operator==(const Iterator&, const Iterator&);
+ DISALLOW_ASSIGN(Iterator);
};
+SANDBOX_EXPORT bool operator==(const SyscallSet::Iterator& lhs,
+ const SyscallSet::Iterator& rhs);
+SANDBOX_EXPORT bool operator!=(const SyscallSet::Iterator& lhs,
+ const SyscallSet::Iterator& rhs);
+
} // namespace sandbox
#endif // SANDBOX_LINUX_SECCOMP_BPF_SYSCALL_ITERATOR_H__
diff --git a/sandbox/linux/seccomp-bpf/syscall_iterator_unittest.cc b/sandbox/linux/seccomp-bpf/syscall_iterator_unittest.cc
index b01bfc6..e277f86 100644
--- a/sandbox/linux/seccomp-bpf/syscall_iterator_unittest.cc
+++ b/sandbox/linux/seccomp-bpf/syscall_iterator_unittest.cc
@@ -13,18 +13,19 @@ namespace sandbox {
namespace {
-const bool kFalseTrue[] = {false, true};
+const SyscallSet kSyscallSets[] = {
+ SyscallSet::All(),
+ SyscallSet::InvalidOnly(),
+};
SANDBOX_TEST(SyscallIterator, Monotonous) {
- for (bool invalid_only : kFalseTrue) {
+ for (const SyscallSet& set : kSyscallSets) {
uint32_t prev = 0;
bool have_prev = false;
- for (SyscallIterator iter(invalid_only); !iter.Done();) {
- uint32_t sysnum = iter.Next();
-
+ for (uint32_t sysnum : set) {
if (have_prev) {
SANDBOX_ASSERT(sysnum > prev);
- } else if (!invalid_only) {
+ } else if (set == SyscallSet::All()) {
// The iterator should start at 0.
SANDBOX_ASSERT(sysnum == 0);
}
@@ -44,8 +45,7 @@ SANDBOX_TEST(SyscallIterator, Monotonous) {
void AssertRange(uint32_t min, uint32_t max) {
SANDBOX_ASSERT(min < max);
uint32_t prev = min - 1;
- for (SyscallIterator iter(false); !iter.Done();) {
- uint32_t sysnum = iter.Next();
+ for (uint32_t sysnum : SyscallSet::All()) {
if (sysnum >= min && sysnum <= max) {
SANDBOX_ASSERT(prev == sysnum - 1);
prev = sysnum;
@@ -80,11 +80,10 @@ SANDBOX_TEST(SyscallIterator, InvalidSyscalls) {
0xFFFFFFFFu,
};
- for (bool invalid_only : kFalseTrue) {
+ for (const SyscallSet& set : kSyscallSets) {
size_t i = 0;
- for (SyscallIterator iter(invalid_only); !iter.Done();) {
- uint32_t sysnum = iter.Next();
- if (!SyscallIterator::IsValid(sysnum)) {
+ for (uint32_t sysnum : set) {
+ if (!SyscallSet::IsValid(sysnum)) {
SANDBOX_ASSERT(i < arraysize(kExpected));
SANDBOX_ASSERT(kExpected[i] == sysnum);
++i;
@@ -94,6 +93,12 @@ SANDBOX_TEST(SyscallIterator, InvalidSyscalls) {
}
}
+SANDBOX_TEST(SyscallIterator, InvalidOnlyIsOnlyInvalid) {
+ for (uint32_t sysnum : SyscallSet::InvalidOnly()) {
+ SANDBOX_ASSERT(!SyscallSet::IsValid(sysnum));
+ }
+}
+
} // namespace
} // namespace sandbox
diff --git a/sandbox/linux/seccomp-bpf/verifier.cc b/sandbox/linux/seccomp-bpf/verifier.cc
index 707bc45..0c344b0 100644
--- a/sandbox/linux/seccomp-bpf/verifier.cc
+++ b/sandbox/linux/seccomp-bpf/verifier.cc
@@ -318,8 +318,7 @@ bool Verifier::VerifyBPF(bpf_dsl::PolicyCompiler* compiler,
const bpf_dsl::SandboxBPFDSLPolicy& policy,
const char** err) {
*err = NULL;
- for (SyscallIterator iter(false); !iter.Done();) {
- uint32_t sysnum = iter.Next();
+ for (uint32_t sysnum : SyscallSet::All()) {
// We ideally want to iterate over the full system call range and values
// just above and just below this range. This gives us the full result set
// of the "evaluators".
@@ -340,7 +339,7 @@ bool Verifier::VerifyBPF(bpf_dsl::PolicyCompiler* compiler,
}
#endif
#endif
- ErrorCode code = iter.IsValid(sysnum)
+ ErrorCode code = SyscallSet::IsValid(sysnum)
? policy.EvaluateSyscall(sysnum)->Compile(compiler)
: policy.InvalidSyscall()->Compile(compiler);
if (!VerifyErrorCode(compiler, program, &data, code, code, err)) {