OLD | NEW |
(Empty) | |
| 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 |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "sandbox/linux/seccomp-bpf/sandbox_bpf.h" |
| 6 |
| 7 // Some headers on Android are missing cdefs: crbug.com/172337. |
| 8 // (We can't use OS_ANDROID here since build_config.h is not included). |
| 9 #if defined(ANDROID) |
| 10 #include <sys/cdefs.h> |
| 11 #endif |
| 12 |
| 13 #include <errno.h> |
| 14 #include <fcntl.h> |
| 15 #include <linux/filter.h> |
| 16 #include <signal.h> |
| 17 #include <string.h> |
| 18 #include <sys/prctl.h> |
| 19 #include <sys/stat.h> |
| 20 #include <sys/syscall.h> |
| 21 #include <sys/types.h> |
| 22 #include <sys/wait.h> |
| 23 #include <time.h> |
| 24 #include <unistd.h> |
| 25 |
| 26 #include "base/compiler_specific.h" |
| 27 #include "base/logging.h" |
| 28 #include "base/macros.h" |
| 29 #include "base/memory/scoped_ptr.h" |
| 30 #include "base/posix/eintr_wrapper.h" |
| 31 #include "sandbox/linux/bpf_dsl/bpf_dsl.h" |
| 32 #include "sandbox/linux/bpf_dsl/policy_compiler.h" |
| 33 #include "sandbox/linux/seccomp-bpf/codegen.h" |
| 34 #include "sandbox/linux/seccomp-bpf/die.h" |
| 35 #include "sandbox/linux/seccomp-bpf/errorcode.h" |
| 36 #include "sandbox/linux/seccomp-bpf/linux_seccomp.h" |
| 37 #include "sandbox/linux/seccomp-bpf/syscall.h" |
| 38 #include "sandbox/linux/seccomp-bpf/syscall_iterator.h" |
| 39 #include "sandbox/linux/seccomp-bpf/trap.h" |
| 40 #include "sandbox/linux/seccomp-bpf/verifier.h" |
| 41 #include "sandbox/linux/services/linux_syscalls.h" |
| 42 |
| 43 using sandbox::bpf_dsl::Allow; |
| 44 using sandbox::bpf_dsl::Error; |
| 45 using sandbox::bpf_dsl::ResultExpr; |
| 46 using sandbox::bpf_dsl::SandboxBPFDSLPolicy; |
| 47 |
| 48 namespace sandbox { |
| 49 |
| 50 namespace { |
| 51 |
| 52 const int kExpectedExitCode = 100; |
| 53 |
| 54 #if !defined(NDEBUG) |
| 55 void WriteFailedStderrSetupMessage(int out_fd) { |
| 56 const char* error_string = strerror(errno); |
| 57 static const char msg[] = |
| 58 "You have reproduced a puzzling issue.\n" |
| 59 "Please, report to crbug.com/152530!\n" |
| 60 "Failed to set up stderr: "; |
| 61 if (HANDLE_EINTR(write(out_fd, msg, sizeof(msg) - 1)) > 0 && error_string && |
| 62 HANDLE_EINTR(write(out_fd, error_string, strlen(error_string))) > 0 && |
| 63 HANDLE_EINTR(write(out_fd, "\n", 1))) { |
| 64 } |
| 65 } |
| 66 #endif // !defined(NDEBUG) |
| 67 |
| 68 // We define a really simple sandbox policy. It is just good enough for us |
| 69 // to tell that the sandbox has actually been activated. |
| 70 class ProbePolicy : public SandboxBPFDSLPolicy { |
| 71 public: |
| 72 ProbePolicy() {} |
| 73 virtual ~ProbePolicy() {} |
| 74 |
| 75 virtual ResultExpr EvaluateSyscall(int sysnum) const override { |
| 76 switch (sysnum) { |
| 77 case __NR_getpid: |
| 78 // Return EPERM so that we can check that the filter actually ran. |
| 79 return Error(EPERM); |
| 80 case __NR_exit_group: |
| 81 // Allow exit() with a non-default return code. |
| 82 return Allow(); |
| 83 default: |
| 84 // Make everything else fail in an easily recognizable way. |
| 85 return Error(EINVAL); |
| 86 } |
| 87 } |
| 88 |
| 89 private: |
| 90 DISALLOW_COPY_AND_ASSIGN(ProbePolicy); |
| 91 }; |
| 92 |
| 93 void ProbeProcess(void) { |
| 94 if (syscall(__NR_getpid) < 0 && errno == EPERM) { |
| 95 syscall(__NR_exit_group, static_cast<intptr_t>(kExpectedExitCode)); |
| 96 } |
| 97 } |
| 98 |
| 99 class AllowAllPolicy : public SandboxBPFDSLPolicy { |
| 100 public: |
| 101 AllowAllPolicy() {} |
| 102 virtual ~AllowAllPolicy() {} |
| 103 |
| 104 virtual ResultExpr EvaluateSyscall(int sysnum) const override { |
| 105 DCHECK(SandboxBPF::IsValidSyscallNumber(sysnum)); |
| 106 return Allow(); |
| 107 } |
| 108 |
| 109 private: |
| 110 DISALLOW_COPY_AND_ASSIGN(AllowAllPolicy); |
| 111 }; |
| 112 |
| 113 void TryVsyscallProcess(void) { |
| 114 time_t current_time; |
| 115 // time() is implemented as a vsyscall. With an older glibc, with |
| 116 // vsyscall=emulate and some versions of the seccomp BPF patch |
| 117 // we may get SIGKILL-ed. Detect this! |
| 118 if (time(¤t_time) != static_cast<time_t>(-1)) { |
| 119 syscall(__NR_exit_group, static_cast<intptr_t>(kExpectedExitCode)); |
| 120 } |
| 121 } |
| 122 |
| 123 bool IsSingleThreaded(int proc_fd) { |
| 124 if (proc_fd < 0) { |
| 125 // Cannot determine whether program is single-threaded. Hope for |
| 126 // the best... |
| 127 return true; |
| 128 } |
| 129 |
| 130 struct stat sb; |
| 131 int task = -1; |
| 132 if ((task = openat(proc_fd, "self/task", O_RDONLY | O_DIRECTORY)) < 0 || |
| 133 fstat(task, &sb) != 0 || sb.st_nlink != 3 || IGNORE_EINTR(close(task))) { |
| 134 if (task >= 0) { |
| 135 if (IGNORE_EINTR(close(task))) { |
| 136 } |
| 137 } |
| 138 return false; |
| 139 } |
| 140 return true; |
| 141 } |
| 142 |
| 143 } // namespace |
| 144 |
| 145 SandboxBPF::SandboxBPF() |
| 146 : quiet_(false), proc_fd_(-1), sandbox_has_started_(false), policy_() { |
| 147 } |
| 148 |
| 149 SandboxBPF::~SandboxBPF() { |
| 150 } |
| 151 |
| 152 bool SandboxBPF::IsValidSyscallNumber(int sysnum) { |
| 153 return SyscallSet::IsValid(sysnum); |
| 154 } |
| 155 |
| 156 bool SandboxBPF::RunFunctionInPolicy( |
| 157 void (*code_in_sandbox)(), |
| 158 scoped_ptr<bpf_dsl::SandboxBPFDSLPolicy> policy) { |
| 159 // Block all signals before forking a child process. This prevents an |
| 160 // attacker from manipulating our test by sending us an unexpected signal. |
| 161 sigset_t old_mask, new_mask; |
| 162 if (sigfillset(&new_mask) || sigprocmask(SIG_BLOCK, &new_mask, &old_mask)) { |
| 163 SANDBOX_DIE("sigprocmask() failed"); |
| 164 } |
| 165 int fds[2]; |
| 166 if (pipe2(fds, O_NONBLOCK | O_CLOEXEC)) { |
| 167 SANDBOX_DIE("pipe() failed"); |
| 168 } |
| 169 |
| 170 if (fds[0] <= 2 || fds[1] <= 2) { |
| 171 SANDBOX_DIE("Process started without standard file descriptors"); |
| 172 } |
| 173 |
| 174 // This code is using fork() and should only ever run single-threaded. |
| 175 // Most of the code below is "async-signal-safe" and only minor changes |
| 176 // would be needed to support threads. |
| 177 DCHECK(IsSingleThreaded(proc_fd_)); |
| 178 pid_t pid = fork(); |
| 179 if (pid < 0) { |
| 180 // Die if we cannot fork(). We would probably fail a little later |
| 181 // anyway, as the machine is likely very close to running out of |
| 182 // memory. |
| 183 // But what we don't want to do is return "false", as a crafty |
| 184 // attacker might cause fork() to fail at will and could trick us |
| 185 // into running without a sandbox. |
| 186 sigprocmask(SIG_SETMASK, &old_mask, NULL); // OK, if it fails |
| 187 SANDBOX_DIE("fork() failed unexpectedly"); |
| 188 } |
| 189 |
| 190 // In the child process |
| 191 if (!pid) { |
| 192 // Test a very simple sandbox policy to verify that we can |
| 193 // successfully turn on sandboxing. |
| 194 Die::EnableSimpleExit(); |
| 195 |
| 196 errno = 0; |
| 197 if (IGNORE_EINTR(close(fds[0]))) { |
| 198 // This call to close() has been failing in strange ways. See |
| 199 // crbug.com/152530. So we only fail in debug mode now. |
| 200 #if !defined(NDEBUG) |
| 201 WriteFailedStderrSetupMessage(fds[1]); |
| 202 SANDBOX_DIE(NULL); |
| 203 #endif |
| 204 } |
| 205 if (HANDLE_EINTR(dup2(fds[1], 2)) != 2) { |
| 206 // Stderr could very well be a file descriptor to .xsession-errors, or |
| 207 // another file, which could be backed by a file system that could cause |
| 208 // dup2 to fail while trying to close stderr. It's important that we do |
| 209 // not fail on trying to close stderr. |
| 210 // If dup2 fails here, we will continue normally, this means that our |
| 211 // parent won't cause a fatal failure if something writes to stderr in |
| 212 // this child. |
| 213 #if !defined(NDEBUG) |
| 214 // In DEBUG builds, we still want to get a report. |
| 215 WriteFailedStderrSetupMessage(fds[1]); |
| 216 SANDBOX_DIE(NULL); |
| 217 #endif |
| 218 } |
| 219 if (IGNORE_EINTR(close(fds[1]))) { |
| 220 // This call to close() has been failing in strange ways. See |
| 221 // crbug.com/152530. So we only fail in debug mode now. |
| 222 #if !defined(NDEBUG) |
| 223 WriteFailedStderrSetupMessage(fds[1]); |
| 224 SANDBOX_DIE(NULL); |
| 225 #endif |
| 226 } |
| 227 |
| 228 SetSandboxPolicy(policy.release()); |
| 229 if (!StartSandbox(PROCESS_SINGLE_THREADED)) { |
| 230 SANDBOX_DIE(NULL); |
| 231 } |
| 232 |
| 233 // Run our code in the sandbox. |
| 234 code_in_sandbox(); |
| 235 |
| 236 // code_in_sandbox() is not supposed to return here. |
| 237 SANDBOX_DIE(NULL); |
| 238 } |
| 239 |
| 240 // In the parent process. |
| 241 if (IGNORE_EINTR(close(fds[1]))) { |
| 242 SANDBOX_DIE("close() failed"); |
| 243 } |
| 244 if (sigprocmask(SIG_SETMASK, &old_mask, NULL)) { |
| 245 SANDBOX_DIE("sigprocmask() failed"); |
| 246 } |
| 247 int status; |
| 248 if (HANDLE_EINTR(waitpid(pid, &status, 0)) != pid) { |
| 249 SANDBOX_DIE("waitpid() failed unexpectedly"); |
| 250 } |
| 251 bool rc = WIFEXITED(status) && WEXITSTATUS(status) == kExpectedExitCode; |
| 252 |
| 253 // If we fail to support sandboxing, there might be an additional |
| 254 // error message. If so, this was an entirely unexpected and fatal |
| 255 // failure. We should report the failure and somebody must fix |
| 256 // things. This is probably a security-critical bug in the sandboxing |
| 257 // code. |
| 258 if (!rc) { |
| 259 char buf[4096]; |
| 260 ssize_t len = HANDLE_EINTR(read(fds[0], buf, sizeof(buf) - 1)); |
| 261 if (len > 0) { |
| 262 while (len > 1 && buf[len - 1] == '\n') { |
| 263 --len; |
| 264 } |
| 265 buf[len] = '\000'; |
| 266 SANDBOX_DIE(buf); |
| 267 } |
| 268 } |
| 269 if (IGNORE_EINTR(close(fds[0]))) { |
| 270 SANDBOX_DIE("close() failed"); |
| 271 } |
| 272 |
| 273 return rc; |
| 274 } |
| 275 |
| 276 bool SandboxBPF::KernelSupportSeccompBPF() { |
| 277 return RunFunctionInPolicy( |
| 278 ProbeProcess, |
| 279 scoped_ptr<bpf_dsl::SandboxBPFDSLPolicy>(new ProbePolicy())) && |
| 280 RunFunctionInPolicy( |
| 281 TryVsyscallProcess, |
| 282 scoped_ptr<bpf_dsl::SandboxBPFDSLPolicy>(new AllowAllPolicy())); |
| 283 } |
| 284 |
| 285 // static |
| 286 SandboxBPF::SandboxStatus SandboxBPF::SupportsSeccompSandbox(int proc_fd) { |
| 287 // It the sandbox is currently active, we clearly must have support for |
| 288 // sandboxing. |
| 289 if (status_ == STATUS_ENABLED) { |
| 290 return status_; |
| 291 } |
| 292 |
| 293 // Even if the sandbox was previously available, something might have |
| 294 // changed in our run-time environment. Check one more time. |
| 295 if (status_ == STATUS_AVAILABLE) { |
| 296 if (!IsSingleThreaded(proc_fd)) { |
| 297 status_ = STATUS_UNAVAILABLE; |
| 298 } |
| 299 return status_; |
| 300 } |
| 301 |
| 302 if (status_ == STATUS_UNAVAILABLE && IsSingleThreaded(proc_fd)) { |
| 303 // All state transitions resulting in STATUS_UNAVAILABLE are immediately |
| 304 // preceded by STATUS_AVAILABLE. Furthermore, these transitions all |
| 305 // happen, if and only if they are triggered by the process being multi- |
| 306 // threaded. |
| 307 // In other words, if a single-threaded process is currently in the |
| 308 // STATUS_UNAVAILABLE state, it is safe to assume that sandboxing is |
| 309 // actually available. |
| 310 status_ = STATUS_AVAILABLE; |
| 311 return status_; |
| 312 } |
| 313 |
| 314 // If we have not previously checked for availability of the sandbox or if |
| 315 // we otherwise don't believe to have a good cached value, we have to |
| 316 // perform a thorough check now. |
| 317 if (status_ == STATUS_UNKNOWN) { |
| 318 // We create our own private copy of a "Sandbox" object. This ensures that |
| 319 // the object does not have any policies configured, that might interfere |
| 320 // with the tests done by "KernelSupportSeccompBPF()". |
| 321 SandboxBPF sandbox; |
| 322 |
| 323 // By setting "quiet_ = true" we suppress messages for expected and benign |
| 324 // failures (e.g. if the current kernel lacks support for BPF filters). |
| 325 sandbox.quiet_ = true; |
| 326 sandbox.set_proc_fd(proc_fd); |
| 327 status_ = sandbox.KernelSupportSeccompBPF() ? STATUS_AVAILABLE |
| 328 : STATUS_UNSUPPORTED; |
| 329 |
| 330 // As we are performing our tests from a child process, the run-time |
| 331 // environment that is visible to the sandbox is always guaranteed to be |
| 332 // single-threaded. Let's check here whether the caller is single- |
| 333 // threaded. Otherwise, we mark the sandbox as temporarily unavailable. |
| 334 if (status_ == STATUS_AVAILABLE && !IsSingleThreaded(proc_fd)) { |
| 335 status_ = STATUS_UNAVAILABLE; |
| 336 } |
| 337 } |
| 338 return status_; |
| 339 } |
| 340 |
| 341 // static |
| 342 SandboxBPF::SandboxStatus |
| 343 SandboxBPF::SupportsSeccompThreadFilterSynchronization() { |
| 344 // Applying NO_NEW_PRIVS, a BPF filter, and synchronizing the filter across |
| 345 // the thread group are all handled atomically by this syscall. |
| 346 const int rv = syscall( |
| 347 __NR_seccomp, SECCOMP_SET_MODE_FILTER, SECCOMP_FILTER_FLAG_TSYNC, NULL); |
| 348 |
| 349 if (rv == -1 && errno == EFAULT) { |
| 350 return STATUS_AVAILABLE; |
| 351 } else { |
| 352 // TODO(jln): turn these into DCHECK after 417888 is considered fixed. |
| 353 CHECK_EQ(-1, rv); |
| 354 CHECK(ENOSYS == errno || EINVAL == errno); |
| 355 return STATUS_UNSUPPORTED; |
| 356 } |
| 357 } |
| 358 |
| 359 void SandboxBPF::set_proc_fd(int proc_fd) { proc_fd_ = proc_fd; } |
| 360 |
| 361 bool SandboxBPF::StartSandbox(SandboxThreadState thread_state) { |
| 362 CHECK(thread_state == PROCESS_SINGLE_THREADED || |
| 363 thread_state == PROCESS_MULTI_THREADED); |
| 364 |
| 365 if (status_ == STATUS_UNSUPPORTED || status_ == STATUS_UNAVAILABLE) { |
| 366 SANDBOX_DIE( |
| 367 "Trying to start sandbox, even though it is known to be " |
| 368 "unavailable"); |
| 369 return false; |
| 370 } else if (sandbox_has_started_) { |
| 371 SANDBOX_DIE( |
| 372 "Cannot repeatedly start sandbox. Create a separate Sandbox " |
| 373 "object instead."); |
| 374 return false; |
| 375 } |
| 376 if (proc_fd_ < 0) { |
| 377 proc_fd_ = open("/proc", O_RDONLY | O_DIRECTORY); |
| 378 } |
| 379 if (proc_fd_ < 0) { |
| 380 // For now, continue in degraded mode, if we can't access /proc. |
| 381 // In the future, we might want to tighten this requirement. |
| 382 } |
| 383 |
| 384 bool supports_tsync = |
| 385 SupportsSeccompThreadFilterSynchronization() == STATUS_AVAILABLE; |
| 386 |
| 387 if (thread_state == PROCESS_SINGLE_THREADED) { |
| 388 if (!IsSingleThreaded(proc_fd_)) { |
| 389 SANDBOX_DIE("Cannot start sandbox; process is already multi-threaded"); |
| 390 return false; |
| 391 } |
| 392 } else if (thread_state == PROCESS_MULTI_THREADED) { |
| 393 if (IsSingleThreaded(proc_fd_)) { |
| 394 SANDBOX_DIE("Cannot start sandbox; " |
| 395 "process may be single-threaded when reported as not"); |
| 396 return false; |
| 397 } |
| 398 if (!supports_tsync) { |
| 399 SANDBOX_DIE("Cannot start sandbox; kernel does not support synchronizing " |
| 400 "filters for a threadgroup"); |
| 401 return false; |
| 402 } |
| 403 } |
| 404 |
| 405 // We no longer need access to any files in /proc. We want to do this |
| 406 // before installing the filters, just in case that our policy denies |
| 407 // close(). |
| 408 if (proc_fd_ >= 0) { |
| 409 if (IGNORE_EINTR(close(proc_fd_))) { |
| 410 SANDBOX_DIE("Failed to close file descriptor for /proc"); |
| 411 return false; |
| 412 } |
| 413 proc_fd_ = -1; |
| 414 } |
| 415 |
| 416 // Install the filters. |
| 417 InstallFilter(supports_tsync || thread_state == PROCESS_MULTI_THREADED); |
| 418 |
| 419 // We are now inside the sandbox. |
| 420 status_ = STATUS_ENABLED; |
| 421 |
| 422 return true; |
| 423 } |
| 424 |
| 425 // Don't take a scoped_ptr here, polymorphism make their use awkward. |
| 426 void SandboxBPF::SetSandboxPolicy(bpf_dsl::SandboxBPFDSLPolicy* policy) { |
| 427 DCHECK(!policy_); |
| 428 if (sandbox_has_started_) { |
| 429 SANDBOX_DIE("Cannot change policy after sandbox has started"); |
| 430 } |
| 431 policy_.reset(policy); |
| 432 } |
| 433 |
| 434 void SandboxBPF::InstallFilter(bool must_sync_threads) { |
| 435 // We want to be very careful in not imposing any requirements on the |
| 436 // policies that are set with SetSandboxPolicy(). This means, as soon as |
| 437 // the sandbox is active, we shouldn't be relying on libraries that could |
| 438 // be making system calls. This, for example, means we should avoid |
| 439 // using the heap and we should avoid using STL functions. |
| 440 // Temporarily copy the contents of the "program" vector into a |
| 441 // stack-allocated array; and then explicitly destroy that object. |
| 442 // This makes sure we don't ex- or implicitly call new/delete after we |
| 443 // installed the BPF filter program in the kernel. Depending on the |
| 444 // system memory allocator that is in effect, these operators can result |
| 445 // in system calls to things like munmap() or brk(). |
| 446 CodeGen::Program* program = AssembleFilter(false).release(); |
| 447 |
| 448 struct sock_filter bpf[program->size()]; |
| 449 const struct sock_fprog prog = {static_cast<unsigned short>(program->size()), |
| 450 bpf}; |
| 451 memcpy(bpf, &(*program)[0], sizeof(bpf)); |
| 452 delete program; |
| 453 |
| 454 // Make an attempt to release memory that is no longer needed here, rather |
| 455 // than in the destructor. Try to avoid as much as possible to presume of |
| 456 // what will be possible to do in the new (sandboxed) execution environment. |
| 457 policy_.reset(); |
| 458 |
| 459 if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) { |
| 460 SANDBOX_DIE(quiet_ ? NULL : "Kernel refuses to enable no-new-privs"); |
| 461 } |
| 462 |
| 463 // Install BPF filter program. If the thread state indicates multi-threading |
| 464 // support, then the kernel hass the seccomp system call. Otherwise, fall |
| 465 // back on prctl, which requires the process to be single-threaded. |
| 466 if (must_sync_threads) { |
| 467 int rv = syscall(__NR_seccomp, SECCOMP_SET_MODE_FILTER, |
| 468 SECCOMP_FILTER_FLAG_TSYNC, reinterpret_cast<const char*>(&prog)); |
| 469 if (rv) { |
| 470 SANDBOX_DIE(quiet_ ? NULL : |
| 471 "Kernel refuses to turn on and synchronize threads for BPF filters"); |
| 472 } |
| 473 } else { |
| 474 if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog)) { |
| 475 SANDBOX_DIE(quiet_ ? NULL : "Kernel refuses to turn on BPF filters"); |
| 476 } |
| 477 } |
| 478 |
| 479 sandbox_has_started_ = true; |
| 480 } |
| 481 |
| 482 scoped_ptr<CodeGen::Program> SandboxBPF::AssembleFilter( |
| 483 bool force_verification) { |
| 484 #if !defined(NDEBUG) |
| 485 force_verification = true; |
| 486 #endif |
| 487 |
| 488 bpf_dsl::PolicyCompiler compiler(policy_.get(), Trap::Registry()); |
| 489 scoped_ptr<CodeGen::Program> program = compiler.Compile(); |
| 490 |
| 491 // Make sure compilation resulted in BPF program that executes |
| 492 // correctly. Otherwise, there is an internal error in our BPF compiler. |
| 493 // There is really nothing the caller can do until the bug is fixed. |
| 494 if (force_verification) { |
| 495 // Verification is expensive. We only perform this step, if we are |
| 496 // compiled in debug mode, or if the caller explicitly requested |
| 497 // verification. |
| 498 |
| 499 const char* err = NULL; |
| 500 if (!Verifier::VerifyBPF(&compiler, *program, *policy_, &err)) { |
| 501 CodeGen::PrintProgram(*program); |
| 502 SANDBOX_DIE(err); |
| 503 } |
| 504 } |
| 505 |
| 506 return program.Pass(); |
| 507 } |
| 508 |
| 509 bool SandboxBPF::IsRequiredForUnsafeTrap(int sysno) { |
| 510 return bpf_dsl::PolicyCompiler::IsRequiredForUnsafeTrap(sysno); |
| 511 } |
| 512 |
| 513 intptr_t SandboxBPF::ForwardSyscall(const struct arch_seccomp_data& args) { |
| 514 return Syscall::Call(args.nr, |
| 515 static_cast<intptr_t>(args.args[0]), |
| 516 static_cast<intptr_t>(args.args[1]), |
| 517 static_cast<intptr_t>(args.args[2]), |
| 518 static_cast<intptr_t>(args.args[3]), |
| 519 static_cast<intptr_t>(args.args[4]), |
| 520 static_cast<intptr_t>(args.args[5])); |
| 521 } |
| 522 |
| 523 SandboxBPF::SandboxStatus SandboxBPF::status_ = STATUS_UNKNOWN; |
| 524 |
| 525 } // namespace sandbox |
OLD | NEW |