Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(82)

Side by Side Diff: sandbox/linux/bpf_dsl/policy_compiler.cc

Issue 945743002: bpf_dsl: switch PolicyCompiler from seccomp-bpf/die.h to base/logging.h (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | sandbox/linux/bpf_dsl/trap_registry.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "sandbox/linux/bpf_dsl/policy_compiler.h" 5 #include "sandbox/linux/bpf_dsl/policy_compiler.h"
6 6
7 #include <errno.h> 7 #include <errno.h>
8 #include <linux/filter.h> 8 #include <linux/filter.h>
9 #include <sys/syscall.h> 9 #include <sys/syscall.h>
10 10
11 #include <limits> 11 #include <limits>
12 12
13 #include "base/logging.h" 13 #include "base/logging.h"
14 #include "base/macros.h" 14 #include "base/macros.h"
15 #include "sandbox/linux/bpf_dsl/bpf_dsl.h" 15 #include "sandbox/linux/bpf_dsl/bpf_dsl.h"
16 #include "sandbox/linux/bpf_dsl/bpf_dsl_impl.h" 16 #include "sandbox/linux/bpf_dsl/bpf_dsl_impl.h"
17 #include "sandbox/linux/bpf_dsl/codegen.h" 17 #include "sandbox/linux/bpf_dsl/codegen.h"
18 #include "sandbox/linux/bpf_dsl/policy.h" 18 #include "sandbox/linux/bpf_dsl/policy.h"
19 #include "sandbox/linux/bpf_dsl/seccomp_macros.h" 19 #include "sandbox/linux/bpf_dsl/seccomp_macros.h"
20 #include "sandbox/linux/bpf_dsl/syscall_set.h" 20 #include "sandbox/linux/bpf_dsl/syscall_set.h"
21 #include "sandbox/linux/seccomp-bpf/die.h"
22 #include "sandbox/linux/seccomp-bpf/errorcode.h" 21 #include "sandbox/linux/seccomp-bpf/errorcode.h"
23 #include "sandbox/linux/system_headers/linux_seccomp.h" 22 #include "sandbox/linux/system_headers/linux_seccomp.h"
24 23
25 namespace sandbox { 24 namespace sandbox {
26 namespace bpf_dsl { 25 namespace bpf_dsl {
27 26
28 namespace { 27 namespace {
29 28
30 #if defined(__i386__) || defined(__x86_64__) 29 #if defined(__i386__) || defined(__x86_64__)
31 const bool kIsIntel = true; 30 const bool kIsIntel = true;
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after
89 conds_(), 88 conds_(),
90 gen_(), 89 gen_(),
91 has_unsafe_traps_(HasUnsafeTraps(policy_)) { 90 has_unsafe_traps_(HasUnsafeTraps(policy_)) {
92 DCHECK(policy); 91 DCHECK(policy);
93 } 92 }
94 93
95 PolicyCompiler::~PolicyCompiler() { 94 PolicyCompiler::~PolicyCompiler() {
96 } 95 }
97 96
98 scoped_ptr<CodeGen::Program> PolicyCompiler::Compile() { 97 scoped_ptr<CodeGen::Program> PolicyCompiler::Compile() {
99 if (!policy_->InvalidSyscall()->IsDeny()) { 98 CHECK(policy_->InvalidSyscall()->IsDeny())
100 SANDBOX_DIE("Policies should deny invalid system calls."); 99 << "Policies should deny invalid system calls";
101 }
102 100
103 // If our BPF program has unsafe traps, enable support for them. 101 // If our BPF program has unsafe traps, enable support for them.
104 if (has_unsafe_traps_) { 102 if (has_unsafe_traps_) {
105 // As support for unsafe jumps essentially defeats all the security
106 // measures that the sandbox provides, we print a big warning message --
107 // and of course, we make sure to only ever enable this feature if it
108 // is actually requested by the sandbox policy.
109
110 CHECK_NE(0U, escapepc_) << "UnsafeTrap() requires a valid escape PC"; 103 CHECK_NE(0U, escapepc_) << "UnsafeTrap() requires a valid escape PC";
111 104
112 for (int sysnum : kSyscallsRequiredForUnsafeTraps) { 105 for (int sysnum : kSyscallsRequiredForUnsafeTraps) {
113 if (!policy_->EvaluateSyscall(sysnum)->IsAllow()) { 106 CHECK(policy_->EvaluateSyscall(sysnum)->IsAllow())
114 SANDBOX_DIE( 107 << "Policies that use UnsafeTrap() must unconditionally allow all "
115 "Policies that use UnsafeTrap() must unconditionally allow all " 108 "required system calls";
116 "required system calls");
117 }
118 } 109 }
119 110
120 if (!registry_->EnableUnsafeTraps()) { 111 CHECK(registry_->EnableUnsafeTraps())
121 // We should never be able to get here, as UnsafeTrap() should never 112 << "We'd rather die than enable unsafe traps";
122 // actually return a valid ErrorCode object unless the user set the
123 // CHROME_SANDBOX_DEBUGGING environment variable; and therefore,
124 // "has_unsafe_traps" would always be false. But better double-check
125 // than enabling dangerous code.
126 SANDBOX_DIE("We'd rather die than enable unsafe traps");
127 }
128 } 113 }
129 114
130 // Assemble the BPF filter program. 115 // Assemble the BPF filter program.
131 scoped_ptr<CodeGen::Program> program(new CodeGen::Program()); 116 scoped_ptr<CodeGen::Program> program(new CodeGen::Program());
132 gen_.Compile(AssemblePolicy(), program.get()); 117 gen_.Compile(AssemblePolicy(), program.get());
133 return program.Pass(); 118 return program.Pass();
134 } 119 }
135 120
136 void PolicyCompiler::DangerousSetEscapePC(uint64_t escapepc) { 121 void PolicyCompiler::DangerousSetEscapePC(uint64_t escapepc) {
137 escapepc_ = escapepc; 122 escapepc_ = escapepc;
(...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after
254 } 239 }
255 ranges->push_back(Range{old_sysnum, old_node}); 240 ranges->push_back(Range{old_sysnum, old_node});
256 } 241 }
257 242
258 CodeGen::Node PolicyCompiler::AssembleJumpTable(Ranges::const_iterator start, 243 CodeGen::Node PolicyCompiler::AssembleJumpTable(Ranges::const_iterator start,
259 Ranges::const_iterator stop) { 244 Ranges::const_iterator stop) {
260 // We convert the list of system call ranges into jump table that performs 245 // We convert the list of system call ranges into jump table that performs
261 // a binary search over the ranges. 246 // a binary search over the ranges.
262 // As a sanity check, we need to have at least one distinct ranges for us 247 // As a sanity check, we need to have at least one distinct ranges for us
263 // to be able to build a jump table. 248 // to be able to build a jump table.
264 if (stop - start <= 0) { 249 CHECK(start < stop) << "Invalid iterator range";
265 SANDBOX_DIE("Invalid set of system call ranges"); 250 const auto n = stop - start;
266 } else if (stop - start == 1) { 251 if (n == 1) {
267 // If we have narrowed things down to a single range object, we can 252 // If we have narrowed things down to a single range object, we can
268 // return from the BPF filter program. 253 // return from the BPF filter program.
269 return start->node; 254 return start->node;
270 } 255 }
271 256
272 // Pick the range object that is located at the mid point of our list. 257 // Pick the range object that is located at the mid point of our list.
273 // We compare our system call number against the lowest valid system call 258 // We compare our system call number against the lowest valid system call
274 // number in this range object. If our number is lower, it is outside of 259 // number in this range object. If our number is lower, it is outside of
275 // this range object. If it is greater or equal, it might be inside. 260 // this range object. If it is greater or equal, it might be inside.
276 Ranges::const_iterator mid = start + (stop - start) / 2; 261 Ranges::const_iterator mid = start + n / 2;
277 262
278 // Sub-divide the list of ranges and continue recursively. 263 // Sub-divide the list of ranges and continue recursively.
279 CodeGen::Node jf = AssembleJumpTable(start, mid); 264 CodeGen::Node jf = AssembleJumpTable(start, mid);
280 CodeGen::Node jt = AssembleJumpTable(mid, stop); 265 CodeGen::Node jt = AssembleJumpTable(mid, stop);
281 return gen_.MakeInstruction(BPF_JMP + BPF_JGE + BPF_K, mid->from, jt, jf); 266 return gen_.MakeInstruction(BPF_JMP + BPF_JGE + BPF_K, mid->from, jt, jf);
282 } 267 }
283 268
284 CodeGen::Node PolicyCompiler::CompileResult(const ResultExpr& res) { 269 CodeGen::Node PolicyCompiler::CompileResult(const ResultExpr& res) {
285 return RetExpression(res->Compile(this)); 270 return RetExpression(res->Compile(this));
286 } 271 }
287 272
288 CodeGen::Node PolicyCompiler::RetExpression(const ErrorCode& err) { 273 CodeGen::Node PolicyCompiler::RetExpression(const ErrorCode& err) {
289 switch (err.error_type()) { 274 switch (err.error_type()) {
290 case ErrorCode::ET_COND: 275 case ErrorCode::ET_COND:
291 return CondExpression(err); 276 return CondExpression(err);
292 case ErrorCode::ET_SIMPLE: 277 case ErrorCode::ET_SIMPLE:
293 case ErrorCode::ET_TRAP: 278 case ErrorCode::ET_TRAP:
294 return gen_.MakeInstruction(BPF_RET + BPF_K, err.err()); 279 return gen_.MakeInstruction(BPF_RET + BPF_K, err.err());
295 default: 280 default:
296 SANDBOX_DIE("ErrorCode is not suitable for returning from a BPF program"); 281 LOG(FATAL)
282 << "ErrorCode is not suitable for returning from a BPF program";
283 return CodeGen::kNullNode;
297 } 284 }
298 } 285 }
299 286
300 CodeGen::Node PolicyCompiler::CondExpression(const ErrorCode& cond) { 287 CodeGen::Node PolicyCompiler::CondExpression(const ErrorCode& cond) {
301 // Sanity check that |cond| makes sense. 288 // Sanity check that |cond| makes sense.
302 if (cond.argno_ < 0 || cond.argno_ >= 6) { 289 CHECK(cond.argno_ >= 0 && cond.argno_ < 6) << "Invalid argument number "
303 SANDBOX_DIE("sandbox_bpf: invalid argument number"); 290 << cond.argno_;
291 CHECK(cond.width_ == ErrorCode::TP_32BIT ||
292 cond.width_ == ErrorCode::TP_64BIT)
293 << "Invalid argument width " << cond.width_;
294 CHECK_NE(0U, cond.mask_) << "Zero mask is invalid";
295 CHECK_EQ(cond.value_, cond.value_ & cond.mask_)
296 << "Value contains masked out bits";
297 if (sizeof(void*) == 4) {
298 CHECK_EQ(ErrorCode::TP_32BIT, cond.width_)
299 << "Invalid width on 32-bit platform";
304 } 300 }
305 if (cond.width_ != ErrorCode::TP_32BIT && 301 if (cond.width_ == ErrorCode::TP_32BIT) {
306 cond.width_ != ErrorCode::TP_64BIT) { 302 CHECK_EQ(0U, cond.mask_ >> 32) << "Mask exceeds argument size";
307 SANDBOX_DIE("sandbox_bpf: invalid argument width"); 303 CHECK_EQ(0U, cond.value_ >> 32) << "Value exceeds argument size";
308 } 304 }
309 if (cond.mask_ == 0) {
310 SANDBOX_DIE("sandbox_bpf: zero mask is invalid");
311 }
312 if ((cond.value_ & cond.mask_) != cond.value_) {
313 SANDBOX_DIE("sandbox_bpf: value contains masked out bits");
314 }
315 if (cond.width_ == ErrorCode::TP_32BIT &&
316 ((cond.mask_ >> 32) != 0 || (cond.value_ >> 32) != 0)) {
317 SANDBOX_DIE("sandbox_bpf: test exceeds argument size");
318 }
319 // TODO(mdempsky): Reject TP_64BIT on 32-bit platforms. For now we allow it
320 // because some SandboxBPF unit tests exercise it.
jln (very slow on Chromium) 2015/02/20 07:00:44 So these disappeared? Cool, but I don't remember :
321 305
322 CodeGen::Node passed = RetExpression(*cond.passed_); 306 CodeGen::Node passed = RetExpression(*cond.passed_);
323 CodeGen::Node failed = RetExpression(*cond.failed_); 307 CodeGen::Node failed = RetExpression(*cond.failed_);
324 308
325 // We want to emit code to check "(arg & mask) == value" where arg, mask, and 309 // We want to emit code to check "(arg & mask) == value" where arg, mask, and
326 // value are 64-bit values, but the BPF machine is only 32-bit. We implement 310 // value are 64-bit values, but the BPF machine is only 32-bit. We implement
327 // this by independently testing the upper and lower 32-bits and continuing to 311 // this by independently testing the upper and lower 32-bits and continuing to
328 // |passed| if both evaluate true, or to |failed| if either evaluate false. 312 // |passed| if both evaluate true, or to |failed| if either evaluate false.
329 return CondExpressionHalf(cond, 313 return CondExpressionHalf(cond,
330 UpperHalf, 314 UpperHalf,
(...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after
491 return ErrorCode(argno, 475 return ErrorCode(argno,
492 width, 476 width,
493 mask, 477 mask,
494 value, 478 value,
495 &*conds_.insert(passed).first, 479 &*conds_.insert(passed).first,
496 &*conds_.insert(failed).first); 480 &*conds_.insert(failed).first);
497 } 481 }
498 482
499 } // namespace bpf_dsl 483 } // namespace bpf_dsl
500 } // namespace sandbox 484 } // namespace sandbox
OLDNEW
« no previous file with comments | « no previous file | sandbox/linux/bpf_dsl/trap_registry.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698