xref: /aosp_15_r20/external/cronet/ipc/ipc_send_fds_test.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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