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/syscall_broker/broker_process.h" | 5 #include "sandbox/linux/syscall_broker/broker_process.h" |
6 | 6 |
7 #include <errno.h> | 7 #include <errno.h> |
8 #include <fcntl.h> | 8 #include <fcntl.h> |
| 9 #include <poll.h> |
9 #include <sys/resource.h> | 10 #include <sys/resource.h> |
10 #include <sys/stat.h> | 11 #include <sys/stat.h> |
11 #include <sys/types.h> | 12 #include <sys/types.h> |
12 #include <sys/wait.h> | 13 #include <sys/wait.h> |
13 #include <unistd.h> | 14 #include <unistd.h> |
14 | 15 |
15 #include <algorithm> | 16 #include <algorithm> |
16 #include <string> | 17 #include <string> |
17 #include <vector> | 18 #include <vector> |
18 | 19 |
19 #include "base/basictypes.h" | 20 #include "base/basictypes.h" |
20 #include "base/bind.h" | 21 #include "base/bind.h" |
21 #include "base/files/file_util.h" | 22 #include "base/files/file_util.h" |
22 #include "base/files/scoped_file.h" | 23 #include "base/files/scoped_file.h" |
23 #include "base/logging.h" | 24 #include "base/logging.h" |
24 #include "base/memory/scoped_ptr.h" | 25 #include "base/memory/scoped_ptr.h" |
25 #include "base/posix/eintr_wrapper.h" | 26 #include "base/posix/eintr_wrapper.h" |
26 #include "base/posix/unix_domain_socket_linux.h" | 27 #include "base/posix/unix_domain_socket_linux.h" |
| 28 #include "sandbox/linux/syscall_broker/broker_client.h" |
27 #include "sandbox/linux/tests/scoped_temporary_file.h" | 29 #include "sandbox/linux/tests/scoped_temporary_file.h" |
28 #include "sandbox/linux/tests/test_utils.h" | 30 #include "sandbox/linux/tests/test_utils.h" |
29 #include "sandbox/linux/tests/unit_tests.h" | 31 #include "sandbox/linux/tests/unit_tests.h" |
30 #include "testing/gtest/include/gtest/gtest.h" | 32 #include "testing/gtest/include/gtest/gtest.h" |
31 | 33 |
32 namespace sandbox { | 34 namespace sandbox { |
33 | 35 |
| 36 namespace syscall_broker { |
| 37 |
34 class BrokerProcessTestHelper { | 38 class BrokerProcessTestHelper { |
35 public: | 39 public: |
36 static int get_ipc_socketpair(const BrokerProcess* broker) { | 40 static void CloseChannel(BrokerProcess* broker) { broker->CloseChannel(); } |
37 return broker->ipc_socketpair_; | 41 // Get the client's IPC descriptor to send IPC requests directly. |
| 42 // TODO(jln): refator tests to get rid of this. |
| 43 static int GetIPCDescriptor(const BrokerProcess* broker) { |
| 44 return broker->broker_client_->GetIPCDescriptor(); |
38 } | 45 } |
39 }; | 46 }; |
40 | 47 |
41 namespace { | 48 namespace { |
42 | 49 |
43 bool NoOpCallback() { | 50 bool NoOpCallback() { |
44 return true; | 51 return true; |
45 } | 52 } |
46 | 53 |
47 } // namespace | 54 } // namespace |
(...skipping 398 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
446 rlim.rlim_cur = fd_limit; | 453 rlim.rlim_cur = fd_limit; |
447 SANDBOX_ASSERT(0 == setrlimit(RLIMIT_NOFILE, &rlim)); | 454 SANDBOX_ASSERT(0 == setrlimit(RLIMIT_NOFILE, &rlim)); |
448 | 455 |
449 static const char kCpuInfo[] = "/proc/cpuinfo"; | 456 static const char kCpuInfo[] = "/proc/cpuinfo"; |
450 std::vector<std::string> read_whitelist; | 457 std::vector<std::string> read_whitelist; |
451 read_whitelist.push_back(kCpuInfo); | 458 read_whitelist.push_back(kCpuInfo); |
452 | 459 |
453 BrokerProcess open_broker(EPERM, read_whitelist, std::vector<std::string>()); | 460 BrokerProcess open_broker(EPERM, read_whitelist, std::vector<std::string>()); |
454 SANDBOX_ASSERT(open_broker.Init(base::Bind(&NoOpCallback))); | 461 SANDBOX_ASSERT(open_broker.Init(base::Bind(&NoOpCallback))); |
455 | 462 |
456 const int ipc_fd = BrokerProcessTestHelper::get_ipc_socketpair(&open_broker); | 463 const int ipc_fd = BrokerProcessTestHelper::GetIPCDescriptor(&open_broker); |
457 SANDBOX_ASSERT(ipc_fd >= 0); | 464 SANDBOX_ASSERT(ipc_fd >= 0); |
458 | 465 |
459 static const char kBogus[] = "not a pickle"; | 466 static const char kBogus[] = "not a pickle"; |
460 std::vector<int> fds; | 467 std::vector<int> fds; |
461 fds.push_back(message_fd.get()); | 468 fds.push_back(message_fd.get()); |
462 | 469 |
463 // The broker process should only have a couple spare file descriptors | 470 // The broker process should only have a couple spare file descriptors |
464 // available, but for good measure we send it fd_limit bogus IPCs anyway. | 471 // available, but for good measure we send it fd_limit bogus IPCs anyway. |
465 for (rlim_t i = 0; i < fd_limit; ++i) { | 472 for (rlim_t i = 0; i < fd_limit; ++i) { |
466 SANDBOX_ASSERT( | 473 SANDBOX_ASSERT( |
467 UnixDomainSocket::SendMsg(ipc_fd, kBogus, sizeof(kBogus), fds)); | 474 UnixDomainSocket::SendMsg(ipc_fd, kBogus, sizeof(kBogus), fds)); |
468 } | 475 } |
469 | 476 |
470 const int fd = open_broker.Open(kCpuInfo, O_RDONLY); | 477 const int fd = open_broker.Open(kCpuInfo, O_RDONLY); |
471 SANDBOX_ASSERT(fd >= 0); | 478 SANDBOX_ASSERT(fd >= 0); |
472 SANDBOX_ASSERT(0 == IGNORE_EINTR(close(fd))); | 479 SANDBOX_ASSERT(0 == IGNORE_EINTR(close(fd))); |
473 } | 480 } |
474 | 481 |
| 482 bool CloseFD(int fd) { |
| 483 PCHECK(0 == IGNORE_EINTR(close(fd))); |
| 484 return true; |
| 485 } |
| 486 |
| 487 // Return true if the other end of the |reader| pipe was closed, |
| 488 // false if |timeout_in_seconds| was reached or another event |
| 489 // or error occured. |
| 490 bool WaitForClosedPipeWriter(int reader, int timeout_in_ms) { |
| 491 struct pollfd poll_fd = {reader, POLLIN | POLLRDHUP, 0}; |
| 492 const int num_events = HANDLE_EINTR(poll(&poll_fd, 1, timeout_in_ms)); |
| 493 if (1 == num_events && poll_fd.revents | POLLHUP) |
| 494 return true; |
| 495 return false; |
| 496 } |
| 497 |
| 498 // Closing the broker client's IPC channel should terminate the broker |
| 499 // process. |
| 500 TEST(BrokerProcess, BrokerDiesOnClosedChannel) { |
| 501 std::vector<std::string> read_whitelist; |
| 502 read_whitelist.push_back("/proc/cpuinfo"); |
| 503 |
| 504 // Get the writing end of a pipe into the broker (child) process so |
| 505 // that we can reliably detect when it dies. |
| 506 int lifeline_fds[2]; |
| 507 PCHECK(0 == pipe(lifeline_fds)); |
| 508 |
| 509 BrokerProcess open_broker(EPERM, read_whitelist, std::vector<std::string>(), |
| 510 true /* fast_check_in_client */, |
| 511 false /* quiet_failures_for_tests */); |
| 512 ASSERT_TRUE(open_broker.Init(base::Bind(&CloseFD, lifeline_fds[0]))); |
| 513 // Make sure the writing end only exists in the broker process. |
| 514 CloseFD(lifeline_fds[1]); |
| 515 base::ScopedFD reader(lifeline_fds[0]); |
| 516 |
| 517 const pid_t broker_pid = open_broker.broker_pid(); |
| 518 |
| 519 // This should cause the broker process to exit. |
| 520 BrokerProcessTestHelper::CloseChannel(&open_broker); |
| 521 |
| 522 const int kTimeoutInMilliseconds = 5000; |
| 523 const bool broker_lifeline_closed = |
| 524 WaitForClosedPipeWriter(reader.get(), kTimeoutInMilliseconds); |
| 525 // If the broker exited, its lifeline fd should be closed. |
| 526 ASSERT_TRUE(broker_lifeline_closed); |
| 527 // Now check that the broker has exited, but do not reap it. |
| 528 siginfo_t process_info; |
| 529 ASSERT_EQ(0, HANDLE_EINTR(waitid(P_PID, broker_pid, &process_info, |
| 530 WEXITED | WNOWAIT))); |
| 531 EXPECT_EQ(broker_pid, process_info.si_pid); |
| 532 EXPECT_EQ(CLD_EXITED, process_info.si_code); |
| 533 EXPECT_EQ(1, process_info.si_status); |
| 534 } |
| 535 |
| 536 } // namespace syscall_broker |
| 537 |
475 } // namespace sandbox | 538 } // namespace sandbox |
OLD | NEW |