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 <sys/syscall.h> | 8 #include <sys/syscall.h> |
9 | 9 |
10 #include <limits> | 10 #include <limits> |
11 | 11 |
12 #include "base/logging.h" | 12 #include "base/logging.h" |
13 #include "base/macros.h" | 13 #include "base/macros.h" |
14 #include "sandbox/linux/bpf_dsl/bpf_dsl.h" | 14 #include "sandbox/linux/bpf_dsl/bpf_dsl.h" |
15 #include "sandbox/linux/bpf_dsl/bpf_dsl_impl.h" | 15 #include "sandbox/linux/bpf_dsl/bpf_dsl_impl.h" |
16 #include "sandbox/linux/bpf_dsl/codegen.h" | 16 #include "sandbox/linux/bpf_dsl/codegen.h" |
17 #include "sandbox/linux/bpf_dsl/dump_bpf.h" | 17 #include "sandbox/linux/bpf_dsl/dump_bpf.h" |
| 18 #include "sandbox/linux/bpf_dsl/errorcode.h" |
18 #include "sandbox/linux/bpf_dsl/policy.h" | 19 #include "sandbox/linux/bpf_dsl/policy.h" |
19 #include "sandbox/linux/bpf_dsl/seccomp_macros.h" | 20 #include "sandbox/linux/bpf_dsl/seccomp_macros.h" |
20 #include "sandbox/linux/bpf_dsl/syscall_set.h" | 21 #include "sandbox/linux/bpf_dsl/syscall_set.h" |
21 #include "sandbox/linux/bpf_dsl/verifier.h" | 22 #include "sandbox/linux/bpf_dsl/verifier.h" |
22 #include "sandbox/linux/seccomp-bpf/errorcode.h" | |
23 #include "sandbox/linux/system_headers/linux_filter.h" | 23 #include "sandbox/linux/system_headers/linux_filter.h" |
24 #include "sandbox/linux/system_headers/linux_seccomp.h" | 24 #include "sandbox/linux/system_headers/linux_seccomp.h" |
25 #include "sandbox/linux/system_headers/linux_syscalls.h" | 25 #include "sandbox/linux/system_headers/linux_syscalls.h" |
26 | 26 |
27 namespace sandbox { | 27 namespace sandbox { |
28 namespace bpf_dsl { | 28 namespace bpf_dsl { |
29 | 29 |
30 namespace { | 30 namespace { |
31 | 31 |
32 #if defined(__i386__) || defined(__x86_64__) | 32 #if defined(__i386__) || defined(__x86_64__) |
(...skipping 16 matching lines...) Expand all Loading... |
49 #if defined(__NR_sigreturn) | 49 #if defined(__NR_sigreturn) |
50 __NR_sigreturn, | 50 __NR_sigreturn, |
51 #endif | 51 #endif |
52 }; | 52 }; |
53 | 53 |
54 bool HasExactlyOneBit(uint64_t x) { | 54 bool HasExactlyOneBit(uint64_t x) { |
55 // Common trick; e.g., see http://stackoverflow.com/a/108329. | 55 // Common trick; e.g., see http://stackoverflow.com/a/108329. |
56 return x != 0 && (x & (x - 1)) == 0; | 56 return x != 0 && (x & (x - 1)) == 0; |
57 } | 57 } |
58 | 58 |
| 59 ResultExpr DefaultPanic(const char* error) { |
| 60 return Kill(); |
| 61 } |
| 62 |
59 // A Trap() handler that returns an "errno" value. The value is encoded | 63 // A Trap() handler that returns an "errno" value. The value is encoded |
60 // in the "aux" parameter. | 64 // in the "aux" parameter. |
61 intptr_t ReturnErrno(const struct arch_seccomp_data&, void* aux) { | 65 intptr_t ReturnErrno(const struct arch_seccomp_data&, void* aux) { |
62 // TrapFnc functions report error by following the native kernel convention | 66 // TrapFnc functions report error by following the native kernel convention |
63 // of returning an exit code in the range of -1..-4096. They do not try to | 67 // of returning an exit code in the range of -1..-4096. They do not try to |
64 // set errno themselves. The glibc wrapper that triggered the SIGSYS will | 68 // set errno themselves. The glibc wrapper that triggered the SIGSYS will |
65 // ultimately do so for us. | 69 // ultimately do so for us. |
66 int err = reinterpret_cast<intptr_t>(aux) & SECCOMP_RET_DATA; | 70 int err = reinterpret_cast<intptr_t>(aux) & SECCOMP_RET_DATA; |
67 return -err; | 71 return -err; |
68 } | 72 } |
(...skipping 12 matching lines...) Expand all Loading... |
81 | 85 |
82 struct PolicyCompiler::Range { | 86 struct PolicyCompiler::Range { |
83 uint32_t from; | 87 uint32_t from; |
84 CodeGen::Node node; | 88 CodeGen::Node node; |
85 }; | 89 }; |
86 | 90 |
87 PolicyCompiler::PolicyCompiler(const Policy* policy, TrapRegistry* registry) | 91 PolicyCompiler::PolicyCompiler(const Policy* policy, TrapRegistry* registry) |
88 : policy_(policy), | 92 : policy_(policy), |
89 registry_(registry), | 93 registry_(registry), |
90 escapepc_(0), | 94 escapepc_(0), |
| 95 panic_func_(DefaultPanic), |
91 conds_(), | 96 conds_(), |
92 gen_(), | 97 gen_(), |
93 has_unsafe_traps_(HasUnsafeTraps(policy_)) { | 98 has_unsafe_traps_(HasUnsafeTraps(policy_)) { |
94 DCHECK(policy); | 99 DCHECK(policy); |
95 } | 100 } |
96 | 101 |
97 PolicyCompiler::~PolicyCompiler() { | 102 PolicyCompiler::~PolicyCompiler() { |
98 } | 103 } |
99 | 104 |
100 scoped_ptr<CodeGen::Program> PolicyCompiler::Compile(bool verify) { | 105 scoped_ptr<CodeGen::Program> PolicyCompiler::Compile(bool verify) { |
(...skipping 29 matching lines...) Expand all Loading... |
130 } | 135 } |
131 } | 136 } |
132 | 137 |
133 return program.Pass(); | 138 return program.Pass(); |
134 } | 139 } |
135 | 140 |
136 void PolicyCompiler::DangerousSetEscapePC(uint64_t escapepc) { | 141 void PolicyCompiler::DangerousSetEscapePC(uint64_t escapepc) { |
137 escapepc_ = escapepc; | 142 escapepc_ = escapepc; |
138 } | 143 } |
139 | 144 |
| 145 void PolicyCompiler::SetPanicFunc(PanicFunc panic_func) { |
| 146 panic_func_ = panic_func; |
| 147 } |
| 148 |
140 CodeGen::Node PolicyCompiler::AssemblePolicy() { | 149 CodeGen::Node PolicyCompiler::AssemblePolicy() { |
141 // A compiled policy consists of three logical parts: | 150 // A compiled policy consists of three logical parts: |
142 // 1. Check that the "arch" field matches the expected architecture. | 151 // 1. Check that the "arch" field matches the expected architecture. |
143 // 2. If the policy involves unsafe traps, check if the syscall was | 152 // 2. If the policy involves unsafe traps, check if the syscall was |
144 // invoked by Syscall::Call, and then allow it unconditionally. | 153 // invoked by Syscall::Call, and then allow it unconditionally. |
145 // 3. Check the system call number and jump to the appropriate compiled | 154 // 3. Check the system call number and jump to the appropriate compiled |
146 // system call policy number. | 155 // system call policy number. |
147 return CheckArch(MaybeAddEscapeHatch(DispatchSyscall())); | 156 return CheckArch(MaybeAddEscapeHatch(DispatchSyscall())); |
148 } | 157 } |
149 | 158 |
150 CodeGen::Node PolicyCompiler::CheckArch(CodeGen::Node passed) { | 159 CodeGen::Node PolicyCompiler::CheckArch(CodeGen::Node passed) { |
151 // If the architecture doesn't match SECCOMP_ARCH, disallow the | 160 // If the architecture doesn't match SECCOMP_ARCH, disallow the |
152 // system call. | 161 // system call. |
153 return gen_.MakeInstruction( | 162 return gen_.MakeInstruction( |
154 BPF_LD + BPF_W + BPF_ABS, SECCOMP_ARCH_IDX, | 163 BPF_LD + BPF_W + BPF_ABS, SECCOMP_ARCH_IDX, |
155 gen_.MakeInstruction( | 164 gen_.MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, SECCOMP_ARCH, passed, |
156 BPF_JMP + BPF_JEQ + BPF_K, SECCOMP_ARCH, passed, | 165 CompileResult(panic_func_( |
157 CompileResult(Kill("Invalid audit architecture in BPF filter")))); | 166 "Invalid audit architecture in BPF filter")))); |
158 } | 167 } |
159 | 168 |
160 CodeGen::Node PolicyCompiler::MaybeAddEscapeHatch(CodeGen::Node rest) { | 169 CodeGen::Node PolicyCompiler::MaybeAddEscapeHatch(CodeGen::Node rest) { |
161 // If no unsafe traps, then simply return |rest|. | 170 // If no unsafe traps, then simply return |rest|. |
162 if (!has_unsafe_traps_) { | 171 if (!has_unsafe_traps_) { |
163 return rest; | 172 return rest; |
164 } | 173 } |
165 | 174 |
166 // We already enabled unsafe traps in Compile, but enable them again to give | 175 // We already enabled unsafe traps in Compile, but enable them again to give |
167 // the trap registry a second chance to complain before we add the backdoor. | 176 // the trap registry a second chance to complain before we add the backdoor. |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
202 // execute the jump table. | 211 // execute the jump table. |
203 return gen_.MakeInstruction( | 212 return gen_.MakeInstruction( |
204 BPF_LD + BPF_W + BPF_ABS, SECCOMP_NR_IDX, CheckSyscallNumber(jumptable)); | 213 BPF_LD + BPF_W + BPF_ABS, SECCOMP_NR_IDX, CheckSyscallNumber(jumptable)); |
205 } | 214 } |
206 | 215 |
207 CodeGen::Node PolicyCompiler::CheckSyscallNumber(CodeGen::Node passed) { | 216 CodeGen::Node PolicyCompiler::CheckSyscallNumber(CodeGen::Node passed) { |
208 if (kIsIntel) { | 217 if (kIsIntel) { |
209 // On Intel architectures, verify that system call numbers are in the | 218 // On Intel architectures, verify that system call numbers are in the |
210 // expected number range. | 219 // expected number range. |
211 CodeGen::Node invalidX32 = | 220 CodeGen::Node invalidX32 = |
212 CompileResult(Kill("Illegal mixing of system call ABIs")); | 221 CompileResult(panic_func_("Illegal mixing of system call ABIs")); |
213 if (kIsX32) { | 222 if (kIsX32) { |
214 // The newer x32 API always sets bit 30. | 223 // The newer x32 API always sets bit 30. |
215 return gen_.MakeInstruction( | 224 return gen_.MakeInstruction( |
216 BPF_JMP + BPF_JSET + BPF_K, 0x40000000, passed, invalidX32); | 225 BPF_JMP + BPF_JSET + BPF_K, 0x40000000, passed, invalidX32); |
217 } else { | 226 } else { |
218 // The older i386 and x86-64 APIs clear bit 30 on all system calls. | 227 // The older i386 and x86-64 APIs clear bit 30 on all system calls. |
219 return gen_.MakeInstruction( | 228 return gen_.MakeInstruction( |
220 BPF_JMP + BPF_JSET + BPF_K, 0x40000000, invalidX32, passed); | 229 BPF_JMP + BPF_JSET + BPF_K, 0x40000000, invalidX32, passed); |
221 } | 230 } |
222 } | 231 } |
(...skipping 215 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
438 BPF_LD + BPF_W + BPF_ABS, | 447 BPF_LD + BPF_W + BPF_ABS, |
439 idx, | 448 idx, |
440 gen_.MakeInstruction( | 449 gen_.MakeInstruction( |
441 BPF_ALU + BPF_AND + BPF_K, | 450 BPF_ALU + BPF_AND + BPF_K, |
442 mask, | 451 mask, |
443 gen_.MakeInstruction( | 452 gen_.MakeInstruction( |
444 BPF_JMP + BPF_JEQ + BPF_K, value, passed, failed))); | 453 BPF_JMP + BPF_JEQ + BPF_K, value, passed, failed))); |
445 } | 454 } |
446 | 455 |
447 ErrorCode PolicyCompiler::Unexpected64bitArgument() { | 456 ErrorCode PolicyCompiler::Unexpected64bitArgument() { |
448 return Kill("Unexpected 64bit argument detected")->Compile(this); | 457 return panic_func_("Unexpected 64bit argument detected")->Compile(this); |
449 } | 458 } |
450 | 459 |
451 ErrorCode PolicyCompiler::Error(int err) { | 460 ErrorCode PolicyCompiler::Error(int err) { |
452 if (has_unsafe_traps_) { | 461 if (has_unsafe_traps_) { |
453 // When inside an UnsafeTrap() callback, we want to allow all system calls. | 462 // When inside an UnsafeTrap() callback, we want to allow all system calls. |
454 // This means, we must conditionally disable the sandbox -- and that's not | 463 // This means, we must conditionally disable the sandbox -- and that's not |
455 // something that kernel-side BPF filters can do, as they cannot inspect | 464 // something that kernel-side BPF filters can do, as they cannot inspect |
456 // any state other than the syscall arguments. | 465 // any state other than the syscall arguments. |
457 // But if we redirect all error handlers to user-space, then we can easily | 466 // But if we redirect all error handlers to user-space, then we can easily |
458 // make this decision. | 467 // make this decision. |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
490 return ErrorCode(argno, | 499 return ErrorCode(argno, |
491 width, | 500 width, |
492 mask, | 501 mask, |
493 value, | 502 value, |
494 &*conds_.insert(passed).first, | 503 &*conds_.insert(passed).first, |
495 &*conds_.insert(failed).first); | 504 &*conds_.insert(failed).first); |
496 } | 505 } |
497 | 506 |
498 } // namespace bpf_dsl | 507 } // namespace bpf_dsl |
499 } // namespace sandbox | 508 } // namespace sandbox |
OLD | NEW |