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