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 <linux/filter.h> | 8 #include <linux/filter.h> |
9 #include <sys/syscall.h> | 9 #include <sys/syscall.h> |
10 | 10 |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
47 #if defined(__NR_sigreturn) | 47 #if defined(__NR_sigreturn) |
48 __NR_sigreturn, | 48 __NR_sigreturn, |
49 #endif | 49 #endif |
50 }; | 50 }; |
51 | 51 |
52 bool HasExactlyOneBit(uint64_t x) { | 52 bool HasExactlyOneBit(uint64_t x) { |
53 // Common trick; e.g., see http://stackoverflow.com/a/108329. | 53 // Common trick; e.g., see http://stackoverflow.com/a/108329. |
54 return x != 0 && (x & (x - 1)) == 0; | 54 return x != 0 && (x & (x - 1)) == 0; |
55 } | 55 } |
56 | 56 |
57 bool IsDenied(const ErrorCode& code) { | |
58 return (code.err() & SECCOMP_RET_ACTION) == SECCOMP_RET_TRAP || | |
59 (code.err() >= (SECCOMP_RET_ERRNO + ErrorCode::ERR_MIN_ERRNO) && | |
60 code.err() <= (SECCOMP_RET_ERRNO + ErrorCode::ERR_MAX_ERRNO)); | |
61 } | |
62 | |
63 // A Trap() handler that returns an "errno" value. The value is encoded | 57 // A Trap() handler that returns an "errno" value. The value is encoded |
64 // in the "aux" parameter. | 58 // in the "aux" parameter. |
65 intptr_t ReturnErrno(const struct arch_seccomp_data&, void* aux) { | 59 intptr_t ReturnErrno(const struct arch_seccomp_data&, void* aux) { |
66 // TrapFnc functions report error by following the native kernel convention | 60 // TrapFnc functions report error by following the native kernel convention |
67 // of returning an exit code in the range of -1..-4096. They do not try to | 61 // of returning an exit code in the range of -1..-4096. They do not try to |
68 // set errno themselves. The glibc wrapper that triggered the SIGSYS will | 62 // set errno themselves. The glibc wrapper that triggered the SIGSYS will |
69 // ultimately do so for us. | 63 // ultimately do so for us. |
70 int err = reinterpret_cast<intptr_t>(aux) & SECCOMP_RET_DATA; | 64 int err = reinterpret_cast<intptr_t>(aux) & SECCOMP_RET_DATA; |
71 return -err; | 65 return -err; |
72 } | 66 } |
73 | 67 |
74 intptr_t BPFFailure(const struct arch_seccomp_data&, void* aux) { | |
75 SANDBOX_DIE(static_cast<char*>(aux)); | |
76 } | |
77 | |
78 bool HasUnsafeTraps(const Policy* policy) { | 68 bool HasUnsafeTraps(const Policy* policy) { |
| 69 DCHECK(policy); |
79 for (uint32_t sysnum : SyscallSet::ValidOnly()) { | 70 for (uint32_t sysnum : SyscallSet::ValidOnly()) { |
80 if (policy->EvaluateSyscall(sysnum)->HasUnsafeTraps()) { | 71 if (policy->EvaluateSyscall(sysnum)->HasUnsafeTraps()) { |
81 return true; | 72 return true; |
82 } | 73 } |
83 } | 74 } |
84 return policy->InvalidSyscall()->HasUnsafeTraps(); | 75 return policy->InvalidSyscall()->HasUnsafeTraps(); |
85 } | 76 } |
86 | 77 |
87 } // namespace | 78 } // namespace |
88 | 79 |
89 struct PolicyCompiler::Range { | 80 struct PolicyCompiler::Range { |
90 Range(uint32_t f, const ErrorCode& e) : from(f), err(e) {} | |
91 uint32_t from; | 81 uint32_t from; |
92 ErrorCode err; | 82 CodeGen::Node node; |
93 }; | 83 }; |
94 | 84 |
95 PolicyCompiler::PolicyCompiler(const Policy* policy, TrapRegistry* registry) | 85 PolicyCompiler::PolicyCompiler(const Policy* policy, TrapRegistry* registry) |
96 : policy_(policy), | 86 : policy_(policy), |
97 registry_(registry), | 87 registry_(registry), |
98 conds_(), | 88 conds_(), |
99 gen_(), | 89 gen_(), |
100 has_unsafe_traps_(HasUnsafeTraps(policy_)) { | 90 has_unsafe_traps_(HasUnsafeTraps(policy_)) { |
| 91 DCHECK(policy); |
101 } | 92 } |
102 | 93 |
103 PolicyCompiler::~PolicyCompiler() { | 94 PolicyCompiler::~PolicyCompiler() { |
104 } | 95 } |
105 | 96 |
106 scoped_ptr<CodeGen::Program> PolicyCompiler::Compile() { | 97 scoped_ptr<CodeGen::Program> PolicyCompiler::Compile() { |
107 if (!IsDenied(policy_->InvalidSyscall()->Compile(this))) { | 98 if (!policy_->InvalidSyscall()->IsDeny()) { |
108 SANDBOX_DIE("Policies should deny invalid system calls."); | 99 SANDBOX_DIE("Policies should deny invalid system calls."); |
109 } | 100 } |
110 | 101 |
111 // If our BPF program has unsafe traps, enable support for them. | 102 // If our BPF program has unsafe traps, enable support for them. |
112 if (has_unsafe_traps_) { | 103 if (has_unsafe_traps_) { |
113 // As support for unsafe jumps essentially defeats all the security | 104 // As support for unsafe jumps essentially defeats all the security |
114 // measures that the sandbox provides, we print a big warning message -- | 105 // measures that the sandbox provides, we print a big warning message -- |
115 // and of course, we make sure to only ever enable this feature if it | 106 // and of course, we make sure to only ever enable this feature if it |
116 // is actually requested by the sandbox policy. | 107 // is actually requested by the sandbox policy. |
117 if (Syscall::Call(-1) == -1 && errno == ENOSYS) { | 108 if (Syscall::Call(-1) == -1 && errno == ENOSYS) { |
118 SANDBOX_DIE( | 109 SANDBOX_DIE( |
119 "Support for UnsafeTrap() has not yet been ported to this " | 110 "Support for UnsafeTrap() has not yet been ported to this " |
120 "architecture"); | 111 "architecture"); |
121 } | 112 } |
122 | 113 |
123 for (int sysnum : kSyscallsRequiredForUnsafeTraps) { | 114 for (int sysnum : kSyscallsRequiredForUnsafeTraps) { |
124 if (!policy_->EvaluateSyscall(sysnum)->Compile(this) | 115 if (!policy_->EvaluateSyscall(sysnum)->IsAllow()) { |
125 .Equals(ErrorCode(ErrorCode::ERR_ALLOWED))) { | |
126 SANDBOX_DIE( | 116 SANDBOX_DIE( |
127 "Policies that use UnsafeTrap() must unconditionally allow all " | 117 "Policies that use UnsafeTrap() must unconditionally allow all " |
128 "required system calls"); | 118 "required system calls"); |
129 } | 119 } |
130 } | 120 } |
131 | 121 |
132 if (!registry_->EnableUnsafeTraps()) { | 122 if (!registry_->EnableUnsafeTraps()) { |
133 // We should never be able to get here, as UnsafeTrap() should never | 123 // We should never be able to get here, as UnsafeTrap() should never |
134 // actually return a valid ErrorCode object unless the user set the | 124 // actually return a valid ErrorCode object unless the user set the |
135 // CHROME_SANDBOX_DEBUGGING environment variable; and therefore, | 125 // CHROME_SANDBOX_DEBUGGING environment variable; and therefore, |
(...skipping 16 matching lines...) Expand all Loading... |
152 // invoked by Syscall::Call, and then allow it unconditionally. | 142 // invoked by Syscall::Call, and then allow it unconditionally. |
153 // 3. Check the system call number and jump to the appropriate compiled | 143 // 3. Check the system call number and jump to the appropriate compiled |
154 // system call policy number. | 144 // system call policy number. |
155 return CheckArch(MaybeAddEscapeHatch(DispatchSyscall())); | 145 return CheckArch(MaybeAddEscapeHatch(DispatchSyscall())); |
156 } | 146 } |
157 | 147 |
158 CodeGen::Node PolicyCompiler::CheckArch(CodeGen::Node passed) { | 148 CodeGen::Node PolicyCompiler::CheckArch(CodeGen::Node passed) { |
159 // If the architecture doesn't match SECCOMP_ARCH, disallow the | 149 // If the architecture doesn't match SECCOMP_ARCH, disallow the |
160 // system call. | 150 // system call. |
161 return gen_.MakeInstruction( | 151 return gen_.MakeInstruction( |
162 BPF_LD + BPF_W + BPF_ABS, | 152 BPF_LD + BPF_W + BPF_ABS, SECCOMP_ARCH_IDX, |
163 SECCOMP_ARCH_IDX, | |
164 gen_.MakeInstruction( | 153 gen_.MakeInstruction( |
165 BPF_JMP + BPF_JEQ + BPF_K, | 154 BPF_JMP + BPF_JEQ + BPF_K, SECCOMP_ARCH, passed, |
166 SECCOMP_ARCH, | 155 CompileResult(Kill("Invalid audit architecture in BPF filter")))); |
167 passed, | |
168 RetExpression(Kill("Invalid audit architecture in BPF filter")))); | |
169 } | 156 } |
170 | 157 |
171 CodeGen::Node PolicyCompiler::MaybeAddEscapeHatch(CodeGen::Node rest) { | 158 CodeGen::Node PolicyCompiler::MaybeAddEscapeHatch(CodeGen::Node rest) { |
172 // If no unsafe traps, then simply return |rest|. | 159 // If no unsafe traps, then simply return |rest|. |
173 if (!has_unsafe_traps_) { | 160 if (!has_unsafe_traps_) { |
174 return rest; | 161 return rest; |
175 } | 162 } |
176 | 163 |
177 // Allow system calls, if they originate from our magic return address | 164 // Allow system calls, if they originate from our magic return address |
178 // (which we can query by calling Syscall::Call(-1)). | 165 // (which we can query by calling Syscall::Call(-1)). |
179 uint64_t syscall_entry_point = | 166 uint64_t syscall_entry_point = |
180 static_cast<uint64_t>(static_cast<uintptr_t>(Syscall::Call(-1))); | 167 static_cast<uint64_t>(static_cast<uintptr_t>(Syscall::Call(-1))); |
181 uint32_t low = static_cast<uint32_t>(syscall_entry_point); | 168 uint32_t low = static_cast<uint32_t>(syscall_entry_point); |
182 uint32_t hi = static_cast<uint32_t>(syscall_entry_point >> 32); | 169 uint32_t hi = static_cast<uint32_t>(syscall_entry_point >> 32); |
183 | 170 |
184 // BPF cannot do native 64-bit comparisons, so we have to compare | 171 // BPF cannot do native 64-bit comparisons, so we have to compare |
185 // both 32-bit halves of the instruction pointer. If they match what | 172 // both 32-bit halves of the instruction pointer. If they match what |
186 // we expect, we return ERR_ALLOWED. If either or both don't match, | 173 // we expect, we return ERR_ALLOWED. If either or both don't match, |
187 // we continue evalutating the rest of the sandbox policy. | 174 // we continue evalutating the rest of the sandbox policy. |
188 // | 175 // |
189 // For simplicity, we check the full 64-bit instruction pointer even | 176 // For simplicity, we check the full 64-bit instruction pointer even |
190 // on 32-bit architectures. | 177 // on 32-bit architectures. |
191 return gen_.MakeInstruction( | 178 return gen_.MakeInstruction( |
192 BPF_LD + BPF_W + BPF_ABS, | 179 BPF_LD + BPF_W + BPF_ABS, SECCOMP_IP_LSB_IDX, |
193 SECCOMP_IP_LSB_IDX, | |
194 gen_.MakeInstruction( | 180 gen_.MakeInstruction( |
195 BPF_JMP + BPF_JEQ + BPF_K, | 181 BPF_JMP + BPF_JEQ + BPF_K, low, |
196 low, | |
197 gen_.MakeInstruction( | 182 gen_.MakeInstruction( |
198 BPF_LD + BPF_W + BPF_ABS, | 183 BPF_LD + BPF_W + BPF_ABS, SECCOMP_IP_MSB_IDX, |
199 SECCOMP_IP_MSB_IDX, | 184 gen_.MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, hi, |
200 gen_.MakeInstruction( | 185 CompileResult(Allow()), rest)), |
201 BPF_JMP + BPF_JEQ + BPF_K, | |
202 hi, | |
203 RetExpression(ErrorCode(ErrorCode::ERR_ALLOWED)), | |
204 rest)), | |
205 rest)); | 186 rest)); |
206 } | 187 } |
207 | 188 |
208 CodeGen::Node PolicyCompiler::DispatchSyscall() { | 189 CodeGen::Node PolicyCompiler::DispatchSyscall() { |
209 // Evaluate all possible system calls and group their ErrorCodes into | 190 // Evaluate all possible system calls and group their ErrorCodes into |
210 // ranges of identical codes. | 191 // ranges of identical codes. |
211 Ranges ranges; | 192 Ranges ranges; |
212 FindRanges(&ranges); | 193 FindRanges(&ranges); |
213 | 194 |
214 // Compile the system call ranges to an optimized BPF jumptable | 195 // Compile the system call ranges to an optimized BPF jumptable |
215 CodeGen::Node jumptable = AssembleJumpTable(ranges.begin(), ranges.end()); | 196 CodeGen::Node jumptable = AssembleJumpTable(ranges.begin(), ranges.end()); |
216 | 197 |
217 // Grab the system call number, so that we can check it and then | 198 // Grab the system call number, so that we can check it and then |
218 // execute the jump table. | 199 // execute the jump table. |
219 return gen_.MakeInstruction( | 200 return gen_.MakeInstruction( |
220 BPF_LD + BPF_W + BPF_ABS, SECCOMP_NR_IDX, CheckSyscallNumber(jumptable)); | 201 BPF_LD + BPF_W + BPF_ABS, SECCOMP_NR_IDX, CheckSyscallNumber(jumptable)); |
221 } | 202 } |
222 | 203 |
223 CodeGen::Node PolicyCompiler::CheckSyscallNumber(CodeGen::Node passed) { | 204 CodeGen::Node PolicyCompiler::CheckSyscallNumber(CodeGen::Node passed) { |
224 if (kIsIntel) { | 205 if (kIsIntel) { |
225 // On Intel architectures, verify that system call numbers are in the | 206 // On Intel architectures, verify that system call numbers are in the |
226 // expected number range. | 207 // expected number range. |
227 CodeGen::Node invalidX32 = | 208 CodeGen::Node invalidX32 = |
228 RetExpression(Kill("Illegal mixing of system call ABIs")); | 209 CompileResult(Kill("Illegal mixing of system call ABIs")); |
229 if (kIsX32) { | 210 if (kIsX32) { |
230 // The newer x32 API always sets bit 30. | 211 // The newer x32 API always sets bit 30. |
231 return gen_.MakeInstruction( | 212 return gen_.MakeInstruction( |
232 BPF_JMP + BPF_JSET + BPF_K, 0x40000000, passed, invalidX32); | 213 BPF_JMP + BPF_JSET + BPF_K, 0x40000000, passed, invalidX32); |
233 } else { | 214 } else { |
234 // The older i386 and x86-64 APIs clear bit 30 on all system calls. | 215 // The older i386 and x86-64 APIs clear bit 30 on all system calls. |
235 return gen_.MakeInstruction( | 216 return gen_.MakeInstruction( |
236 BPF_JMP + BPF_JSET + BPF_K, 0x40000000, invalidX32, passed); | 217 BPF_JMP + BPF_JSET + BPF_K, 0x40000000, invalidX32, passed); |
237 } | 218 } |
238 } | 219 } |
239 | 220 |
240 // TODO(mdempsky): Similar validation for other architectures? | 221 // TODO(mdempsky): Similar validation for other architectures? |
241 return passed; | 222 return passed; |
242 } | 223 } |
243 | 224 |
244 void PolicyCompiler::FindRanges(Ranges* ranges) { | 225 void PolicyCompiler::FindRanges(Ranges* ranges) { |
245 // Please note that "struct seccomp_data" defines system calls as a signed | 226 // Please note that "struct seccomp_data" defines system calls as a signed |
246 // int32_t, but BPF instructions always operate on unsigned quantities. We | 227 // int32_t, but BPF instructions always operate on unsigned quantities. We |
247 // deal with this disparity by enumerating from MIN_SYSCALL to MAX_SYSCALL, | 228 // deal with this disparity by enumerating from MIN_SYSCALL to MAX_SYSCALL, |
248 // and then verifying that the rest of the number range (both positive and | 229 // and then verifying that the rest of the number range (both positive and |
249 // negative) all return the same ErrorCode. | 230 // negative) all return the same ErrorCode. |
250 const ErrorCode invalid_err = policy_->InvalidSyscall()->Compile(this); | 231 const CodeGen::Node invalid_node = CompileResult(policy_->InvalidSyscall()); |
251 uint32_t old_sysnum = 0; | 232 uint32_t old_sysnum = 0; |
252 ErrorCode old_err = SyscallSet::IsValid(old_sysnum) | 233 CodeGen::Node old_node = |
253 ? policy_->EvaluateSyscall(old_sysnum)->Compile(this) | 234 SyscallSet::IsValid(old_sysnum) |
254 : invalid_err; | 235 ? CompileResult(policy_->EvaluateSyscall(old_sysnum)) |
| 236 : invalid_node; |
255 | 237 |
256 for (uint32_t sysnum : SyscallSet::All()) { | 238 for (uint32_t sysnum : SyscallSet::All()) { |
257 ErrorCode err = | 239 CodeGen::Node node = |
258 SyscallSet::IsValid(sysnum) | 240 SyscallSet::IsValid(sysnum) |
259 ? policy_->EvaluateSyscall(static_cast<int>(sysnum))->Compile(this) | 241 ? CompileResult(policy_->EvaluateSyscall(static_cast<int>(sysnum))) |
260 : invalid_err; | 242 : invalid_node; |
261 if (!err.Equals(old_err)) { | 243 // N.B., here we rely on CodeGen folding (i.e., returning the same |
262 ranges->push_back(Range(old_sysnum, old_err)); | 244 // node value for) identical code sequences, otherwise our jump |
| 245 // table will blow up in size. |
| 246 if (node != old_node) { |
| 247 ranges->push_back(Range{old_sysnum, old_node}); |
263 old_sysnum = sysnum; | 248 old_sysnum = sysnum; |
264 old_err = err; | 249 old_node = node; |
265 } | 250 } |
266 } | 251 } |
267 ranges->push_back(Range(old_sysnum, old_err)); | 252 ranges->push_back(Range{old_sysnum, old_node}); |
268 } | 253 } |
269 | 254 |
270 CodeGen::Node PolicyCompiler::AssembleJumpTable(Ranges::const_iterator start, | 255 CodeGen::Node PolicyCompiler::AssembleJumpTable(Ranges::const_iterator start, |
271 Ranges::const_iterator stop) { | 256 Ranges::const_iterator stop) { |
272 // We convert the list of system call ranges into jump table that performs | 257 // We convert the list of system call ranges into jump table that performs |
273 // a binary search over the ranges. | 258 // a binary search over the ranges. |
274 // As a sanity check, we need to have at least one distinct ranges for us | 259 // As a sanity check, we need to have at least one distinct ranges for us |
275 // to be able to build a jump table. | 260 // to be able to build a jump table. |
276 if (stop - start <= 0) { | 261 if (stop - start <= 0) { |
277 SANDBOX_DIE("Invalid set of system call ranges"); | 262 SANDBOX_DIE("Invalid set of system call ranges"); |
278 } else if (stop - start == 1) { | 263 } else if (stop - start == 1) { |
279 // If we have narrowed things down to a single range object, we can | 264 // If we have narrowed things down to a single range object, we can |
280 // return from the BPF filter program. | 265 // return from the BPF filter program. |
281 return RetExpression(start->err); | 266 return start->node; |
282 } | 267 } |
283 | 268 |
284 // Pick the range object that is located at the mid point of our list. | 269 // Pick the range object that is located at the mid point of our list. |
285 // We compare our system call number against the lowest valid system call | 270 // We compare our system call number against the lowest valid system call |
286 // number in this range object. If our number is lower, it is outside of | 271 // number in this range object. If our number is lower, it is outside of |
287 // this range object. If it is greater or equal, it might be inside. | 272 // this range object. If it is greater or equal, it might be inside. |
288 Ranges::const_iterator mid = start + (stop - start) / 2; | 273 Ranges::const_iterator mid = start + (stop - start) / 2; |
289 | 274 |
290 // Sub-divide the list of ranges and continue recursively. | 275 // Sub-divide the list of ranges and continue recursively. |
291 CodeGen::Node jf = AssembleJumpTable(start, mid); | 276 CodeGen::Node jf = AssembleJumpTable(start, mid); |
292 CodeGen::Node jt = AssembleJumpTable(mid, stop); | 277 CodeGen::Node jt = AssembleJumpTable(mid, stop); |
293 return gen_.MakeInstruction(BPF_JMP + BPF_JGE + BPF_K, mid->from, jt, jf); | 278 return gen_.MakeInstruction(BPF_JMP + BPF_JGE + BPF_K, mid->from, jt, jf); |
294 } | 279 } |
295 | 280 |
| 281 CodeGen::Node PolicyCompiler::CompileResult(const ResultExpr& res) { |
| 282 return RetExpression(res->Compile(this)); |
| 283 } |
| 284 |
296 CodeGen::Node PolicyCompiler::RetExpression(const ErrorCode& err) { | 285 CodeGen::Node PolicyCompiler::RetExpression(const ErrorCode& err) { |
297 switch (err.error_type()) { | 286 switch (err.error_type()) { |
298 case ErrorCode::ET_COND: | 287 case ErrorCode::ET_COND: |
299 return CondExpression(err); | 288 return CondExpression(err); |
300 case ErrorCode::ET_SIMPLE: | 289 case ErrorCode::ET_SIMPLE: |
301 case ErrorCode::ET_TRAP: | 290 case ErrorCode::ET_TRAP: |
302 return gen_.MakeInstruction(BPF_RET + BPF_K, err.err()); | 291 return gen_.MakeInstruction(BPF_RET + BPF_K, err.err()); |
303 default: | 292 default: |
304 SANDBOX_DIE("ErrorCode is not suitable for returning from a BPF program"); | 293 SANDBOX_DIE("ErrorCode is not suitable for returning from a BPF program"); |
305 } | 294 } |
(...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
447 BPF_LD + BPF_W + BPF_ABS, | 436 BPF_LD + BPF_W + BPF_ABS, |
448 idx, | 437 idx, |
449 gen_.MakeInstruction( | 438 gen_.MakeInstruction( |
450 BPF_ALU + BPF_AND + BPF_K, | 439 BPF_ALU + BPF_AND + BPF_K, |
451 mask, | 440 mask, |
452 gen_.MakeInstruction( | 441 gen_.MakeInstruction( |
453 BPF_JMP + BPF_JEQ + BPF_K, value, passed, failed))); | 442 BPF_JMP + BPF_JEQ + BPF_K, value, passed, failed))); |
454 } | 443 } |
455 | 444 |
456 ErrorCode PolicyCompiler::Unexpected64bitArgument() { | 445 ErrorCode PolicyCompiler::Unexpected64bitArgument() { |
457 return Kill("Unexpected 64bit argument detected"); | 446 return Kill("Unexpected 64bit argument detected")->Compile(this); |
458 } | 447 } |
459 | 448 |
460 ErrorCode PolicyCompiler::Error(int err) { | 449 ErrorCode PolicyCompiler::Error(int err) { |
461 if (has_unsafe_traps_) { | 450 if (has_unsafe_traps_) { |
462 // When inside an UnsafeTrap() callback, we want to allow all system calls. | 451 // When inside an UnsafeTrap() callback, we want to allow all system calls. |
463 // This means, we must conditionally disable the sandbox -- and that's not | 452 // This means, we must conditionally disable the sandbox -- and that's not |
464 // something that kernel-side BPF filters can do, as they cannot inspect | 453 // something that kernel-side BPF filters can do, as they cannot inspect |
465 // any state other than the syscall arguments. | 454 // any state other than the syscall arguments. |
466 // But if we redirect all error handlers to user-space, then we can easily | 455 // But if we redirect all error handlers to user-space, then we can easily |
467 // make this decision. | 456 // make this decision. |
468 // The performance penalty for this extra round-trip to user-space is not | 457 // The performance penalty for this extra round-trip to user-space is not |
469 // actually that bad, as we only ever pay it for denied system calls; and a | 458 // actually that bad, as we only ever pay it for denied system calls; and a |
470 // typical program has very few of these. | 459 // typical program has very few of these. |
471 return Trap(ReturnErrno, reinterpret_cast<void*>(err)); | 460 return Trap(ReturnErrno, reinterpret_cast<void*>(err), true); |
472 } | 461 } |
473 | 462 |
474 return ErrorCode(err); | 463 return ErrorCode(err); |
475 } | 464 } |
476 | 465 |
477 ErrorCode PolicyCompiler::MakeTrap(TrapRegistry::TrapFnc fnc, | 466 ErrorCode PolicyCompiler::Trap(TrapRegistry::TrapFnc fnc, |
478 const void* aux, | 467 const void* aux, |
479 bool safe) { | 468 bool safe) { |
480 uint16_t trap_id = registry_->Add(fnc, aux, safe); | 469 uint16_t trap_id = registry_->Add(fnc, aux, safe); |
481 return ErrorCode(trap_id, fnc, aux, safe); | 470 return ErrorCode(trap_id, fnc, aux, safe); |
482 } | 471 } |
483 | 472 |
484 ErrorCode PolicyCompiler::Trap(TrapRegistry::TrapFnc fnc, const void* aux) { | |
485 return MakeTrap(fnc, aux, true /* Safe Trap */); | |
486 } | |
487 | |
488 ErrorCode PolicyCompiler::UnsafeTrap(TrapRegistry::TrapFnc fnc, | |
489 const void* aux) { | |
490 return MakeTrap(fnc, aux, false /* Unsafe Trap */); | |
491 } | |
492 | |
493 bool PolicyCompiler::IsRequiredForUnsafeTrap(int sysno) { | 473 bool PolicyCompiler::IsRequiredForUnsafeTrap(int sysno) { |
494 for (size_t i = 0; i < arraysize(kSyscallsRequiredForUnsafeTraps); ++i) { | 474 for (size_t i = 0; i < arraysize(kSyscallsRequiredForUnsafeTraps); ++i) { |
495 if (sysno == kSyscallsRequiredForUnsafeTraps[i]) { | 475 if (sysno == kSyscallsRequiredForUnsafeTraps[i]) { |
496 return true; | 476 return true; |
497 } | 477 } |
498 } | 478 } |
499 return false; | 479 return false; |
500 } | 480 } |
501 | 481 |
502 ErrorCode PolicyCompiler::CondMaskedEqual(int argno, | 482 ErrorCode PolicyCompiler::CondMaskedEqual(int argno, |
503 ErrorCode::ArgType width, | 483 ErrorCode::ArgType width, |
504 uint64_t mask, | 484 uint64_t mask, |
505 uint64_t value, | 485 uint64_t value, |
506 const ErrorCode& passed, | 486 const ErrorCode& passed, |
507 const ErrorCode& failed) { | 487 const ErrorCode& failed) { |
508 return ErrorCode(argno, | 488 return ErrorCode(argno, |
509 width, | 489 width, |
510 mask, | 490 mask, |
511 value, | 491 value, |
512 &*conds_.insert(passed).first, | 492 &*conds_.insert(passed).first, |
513 &*conds_.insert(failed).first); | 493 &*conds_.insert(failed).first); |
514 } | 494 } |
515 | 495 |
516 ErrorCode PolicyCompiler::Kill(const char* msg) { | |
517 return Trap(BPFFailure, const_cast<char*>(msg)); | |
518 } | |
519 | |
520 } // namespace bpf_dsl | 496 } // namespace bpf_dsl |
521 } // namespace sandbox | 497 } // namespace sandbox |
OLD | NEW |