1 // Copyright 2014 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #ifdef UNSAFE_BUFFERS_BUILD
6 // TODO(crbug.com/351564777): Remove this and convert code to safer constructs.
7 #pragma allow_unsafe_buffers
8 #endif
9
10 #include "ipc/ipc_mojo_bootstrap.h"
11
12 #include <cstdint>
13 #include <memory>
14 #include <utility>
15
16 #include "base/run_loop.h"
17 #include "base/task/single_thread_task_runner.h"
18 #include "base/test/task_environment.h"
19 #include "ipc/ipc.mojom.h"
20 #include "ipc/ipc_test_base.h"
21 #include "mojo/core/test/multiprocess_test_helper.h"
22 #include "mojo/public/cpp/bindings/associated_receiver.h"
23
24 namespace {
25
26 constexpr int32_t kTestServerPid = 42;
27 constexpr int32_t kTestClientPid = 4242;
28
29 class Connection {
30 public:
Connection(std::unique_ptr<IPC::MojoBootstrap> bootstrap,int32_t sender_id)31 explicit Connection(std::unique_ptr<IPC::MojoBootstrap> bootstrap,
32 int32_t sender_id)
33 : bootstrap_(std::move(bootstrap)) {
34 mojo::PendingAssociatedRemote<IPC::mojom::Channel> sender;
35 bootstrap_->Connect(&sender, &receiver_);
36 sender_.Bind(std::move(sender));
37 sender_->SetPeerPid(sender_id);
38
39 // It's OK to start receiving right away even though `receiver_` isn't
40 // bound, because all of these tests are single-threaded and it will be
41 // bound before any incoming messages can be scheduled for processing.
42 bootstrap_->StartReceiving();
43 }
44
TakeReceiver(mojo::PendingAssociatedReceiver<IPC::mojom::Channel> * receiver)45 void TakeReceiver(
46 mojo::PendingAssociatedReceiver<IPC::mojom::Channel>* receiver) {
47 *receiver = std::move(receiver_);
48 }
49
GetSender()50 mojo::AssociatedRemote<IPC::mojom::Channel>& GetSender() { return sender_; }
51
52 private:
53 mojo::AssociatedRemote<IPC::mojom::Channel> sender_;
54 mojo::PendingAssociatedReceiver<IPC::mojom::Channel> receiver_;
55 std::unique_ptr<IPC::MojoBootstrap> bootstrap_;
56 };
57
58 class PeerPidReceiver : public IPC::mojom::Channel {
59 public:
60 enum class MessageExpectation {
61 kNotExpected,
62 kExpectedValid,
63 kExpectedInvalid
64 };
65
PeerPidReceiver(mojo::PendingAssociatedReceiver<IPC::mojom::Channel> receiver,base::OnceClosure on_peer_pid_set,MessageExpectation message_expectation=MessageExpectation::kNotExpected)66 PeerPidReceiver(
67 mojo::PendingAssociatedReceiver<IPC::mojom::Channel> receiver,
68 base::OnceClosure on_peer_pid_set,
69 MessageExpectation message_expectation = MessageExpectation::kNotExpected)
70 : receiver_(this, std::move(receiver)),
71 on_peer_pid_set_(std::move(on_peer_pid_set)),
72 message_expectation_(message_expectation) {
73 receiver_.set_disconnect_handler(disconnect_run_loop_.QuitClosure());
74 }
75
76 PeerPidReceiver(const PeerPidReceiver&) = delete;
77 PeerPidReceiver& operator=(const PeerPidReceiver&) = delete;
78
~PeerPidReceiver()79 ~PeerPidReceiver() override {
80 bool expected_message =
81 message_expectation_ != MessageExpectation::kNotExpected;
82 EXPECT_EQ(expected_message, received_message_);
83 }
84
85 // mojom::Channel:
SetPeerPid(int32_t pid)86 void SetPeerPid(int32_t pid) override {
87 peer_pid_ = pid;
88 std::move(on_peer_pid_set_).Run();
89 }
90
Receive(IPC::MessageView message_view)91 void Receive(IPC::MessageView message_view) override {
92 ASSERT_NE(MessageExpectation::kNotExpected, message_expectation_);
93 received_message_ = true;
94
95 IPC::Message message(
96 reinterpret_cast<const char*>(message_view.bytes().data()),
97 message_view.bytes().size());
98 bool expected_valid =
99 message_expectation_ == MessageExpectation::kExpectedValid;
100 EXPECT_EQ(expected_valid, message.IsValid());
101 }
102
GetAssociatedInterface(mojo::GenericPendingAssociatedReceiver receiver)103 void GetAssociatedInterface(
104 mojo::GenericPendingAssociatedReceiver receiver) override {}
105
peer_pid() const106 int32_t peer_pid() const { return peer_pid_; }
107
RunUntilDisconnect()108 void RunUntilDisconnect() { disconnect_run_loop_.Run(); }
109
110 private:
111 mojo::AssociatedReceiver<IPC::mojom::Channel> receiver_;
112 base::OnceClosure on_peer_pid_set_;
113 MessageExpectation message_expectation_;
114 int32_t peer_pid_ = -1;
115 bool received_message_ = false;
116 base::RunLoop disconnect_run_loop_;
117 };
118
119 class IPCMojoBootstrapTest : public testing::Test {
120 protected:
121 mojo::core::test::MultiprocessTestHelper helper_;
122 };
123
TEST_F(IPCMojoBootstrapTest,Connect)124 TEST_F(IPCMojoBootstrapTest, Connect) {
125 base::test::SingleThreadTaskEnvironment task_environment;
126 Connection connection(IPC::MojoBootstrap::Create(
127 helper_.StartChild("IPCMojoBootstrapTestClient"),
128 IPC::Channel::MODE_SERVER,
129 base::SingleThreadTaskRunner::GetCurrentDefault(),
130 base::SingleThreadTaskRunner::GetCurrentDefault()),
131 kTestServerPid);
132
133 mojo::PendingAssociatedReceiver<IPC::mojom::Channel> receiver;
134 connection.TakeReceiver(&receiver);
135
136 base::RunLoop run_loop;
137 PeerPidReceiver impl(std::move(receiver), run_loop.QuitClosure());
138 run_loop.Run();
139
140 EXPECT_EQ(kTestClientPid, impl.peer_pid());
141
142 impl.RunUntilDisconnect();
143 EXPECT_TRUE(helper_.WaitForChildTestShutdown());
144 }
145
146 // A long running process that connects to us.
MULTIPROCESS_TEST_MAIN_WITH_SETUP(IPCMojoBootstrapTestClientTestChildMain,::mojo::core::test::MultiprocessTestHelper::ChildSetup)147 MULTIPROCESS_TEST_MAIN_WITH_SETUP(
148 IPCMojoBootstrapTestClientTestChildMain,
149 ::mojo::core::test::MultiprocessTestHelper::ChildSetup) {
150 base::test::SingleThreadTaskEnvironment task_environment;
151 Connection connection(
152 IPC::MojoBootstrap::Create(
153 std::move(mojo::core::test::MultiprocessTestHelper::primordial_pipe),
154 IPC::Channel::MODE_CLIENT,
155 base::SingleThreadTaskRunner::GetCurrentDefault(),
156 base::SingleThreadTaskRunner::GetCurrentDefault()),
157 kTestClientPid);
158
159 mojo::PendingAssociatedReceiver<IPC::mojom::Channel> receiver;
160 connection.TakeReceiver(&receiver);
161
162 base::RunLoop run_loop;
163 PeerPidReceiver impl(std::move(receiver), run_loop.QuitClosure());
164 run_loop.Run();
165
166 EXPECT_EQ(kTestServerPid, impl.peer_pid());
167
168 return 0;
169 }
170
TEST_F(IPCMojoBootstrapTest,ReceiveEmptyMessage)171 TEST_F(IPCMojoBootstrapTest, ReceiveEmptyMessage) {
172 base::test::SingleThreadTaskEnvironment task_environment;
173 Connection connection(
174 IPC::MojoBootstrap::Create(
175 helper_.StartChild("IPCMojoBootstrapTestEmptyMessage"),
176 IPC::Channel::MODE_SERVER,
177 base::SingleThreadTaskRunner::GetCurrentDefault(),
178 base::SingleThreadTaskRunner::GetCurrentDefault()),
179 kTestServerPid);
180
181 mojo::PendingAssociatedReceiver<IPC::mojom::Channel> receiver;
182 connection.TakeReceiver(&receiver);
183
184 base::RunLoop run_loop;
185 PeerPidReceiver impl(std::move(receiver), run_loop.QuitClosure(),
186 PeerPidReceiver::MessageExpectation::kExpectedInvalid);
187 run_loop.Run();
188
189 // Wait for the Channel to be disconnected so we can reasonably assert that
190 // the child's empty message must have been received before we pass the test.
191 impl.RunUntilDisconnect();
192
193 EXPECT_TRUE(helper_.WaitForChildTestShutdown());
194 }
195
196 // A long running process that connects to us.
MULTIPROCESS_TEST_MAIN_WITH_SETUP(IPCMojoBootstrapTestEmptyMessageTestChildMain,::mojo::core::test::MultiprocessTestHelper::ChildSetup)197 MULTIPROCESS_TEST_MAIN_WITH_SETUP(
198 IPCMojoBootstrapTestEmptyMessageTestChildMain,
199 ::mojo::core::test::MultiprocessTestHelper::ChildSetup) {
200 base::test::SingleThreadTaskEnvironment task_environment;
201 Connection connection(
202 IPC::MojoBootstrap::Create(
203 std::move(mojo::core::test::MultiprocessTestHelper::primordial_pipe),
204 IPC::Channel::MODE_CLIENT,
205 base::SingleThreadTaskRunner::GetCurrentDefault(),
206 base::SingleThreadTaskRunner::GetCurrentDefault()),
207 kTestClientPid);
208
209 mojo::PendingAssociatedReceiver<IPC::mojom::Channel> receiver;
210 connection.TakeReceiver(&receiver);
211 auto& sender = connection.GetSender();
212
213 uint8_t data = 0;
214 sender->Receive(
215 IPC::MessageView(base::span(&data, 0u), std::nullopt /* handles */));
216
217 base::RunLoop run_loop;
218 PeerPidReceiver impl(std::move(receiver), run_loop.QuitClosure());
219 run_loop.Run();
220
221 return 0;
222 }
223
224 } // namespace
225