xref: /aosp_15_r20/external/libchrome/ipc/ipc_send_fds_test.cc (revision 635a864187cb8b6c713ff48b7e790a6b21769273)
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