| 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 232 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 (uint32_t 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 #ifndef NDEBUG |
| 291 BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_KILL)); | 299 const char *err = NULL; |
| 300 if (!Verifier::verifyBPF(program, evaluators_, &err)) { |
| 301 die(err); |
| 302 } |
| 303 #endif |
| 292 | 304 |
| 293 // Install BPF filter program | 305 // Install BPF filter program |
| 294 const struct sock_fprog prog = { program.size(), &program[0] }; | 306 const struct sock_fprog prog = { program.size(), &program[0] }; |
| 295 if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) || | 307 if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) || |
| 296 prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog)) { | 308 prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog)) { |
| 297 goto filter_failed; | 309 goto filter_failed; |
| 298 } | 310 } |
| 299 | 311 |
| 300 return; | 312 return; |
| 301 } | 313 } |
| (...skipping 25 matching lines...) Expand all Loading... |
| 327 | 339 |
| 328 ctx->uc_mcontext.gregs[REG_RESULT] = reinterpret_cast<greg_t>(rc); | 340 ctx->uc_mcontext.gregs[REG_RESULT] = reinterpret_cast<greg_t>(rc); |
| 329 errno = old_errno; | 341 errno = old_errno; |
| 330 return; | 342 return; |
| 331 } | 343 } |
| 332 | 344 |
| 333 | 345 |
| 334 bool Sandbox::suppressLogging_ = false; | 346 bool Sandbox::suppressLogging_ = false; |
| 335 Sandbox::SandboxStatus Sandbox::status_ = STATUS_UNKNOWN; | 347 Sandbox::SandboxStatus Sandbox::status_ = STATUS_UNKNOWN; |
| 336 int Sandbox::proc_fd_ = -1; | 348 int Sandbox::proc_fd_ = -1; |
| 337 std::vector<std::pair<Sandbox::EvaluateSyscall, | 349 Sandbox::Evaluators Sandbox::evaluators_; |
| 338 Sandbox::EvaluateArguments> > Sandbox::evaluators_; | |
| 339 | 350 |
| 340 } // namespace | 351 } // namespace |
| OLD | NEW |