ipc_send_fds_test.cc 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  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. #include "build/build_config.h"
  5. #if BUILDFLAG(IS_MAC)
  6. extern "C" {
  7. #include <sandbox.h>
  8. }
  9. #endif
  10. #include <fcntl.h>
  11. #include <stddef.h>
  12. #include <sys/socket.h>
  13. #include <sys/stat.h>
  14. #include <unistd.h>
  15. #include <memory>
  16. #include <queue>
  17. #include "base/file_descriptor_posix.h"
  18. #include "base/pickle.h"
  19. #include "base/posix/eintr_wrapper.h"
  20. #include "base/run_loop.h"
  21. #include "base/synchronization/waitable_event.h"
  22. #include "base/task/single_thread_task_runner.h"
  23. #include "base/threading/thread.h"
  24. #include "base/threading/thread_task_runner_handle.h"
  25. #include "ipc/ipc_message_attachment_set.h"
  26. #include "ipc/ipc_message_utils.h"
  27. #include "ipc/ipc_test_base.h"
  28. #if BUILDFLAG(IS_MAC)
  29. #include "sandbox/mac/seatbelt.h"
  30. #elif BUILDFLAG(IS_FUCHSIA)
  31. #include "base/memory/scoped_refptr.h"
  32. #include "base/test/scoped_dev_zero_fuchsia.h"
  33. #endif
  34. namespace {
  35. const unsigned kNumFDsToSend = 7; // per message
  36. const unsigned kNumMessages = 20;
  37. const char* kDevZeroPath = "/dev/zero";
  38. static_assert(kNumFDsToSend ==
  39. IPC::MessageAttachmentSet::kMaxDescriptorsPerMessage,
  40. "The number of FDs to send must be kMaxDescriptorsPerMessage.");
  41. class MyChannelDescriptorListenerBase : public IPC::Listener {
  42. public:
  43. bool OnMessageReceived(const IPC::Message& message) override {
  44. base::PickleIterator iter(message);
  45. base::FileDescriptor descriptor;
  46. while (IPC::ParamTraits<base::FileDescriptor>::Read(
  47. &message, &iter, &descriptor)) {
  48. HandleFD(descriptor.fd);
  49. }
  50. return true;
  51. }
  52. protected:
  53. virtual void HandleFD(int fd) = 0;
  54. };
  55. class MyChannelDescriptorListener : public MyChannelDescriptorListenerBase {
  56. public:
  57. explicit MyChannelDescriptorListener(ino_t expected_inode_num)
  58. : MyChannelDescriptorListenerBase(),
  59. expected_inode_num_(expected_inode_num),
  60. num_fds_received_(0) {
  61. }
  62. unsigned num_fds_received() const {
  63. return num_fds_received_;
  64. }
  65. void OnChannelError() override {
  66. base::RunLoop::QuitCurrentWhenIdleDeprecated();
  67. }
  68. protected:
  69. void HandleFD(int fd) override {
  70. ASSERT_GE(fd, 0);
  71. // Check that we can read from the FD.
  72. char buf;
  73. ssize_t amt_read = read(fd, &buf, 1);
  74. ASSERT_EQ(amt_read, 1);
  75. ASSERT_EQ(buf, 0); // /dev/zero always reads 0 bytes.
  76. struct stat st;
  77. ASSERT_EQ(fstat(fd, &st), 0);
  78. ASSERT_EQ(close(fd), 0);
  79. // Compare inode numbers to check that the file sent over the wire is
  80. // actually the one expected.
  81. ASSERT_EQ(expected_inode_num_, st.st_ino);
  82. ++num_fds_received_;
  83. if (num_fds_received_ == kNumFDsToSend * kNumMessages)
  84. base::RunLoop::QuitCurrentWhenIdleDeprecated();
  85. }
  86. private:
  87. ino_t expected_inode_num_;
  88. unsigned num_fds_received_;
  89. };
  90. class IPCSendFdsTest : public IPCChannelMojoTestBase {
  91. protected:
  92. void SetUp() override {
  93. #if BUILDFLAG(IS_FUCHSIA)
  94. ASSERT_TRUE(dev_zero_);
  95. #endif
  96. }
  97. void RunServer() {
  98. // Set up IPC channel and start client.
  99. MyChannelDescriptorListener listener(-1);
  100. CreateChannel(&listener);
  101. ASSERT_TRUE(ConnectChannel());
  102. for (unsigned i = 0; i < kNumMessages; ++i) {
  103. IPC::Message* message =
  104. new IPC::Message(0, 3, IPC::Message::PRIORITY_NORMAL);
  105. for (unsigned j = 0; j < kNumFDsToSend; ++j) {
  106. const int fd = open(kDevZeroPath, O_RDONLY);
  107. ASSERT_GE(fd, 0);
  108. base::FileDescriptor descriptor(fd, true);
  109. IPC::ParamTraits<base::FileDescriptor>::Write(message, descriptor);
  110. }
  111. ASSERT_TRUE(sender()->Send(message));
  112. }
  113. // Run message loop.
  114. base::RunLoop().Run();
  115. // Close the channel so the client's OnChannelError() gets fired.
  116. channel()->Close();
  117. EXPECT_TRUE(WaitForClientShutdown());
  118. DestroyChannel();
  119. }
  120. private:
  121. #if BUILDFLAG(IS_FUCHSIA)
  122. scoped_refptr<base::ScopedDevZero> dev_zero_ = base::ScopedDevZero::Get();
  123. #endif
  124. };
  125. // Disabled on Fuchsia due to failures; see https://crbug.com/1272424.
  126. #if BUILDFLAG(IS_FUCHSIA)
  127. #define MAYBE_DescriptorTest DISABLED_DescriptorTest
  128. #else
  129. #define MAYBE_DescriptorTest DescriptorTest
  130. #endif
  131. TEST_F(IPCSendFdsTest, MAYBE_DescriptorTest) {
  132. Init("SendFdsClient");
  133. RunServer();
  134. }
  135. class SendFdsTestClientFixture : public IpcChannelMojoTestClient {
  136. protected:
  137. void SendFdsClientCommon(const std::string& test_client_name,
  138. ino_t expected_inode_num) {
  139. MyChannelDescriptorListener listener(expected_inode_num);
  140. // Set up IPC channel.
  141. Connect(&listener);
  142. // Run message loop.
  143. base::RunLoop().Run();
  144. // Verify that the message loop was exited due to getting the correct number
  145. // of descriptors, and not because of the channel closing unexpectedly.
  146. EXPECT_EQ(kNumFDsToSend * kNumMessages, listener.num_fds_received());
  147. Close();
  148. }
  149. };
  150. DEFINE_IPC_CHANNEL_MOJO_TEST_CLIENT_WITH_CUSTOM_FIXTURE(
  151. SendFdsClient,
  152. SendFdsTestClientFixture) {
  153. struct stat st;
  154. int fd = open(kDevZeroPath, O_RDONLY);
  155. fstat(fd, &st);
  156. EXPECT_GE(IGNORE_EINTR(close(fd)), 0);
  157. SendFdsClientCommon("SendFdsClient", st.st_ino);
  158. }
  159. #if BUILDFLAG(IS_MAC)
  160. // Test that FDs are correctly sent to a sandboxed process.
  161. // TODO(port): Make this test cross-platform.
  162. TEST_F(IPCSendFdsTest, DescriptorTestSandboxed) {
  163. Init("SendFdsSandboxedClient");
  164. RunServer();
  165. }
  166. DEFINE_IPC_CHANNEL_MOJO_TEST_CLIENT_WITH_CUSTOM_FIXTURE(
  167. SendFdsSandboxedClient,
  168. SendFdsTestClientFixture) {
  169. struct stat st;
  170. const int fd = open(kDevZeroPath, O_RDONLY);
  171. fstat(fd, &st);
  172. ASSERT_LE(0, IGNORE_EINTR(close(fd)));
  173. // Enable the sandbox.
  174. char* error_buff = NULL;
  175. int error = sandbox::Seatbelt::Init(
  176. sandbox::Seatbelt::kProfilePureComputation, SANDBOX_NAMED, &error_buff);
  177. ASSERT_EQ(0, error);
  178. ASSERT_FALSE(error_buff);
  179. sandbox::Seatbelt::FreeError(error_buff);
  180. // Make sure sandbox is really enabled.
  181. ASSERT_EQ(-1, open(kDevZeroPath, O_RDONLY))
  182. << "Sandbox wasn't properly enabled";
  183. // See if we can receive a file descriptor.
  184. SendFdsClientCommon("SendFdsSandboxedClient", st.st_ino);
  185. }
  186. #endif // BUILDFLAG(IS_MAC)
  187. } // namespace