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

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

Issue 939943002: bpf_dsl: decouple PolicyCompiler from Syscall (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: clang-format 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
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" 21 #include "sandbox/linux/seccomp-bpf/die.h"
22 #include "sandbox/linux/seccomp-bpf/errorcode.h" 22 #include "sandbox/linux/seccomp-bpf/errorcode.h"
23 #include "sandbox/linux/seccomp-bpf/syscall.h"
24 #include "sandbox/linux/system_headers/linux_seccomp.h" 23 #include "sandbox/linux/system_headers/linux_seccomp.h"
25 24
26 namespace sandbox { 25 namespace sandbox {
27 namespace bpf_dsl { 26 namespace bpf_dsl {
28 27
29 namespace { 28 namespace {
30 29
31 #if defined(__i386__) || defined(__x86_64__) 30 #if defined(__i386__) || defined(__x86_64__)
32 const bool kIsIntel = true; 31 const bool kIsIntel = true;
33 #else 32 #else
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
79 } // namespace 78 } // namespace
80 79
81 struct PolicyCompiler::Range { 80 struct PolicyCompiler::Range {
82 uint32_t from; 81 uint32_t from;
83 CodeGen::Node node; 82 CodeGen::Node node;
84 }; 83 };
85 84
86 PolicyCompiler::PolicyCompiler(const Policy* policy, TrapRegistry* registry) 85 PolicyCompiler::PolicyCompiler(const Policy* policy, TrapRegistry* registry)
87 : policy_(policy), 86 : policy_(policy),
88 registry_(registry), 87 registry_(registry),
88 escapepc_(0),
89 conds_(), 89 conds_(),
90 gen_(), 90 gen_(),
91 has_unsafe_traps_(HasUnsafeTraps(policy_)) { 91 has_unsafe_traps_(HasUnsafeTraps(policy_)) {
92 DCHECK(policy); 92 DCHECK(policy);
93 } 93 }
94 94
95 PolicyCompiler::~PolicyCompiler() { 95 PolicyCompiler::~PolicyCompiler() {
96 } 96 }
97 97
98 scoped_ptr<CodeGen::Program> PolicyCompiler::Compile() { 98 scoped_ptr<CodeGen::Program> PolicyCompiler::Compile() {
99 if (!policy_->InvalidSyscall()->IsDeny()) { 99 if (!policy_->InvalidSyscall()->IsDeny()) {
100 SANDBOX_DIE("Policies should deny invalid system calls."); 100 SANDBOX_DIE("Policies should deny invalid system calls.");
101 } 101 }
102 102
103 // If our BPF program has unsafe traps, enable support for them. 103 // If our BPF program has unsafe traps, enable support for them.
104 if (has_unsafe_traps_) { 104 if (has_unsafe_traps_) {
105 // As support for unsafe jumps essentially defeats all the security 105 // As support for unsafe jumps essentially defeats all the security
106 // measures that the sandbox provides, we print a big warning message -- 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 107 // and of course, we make sure to only ever enable this feature if it
108 // is actually requested by the sandbox policy. 108 // is actually requested by the sandbox policy.
109 if (Syscall::Call(-1) == -1 && errno == ENOSYS) { 109
110 SANDBOX_DIE( 110 CHECK_NE(0U, escapepc_) << "UnsafeTrap() requires a valid escape PC";
111 "Support for UnsafeTrap() has not yet been ported to this "
112 "architecture");
113 }
114 111
115 for (int sysnum : kSyscallsRequiredForUnsafeTraps) { 112 for (int sysnum : kSyscallsRequiredForUnsafeTraps) {
116 if (!policy_->EvaluateSyscall(sysnum)->IsAllow()) { 113 if (!policy_->EvaluateSyscall(sysnum)->IsAllow()) {
117 SANDBOX_DIE( 114 SANDBOX_DIE(
118 "Policies that use UnsafeTrap() must unconditionally allow all " 115 "Policies that use UnsafeTrap() must unconditionally allow all "
119 "required system calls"); 116 "required system calls");
120 } 117 }
121 } 118 }
122 119
123 if (!registry_->EnableUnsafeTraps()) { 120 if (!registry_->EnableUnsafeTraps()) {
124 // We should never be able to get here, as UnsafeTrap() should never 121 // We should never be able to get here, as UnsafeTrap() should never
125 // actually return a valid ErrorCode object unless the user set the 122 // actually return a valid ErrorCode object unless the user set the
126 // CHROME_SANDBOX_DEBUGGING environment variable; and therefore, 123 // CHROME_SANDBOX_DEBUGGING environment variable; and therefore,
127 // "has_unsafe_traps" would always be false. But better double-check 124 // "has_unsafe_traps" would always be false. But better double-check
128 // than enabling dangerous code. 125 // than enabling dangerous code.
129 SANDBOX_DIE("We'd rather die than enable unsafe traps"); 126 SANDBOX_DIE("We'd rather die than enable unsafe traps");
130 } 127 }
131 } 128 }
132 129
133 // Assemble the BPF filter program. 130 // Assemble the BPF filter program.
134 scoped_ptr<CodeGen::Program> program(new CodeGen::Program()); 131 scoped_ptr<CodeGen::Program> program(new CodeGen::Program());
135 gen_.Compile(AssemblePolicy(), program.get()); 132 gen_.Compile(AssemblePolicy(), program.get());
136 return program.Pass(); 133 return program.Pass();
137 } 134 }
138 135
136 void PolicyCompiler::DangerousSetEscapePC(uint64_t escapepc) {
137 escapepc_ = escapepc;
138 }
139
139 CodeGen::Node PolicyCompiler::AssemblePolicy() { 140 CodeGen::Node PolicyCompiler::AssemblePolicy() {
140 // A compiled policy consists of three logical parts: 141 // A compiled policy consists of three logical parts:
141 // 1. Check that the "arch" field matches the expected architecture. 142 // 1. Check that the "arch" field matches the expected architecture.
142 // 2. If the policy involves unsafe traps, check if the syscall was 143 // 2. If the policy involves unsafe traps, check if the syscall was
143 // invoked by Syscall::Call, and then allow it unconditionally. 144 // invoked by Syscall::Call, and then allow it unconditionally.
144 // 3. Check the system call number and jump to the appropriate compiled 145 // 3. Check the system call number and jump to the appropriate compiled
145 // system call policy number. 146 // system call policy number.
146 return CheckArch(MaybeAddEscapeHatch(DispatchSyscall())); 147 return CheckArch(MaybeAddEscapeHatch(DispatchSyscall()));
147 } 148 }
148 149
149 CodeGen::Node PolicyCompiler::CheckArch(CodeGen::Node passed) { 150 CodeGen::Node PolicyCompiler::CheckArch(CodeGen::Node passed) {
150 // If the architecture doesn't match SECCOMP_ARCH, disallow the 151 // If the architecture doesn't match SECCOMP_ARCH, disallow the
151 // system call. 152 // system call.
152 return gen_.MakeInstruction( 153 return gen_.MakeInstruction(
153 BPF_LD + BPF_W + BPF_ABS, SECCOMP_ARCH_IDX, 154 BPF_LD + BPF_W + BPF_ABS, SECCOMP_ARCH_IDX,
154 gen_.MakeInstruction( 155 gen_.MakeInstruction(
155 BPF_JMP + BPF_JEQ + BPF_K, SECCOMP_ARCH, passed, 156 BPF_JMP + BPF_JEQ + BPF_K, SECCOMP_ARCH, passed,
156 CompileResult(Kill("Invalid audit architecture in BPF filter")))); 157 CompileResult(Kill("Invalid audit architecture in BPF filter"))));
157 } 158 }
158 159
159 CodeGen::Node PolicyCompiler::MaybeAddEscapeHatch(CodeGen::Node rest) { 160 CodeGen::Node PolicyCompiler::MaybeAddEscapeHatch(CodeGen::Node rest) {
160 // If no unsafe traps, then simply return |rest|. 161 // If no unsafe traps, then simply return |rest|.
161 if (!has_unsafe_traps_) { 162 if (!has_unsafe_traps_) {
162 return rest; 163 return rest;
163 } 164 }
164 165
165 // Allow system calls, if they originate from our magic return address 166 // We already enabled unsafe traps in Compile, but enable them again to give
166 // (which we can query by calling Syscall::Call(-1)). 167 // the trap registry a second chance to complain before we add the backdoor.
167 uint64_t syscall_entry_point = 168 CHECK(registry_->EnableUnsafeTraps());
168 static_cast<uint64_t>(static_cast<uintptr_t>(Syscall::Call(-1))); 169
169 uint32_t low = static_cast<uint32_t>(syscall_entry_point); 170 // Allow system calls, if they originate from our magic return address.
170 uint32_t hi = static_cast<uint32_t>(syscall_entry_point >> 32); 171 const uint32_t lopc = static_cast<uint32_t>(escapepc_);
172 const uint32_t hipc = static_cast<uint32_t>(escapepc_ >> 32);
171 173
172 // BPF cannot do native 64-bit comparisons, so we have to compare 174 // BPF cannot do native 64-bit comparisons, so we have to compare
173 // both 32-bit halves of the instruction pointer. If they match what 175 // both 32-bit halves of the instruction pointer. If they match what
174 // we expect, we return ERR_ALLOWED. If either or both don't match, 176 // we expect, we return ERR_ALLOWED. If either or both don't match,
175 // we continue evalutating the rest of the sandbox policy. 177 // we continue evalutating the rest of the sandbox policy.
176 // 178 //
177 // For simplicity, we check the full 64-bit instruction pointer even 179 // For simplicity, we check the full 64-bit instruction pointer even
178 // on 32-bit architectures. 180 // on 32-bit architectures.
179 return gen_.MakeInstruction( 181 return gen_.MakeInstruction(
180 BPF_LD + BPF_W + BPF_ABS, SECCOMP_IP_LSB_IDX, 182 BPF_LD + BPF_W + BPF_ABS, SECCOMP_IP_LSB_IDX,
181 gen_.MakeInstruction( 183 gen_.MakeInstruction(
182 BPF_JMP + BPF_JEQ + BPF_K, low, 184 BPF_JMP + BPF_JEQ + BPF_K, lopc,
183 gen_.MakeInstruction( 185 gen_.MakeInstruction(
184 BPF_LD + BPF_W + BPF_ABS, SECCOMP_IP_MSB_IDX, 186 BPF_LD + BPF_W + BPF_ABS, SECCOMP_IP_MSB_IDX,
185 gen_.MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, hi, 187 gen_.MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, hipc,
186 CompileResult(Allow()), rest)), 188 CompileResult(Allow()), rest)),
187 rest)); 189 rest));
188 } 190 }
189 191
190 CodeGen::Node PolicyCompiler::DispatchSyscall() { 192 CodeGen::Node PolicyCompiler::DispatchSyscall() {
191 // Evaluate all possible system calls and group their ErrorCodes into 193 // Evaluate all possible system calls and group their ErrorCodes into
192 // ranges of identical codes. 194 // ranges of identical codes.
193 Ranges ranges; 195 Ranges ranges;
194 FindRanges(&ranges); 196 FindRanges(&ranges);
195 197
(...skipping 293 matching lines...) Expand 10 before | Expand all | Expand 10 after
489 return ErrorCode(argno, 491 return ErrorCode(argno,
490 width, 492 width,
491 mask, 493 mask,
492 value, 494 value,
493 &*conds_.insert(passed).first, 495 &*conds_.insert(passed).first,
494 &*conds_.insert(failed).first); 496 &*conds_.insert(failed).first);
495 } 497 }
496 498
497 } // namespace bpf_dsl 499 } // namespace bpf_dsl
498 } // namespace sandbox 500 } // namespace sandbox
OLDNEW
« no previous file with comments | « sandbox/linux/bpf_dsl/policy_compiler.h ('k') | sandbox/linux/integration_tests/bpf_dsl_seccomp_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698