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.
5 #include "build/build_config.h"
17 #include "base/file_descriptor_posix.h"
18 #include "base/message_loop.h"
19 #include "base/pickle.h"
20 #include "base/posix/eintr_wrapper.h"
21 #include "ipc/ipc_message_utils.h"
22 #include "ipc/ipc_test_base.h"
26 const unsigned kNumFDsToSend
= 20;
27 const char* kDevZeroPath
= "/dev/zero";
29 static void VerifyAndCloseDescriptor(int fd
, ino_t inode_num
) {
30 // Check that we can read from the FD.
32 ssize_t amt_read
= read(fd
, &buf
, 1);
33 ASSERT_EQ(amt_read
, 1);
34 ASSERT_EQ(buf
, 0); // /dev/zero always reads 0 bytes.
37 ASSERT_EQ(fstat(fd
, &st
), 0);
39 ASSERT_EQ(close(fd
), 0);
41 // Compare inode numbers to check that the file sent over the wire is actually
43 ASSERT_EQ(inode_num
, st
.st_ino
);
46 class MyChannelDescriptorListener
: public IPC::Listener
{
48 explicit MyChannelDescriptorListener(ino_t expected_inode_num
)
49 : expected_inode_num_(expected_inode_num
),
50 num_fds_received_(0) {}
52 virtual bool OnMessageReceived(const IPC::Message
& message
) OVERRIDE
{
53 PickleIterator
iter(message
);
56 base::FileDescriptor descriptor
;
58 IPC::ParamTraits
<base::FileDescriptor
>::Read(&message
, &iter
, &descriptor
);
60 VerifyAndCloseDescriptor(descriptor
.fd
, expected_inode_num_
);
61 if (num_fds_received_
== kNumFDsToSend
)
62 MessageLoop::current()->Quit();
67 virtual void OnChannelError() OVERRIDE
{
68 MessageLoop::current()->Quit();
71 bool GotExpectedNumberOfDescriptors() const {
72 return num_fds_received_
== kNumFDsToSend
;
76 ino_t expected_inode_num_
;
77 unsigned num_fds_received_
;
80 class IPCSendFdsTest
: public IPCTestBase
{
83 // Set up IPC channel and start client.
84 MyChannelDescriptorListener
listener(-1);
85 CreateChannel(&listener
);
86 ASSERT_TRUE(ConnectChannel());
87 ASSERT_TRUE(StartClient());
89 for (unsigned i
= 0; i
< kNumFDsToSend
; ++i
) {
90 const int fd
= open(kDevZeroPath
, O_RDONLY
);
92 base::FileDescriptor
descriptor(fd
, true);
94 IPC::Message
* message
=
95 new IPC::Message(0, 3, IPC::Message::PRIORITY_NORMAL
);
96 IPC::ParamTraits
<base::FileDescriptor
>::Write(message
, descriptor
);
97 ASSERT_TRUE(sender()->Send(message
));
101 MessageLoop::current()->Run();
103 // Close the channel so the client's OnChannelError() gets fired.
106 EXPECT_TRUE(WaitForClientShutdown());
111 TEST_F(IPCSendFdsTest
, DescriptorTest
) {
112 Init("SendFdsClient");
116 int SendFdsClientCommon(const std::string
& test_client_name
,
117 ino_t expected_inode_num
) {
118 MessageLoopForIO main_message_loop
;
119 MyChannelDescriptorListener
listener(expected_inode_num
);
121 // Set up IPC channel.
122 IPC::Channel
channel(IPCTestBase::GetChannelName(test_client_name
),
123 IPC::Channel::MODE_CLIENT
,
125 CHECK(channel
.Connect());
128 MessageLoop::current()->Run();
130 // Verify that the message loop was exited due to getting the correct number
131 // of descriptors, and not because of the channel closing unexpectedly.
132 CHECK(listener
.GotExpectedNumberOfDescriptors());
137 MULTIPROCESS_IPC_TEST_CLIENT_MAIN(SendFdsClient
) {
139 int fd
= open(kDevZeroPath
, O_RDONLY
);
141 EXPECT_GE(HANDLE_EINTR(close(fd
)), 0);
142 return SendFdsClientCommon("SendFdsClient", st
.st_ino
);
145 #if defined(OS_MACOSX)
146 // Test that FDs are correctly sent to a sandboxed process.
147 // TODO(port): Make this test cross-platform.
148 TEST_F(IPCSendFdsTest
, DescriptorTestSandboxed
) {
149 Init("SendFdsSandboxedClient");
153 MULTIPROCESS_IPC_TEST_CLIENT_MAIN(SendFdsSandboxedClient
) {
155 const int fd
= open(kDevZeroPath
, O_RDONLY
);
157 if (HANDLE_EINTR(close(fd
)) < 0)
160 // Enable the sandbox.
161 char* error_buff
= NULL
;
162 int error
= sandbox_init(kSBXProfilePureComputation
, SANDBOX_NAMED
,
164 bool success
= (error
== 0 && error_buff
== NULL
);
168 sandbox_free_error(error_buff
);
170 // Make sure sandbox is really enabled.
171 if (open(kDevZeroPath
, O_RDONLY
) != -1) {
172 LOG(ERROR
) << "Sandbox wasn't properly enabled";
176 // See if we can receive a file descriptor.
177 return SendFdsClientCommon("SendFdsSandboxedClient", st
.st_ino
);
179 #endif // defined(OS_MACOSX)
183 #endif // defined(OS_POSIX)