| OLD | NEW |
| 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 <stddef.h> | 8 #include <stddef.h> |
| 9 #include <stdint.h> | 9 #include <stdint.h> |
| 10 #include <sys/syscall.h> | 10 #include <sys/syscall.h> |
| (...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 94 panic_func_(DefaultPanic), | 94 panic_func_(DefaultPanic), |
| 95 gen_(), | 95 gen_(), |
| 96 has_unsafe_traps_(HasUnsafeTraps(policy_)) { | 96 has_unsafe_traps_(HasUnsafeTraps(policy_)) { |
| 97 DCHECK(policy); | 97 DCHECK(policy); |
| 98 } | 98 } |
| 99 | 99 |
| 100 PolicyCompiler::~PolicyCompiler() { | 100 PolicyCompiler::~PolicyCompiler() { |
| 101 } | 101 } |
| 102 | 102 |
| 103 CodeGen::Program PolicyCompiler::Compile() { | 103 CodeGen::Program PolicyCompiler::Compile() { |
| 104 CHECK(policy_->InvalidSyscall()->IsDeny()) | 104 // Policies should deny invalid system calls |
| 105 << "Policies should deny invalid system calls"; | 105 CHECK(policy_->InvalidSyscall()->IsDeny()); |
| 106 | 106 |
| 107 // If our BPF program has unsafe traps, enable support for them. | 107 // If our BPF program has unsafe traps, enable support for them. |
| 108 if (has_unsafe_traps_) { | 108 if (has_unsafe_traps_) { |
| 109 CHECK_NE(0U, escapepc_) << "UnsafeTrap() requires a valid escape PC"; | 109 // UnsafeTrap() requires a valid escape PC |
| 110 CHECK_NE(0U, escapepc_); |
| 110 | 111 |
| 111 for (int sysnum : kSyscallsRequiredForUnsafeTraps) { | 112 for (int sysnum : kSyscallsRequiredForUnsafeTraps) { |
| 112 CHECK(policy_->EvaluateSyscall(sysnum)->IsAllow()) | 113 // Policies that use UnsafeTrap() must unconditionally allow all required |
| 113 << "Policies that use UnsafeTrap() must unconditionally allow all " | 114 // system calls |
| 114 "required system calls"; | 115 CHECK(policy_->EvaluateSyscall(sysnum)->IsAllow()); |
| 115 } | 116 } |
| 116 | 117 |
| 117 CHECK(registry_->EnableUnsafeTraps()) | 118 // We'd rather die than enable unsafe traps |
| 118 << "We'd rather die than enable unsafe traps"; | 119 CHECK(registry_->EnableUnsafeTraps()); |
| 119 } | 120 } |
| 120 | 121 |
| 121 // Assemble the BPF filter program. | 122 // Assemble the BPF filter program. |
| 122 return gen_.Compile(AssemblePolicy()); | 123 return gen_.Compile(AssemblePolicy()); |
| 123 } | 124 } |
| 124 | 125 |
| 125 void PolicyCompiler::DangerousSetEscapePC(uint64_t escapepc) { | 126 void PolicyCompiler::DangerousSetEscapePC(uint64_t escapepc) { |
| 126 escapepc_ = escapepc; | 127 escapepc_ = escapepc; |
| 127 } | 128 } |
| 128 | 129 |
| (...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 247 } | 248 } |
| 248 ranges->push_back(Range{old_sysnum, old_node}); | 249 ranges->push_back(Range{old_sysnum, old_node}); |
| 249 } | 250 } |
| 250 | 251 |
| 251 CodeGen::Node PolicyCompiler::AssembleJumpTable(Ranges::const_iterator start, | 252 CodeGen::Node PolicyCompiler::AssembleJumpTable(Ranges::const_iterator start, |
| 252 Ranges::const_iterator stop) { | 253 Ranges::const_iterator stop) { |
| 253 // We convert the list of system call ranges into jump table that performs | 254 // We convert the list of system call ranges into jump table that performs |
| 254 // a binary search over the ranges. | 255 // a binary search over the ranges. |
| 255 // As a sanity check, we need to have at least one distinct ranges for us | 256 // As a sanity check, we need to have at least one distinct ranges for us |
| 256 // to be able to build a jump table. | 257 // to be able to build a jump table. |
| 257 CHECK(start < stop) << "Invalid iterator range"; | 258 // Invalid iterator range |
| 259 CHECK(start < stop); |
| 258 const auto n = stop - start; | 260 const auto n = stop - start; |
| 259 if (n == 1) { | 261 if (n == 1) { |
| 260 // If we have narrowed things down to a single range object, we can | 262 // If we have narrowed things down to a single range object, we can |
| 261 // return from the BPF filter program. | 263 // return from the BPF filter program. |
| 262 return start->node; | 264 return start->node; |
| 263 } | 265 } |
| 264 | 266 |
| 265 // Pick the range object that is located at the mid point of our list. | 267 // Pick the range object that is located at the mid point of our list. |
| 266 // We compare our system call number against the lowest valid system call | 268 // We compare our system call number against the lowest valid system call |
| 267 // number in this range object. If our number is lower, it is outside of | 269 // number in this range object. If our number is lower, it is outside of |
| (...skipping 10 matching lines...) Expand all Loading... |
| 278 return res->Compile(this); | 280 return res->Compile(this); |
| 279 } | 281 } |
| 280 | 282 |
| 281 CodeGen::Node PolicyCompiler::MaskedEqual(int argno, | 283 CodeGen::Node PolicyCompiler::MaskedEqual(int argno, |
| 282 size_t width, | 284 size_t width, |
| 283 uint64_t mask, | 285 uint64_t mask, |
| 284 uint64_t value, | 286 uint64_t value, |
| 285 CodeGen::Node passed, | 287 CodeGen::Node passed, |
| 286 CodeGen::Node failed) { | 288 CodeGen::Node failed) { |
| 287 // Sanity check that arguments make sense. | 289 // Sanity check that arguments make sense. |
| 288 CHECK(argno >= 0 && argno < 6) << "Invalid argument number " << argno; | 290 // Invalid argument number |argno| |
| 289 CHECK(width == 4 || width == 8) << "Invalid argument width " << width; | 291 CHECK(argno >= 0 && argno < 6); |
| 290 CHECK_NE(0U, mask) << "Zero mask is invalid"; | 292 // Invalid argument width |width| |
| 291 CHECK_EQ(value, value & mask) << "Value contains masked out bits"; | 293 CHECK(width == 4 || width == 8); |
| 294 // Zero mask is invalid |
| 295 CHECK_NE(0U, mask); |
| 296 // Value contains masked out bits |
| 297 CHECK_EQ(value, value & mask); |
| 292 if (sizeof(void*) == 4) { | 298 if (sizeof(void*) == 4) { |
| 293 CHECK_EQ(4U, width) << "Invalid width on 32-bit platform"; | 299 // Invalid width on 32-bit platform |
| 300 CHECK_EQ(4U, width); |
| 294 } | 301 } |
| 295 if (width == 4) { | 302 if (width == 4) { |
| 296 CHECK_EQ(0U, mask >> 32) << "Mask exceeds argument size"; | 303 // Mask exceeds argument size |
| 297 CHECK_EQ(0U, value >> 32) << "Value exceeds argument size"; | 304 CHECK_EQ(0U, mask >> 32); |
| 305 // Value exceeds argument size |
| 306 CHECK_EQ(0U, value >> 32); |
| 298 } | 307 } |
| 299 | 308 |
| 300 // 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 |
| 301 // 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 |
| 302 // 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 |
| 303 // |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. |
| 304 return MaskedEqualHalf(argno, width, mask, value, ArgHalf::UPPER, | 313 return MaskedEqualHalf(argno, width, mask, value, ArgHalf::UPPER, |
| 305 MaskedEqualHalf(argno, width, mask, value, | 314 MaskedEqualHalf(argno, width, mask, value, |
| 306 ArgHalf::LOWER, passed, failed), | 315 ArgHalf::LOWER, passed, failed), |
| 307 failed); | 316 failed); |
| (...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 457 for (size_t i = 0; i < arraysize(kSyscallsRequiredForUnsafeTraps); ++i) { | 466 for (size_t i = 0; i < arraysize(kSyscallsRequiredForUnsafeTraps); ++i) { |
| 458 if (sysno == kSyscallsRequiredForUnsafeTraps[i]) { | 467 if (sysno == kSyscallsRequiredForUnsafeTraps[i]) { |
| 459 return true; | 468 return true; |
| 460 } | 469 } |
| 461 } | 470 } |
| 462 return false; | 471 return false; |
| 463 } | 472 } |
| 464 | 473 |
| 465 } // namespace bpf_dsl | 474 } // namespace bpf_dsl |
| 466 } // namespace sandbox | 475 } // namespace sandbox |
| OLD | NEW |