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 |
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 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
76 return policy->InvalidSyscall()->HasUnsafeTraps(); | 75 return policy->InvalidSyscall()->HasUnsafeTraps(); |
77 } | 76 } |
78 | 77 |
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, |
| 86 TrapRegistry* registry, |
| 87 uint64_t escapepc) |
87 : policy_(policy), | 88 : policy_(policy), |
88 registry_(registry), | 89 registry_(registry), |
| 90 escapepc_(escapepc), |
89 conds_(), | 91 conds_(), |
90 gen_(), | 92 gen_(), |
91 has_unsafe_traps_(HasUnsafeTraps(policy_)) { | 93 has_unsafe_traps_(HasUnsafeTraps(policy_)) { |
92 DCHECK(policy); | 94 DCHECK(policy); |
93 } | 95 } |
94 | 96 |
95 PolicyCompiler::~PolicyCompiler() { | 97 PolicyCompiler::~PolicyCompiler() { |
96 } | 98 } |
97 | 99 |
98 scoped_ptr<CodeGen::Program> PolicyCompiler::Compile() { | 100 scoped_ptr<CodeGen::Program> PolicyCompiler::Compile() { |
99 if (!policy_->InvalidSyscall()->IsDeny()) { | 101 if (!policy_->InvalidSyscall()->IsDeny()) { |
100 SANDBOX_DIE("Policies should deny invalid system calls."); | 102 SANDBOX_DIE("Policies should deny invalid system calls."); |
101 } | 103 } |
102 | 104 |
103 // If our BPF program has unsafe traps, enable support for them. | 105 // If our BPF program has unsafe traps, enable support for them. |
104 if (has_unsafe_traps_) { | 106 if (has_unsafe_traps_) { |
105 // As support for unsafe jumps essentially defeats all the security | 107 // As support for unsafe jumps essentially defeats all the security |
106 // measures that the sandbox provides, we print a big warning message -- | 108 // 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 | 109 // and of course, we make sure to only ever enable this feature if it |
108 // is actually requested by the sandbox policy. | 110 // is actually requested by the sandbox policy. |
109 if (Syscall::Call(-1) == -1 && errno == ENOSYS) { | 111 |
110 SANDBOX_DIE( | 112 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 | 113 |
115 for (int sysnum : kSyscallsRequiredForUnsafeTraps) { | 114 for (int sysnum : kSyscallsRequiredForUnsafeTraps) { |
116 if (!policy_->EvaluateSyscall(sysnum)->IsAllow()) { | 115 if (!policy_->EvaluateSyscall(sysnum)->IsAllow()) { |
117 SANDBOX_DIE( | 116 SANDBOX_DIE( |
118 "Policies that use UnsafeTrap() must unconditionally allow all " | 117 "Policies that use UnsafeTrap() must unconditionally allow all " |
119 "required system calls"); | 118 "required system calls"); |
120 } | 119 } |
121 } | 120 } |
122 | 121 |
123 if (!registry_->EnableUnsafeTraps()) { | 122 if (!registry_->EnableUnsafeTraps()) { |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
155 BPF_JMP + BPF_JEQ + BPF_K, SECCOMP_ARCH, passed, | 154 BPF_JMP + BPF_JEQ + BPF_K, SECCOMP_ARCH, passed, |
156 CompileResult(Kill("Invalid audit architecture in BPF filter")))); | 155 CompileResult(Kill("Invalid audit architecture in BPF filter")))); |
157 } | 156 } |
158 | 157 |
159 CodeGen::Node PolicyCompiler::MaybeAddEscapeHatch(CodeGen::Node rest) { | 158 CodeGen::Node PolicyCompiler::MaybeAddEscapeHatch(CodeGen::Node rest) { |
160 // If no unsafe traps, then simply return |rest|. | 159 // If no unsafe traps, then simply return |rest|. |
161 if (!has_unsafe_traps_) { | 160 if (!has_unsafe_traps_) { |
162 return rest; | 161 return rest; |
163 } | 162 } |
164 | 163 |
165 // Allow system calls, if they originate from our magic return address | 164 // Allow system calls, if they originate from our magic return address. |
166 // (which we can query by calling Syscall::Call(-1)). | 165 const uint32_t lopc = static_cast<uint32_t>(escapepc_); |
167 uint64_t syscall_entry_point = | 166 const uint32_t hipc = static_cast<uint32_t>(escapepc_ >> 32); |
168 static_cast<uint64_t>(static_cast<uintptr_t>(Syscall::Call(-1))); | |
169 uint32_t low = static_cast<uint32_t>(syscall_entry_point); | |
170 uint32_t hi = static_cast<uint32_t>(syscall_entry_point >> 32); | |
171 | 167 |
172 // BPF cannot do native 64-bit comparisons, so we have to compare | 168 // 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 | 169 // 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, | 170 // we expect, we return ERR_ALLOWED. If either or both don't match, |
175 // we continue evalutating the rest of the sandbox policy. | 171 // we continue evalutating the rest of the sandbox policy. |
176 // | 172 // |
177 // For simplicity, we check the full 64-bit instruction pointer even | 173 // For simplicity, we check the full 64-bit instruction pointer even |
178 // on 32-bit architectures. | 174 // on 32-bit architectures. |
179 return gen_.MakeInstruction( | 175 return gen_.MakeInstruction( |
180 BPF_LD + BPF_W + BPF_ABS, SECCOMP_IP_LSB_IDX, | 176 BPF_LD + BPF_W + BPF_ABS, SECCOMP_IP_LSB_IDX, |
181 gen_.MakeInstruction( | 177 gen_.MakeInstruction( |
182 BPF_JMP + BPF_JEQ + BPF_K, low, | 178 BPF_JMP + BPF_JEQ + BPF_K, lopc, |
183 gen_.MakeInstruction( | 179 gen_.MakeInstruction( |
184 BPF_LD + BPF_W + BPF_ABS, SECCOMP_IP_MSB_IDX, | 180 BPF_LD + BPF_W + BPF_ABS, SECCOMP_IP_MSB_IDX, |
185 gen_.MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, hi, | 181 gen_.MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, hipc, |
186 CompileResult(Allow()), rest)), | 182 CompileResult(Allow()), rest)), |
187 rest)); | 183 rest)); |
188 } | 184 } |
189 | 185 |
190 CodeGen::Node PolicyCompiler::DispatchSyscall() { | 186 CodeGen::Node PolicyCompiler::DispatchSyscall() { |
191 // Evaluate all possible system calls and group their ErrorCodes into | 187 // Evaluate all possible system calls and group their ErrorCodes into |
192 // ranges of identical codes. | 188 // ranges of identical codes. |
193 Ranges ranges; | 189 Ranges ranges; |
194 FindRanges(&ranges); | 190 FindRanges(&ranges); |
195 | 191 |
(...skipping 293 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
489 return ErrorCode(argno, | 485 return ErrorCode(argno, |
490 width, | 486 width, |
491 mask, | 487 mask, |
492 value, | 488 value, |
493 &*conds_.insert(passed).first, | 489 &*conds_.insert(passed).first, |
494 &*conds_.insert(failed).first); | 490 &*conds_.insert(failed).first); |
495 } | 491 } |
496 | 492 |
497 } // namespace bpf_dsl | 493 } // namespace bpf_dsl |
498 } // namespace sandbox | 494 } // namespace sandbox |
OLD | NEW |