Chromium Code Reviews| 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 | 7 |
| 7 // 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 :-) |
| 8 // 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 |
| 9 // pre-BPF seccomp mode. | 10 // pre-BPF seccomp mode. |
| 10 namespace playground2 { | 11 namespace playground2 { |
| 11 | 12 |
| 12 Sandbox::ErrorCode Sandbox::probeEvaluator(int signo) { | 13 Sandbox::ErrorCode Sandbox::probeEvaluator(int signo) { |
| 13 switch (signo) { | 14 switch (signo) { |
| 14 case __NR_getpid: | 15 case __NR_getpid: |
| 15 // Return EPERM so that we can check that the filter actually ran. | 16 // Return EPERM so that we can check that the filter actually ran. |
| (...skipping 25 matching lines...) Expand all Loading... | |
| 41 // attacker might cause fork() to fail at will and could trick us | 42 // attacker might cause fork() to fail at will and could trick us |
| 42 // into running without a sandbox. | 43 // into running without a sandbox. |
| 43 sigprocmask(SIG_SETMASK, &oldMask, NULL); // OK, if it fails | 44 sigprocmask(SIG_SETMASK, &oldMask, NULL); // OK, if it fails |
| 44 die("fork() failed unexpectedly"); | 45 die("fork() failed unexpectedly"); |
| 45 } | 46 } |
| 46 | 47 |
| 47 // In the child process | 48 // In the child process |
| 48 if (!pid) { | 49 if (!pid) { |
| 49 // Test a very simple sandbox policy to verify that we can | 50 // Test a very simple sandbox policy to verify that we can |
| 50 // successfully turn on sandboxing. | 51 // successfully turn on sandboxing. |
| 51 suppressLogging_ = true; | 52 // suppressLogging_ = true; |
| 52 evaluators_.clear(); | 53 evaluators_.clear(); |
| 53 setSandboxPolicy(probeEvaluator, NULL); | 54 setSandboxPolicy(probeEvaluator, NULL); |
| 54 setProcFd(proc_fd); | 55 setProcFd(proc_fd); |
| 55 startSandbox(); | 56 startSandbox(); |
| 56 if (syscall(__NR_getpid) < 0 && errno == EPERM) { | 57 if (syscall(__NR_getpid) < 0 && errno == EPERM) { |
| 57 syscall(__NR_exit_group, (intptr_t)100); | 58 syscall(__NR_exit_group, (intptr_t)100); |
| 58 } | 59 } |
| 59 die(NULL); | 60 die(NULL); |
| 60 } | 61 } |
| 61 | 62 |
| (...skipping 186 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 248 | 249 |
| 249 // Evaluate all possible system calls and depending on their | 250 // Evaluate all possible system calls and depending on their |
| 250 // exit codes generate a BPF filter. | 251 // exit codes generate a BPF filter. |
| 251 // This is very inefficient right now. We need to be much smarter | 252 // This is very inefficient right now. We need to be much smarter |
| 252 // eventually. | 253 // eventually. |
| 253 // We currently incur a O(N) overhead on each system call, with N | 254 // We currently incur a O(N) overhead on each system call, with N |
| 254 // being the number of system calls. It is easy to get this down to | 255 // being the number of system calls. It is easy to get this down to |
| 255 // O(log_2(M)) with M being the number of system calls that need special | 256 // O(log_2(M)) with M being the number of system calls that need special |
| 256 // treatment. | 257 // treatment. |
| 257 EvaluateSyscall evaluateSyscall = evaluators_.begin()->first; | 258 EvaluateSyscall evaluateSyscall = evaluators_.begin()->first; |
| 258 for (int sysnum = MIN_SYSCALL; sysnum <= MAX_SYSCALL; ++sysnum) { | 259 for (int sysnum = MIN_SYSCALL; sysnum <= MAX_SYSCALL+1; ++sysnum) { |
| 259 ErrorCode err = evaluateSyscall(sysnum); | 260 ErrorCode err = evaluateSyscall(sysnum); |
| 260 int ret; | 261 int ret; |
| 261 switch (err) { | 262 switch (err) { |
| 262 case SB_INSPECT_ARG_1...SB_INSPECT_ARG_6: | 263 case SB_INSPECT_ARG_1...SB_INSPECT_ARG_6: |
| 263 die("Not implemented"); | 264 die("Not implemented"); |
| 264 case SB_TRAP: | 265 case SB_TRAP: |
| 265 ret = SECCOMP_RET_TRAP; | 266 ret = SECCOMP_RET_TRAP; |
| 266 break; | 267 break; |
| 267 case SB_ALLOWED: | 268 case SB_ALLOWED: |
| 268 ret = SECCOMP_RET_ALLOW; | 269 ret = SECCOMP_RET_ALLOW; |
| 269 break; | 270 break; |
| 270 default: | 271 default: |
| 271 if (err >= static_cast<ErrorCode>(1) && | 272 if (err >= static_cast<ErrorCode>(1) && |
| 272 err <= static_cast<ErrorCode>(4096)) { | 273 err <= static_cast<ErrorCode>(4096)) { |
| 273 // We limit errno values to a reasonable range. In fact, the Linux ABI | 274 // We limit errno values to a reasonable range. In fact, the Linux ABI |
| 274 // doesn't support errno values outside of this range. | 275 // doesn't support errno values outside of this range. |
| 275 ret = SECCOMP_RET_ERRNO + err; | 276 ret = SECCOMP_RET_ERRNO + err; |
| 276 } else { | 277 } else { |
| 277 die("Invalid ErrorCode reported by sandbox system call evaluator"); | 278 die("Invalid ErrorCode reported by sandbox system call evaluator"); |
| 278 } | 279 } |
| 279 break; | 280 break; |
| 280 } | 281 } |
| 281 program.push_back((struct sock_filter) | 282 if (sysnum <= MAX_SYSCALL) { |
| 282 BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, sysnum, 0, 1)); | 283 // 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 | |
| 285 // MAX_SYSCALL. | |
| 286 // In other words, the very last iteration in our loop becomes the | |
| 287 // fallback case and we don't need to do any comparisons. | |
| 288 program.push_back((struct sock_filter) | |
| 289 BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, sysnum, 0, 1)); | |
| 290 } | |
| 283 program.push_back((struct sock_filter) | 291 program.push_back((struct sock_filter) |
| 284 BPF_STMT(BPF_RET+BPF_K, ret)); | 292 BPF_STMT(BPF_RET+BPF_K, ret)); |
| 285 } | 293 } |
| 286 | 294 |
| 287 // Everything that isn't allowed is forbidden. Eventually, we would | 295 // Make sure compilation resulted in BPF program that executes |
| 288 // like to have a way to log forbidden calls, when in debug mode. | 296 // correctly. Otherwise, there is an internal error in our BPF compiler. |
| 289 // TODO: raise a suitable SIGSYS signal | 297 // There is really nothing the caller can do until the bug is fixed. |
| 290 program.push_back((struct sock_filter) | 298 const char *err; |
| 291 BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_KILL)); | 299 if (!Verifier::verifyBPF(program, evaluators_, &err)) { |
| 300 die(err); | |
|
jln (very slow on Chromium)
2012/06/08 19:28:22
I don't like it when functions have u needed side
Markus (顧孟勤)
2012/06/08 20:04:24
There actually is something slightly sub-optimal w
| |
| 301 } | |
| 292 | 302 |
| 293 // Install BPF filter program | 303 // Install BPF filter program |
| 294 const struct sock_fprog prog = { program.size(), &program[0] }; | 304 const struct sock_fprog prog = { program.size(), &program[0] }; |
| 295 if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) || | 305 if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) || |
| 296 prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog)) { | 306 prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog)) { |
| 297 goto filter_failed; | 307 goto filter_failed; |
| 298 } | 308 } |
| 299 | 309 |
| 300 return; | 310 return; |
| 301 } | 311 } |
| (...skipping 25 matching lines...) Expand all Loading... | |
| 327 | 337 |
| 328 ctx->uc_mcontext.gregs[REG_RESULT] = reinterpret_cast<greg_t>(rc); | 338 ctx->uc_mcontext.gregs[REG_RESULT] = reinterpret_cast<greg_t>(rc); |
| 329 errno = old_errno; | 339 errno = old_errno; |
| 330 return; | 340 return; |
| 331 } | 341 } |
| 332 | 342 |
| 333 | 343 |
| 334 bool Sandbox::suppressLogging_ = false; | 344 bool Sandbox::suppressLogging_ = false; |
| 335 Sandbox::SandboxStatus Sandbox::status_ = STATUS_UNKNOWN; | 345 Sandbox::SandboxStatus Sandbox::status_ = STATUS_UNKNOWN; |
| 336 int Sandbox::proc_fd_ = -1; | 346 int Sandbox::proc_fd_ = -1; |
| 337 std::vector<std::pair<Sandbox::EvaluateSyscall, | 347 Sandbox::Evaluators Sandbox::evaluators_; |
| 338 Sandbox::EvaluateArguments> > Sandbox::evaluators_; | |
| 339 | 348 |
| 340 } // namespace | 349 } // namespace |
| OLD | NEW |