[go: nahoru, domu]

blob: 809f4f576e2d438c0627954c46a3223332d4705c [file] [log] [blame]
jeremy@chromium.orgc2f10ed2009-02-10 00:52:571// Copyright (c) 2009 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
5#include "build/build_config.h"
6
agl@chromium.org946d1b22009-07-22 23:57:217#include "ipc/ipc_tests.h"
jeremy@chromium.orgc2f10ed2009-02-10 00:52:578
jeremy@chromium.orge8351b7e2009-02-10 22:25:399#if defined(OS_MACOSX)
10extern "C" {
11#include <sandbox.h>
12}
13#endif
patrick@chromium.orgd67c2492009-03-20 17:26:0214#include <fcntl.h>
jeremy@chromium.orgc2f10ed2009-02-10 00:52:5715#include <sys/stat.h>
16
agl@chromium.org157c61b2009-05-01 21:37:3117#include "base/eintr_wrapper.h"
jeremy@chromium.orgc2f10ed2009-02-10 00:52:5718#include "base/message_loop.h"
agl@chromium.org946d1b22009-07-22 23:57:2119#include "ipc/ipc_channel.h"
20#include "ipc/ipc_message_utils.h"
brettw@chromium.org20e14912010-08-17 19:40:1121#include "testing/multiprocess_func_list.h"
jeremy@chromium.orgc2f10ed2009-02-10 00:52:5722
23#if defined(OS_POSIX)
erg@google.com7a4de7a62010-08-17 18:38:2424#include "base/file_descriptor_posix.h"
jeremy@chromium.orgc2f10ed2009-02-10 00:52:5725
jeremy@chromium.orge8351b7e2009-02-10 22:25:3926namespace {
27
agl@chromium.org926394462009-02-11 23:23:1228const unsigned kNumFDsToSend = 20;
29const char* kDevZeroPath = "/dev/zero";
jeremy@chromium.orge8351b7e2009-02-10 22:25:3930
31static void VerifyAndCloseDescriptor(int fd, ino_t inode_num) {
32 // Check that we can read from the FD.
33 char buf;
34 ssize_t amt_read = read(fd, &buf, 1);
35 ASSERT_EQ(amt_read, 1);
agl@chromium.org926394462009-02-11 23:23:1236 ASSERT_EQ(buf, 0); // /dev/zero always reads NUL bytes.
jeremy@chromium.orge8351b7e2009-02-10 22:25:3937
38 struct stat st;
39 ASSERT_EQ(fstat(fd, &st), 0);
40
41 ASSERT_EQ(close(fd), 0);
42
43 // We compare iNode numbers to check that the file sent over the wire
44 // was actually the same physical file as the one we were expecting.
45 ASSERT_EQ(inode_num, st.st_ino);
46}
47
jeremy@chromium.orgc2f10ed2009-02-10 00:52:5748class MyChannelDescriptorListener : public IPC::Channel::Listener {
49 public:
jeremy@chromium.orge8351b7e2009-02-10 22:25:3950 MyChannelDescriptorListener(ino_t expected_inode_num)
agl@chromium.org926394462009-02-11 23:23:1251 : expected_inode_num_(expected_inode_num),
52 num_fds_received_(0) {}
jeremy@chromium.orge8351b7e2009-02-10 22:25:3953
jeremy@chromium.orgc2f10ed2009-02-10 00:52:5754 virtual void OnMessageReceived(const IPC::Message& message) {
55 void* iter = NULL;
56
agl@chromium.org926394462009-02-11 23:23:1257 ++num_fds_received_;
agl@chromium.org5fe733de2009-02-11 18:59:2058 base::FileDescriptor descriptor;
jeremy@chromium.orge5a3ea32009-02-11 01:41:0259
jeremy@chromium.orgc2f10ed2009-02-10 00:52:5760 ASSERT_TRUE(
agl@chromium.org5fe733de2009-02-11 18:59:2061 IPC::ParamTraits<base::FileDescriptor>::Read(
62 &message, &iter, &descriptor));
jeremy@chromium.orge8351b7e2009-02-10 22:25:3963
64 VerifyAndCloseDescriptor(descriptor.fd, expected_inode_num_);
agl@chromium.org926394462009-02-11 23:23:1265 if (num_fds_received_ == kNumFDsToSend) {
66 MessageLoop::current()->Quit();
67 }
jeremy@chromium.orgc2f10ed2009-02-10 00:52:5768 }
69
70 virtual void OnChannelError() {
71 MessageLoop::current()->Quit();
72 }
dmaclach@chromium.orgd484ab52010-12-09 01:12:2073
74 bool GotExpectedNumberOfDescriptors() {
75 return kNumFDsToSend == num_fds_received_;
76 }
77
jeremy@chromium.orge8351b7e2009-02-10 22:25:3978 private:
79 ino_t expected_inode_num_;
agl@chromium.org926394462009-02-11 23:23:1280 unsigned num_fds_received_;
jeremy@chromium.orgc2f10ed2009-02-10 00:52:5781};
82
jeremy@chromium.orge8351b7e2009-02-10 22:25:3983void TestDescriptorServer(IPC::Channel &chan,
84 base::ProcessHandle process_handle) {
jeremy@chromium.orgc2f10ed2009-02-10 00:52:5785 ASSERT_TRUE(process_handle);
86
agl@chromium.org926394462009-02-11 23:23:1287 for (unsigned i = 0; i < kNumFDsToSend; ++i) {
88 base::FileDescriptor descriptor;
89 const int fd = open(kDevZeroPath, O_RDONLY);
90 ASSERT_GE(fd, 0);
91 descriptor.auto_close = true;
92 descriptor.fd = fd;
jeremy@chromium.orgc2f10ed2009-02-10 00:52:5793
agl@chromium.org926394462009-02-11 23:23:1294 IPC::Message* message = new IPC::Message(0, // routing_id
95 3, // message type
96 IPC::Message::PRIORITY_NORMAL);
97 IPC::ParamTraits<base::FileDescriptor>::Write(message, descriptor);
dmaclach@chromium.orgd484ab52010-12-09 01:12:2098 ASSERT_TRUE(chan.Send(message));
agl@chromium.org926394462009-02-11 23:23:1299 }
jeremy@chromium.orgc2f10ed2009-02-10 00:52:57100
101 // Run message loop.
102 MessageLoop::current()->Run();
103
104 // Close Channel so client gets its OnChannelError() callback fired.
105 chan.Close();
106
107 // Cleanup child process.
108 EXPECT_TRUE(base::WaitForSingleProcess(process_handle, 5000));
109}
110
jeremy@chromium.orge8351b7e2009-02-10 22:25:39111int TestDescriptorClient(ino_t expected_inode_num) {
jeremy@chromium.orgc2f10ed2009-02-10 00:52:57112 MessageLoopForIO main_message_loop;
jeremy@chromium.orge8351b7e2009-02-10 22:25:39113 MyChannelDescriptorListener listener(expected_inode_num);
jeremy@chromium.orgc2f10ed2009-02-10 00:52:57114
jeremy@chromium.orge8351b7e2009-02-10 22:25:39115 // Setup IPC channel.
jeremy@chromium.orgc2f10ed2009-02-10 00:52:57116 IPC::Channel chan(kTestClientChannel, IPC::Channel::MODE_CLIENT,
117 &listener);
evan@chromium.org39703fb2010-10-19 19:11:15118 CHECK(chan.Connect());
dmaclach@chromium.orgd484ab52010-12-09 01:12:20119
120 // Run message loop so IPC Channel can handle message IO.
jeremy@chromium.orgc2f10ed2009-02-10 00:52:57121 MessageLoop::current()->Run();
jeremy@chromium.orge8351b7e2009-02-10 22:25:39122
dmaclach@chromium.orgd484ab52010-12-09 01:12:20123 // Verify that the message loop was exited due to getting the correct
124 // number of descriptors, and not because the channel closing unexpectedly.
125 CHECK(listener.GotExpectedNumberOfDescriptors());
126
jeremy@chromium.orge8351b7e2009-02-10 22:25:39127 return 0;
128}
129
130} // namespace
131
132// ---------------------------------------------------------------------------
133#if defined(OS_MACOSX)
134// TODO(port): Make this test cross-platform.
135MULTIPROCESS_TEST_MAIN(RunTestDescriptorClientSandboxed) {
136 struct stat st;
agl@chromium.org926394462009-02-11 23:23:12137 const int fd = open(kDevZeroPath, O_RDONLY);
jeremy@chromium.orge8351b7e2009-02-10 22:25:39138 fstat(fd, &st);
thakis@chromium.org34f40942010-10-04 00:34:04139 if (HANDLE_EINTR(close(fd)) < 0) {
140 return -1;
141 }
jeremy@chromium.orge8351b7e2009-02-10 22:25:39142
143 // Enable the Sandbox.
144 char* error_buff = NULL;
145 int error = sandbox_init(kSBXProfilePureComputation, SANDBOX_NAMED,
146 &error_buff);
147 bool success = (error == 0 && error_buff == NULL);
148 if (!success) {
149 return -1;
150 }
151
152 sandbox_free_error(error_buff);
153
154 // Make sure Sandbox is really enabled.
agl@chromium.org926394462009-02-11 23:23:12155 if (open(kDevZeroPath, O_RDONLY) != -1) {
jeremy@chromium.orge8351b7e2009-02-10 22:25:39156 LOG(ERROR) << "Sandbox wasn't properly enabled";
157 return -1;
158 }
159
160 // See if we can receive a file descriptor.
161 return TestDescriptorClient(st.st_ino);
162}
163
164// Test that FDs are correctly sent to a sandboxed process.
165TEST_F(IPCChannelTest, DescriptorTestSandboxed) {
166 // Setup IPC channel.
167 MyChannelDescriptorListener listener(-1);
168
169 IPC::Channel chan(kTestClientChannel, IPC::Channel::MODE_SERVER,
170 &listener);
evan@chromium.org39703fb2010-10-19 19:11:15171 ASSERT_TRUE(chan.Connect());
jeremy@chromium.orge8351b7e2009-02-10 22:25:39172
173 base::ProcessHandle process_handle = SpawnChild(
174 TEST_DESCRIPTOR_CLIENT_SANDBOXED,
175 &chan);
176 TestDescriptorServer(chan, process_handle);
177}
178#endif // defined(OS_MACOSX)
179
180MULTIPROCESS_TEST_MAIN(RunTestDescriptorClient) {
181 struct stat st;
agl@chromium.org926394462009-02-11 23:23:12182 const int fd = open(kDevZeroPath, O_RDONLY);
jeremy@chromium.orge8351b7e2009-02-10 22:25:39183 fstat(fd, &st);
hans@chromium.org460da0392010-09-16 08:15:32184 EXPECT_GE(HANDLE_EINTR(close(fd)), 0);
jeremy@chromium.orge8351b7e2009-02-10 22:25:39185
186 return TestDescriptorClient(st.st_ino);
187}
188
189TEST_F(IPCChannelTest, DescriptorTest) {
190 // Setup IPC channel.
191 MyChannelDescriptorListener listener(-1);
192
193 IPC::Channel chan(kTestClientChannel, IPC::Channel::MODE_SERVER,
194 &listener);
evan@chromium.org39703fb2010-10-19 19:11:15195 ASSERT_TRUE(chan.Connect());
jeremy@chromium.orge8351b7e2009-02-10 22:25:39196
197 base::ProcessHandle process_handle = SpawnChild(TEST_DESCRIPTOR_CLIENT,
198 &chan);
199 TestDescriptorServer(chan, process_handle);
jeremy@chromium.orgc2f10ed2009-02-10 00:52:57200}
201
202#endif // defined(OS_POSIX)