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 <sys/prctl.h> | 5 #include <sys/prctl.h> |
6 #include <sys/utsname.h> | 6 #include <sys/utsname.h> |
7 | 7 |
8 #include <ostream> | 8 #include <ostream> |
9 | 9 |
| 10 #include "base/memory/scoped_ptr.h" |
10 #include "sandbox/linux/seccomp-bpf/bpf_tests.h" | 11 #include "sandbox/linux/seccomp-bpf/bpf_tests.h" |
11 #include "sandbox/linux/seccomp-bpf/verifier.h" | 12 #include "sandbox/linux/seccomp-bpf/verifier.h" |
| 13 #include "sandbox/linux/services/broker_process.h" |
12 #include "testing/gtest/include/gtest/gtest.h" | 14 #include "testing/gtest/include/gtest/gtest.h" |
13 | 15 |
14 using namespace playground2; | 16 using namespace playground2; |
| 17 using sandbox::BrokerProcess; |
15 | 18 |
16 namespace { | 19 namespace { |
17 | 20 |
18 const int kExpectedReturnValue = 42; | 21 const int kExpectedReturnValue = 42; |
19 | 22 |
20 // This test should execute no matter whether we have kernel support. So, | 23 // This test should execute no matter whether we have kernel support. So, |
21 // we make it a TEST() instead of a BPF_TEST(). | 24 // we make it a TEST() instead of a BPF_TEST(). |
22 TEST(SandboxBpf, CallSupports) { | 25 TEST(SandboxBpf, CallSupports) { |
23 // We check that we don't crash, but it's ok if the kernel doesn't | 26 // We check that we don't crash, but it's ok if the kernel doesn't |
24 // support it. | 27 // support it. |
(...skipping 448 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
473 // would make system calls, but it allows us to verify that we don't | 476 // would make system calls, but it allows us to verify that we don't |
474 // accidentally mess with errno, when we shouldn't. | 477 // accidentally mess with errno, when we shouldn't. |
475 errno = 0; | 478 errno = 0; |
476 struct arch_seccomp_data args = { }; | 479 struct arch_seccomp_data args = { }; |
477 args.nr = __NR_close; | 480 args.nr = __NR_close; |
478 args.args[0] = -1; | 481 args.args[0] = -1; |
479 BPF_ASSERT(Sandbox::ForwardSyscall(args) == -EBADF); | 482 BPF_ASSERT(Sandbox::ForwardSyscall(args) == -EBADF); |
480 BPF_ASSERT(errno == 0); | 483 BPF_ASSERT(errno == 0); |
481 } | 484 } |
482 | 485 |
| 486 // Test a trap handler that makes use of a broker process to open(). |
| 487 |
| 488 class InitializedOpenBroker { |
| 489 public: |
| 490 InitializedOpenBroker() : initialized_(false) { |
| 491 std::vector<std::string> allowed_files; |
| 492 allowed_files.push_back("/proc/allowed"); |
| 493 allowed_files.push_back("/proc/cpuinfo"); |
| 494 |
| 495 broker_process_.reset(new BrokerProcess(allowed_files, |
| 496 std::vector<std::string>())); |
| 497 BPF_ASSERT(broker_process() != NULL); |
| 498 BPF_ASSERT(broker_process_->Init(NULL)); |
| 499 |
| 500 initialized_ = true; |
| 501 } |
| 502 bool initialized() { return initialized_; } |
| 503 class BrokerProcess* broker_process() { return broker_process_.get(); } |
| 504 private: |
| 505 bool initialized_; |
| 506 scoped_ptr<class BrokerProcess> broker_process_; |
| 507 DISALLOW_COPY_AND_ASSIGN(InitializedOpenBroker); |
| 508 }; |
| 509 |
| 510 intptr_t BrokerOpenTrapHandler(const struct arch_seccomp_data& args, |
| 511 void *aux) { |
| 512 BPF_ASSERT(aux); |
| 513 BrokerProcess* broker_process = static_cast<BrokerProcess*>(aux); |
| 514 switch(args.nr) { |
| 515 case __NR_open: |
| 516 return broker_process->Open(reinterpret_cast<const char*>(args.args[0]), |
| 517 static_cast<int>(args.args[1])); |
| 518 case __NR_openat: |
| 519 // We only call open() so if we arrive here, it's because glibc uses |
| 520 // the openat() system call. |
| 521 BPF_ASSERT(static_cast<int>(args.args[0]) == AT_FDCWD); |
| 522 return broker_process->Open(reinterpret_cast<const char*>(args.args[1]), |
| 523 static_cast<int>(args.args[2])); |
| 524 default: |
| 525 BPF_ASSERT(false); |
| 526 return -ENOSYS; |
| 527 } |
| 528 } |
| 529 |
| 530 ErrorCode DenyOpenPolicy(int sysno, void *aux) { |
| 531 InitializedOpenBroker* iob = static_cast<InitializedOpenBroker*>(aux); |
| 532 if (!Sandbox::isValidSyscallNumber(sysno)) { |
| 533 return ErrorCode(ENOSYS); |
| 534 } |
| 535 |
| 536 switch (sysno) { |
| 537 case __NR_open: |
| 538 case __NR_openat: |
| 539 // We get a InitializedOpenBroker class, but our trap handler wants |
| 540 // the BrokerProcess object. |
| 541 return ErrorCode(Sandbox::Trap(BrokerOpenTrapHandler, |
| 542 iob->broker_process())); |
| 543 default: |
| 544 return ErrorCode(ErrorCode::ERR_ALLOWED); |
| 545 } |
| 546 } |
| 547 |
| 548 // We use a InitializedOpenBroker class, so that we can run unsandboxed |
| 549 // code in its constructor, which is the only way to do so in a BPF_TEST. |
| 550 BPF_TEST(SandboxBpf, UseOpenBroker, DenyOpenPolicy, |
| 551 InitializedOpenBroker /* BPF_AUX */) { |
| 552 BPF_ASSERT(BPF_AUX.initialized()); |
| 553 BrokerProcess* broker_process = BPF_AUX.broker_process(); |
| 554 BPF_ASSERT(broker_process != NULL); |
| 555 |
| 556 // First, use the broker "manually" |
| 557 BPF_ASSERT(broker_process->Open("/proc/denied", O_RDONLY) == -EPERM); |
| 558 BPF_ASSERT(broker_process->Open("/proc/allowed", O_RDONLY) == -ENOENT); |
| 559 |
| 560 // Now use glibc's open() as an external library would. |
| 561 BPF_ASSERT(open("/proc/denied", O_RDONLY) == -1); |
| 562 BPF_ASSERT(errno == EPERM); |
| 563 |
| 564 BPF_ASSERT(open("/proc/allowed", O_RDONLY) == -1); |
| 565 BPF_ASSERT(errno == ENOENT); |
| 566 |
| 567 // Also test glibc's openat(), some versions of libc use it transparently |
| 568 // instead of open(). |
| 569 BPF_ASSERT(openat(AT_FDCWD, "/proc/denied", O_RDONLY) == -1); |
| 570 BPF_ASSERT(errno == EPERM); |
| 571 |
| 572 BPF_ASSERT(openat(AT_FDCWD, "/proc/allowed", O_RDONLY) == -1); |
| 573 BPF_ASSERT(errno == ENOENT); |
| 574 |
| 575 |
| 576 // This is also white listed and does exist. |
| 577 int cpu_info_fd = open("/proc/cpuinfo", O_RDONLY); |
| 578 BPF_ASSERT(cpu_info_fd >= 0); |
| 579 char buf[1024]; |
| 580 BPF_ASSERT(read(cpu_info_fd, buf, sizeof(buf)) > 0); |
| 581 } |
| 582 |
483 } // namespace | 583 } // namespace |
OLD | NEW |