NaCl: disable TLS check on IRT nexe
[chromium-blink-merge.git] / ipc / ipc_send_fds_test.cc
blob47c6dd1d226f97343294b497047952b3417fe2b8
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"
7 #include "ipc/ipc_tests.h"
9 #if defined(OS_MACOSX)
10 extern "C" {
11 #include <sandbox.h>
13 #endif
14 #include <fcntl.h>
15 #include <sys/stat.h>
17 #include "base/eintr_wrapper.h"
18 #include "base/message_loop.h"
19 #include "ipc/ipc_channel.h"
20 #include "ipc/ipc_message_utils.h"
21 #include "ipc/ipc_multiprocess_test.h"
22 #include "testing/multiprocess_func_list.h"
24 #if defined(OS_POSIX)
25 #include "base/file_descriptor_posix.h"
27 namespace {
29 const unsigned kNumFDsToSend = 20;
30 const char* kDevZeroPath = "/dev/zero";
32 static void VerifyAndCloseDescriptor(int fd, ino_t inode_num) {
33 // Check that we can read from the FD.
34 char buf;
35 ssize_t amt_read = read(fd, &buf, 1);
36 ASSERT_EQ(amt_read, 1);
37 ASSERT_EQ(buf, 0); // /dev/zero always reads NUL bytes.
39 struct stat st;
40 ASSERT_EQ(fstat(fd, &st), 0);
42 ASSERT_EQ(close(fd), 0);
44 // We compare iNode numbers to check that the file sent over the wire
45 // was actually the same physical file as the one we were expecting.
46 ASSERT_EQ(inode_num, st.st_ino);
49 class MyChannelDescriptorListener : public IPC::Listener {
50 public:
51 MyChannelDescriptorListener(ino_t expected_inode_num)
52 : expected_inode_num_(expected_inode_num),
53 num_fds_received_(0) {}
55 virtual bool OnMessageReceived(const IPC::Message& message) {
56 PickleIterator iter(message);
58 ++num_fds_received_;
59 base::FileDescriptor descriptor;
61 IPC::ParamTraits<base::FileDescriptor>::Read(
62 &message, &iter, &descriptor);
64 VerifyAndCloseDescriptor(descriptor.fd, expected_inode_num_);
65 if (num_fds_received_ == kNumFDsToSend) {
66 MessageLoop::current()->Quit();
68 return true;
71 virtual void OnChannelError() {
72 MessageLoop::current()->Quit();
75 bool GotExpectedNumberOfDescriptors() {
76 return kNumFDsToSend == num_fds_received_;
79 private:
80 ino_t expected_inode_num_;
81 unsigned num_fds_received_;
84 void TestDescriptorServer(IPC::Channel &chan,
85 base::ProcessHandle process_handle) {
86 ASSERT_TRUE(process_handle);
88 for (unsigned i = 0; i < kNumFDsToSend; ++i) {
89 base::FileDescriptor descriptor;
90 const int fd = open(kDevZeroPath, O_RDONLY);
91 ASSERT_GE(fd, 0);
92 descriptor.auto_close = true;
93 descriptor.fd = fd;
95 IPC::Message* message = new IPC::Message(0, // routing_id
96 3, // message type
97 IPC::Message::PRIORITY_NORMAL);
98 IPC::ParamTraits<base::FileDescriptor>::Write(message, descriptor);
99 ASSERT_TRUE(chan.Send(message));
102 // Run message loop.
103 MessageLoop::current()->Run();
105 // Close Channel so client gets its OnChannelError() callback fired.
106 chan.Close();
108 // Cleanup child process.
109 EXPECT_TRUE(base::WaitForSingleProcess(
110 process_handle, base::TimeDelta::FromSeconds(5)));
113 int TestDescriptorClient(ino_t expected_inode_num) {
114 MessageLoopForIO main_message_loop;
115 MyChannelDescriptorListener listener(expected_inode_num);
117 // Setup IPC channel.
118 IPC::Channel chan(kTestClientChannel, IPC::Channel::MODE_CLIENT,
119 &listener);
120 CHECK(chan.Connect());
122 // Run message loop so IPC Channel can handle message IO.
123 MessageLoop::current()->Run();
125 // Verify that the message loop was exited due to getting the correct
126 // number of descriptors, and not because the channel closing unexpectedly.
127 CHECK(listener.GotExpectedNumberOfDescriptors());
129 return 0;
132 } // namespace
134 // ---------------------------------------------------------------------------
135 #if defined(OS_MACOSX)
136 // TODO(port): Make this test cross-platform.
137 MULTIPROCESS_IPC_TEST_MAIN(RunTestDescriptorClientSandboxed) {
138 struct stat st;
139 const int fd = open(kDevZeroPath, O_RDONLY);
140 fstat(fd, &st);
141 if (HANDLE_EINTR(close(fd)) < 0) {
142 return -1;
145 // Enable the Sandbox.
146 char* error_buff = NULL;
147 int error = sandbox_init(kSBXProfilePureComputation, SANDBOX_NAMED,
148 &error_buff);
149 bool success = (error == 0 && error_buff == NULL);
150 if (!success) {
151 return -1;
154 sandbox_free_error(error_buff);
156 // Make sure Sandbox is really enabled.
157 if (open(kDevZeroPath, O_RDONLY) != -1) {
158 LOG(ERROR) << "Sandbox wasn't properly enabled";
159 return -1;
162 // See if we can receive a file descriptor.
163 return TestDescriptorClient(st.st_ino);
166 // Test that FDs are correctly sent to a sandboxed process.
167 TEST_F(IPCChannelTest, DescriptorTestSandboxed) {
168 // Setup IPC channel.
169 MyChannelDescriptorListener listener(-1);
171 IPC::Channel chan(kTestClientChannel, IPC::Channel::MODE_SERVER,
172 &listener);
173 ASSERT_TRUE(chan.Connect());
175 base::ProcessHandle process_handle = SpawnChild(
176 TEST_DESCRIPTOR_CLIENT_SANDBOXED,
177 &chan);
178 TestDescriptorServer(chan, process_handle);
180 #endif // defined(OS_MACOSX)
182 MULTIPROCESS_IPC_TEST_MAIN(RunTestDescriptorClient) {
183 struct stat st;
184 const int fd = open(kDevZeroPath, O_RDONLY);
185 fstat(fd, &st);
186 EXPECT_GE(HANDLE_EINTR(close(fd)), 0);
188 return TestDescriptorClient(st.st_ino);
191 TEST_F(IPCChannelTest, DescriptorTest) {
192 // Setup IPC channel.
193 MyChannelDescriptorListener listener(-1);
195 IPC::Channel chan(kTestClientChannel, IPC::Channel::MODE_SERVER,
196 &listener);
197 ASSERT_TRUE(chan.Connect());
199 base::ProcessHandle process_handle = SpawnChild(TEST_DESCRIPTOR_CLIENT,
200 &chan);
201 TestDescriptorServer(chan, process_handle);
204 #endif // defined(OS_POSIX)