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/seccomp-bpf/sandbox_bpf.h" | 5 #include "sandbox/linux/seccomp-bpf/sandbox_bpf.h" |
6 #include "sandbox/linux/seccomp-bpf/verifier.h" | 6 #include "sandbox/linux/seccomp-bpf/verifier.h" |
7 | 7 |
8 // The kernel gives us a sandbox, we turn it into a playground :-) | 8 // The kernel gives us a sandbox, we turn it into a playground :-) |
9 // This is version 2 of the playground; version 1 was built on top of | 9 // This is version 2 of the playground; version 1 was built on top of |
10 // pre-BPF seccomp mode. | 10 // pre-BPF seccomp mode. |
(...skipping 194 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
205 sigprocmask(SIG_UNBLOCK, &mask, NULL)) { | 205 sigprocmask(SIG_UNBLOCK, &mask, NULL)) { |
206 goto filter_failed; | 206 goto filter_failed; |
207 } | 207 } |
208 | 208 |
209 // We can't handle stacked evaluators, yet. We'll get there eventually | 209 // We can't handle stacked evaluators, yet. We'll get there eventually |
210 // though. Hang tight. | 210 // though. Hang tight. |
211 if (evaluators_.size() != 1) { | 211 if (evaluators_.size() != 1) { |
212 die("Not implemented"); | 212 die("Not implemented"); |
213 } | 213 } |
214 | 214 |
215 // Assemble the BPF filter program. | |
216 Program *program = new Program(); | |
jln (very slow on Chromium)
2012/06/12 19:16:23
I would love if we didn't have to keep track (and
Markus (顧孟勤)
2012/06/12 19:35:05
This is tricky, and I don't think I can do it with
jln (very slow on Chromium)
2012/06/12 20:22:51
You're right, this becomes even more confusing.
| |
217 if (!program) { | |
218 die("Out of memory"); | |
219 } | |
220 | |
215 // If the architecture doesn't match SECCOMP_ARCH, disallow the | 221 // If the architecture doesn't match SECCOMP_ARCH, disallow the |
216 // system call. | 222 // system call. |
217 std::vector<struct sock_filter> program; | 223 program->push_back((struct sock_filter) |
218 program.push_back((struct sock_filter) | |
219 BPF_STMT(BPF_LD+BPF_W+BPF_ABS, offsetof(struct arch_seccomp_data, arch))); | 224 BPF_STMT(BPF_LD+BPF_W+BPF_ABS, offsetof(struct arch_seccomp_data, arch))); |
220 program.push_back((struct sock_filter) | 225 program->push_back((struct sock_filter) |
221 BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, SECCOMP_ARCH, 1, 0)); | 226 BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, SECCOMP_ARCH, 1, 0)); |
222 | 227 |
223 // TODO: Instead of killing outright, we should raise a SIGSYS and | 228 // TODO: Instead of killing outright, we should raise a SIGSYS and |
224 // report a useful error message. SIGKILL cannot be trapped by the | 229 // report a useful error message. SIGKILL cannot be trapped by the |
225 // debugger and essentially makes the program fail in a way that is | 230 // debugger and essentially makes the program fail in a way that is |
226 // almost impossible to debug. | 231 // almost impossible to debug. |
227 program.push_back((struct sock_filter) | 232 program->push_back((struct sock_filter) |
228 BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_KILL)); | 233 BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_KILL)); |
229 | 234 |
230 // Grab the system call number, so that we can implement jump tables. | 235 // Grab the system call number, so that we can implement jump tables. |
231 program.push_back((struct sock_filter) | 236 program->push_back((struct sock_filter) |
232 BPF_STMT(BPF_LD+BPF_W+BPF_ABS, offsetof(struct arch_seccomp_data, nr))); | 237 BPF_STMT(BPF_LD+BPF_W+BPF_ABS, offsetof(struct arch_seccomp_data, nr))); |
233 | 238 |
234 // On Intel architectures, verify that system call numbers are in the | 239 // On Intel architectures, verify that system call numbers are in the |
235 // expected number range. The older i386 and x86-64 APIs clear bit 30 | 240 // expected number range. The older i386 and x86-64 APIs clear bit 30 |
236 // on all system calls. The newer x86-32 API always sets bit 30. | 241 // on all system calls. The newer x86-32 API always sets bit 30. |
237 #if defined(__i386__) || defined(__x86_64__) | 242 #if defined(__i386__) || defined(__x86_64__) |
238 #if defined(__x86_64__) && defined(__ILP32__) | 243 #if defined(__x86_64__) && defined(__ILP32__) |
239 program.push_back((struct sock_filter) | 244 program->push_back((struct sock_filter) |
240 BPF_JUMP(BPF_JMP+BPF_JSET+BPF_K, 0x40000000, 1, 0)); | 245 BPF_JUMP(BPF_JMP+BPF_JSET+BPF_K, 0x40000000, 1, 0)); |
241 #else | 246 #else |
242 program.push_back((struct sock_filter) | 247 program->push_back((struct sock_filter) |
243 BPF_JUMP(BPF_JMP+BPF_JSET+BPF_K, 0x40000000, 0, 1)); | 248 BPF_JUMP(BPF_JMP+BPF_JSET+BPF_K, 0x40000000, 0, 1)); |
244 #endif | 249 #endif |
245 // TODO: raise a suitable SIGSYS signal | 250 // TODO: raise a suitable SIGSYS signal |
246 program.push_back((struct sock_filter) | 251 program->push_back((struct sock_filter) |
247 BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_KILL)); | 252 BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_KILL)); |
248 #endif | 253 #endif |
249 | 254 |
250 // Evaluate all possible system calls and depending on their | 255 // Evaluate all possible system calls and depending on their |
251 // exit codes generate a BPF filter. | 256 // exit codes generate a BPF filter. |
252 // This is very inefficient right now. We need to be much smarter | 257 // This is very inefficient right now. We need to be much smarter |
253 // eventually. | 258 // eventually. |
254 // We currently incur a O(N) overhead on each system call, with N | 259 // We currently incur a O(N) overhead on each system call, with N |
255 // being the number of system calls. It is easy to get this down to | 260 // being the number of system calls. It is easy to get this down to |
256 // O(log_2(M)) with M being the number of system calls that need special | 261 // O(log_2(M)) with M being the number of system calls that need special |
(...skipping 21 matching lines...) Expand all Loading... | |
278 die("Invalid ErrorCode reported by sandbox system call evaluator"); | 283 die("Invalid ErrorCode reported by sandbox system call evaluator"); |
279 } | 284 } |
280 break; | 285 break; |
281 } | 286 } |
282 if (sysnum <= MAX_SYSCALL) { | 287 if (sysnum <= MAX_SYSCALL) { |
283 // We compute the default behavior (e.g. fail open or fail closed) by | 288 // We compute the default behavior (e.g. fail open or fail closed) by |
284 // calling the system call evaluator with a system call bigger than | 289 // calling the system call evaluator with a system call bigger than |
285 // MAX_SYSCALL. | 290 // MAX_SYSCALL. |
286 // In other words, the very last iteration in our loop becomes the | 291 // In other words, the very last iteration in our loop becomes the |
287 // fallback case and we don't need to do any comparisons. | 292 // fallback case and we don't need to do any comparisons. |
288 program.push_back((struct sock_filter) | 293 program->push_back((struct sock_filter) |
289 BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, sysnum, 0, 1)); | 294 BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, sysnum, 0, 1)); |
290 } | 295 } |
291 program.push_back((struct sock_filter) | 296 program->push_back((struct sock_filter) |
292 BPF_STMT(BPF_RET+BPF_K, ret)); | 297 BPF_STMT(BPF_RET+BPF_K, ret)); |
293 } | 298 } |
294 | 299 |
295 // Make sure compilation resulted in BPF program that executes | 300 // Make sure compilation resulted in BPF program that executes |
296 // correctly. Otherwise, there is an internal error in our BPF compiler. | 301 // correctly. Otherwise, there is an internal error in our BPF compiler. |
297 // There is really nothing the caller can do until the bug is fixed. | 302 // There is really nothing the caller can do until the bug is fixed. |
298 const char *err; | 303 const char *err; |
299 if (!Verifier::verifyBPF(program, evaluators_, &err)) { | 304 if (!Verifier::verifyBPF(*program, evaluators_, &err)) { |
300 die(err); | 305 die(err); |
301 } | 306 } |
302 | 307 |
308 // We want to be very careful in not imposing any requirements on the | |
309 // policies that are set with setSandboxPolicy(). This means, as soon as | |
310 // the sandbox is active, we shouldn't be relying on libraries that could | |
311 // be making system calls. This, for example, means we should avoid | |
312 // using the heap and we should avoid using STL functions. | |
313 // Temporarily copy the contents of the "program" vector into a | |
314 // stack-allocated array. | |
jln (very slow on Chromium)
2012/06/12 19:16:23
Please explain further that you're trying to make
Markus (顧孟勤)
2012/06/12 19:35:05
Sure, I can add a little more to the comment :-) T
| |
315 struct sock_filter bpf[program->size()]; | |
316 const struct sock_fprog prog = { program->size(), bpf }; | |
317 memcpy(bpf, &(*program)[0], sizeof(bpf)); | |
jln (very slow on Chromium)
2012/06/12 19:16:23
Would a static_cast of program be cleaner here ?
Markus (顧孟勤)
2012/06/12 19:35:05
I am not convinced a cast would actually do the ri
jln (very slow on Chromium)
2012/06/12 20:22:51
The correct solution would be to use the new vecto
| |
318 delete program; | |
319 | |
303 // Install BPF filter program | 320 // Install BPF filter program |
304 const struct sock_fprog prog = { program.size(), &program[0] }; | |
305 if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) || | 321 if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) || |
306 prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog)) { | 322 prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog)) { |
307 goto filter_failed; | 323 goto filter_failed; |
308 } | 324 } |
309 | 325 |
310 return; | 326 return; |
311 } | 327 } |
312 | 328 |
313 void Sandbox::sigSys(int nr, siginfo_t *info, void *void_context) { | 329 void Sandbox::sigSys(int nr, siginfo_t *info, void *void_context) { |
314 if (nr != SIGSYS || info->si_code != SYS_SECCOMP || !void_context) { | 330 if (nr != SIGSYS || info->si_code != SYS_SECCOMP || !void_context) { |
(...skipping 25 matching lines...) Expand all Loading... | |
340 return; | 356 return; |
341 } | 357 } |
342 | 358 |
343 | 359 |
344 bool Sandbox::suppressLogging_ = false; | 360 bool Sandbox::suppressLogging_ = false; |
345 Sandbox::SandboxStatus Sandbox::status_ = STATUS_UNKNOWN; | 361 Sandbox::SandboxStatus Sandbox::status_ = STATUS_UNKNOWN; |
346 int Sandbox::proc_fd_ = -1; | 362 int Sandbox::proc_fd_ = -1; |
347 Sandbox::Evaluators Sandbox::evaluators_; | 363 Sandbox::Evaluators Sandbox::evaluators_; |
348 | 364 |
349 } // namespace | 365 } // namespace |
OLD | NEW |