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" | |
11 #include "sandbox/linux/seccomp-bpf/bpf_tests.h" | 10 #include "sandbox/linux/seccomp-bpf/bpf_tests.h" |
12 #include "sandbox/linux/seccomp-bpf/verifier.h" | 11 #include "sandbox/linux/seccomp-bpf/verifier.h" |
13 #include "sandbox/linux/services/broker_process.h" | |
14 #include "testing/gtest/include/gtest/gtest.h" | 12 #include "testing/gtest/include/gtest/gtest.h" |
15 | 13 |
16 using namespace playground2; | 14 using namespace playground2; |
17 using sandbox::BrokerProcess; | |
18 | 15 |
19 namespace { | 16 namespace { |
20 | 17 |
21 const int kExpectedReturnValue = 42; | 18 const int kExpectedReturnValue = 42; |
22 | 19 |
23 // This test should execute no matter whether we have kernel support. So, | 20 // This test should execute no matter whether we have kernel support. So, |
24 // we make it a TEST() instead of a BPF_TEST(). | 21 // we make it a TEST() instead of a BPF_TEST(). |
25 TEST(SandboxBpf, CallSupports) { | 22 TEST(SandboxBpf, CallSupports) { |
26 // We check that we don't crash, but it's ok if the kernel doesn't | 23 // We check that we don't crash, but it's ok if the kernel doesn't |
27 // support it. | 24 // support it. |
(...skipping 448 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
476 // would make system calls, but it allows us to verify that we don't | 473 // would make system calls, but it allows us to verify that we don't |
477 // accidentally mess with errno, when we shouldn't. | 474 // accidentally mess with errno, when we shouldn't. |
478 errno = 0; | 475 errno = 0; |
479 struct arch_seccomp_data args = { }; | 476 struct arch_seccomp_data args = { }; |
480 args.nr = __NR_close; | 477 args.nr = __NR_close; |
481 args.args[0] = -1; | 478 args.args[0] = -1; |
482 BPF_ASSERT(Sandbox::ForwardSyscall(args) == -EBADF); | 479 BPF_ASSERT(Sandbox::ForwardSyscall(args) == -EBADF); |
483 BPF_ASSERT(errno == 0); | 480 BPF_ASSERT(errno == 0); |
484 } | 481 } |
485 | 482 |
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 | |
583 } // namespace | 483 } // namespace |
OLD | NEW |