blob: f648b6411ab27c9c6e150f700e89adb00949feb6 [file] [log] [blame]
jbates@chromium.org0fc87362012-03-08 05:42:56 +09001// Copyright (c) 2012 The Chromium Authors. All rights reserved.
agl@chromium.org1c6dcf22009-07-23 08:57:21 +09002// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "build/build_config.h"
6
viettrungluu@chromium.org00155942013-01-26 06:51:35 +09007#if defined(OS_POSIX)
agl@chromium.org1c6dcf22009-07-23 08:57:21 +09008#if defined(OS_MACOSX)
9extern "C" {
10#include <sandbox.h>
kerrnelf8e810e2016-04-13 01:39:06 +090011};
agl@chromium.org1c6dcf22009-07-23 08:57:21 +090012#endif
13#include <fcntl.h>
avi42ebda42015-12-22 11:39:04 +090014#include <stddef.h>
hubbe@chromium.org683920d2013-10-15 09:07:00 +090015#include <sys/socket.h>
agl@chromium.org1c6dcf22009-07-23 08:57:21 +090016#include <sys/stat.h>
viettrungluu@chromium.org00155942013-01-26 06:51:35 +090017#include <unistd.h>
agl@chromium.org1c6dcf22009-07-23 08:57:21 +090018
danakjc3fb6c52016-04-23 13:21:09 +090019#include <memory>
hubbe@chromium.org683920d2013-10-15 09:07:00 +090020#include <queue>
21
22#include "base/callback.h"
erg@google.come6ffcb52010-08-18 03:38:24 +090023#include "base/file_descriptor_posix.h"
skyostile468e662015-05-12 20:29:21 +090024#include "base/location.h"
viettrungluu@chromium.org00155942013-01-26 06:51:35 +090025#include "base/pickle.h"
26#include "base/posix/eintr_wrapper.h"
fdoray284aae52016-06-23 04:56:16 +090027#include "base/run_loop.h"
skyostile468e662015-05-12 20:29:21 +090028#include "base/single_thread_task_runner.h"
hubbe@chromium.org683920d2013-10-15 09:07:00 +090029#include "base/synchronization/waitable_event.h"
gabd3e68cf2016-09-27 06:00:45 +090030#include "base/threading/thread.h"
rockot37e7fa42016-07-20 13:28:32 +090031#include "base/threading/thread_task_runner_handle.h"
morrita33a35902015-01-15 06:17:06 +090032#include "ipc/ipc_message_attachment_set.h"
viettrungluu@chromium.org00155942013-01-26 06:51:35 +090033#include "ipc/ipc_message_utils.h"
34#include "ipc/ipc_test_base.h"
agl@chromium.org1c6dcf22009-07-23 08:57:21 +090035
yusukesf8a50112015-01-06 15:56:34 +090036#if defined(OS_POSIX)
37#include "base/macros.h"
yusukesf8a50112015-01-06 15:56:34 +090038#endif
39
kerrnelf8e810e2016-04-13 01:39:06 +090040#if defined(OS_MACOSX)
41#include "sandbox/mac/seatbelt.h"
42#endif
43
agl@chromium.org1c6dcf22009-07-23 08:57:21 +090044namespace {
45
yusukesdf3387d2015-05-07 04:45:45 +090046const unsigned kNumFDsToSend = 7; // per message
47const unsigned kNumMessages = 20;
agl@chromium.org1c6dcf22009-07-23 08:57:21 +090048const char* kDevZeroPath = "/dev/zero";
49
yusukesf8a50112015-01-06 15:56:34 +090050#if defined(OS_POSIX)
anujk.sharmaf56be5d2015-01-22 14:39:37 +090051static_assert(kNumFDsToSend ==
52 IPC::MessageAttachmentSet::kMaxDescriptorsPerMessage,
53 "The number of FDs to send must be kMaxDescriptorsPerMessage.");
yusukesf8a50112015-01-06 15:56:34 +090054#endif
55
hubbe@chromium.org683920d2013-10-15 09:07:00 +090056class MyChannelDescriptorListenerBase : public IPC::Listener {
agl@chromium.org1c6dcf22009-07-23 08:57:21 +090057 public:
dchengef7721a2014-10-22 11:29:52 +090058 bool OnMessageReceived(const IPC::Message& message) override {
brettwf3146202015-06-03 13:29:25 +090059 base::PickleIterator iter(message);
agl@chromium.org1c6dcf22009-07-23 08:57:21 +090060 base::FileDescriptor descriptor;
yusukesf8a50112015-01-06 15:56:34 +090061 while (IPC::ParamTraits<base::FileDescriptor>::Read(
62 &message, &iter, &descriptor)) {
63 HandleFD(descriptor.fd);
64 }
jam@chromium.org8a2c7842010-12-24 15:19:28 +090065 return true;
agl@chromium.org1c6dcf22009-07-23 08:57:21 +090066 }
67
hubbe@chromium.org683920d2013-10-15 09:07:00 +090068 protected:
69 virtual void HandleFD(int fd) = 0;
70};
71
72class MyChannelDescriptorListener : public MyChannelDescriptorListenerBase {
73 public:
74 explicit MyChannelDescriptorListener(ino_t expected_inode_num)
75 : MyChannelDescriptorListenerBase(),
76 expected_inode_num_(expected_inode_num),
77 num_fds_received_(0) {
hubbe@chromium.org1b503fc2013-10-11 06:12:14 +090078 }
79
benwells@chromium.org6ecd7122013-10-11 13:22:34 +090080 bool GotExpectedNumberOfDescriptors() const {
yusukesf8a50112015-01-06 15:56:34 +090081 return num_fds_received_ == kNumFDsToSend * kNumMessages;
hubbe@chromium.org1b503fc2013-10-11 06:12:14 +090082 }
83
dchengef7721a2014-10-22 11:29:52 +090084 void OnChannelError() override {
ki.stfuad029642015-10-13 02:26:00 +090085 base::MessageLoop::current()->QuitWhenIdle();
dcheng9b01d242014-10-22 03:02:42 +090086 }
hubbe@chromium.org683920d2013-10-15 09:07:00 +090087
88 protected:
dchengef7721a2014-10-22 11:29:52 +090089 void HandleFD(int fd) override {
yusukesf8a50112015-01-06 15:56:34 +090090 ASSERT_GE(fd, 0);
hubbe@chromium.org683920d2013-10-15 09:07:00 +090091 // Check that we can read from the FD.
92 char buf;
93 ssize_t amt_read = read(fd, &buf, 1);
94 ASSERT_EQ(amt_read, 1);
95 ASSERT_EQ(buf, 0); // /dev/zero always reads 0 bytes.
96
97 struct stat st;
98 ASSERT_EQ(fstat(fd, &st), 0);
99
100 ASSERT_EQ(close(fd), 0);
101
102 // Compare inode numbers to check that the file sent over the wire is
103 // actually the one expected.
104 ASSERT_EQ(expected_inode_num_, st.st_ino);
105
106 ++num_fds_received_;
yusukesf8a50112015-01-06 15:56:34 +0900107 if (num_fds_received_ == kNumFDsToSend * kNumMessages)
ki.stfuad029642015-10-13 02:26:00 +0900108 base::MessageLoop::current()->QuitWhenIdle();
hubbe@chromium.org683920d2013-10-15 09:07:00 +0900109 }
110
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900111 private:
112 ino_t expected_inode_num_;
113 unsigned num_fds_received_;
114};
115
sammce3cae212016-10-27 19:13:59 +0900116class IPCSendFdsTest : public IPCChannelMojoTestBase {
viettrungluu@chromium.org00155942013-01-26 06:51:35 +0900117 protected:
118 void RunServer() {
119 // Set up IPC channel and start client.
120 MyChannelDescriptorListener listener(-1);
121 CreateChannel(&listener);
122 ASSERT_TRUE(ConnectChannel());
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900123
yusukesf8a50112015-01-06 15:56:34 +0900124 for (unsigned i = 0; i < kNumMessages; ++i) {
bbudge@chromium.orgab4c6bc2013-11-05 07:28:12 +0900125 IPC::Message* message =
126 new IPC::Message(0, 3, IPC::Message::PRIORITY_NORMAL);
yusukesf8a50112015-01-06 15:56:34 +0900127 for (unsigned j = 0; j < kNumFDsToSend; ++j) {
128 const int fd = open(kDevZeroPath, O_RDONLY);
129 ASSERT_GE(fd, 0);
130 base::FileDescriptor descriptor(fd, true);
131 IPC::ParamTraits<base::FileDescriptor>::Write(message, descriptor);
132 }
viettrungluu@chromium.org00155942013-01-26 06:51:35 +0900133 ASSERT_TRUE(sender()->Send(message));
134 }
135
136 // Run message loop.
fdoray284aae52016-06-23 04:56:16 +0900137 base::RunLoop().Run();
viettrungluu@chromium.org00155942013-01-26 06:51:35 +0900138
139 // Close the channel so the client's OnChannelError() gets fired.
140 channel()->Close();
141
142 EXPECT_TRUE(WaitForClientShutdown());
143 DestroyChannel();
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900144 }
viettrungluu@chromium.org00155942013-01-26 06:51:35 +0900145};
146
amistry87fc78f2016-05-05 14:12:09 +0900147TEST_F(IPCSendFdsTest, DescriptorTest) {
viettrungluu@chromium.org00155942013-01-26 06:51:35 +0900148 Init("SendFdsClient");
149 RunServer();
150}
151
sammce3cae212016-10-27 19:13:59 +0900152class SendFdsTestClientFixture : public IpcChannelMojoTestClient {
153 protected:
154 void SendFdsClientCommon(const std::string& test_client_name,
155 ino_t expected_inode_num) {
156 MyChannelDescriptorListener listener(expected_inode_num);
viettrungluu@chromium.org00155942013-01-26 06:51:35 +0900157
sammce3cae212016-10-27 19:13:59 +0900158 // Set up IPC channel.
159 Connect(&listener);
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900160
sammce3cae212016-10-27 19:13:59 +0900161 // Run message loop.
162 base::RunLoop().Run();
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900163
sammce3cae212016-10-27 19:13:59 +0900164 // Verify that the message loop was exited due to getting the correct number
165 // of descriptors, and not because of the channel closing unexpectedly.
166 EXPECT_TRUE(listener.GotExpectedNumberOfDescriptors());
dmaclach@chromium.org63b5df72010-12-09 10:12:20 +0900167
sammce3cae212016-10-27 19:13:59 +0900168 Close();
169 }
170};
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900171
sammce3cae212016-10-27 19:13:59 +0900172DEFINE_IPC_CHANNEL_MOJO_TEST_CLIENT_WITH_CUSTOM_FIXTURE(
173 SendFdsClient,
174 SendFdsTestClientFixture) {
viettrungluu@chromium.org00155942013-01-26 06:51:35 +0900175 struct stat st;
176 int fd = open(kDevZeroPath, O_RDONLY);
177 fstat(fd, &st);
mark@chromium.orgfa5a0f92013-12-03 23:10:59 +0900178 EXPECT_GE(IGNORE_EINTR(close(fd)), 0);
sammce3cae212016-10-27 19:13:59 +0900179 SendFdsClientCommon("SendFdsClient", st.st_ino);
viettrungluu@chromium.org00155942013-01-26 06:51:35 +0900180}
viettrungluu@chromium.org7d86af22013-01-12 00:13:37 +0900181
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900182#if defined(OS_MACOSX)
viettrungluu@chromium.org00155942013-01-26 06:51:35 +0900183// Test that FDs are correctly sent to a sandboxed process.
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900184// TODO(port): Make this test cross-platform.
viettrungluu@chromium.org00155942013-01-26 06:51:35 +0900185TEST_F(IPCSendFdsTest, DescriptorTestSandboxed) {
186 Init("SendFdsSandboxedClient");
187 RunServer();
188}
189
sammce3cae212016-10-27 19:13:59 +0900190DEFINE_IPC_CHANNEL_MOJO_TEST_CLIENT_WITH_CUSTOM_FIXTURE(
191 SendFdsSandboxedClient,
192 SendFdsTestClientFixture) {
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900193 struct stat st;
194 const int fd = open(kDevZeroPath, O_RDONLY);
195 fstat(fd, &st);
sammce3cae212016-10-27 19:13:59 +0900196 ASSERT_LE(0, IGNORE_EINTR(close(fd)));
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900197
viettrungluu@chromium.org00155942013-01-26 06:51:35 +0900198 // Enable the sandbox.
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900199 char* error_buff = NULL;
kerrnel342941a2016-09-24 09:39:26 +0900200 int error = sandbox::Seatbelt::Init(
201 sandbox::Seatbelt::kProfilePureComputation, SANDBOX_NAMED, &error_buff);
sammce3cae212016-10-27 19:13:59 +0900202 ASSERT_EQ(0, error);
203 ASSERT_FALSE(error_buff);
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900204
kerrnelf8e810e2016-04-13 01:39:06 +0900205 sandbox::Seatbelt::FreeError(error_buff);
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900206
viettrungluu@chromium.org00155942013-01-26 06:51:35 +0900207 // Make sure sandbox is really enabled.
sammce3cae212016-10-27 19:13:59 +0900208 ASSERT_EQ(-1, open(kDevZeroPath, O_RDONLY))
209 << "Sandbox wasn't properly enabled";
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900210
211 // See if we can receive a file descriptor.
sammce3cae212016-10-27 19:13:59 +0900212 SendFdsClientCommon("SendFdsSandboxedClient", st.st_ino);
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900213}
214#endif // defined(OS_MACOSX)
215
viettrungluu@chromium.org7ca19132013-01-12 05:56:22 +0900216} // namespace
217
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900218#endif // defined(OS_POSIX)