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