xref: /aosp_15_r20/external/cronet/components/nacl/loader/nacl_ipc_adapter_unittest.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2013 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 #include "components/nacl/loader/nacl_ipc_adapter.h"
6 
7 #include <stddef.h>
8 #include <stdint.h>
9 #include <string.h>
10 
11 #include <memory>
12 
13 #include "base/memory/raw_ptr.h"
14 #include "base/run_loop.h"
15 #include "base/task/single_thread_task_runner.h"
16 #include "base/test/task_environment.h"
17 #include "base/threading/platform_thread.h"
18 #include "base/threading/simple_thread.h"
19 #include "ipc/ipc_test_sink.h"
20 #include "native_client/src/public/nacl_desc_custom.h"
21 #include "native_client/src/trusted/service_runtime/include/sys/fcntl.h"
22 #include "ppapi/c/ppb_file_io.h"
23 #include "testing/gtest/include/gtest/gtest.h"
24 
25 namespace {
26 
27 class NaClIPCAdapterTest : public testing::Test {
28  public:
NaClIPCAdapterTest()29   NaClIPCAdapterTest() {}
30 
31   // testing::Test implementation.
SetUp()32   void SetUp() override {
33     sink_ = new IPC::TestSink;
34 
35     // Takes ownership of the sink_ pointer. Note we provide the current message
36     // loop instead of using a real IO thread. This should work OK since we do
37     // not need real IPC for the tests.
38     adapter_ = new NaClIPCAdapter(
39         std::unique_ptr<IPC::Channel>(sink_),
40         base::SingleThreadTaskRunner::GetCurrentDefault().get());
41   }
TearDown()42   void TearDown() override {
43     sink_ = nullptr;  // This pointer is actually owned by the IPCAdapter.
44     adapter_.reset();
45     // The adapter destructor has to post a task to destroy the Channel on the
46     // IO thread. For the purposes of the test, we just need to make sure that
47     // task gets run, or it will appear as a leak.
48     base::RunLoop().RunUntilIdle();
49   }
50 
51  protected:
BlockingReceive(void * buf,size_t buf_size)52   int BlockingReceive(void* buf, size_t buf_size) {
53     NaClImcMsgIoVec iov = {buf, buf_size};
54     NaClImcTypedMsgHdr msg = {&iov, 1};
55     return adapter_->BlockingReceive(&msg);
56   }
57 
Send(void * buf,size_t buf_size)58   int Send(void* buf, size_t buf_size) {
59     NaClImcMsgIoVec iov = {buf, buf_size};
60     NaClImcTypedMsgHdr msg = {&iov, 1};
61     return adapter_->Send(&msg);
62   }
63 
64   base::test::SingleThreadTaskEnvironment task_environment_;
65 
66   scoped_refptr<NaClIPCAdapter> adapter_;
67 
68   // Messages sent from nacl to the adapter end up here. Note that we create
69   // this pointer and pass ownership of it to the IPC adapter, who will keep
70   // it alive as long as the adapter is alive. This means that when the
71   // adapter goes away, this pointer will become invalid.
72   //
73   // In real life the adapter needs to take ownership so the channel can be
74   // destroyed on the right thread.
75   raw_ptr<IPC::TestSink> sink_;
76 };
77 
78 }  // namespace
79 
80 // Tests a simple message getting rewritten sent from native code to NaCl.
TEST_F(NaClIPCAdapterTest,SimpleReceiveRewriting)81 TEST_F(NaClIPCAdapterTest, SimpleReceiveRewriting) {
82   int routing_id = 0x89898989;
83   uint32_t type = 0x55555555;
84   IPC::Message input(routing_id, type, IPC::Message::PRIORITY_NORMAL);
85   uint32_t flags = input.flags();
86 
87   int value = 0x12345678;
88   input.WriteInt(value);
89   adapter_->OnMessageReceived(input);
90 
91   // Buffer just need to be big enough for our message with one int.
92   const int kBufSize = 64;
93   char buf[kBufSize];
94 
95   int bytes_read = BlockingReceive(buf, kBufSize);
96   EXPECT_EQ(sizeof(NaClIPCAdapter::NaClMessageHeader) + sizeof(int),
97             static_cast<size_t>(bytes_read));
98 
99   const NaClIPCAdapter::NaClMessageHeader* output_header =
100       reinterpret_cast<const NaClIPCAdapter::NaClMessageHeader*>(buf);
101   EXPECT_EQ(sizeof(int), output_header->payload_size);
102   EXPECT_EQ(routing_id, output_header->routing);
103   EXPECT_EQ(type, output_header->type);
104   EXPECT_EQ(flags, output_header->flags);
105   EXPECT_EQ(0u, output_header->num_fds);
106   EXPECT_EQ(0u, output_header->pad);
107 
108   // Validate the payload.
109   EXPECT_EQ(value,
110             *reinterpret_cast<const int*>(&buf[
111                 sizeof(NaClIPCAdapter::NaClMessageHeader)]));
112 }
113 
114 // Tests a simple message getting rewritten sent from NaCl to native code.
TEST_F(NaClIPCAdapterTest,SendRewriting)115 TEST_F(NaClIPCAdapterTest, SendRewriting) {
116   int routing_id = 0x89898989;
117   uint32_t type = 0x55555555;
118   int value = 0x12345678;
119 
120   // Send a message with one int inside it.
121   const int buf_size = sizeof(NaClIPCAdapter::NaClMessageHeader) + sizeof(int);
122   char buf[buf_size] = {0};
123 
124   NaClIPCAdapter::NaClMessageHeader* header =
125       reinterpret_cast<NaClIPCAdapter::NaClMessageHeader*>(buf);
126   header->payload_size = sizeof(int);
127   header->routing = routing_id;
128   header->type = type;
129   header->flags = 0;
130   header->num_fds = 0;
131   *reinterpret_cast<int*>(
132       &buf[sizeof(NaClIPCAdapter::NaClMessageHeader)]) = value;
133 
134   int result = Send(buf, buf_size);
135   EXPECT_EQ(buf_size, result);
136 
137   // Check that the message came out the other end in the test sink
138   // (messages are posted, so we have to pump).
139   base::RunLoop().RunUntilIdle();
140   ASSERT_EQ(1u, sink_->message_count());
141   const IPC::Message* msg = sink_->GetMessageAt(0);
142 
143   EXPECT_EQ(sizeof(int), msg->payload_size());
144   EXPECT_EQ(header->routing, msg->routing_id());
145   EXPECT_EQ(header->type, msg->type());
146 
147   // Now test the partial send case. We should be able to break the message
148   // into two parts and it should still work.
149   sink_->ClearMessages();
150   int first_chunk_size = 7;
151   result = Send(buf, first_chunk_size);
152   EXPECT_EQ(first_chunk_size, result);
153 
154   // First partial send should not have made any messages.
155   base::RunLoop().RunUntilIdle();
156   ASSERT_EQ(0u, sink_->message_count());
157 
158   // Second partial send should do the same.
159   int second_chunk_size = 2;
160   result = Send(&buf[first_chunk_size], second_chunk_size);
161   EXPECT_EQ(second_chunk_size, result);
162   base::RunLoop().RunUntilIdle();
163   ASSERT_EQ(0u, sink_->message_count());
164 
165   // Send the rest of the message in a third chunk.
166   int third_chunk_size = buf_size - first_chunk_size - second_chunk_size;
167   result = Send(&buf[first_chunk_size + second_chunk_size],
168                           third_chunk_size);
169   EXPECT_EQ(third_chunk_size, result);
170 
171   // Last send should have generated one message.
172   base::RunLoop().RunUntilIdle();
173   ASSERT_EQ(1u, sink_->message_count());
174   msg = sink_->GetMessageAt(0);
175   EXPECT_EQ(sizeof(int), msg->payload_size());
176   EXPECT_EQ(header->routing, msg->routing_id());
177   EXPECT_EQ(header->type, msg->type());
178 }
179 
180 // Tests when a buffer is too small to receive the entire message.
TEST_F(NaClIPCAdapterTest,PartialReceive)181 TEST_F(NaClIPCAdapterTest, PartialReceive) {
182   int routing_id_1 = 0x89898989;
183   uint32_t type_1 = 0x55555555;
184   IPC::Message input_1(routing_id_1, type_1, IPC::Message::PRIORITY_NORMAL);
185   int value_1 = 0x12121212;
186   input_1.WriteInt(value_1);
187   adapter_->OnMessageReceived(input_1);
188 
189   int routing_id_2 = 0x90909090;
190   uint32_t type_2 = 0x66666666;
191   IPC::Message input_2(routing_id_2, type_2, IPC::Message::PRIORITY_NORMAL);
192   int value_2 = 0x23232323;
193   input_2.WriteInt(value_2);
194   adapter_->OnMessageReceived(input_2);
195 
196   const int kBufSize = 64;
197   char buf[kBufSize];
198 
199   // Read part of the first message.
200   int bytes_requested = 7;
201   int bytes_read = BlockingReceive(buf, bytes_requested);
202   ASSERT_EQ(bytes_requested, bytes_read);
203 
204   // Read the rest, this should give us the rest of the first message only.
205   bytes_read += BlockingReceive(&buf[bytes_requested],
206                                         kBufSize - bytes_requested);
207   EXPECT_EQ(sizeof(NaClIPCAdapter::NaClMessageHeader) + sizeof(int),
208             static_cast<size_t>(bytes_read));
209 
210   // Make sure we got the right message.
211   const NaClIPCAdapter::NaClMessageHeader* output_header =
212       reinterpret_cast<const NaClIPCAdapter::NaClMessageHeader*>(buf);
213   EXPECT_EQ(sizeof(int), output_header->payload_size);
214   EXPECT_EQ(routing_id_1, output_header->routing);
215   EXPECT_EQ(type_1, output_header->type);
216 
217   // Read the second message to make sure we went on to it.
218   bytes_read = BlockingReceive(buf, kBufSize);
219   EXPECT_EQ(sizeof(NaClIPCAdapter::NaClMessageHeader) + sizeof(int),
220             static_cast<size_t>(bytes_read));
221   output_header =
222       reinterpret_cast<const NaClIPCAdapter::NaClMessageHeader*>(buf);
223   EXPECT_EQ(sizeof(int), output_header->payload_size);
224   EXPECT_EQ(routing_id_2, output_header->routing);
225   EXPECT_EQ(type_2, output_header->type);
226 }
227 
228 // Tests sending messages that are too large. We test sends that are too
229 // small implicitly here and in the success case because in that case it
230 // succeeds and buffers the data.
TEST_F(NaClIPCAdapterTest,SendOverflow)231 TEST_F(NaClIPCAdapterTest, SendOverflow) {
232   int routing_id = 0x89898989;
233   uint32_t type = 0x55555555;
234   int value = 0x12345678;
235 
236   // Make a message with one int inside it. Reserve some extra space so
237   // we can test what happens when we send too much data.
238   const int buf_size = sizeof(NaClIPCAdapter::NaClMessageHeader) + sizeof(int);
239   const int big_buf_size = buf_size + 4;
240   char buf[big_buf_size] = {0};
241 
242   NaClIPCAdapter::NaClMessageHeader* header =
243       reinterpret_cast<NaClIPCAdapter::NaClMessageHeader*>(buf);
244   header->payload_size = sizeof(int);
245   header->routing = routing_id;
246   header->type = type;
247   header->flags = 0;
248   header->num_fds = 0;
249   *reinterpret_cast<int*>(
250       &buf[sizeof(NaClIPCAdapter::NaClMessageHeader)]) = value;
251 
252   // Send too much data and make sure that the send fails.
253   int result = Send(buf, big_buf_size);
254   EXPECT_EQ(-1, result);
255   base::RunLoop().RunUntilIdle();
256   ASSERT_EQ(0u, sink_->message_count());
257 
258   // Send too much data in two chunks and make sure that the send fails.
259   int first_chunk_size = 7;
260   result = Send(buf, first_chunk_size);
261   EXPECT_EQ(first_chunk_size, result);
262 
263   // First partial send should not have made any messages.
264   base::RunLoop().RunUntilIdle();
265   ASSERT_EQ(0u, sink_->message_count());
266 
267   int second_chunk_size = big_buf_size - first_chunk_size;
268   result = Send(&buf[first_chunk_size], second_chunk_size);
269   EXPECT_EQ(-1, result);
270   base::RunLoop().RunUntilIdle();
271   ASSERT_EQ(0u, sink_->message_count());
272 }
273 
274 // Tests that when the IPC channel reports an error, that waiting reads are
275 // unblocked and return a -1 error code.
TEST_F(NaClIPCAdapterTest,ReadWithChannelError)276 TEST_F(NaClIPCAdapterTest, ReadWithChannelError) {
277   // Have a background thread that waits a bit and calls the channel error
278   // handler. This should wake up any waiting threads and immediately return
279   // -1. There is an inherent race condition in that we can't be sure if the
280   // other thread is actually waiting when this happens. This is OK, since the
281   // behavior (which we also explicitly test later) is to return -1 if the
282   // channel has already had an error when you start waiting.
283   class MyThread : public base::SimpleThread {
284    public:
285     explicit MyThread(NaClIPCAdapter* adapter)
286         : SimpleThread("NaClIPCAdapterThread"),
287           adapter_(adapter) {}
288     void Run() override {
289       base::PlatformThread::Sleep(base::Seconds(1));
290       adapter_->OnChannelError();
291     }
292    private:
293     scoped_refptr<NaClIPCAdapter> adapter_;
294   };
295   MyThread thread(adapter_.get());
296 
297   // IMPORTANT: do not return early from here down (including ASSERT_*) because
298   // the thread needs to joined or it will assert.
299   thread.Start();
300 
301   // Request data. This will normally (modulo races) block until data is
302   // received or there is an error, and the thread above will wake us up
303   // after 1s.
304   const int kBufSize = 64;
305   char buf[kBufSize];
306   int result = BlockingReceive(buf, kBufSize);
307   EXPECT_EQ(-1, result);
308 
309   // Test the "previously had an error" case. BlockingReceive should return
310   // immediately if there was an error.
311   result = BlockingReceive(buf, kBufSize);
312   EXPECT_EQ(-1, result);
313 
314   thread.Join();
315 }
316 
317 // Tests that TranslatePepperFileOpenFlags translates pepper read/write open
318 // flags into NaCl open flags correctly.
TEST_F(NaClIPCAdapterTest,TranslatePepperFileReadWriteOpenFlags)319 TEST_F(NaClIPCAdapterTest, TranslatePepperFileReadWriteOpenFlags) {
320   EXPECT_EQ(NACL_ABI_O_RDONLY,
321       TranslatePepperFileReadWriteOpenFlagsForTesting(PP_FILEOPENFLAG_READ));
322   EXPECT_EQ(NACL_ABI_O_WRONLY,
323       TranslatePepperFileReadWriteOpenFlagsForTesting(PP_FILEOPENFLAG_WRITE));
324   EXPECT_EQ(NACL_ABI_O_WRONLY | NACL_ABI_O_APPEND,
325       TranslatePepperFileReadWriteOpenFlagsForTesting(
326           PP_FILEOPENFLAG_APPEND));
327   EXPECT_EQ(NACL_ABI_O_RDWR,
328       TranslatePepperFileReadWriteOpenFlagsForTesting(
329           PP_FILEOPENFLAG_READ | PP_FILEOPENFLAG_WRITE));
330   EXPECT_EQ(NACL_ABI_O_WRONLY | NACL_ABI_O_APPEND,
331       TranslatePepperFileReadWriteOpenFlagsForTesting(
332           PP_FILEOPENFLAG_APPEND));
333   EXPECT_EQ(NACL_ABI_O_RDWR | NACL_ABI_O_APPEND,
334       TranslatePepperFileReadWriteOpenFlagsForTesting(
335           PP_FILEOPENFLAG_READ | PP_FILEOPENFLAG_APPEND));
336 
337   // Flags other than PP_FILEOPENFLAG_READ, PP_FILEOPENFLAG_WRITE, and
338   // PP_FILEOPENFLAG_APPEND are discarded.
339   EXPECT_EQ(NACL_ABI_O_WRONLY,
340       TranslatePepperFileReadWriteOpenFlagsForTesting(
341           PP_FILEOPENFLAG_WRITE | PP_FILEOPENFLAG_CREATE));
342   EXPECT_EQ(NACL_ABI_O_WRONLY,
343       TranslatePepperFileReadWriteOpenFlagsForTesting(
344           PP_FILEOPENFLAG_WRITE | PP_FILEOPENFLAG_TRUNCATE));
345   EXPECT_EQ(NACL_ABI_O_WRONLY,
346       TranslatePepperFileReadWriteOpenFlagsForTesting(
347           PP_FILEOPENFLAG_WRITE | PP_FILEOPENFLAG_EXCLUSIVE));
348 
349   // If none of PP_FILEOPENFLAG_READ, PP_FILEOPENFLAG_WRITE, and
350   // PP_FILEOPENFLAG_APPEND are set, the result should fall back to
351   // NACL_ABI_O_READONLY.
352   EXPECT_EQ(NACL_ABI_O_RDONLY,
353       TranslatePepperFileReadWriteOpenFlagsForTesting(0));
354   EXPECT_EQ(NACL_ABI_O_RDONLY,
355       TranslatePepperFileReadWriteOpenFlagsForTesting(
356           PP_FILEOPENFLAG_CREATE));
357   EXPECT_EQ(NACL_ABI_O_RDONLY,
358       TranslatePepperFileReadWriteOpenFlagsForTesting(
359           PP_FILEOPENFLAG_TRUNCATE));
360   EXPECT_EQ(NACL_ABI_O_RDONLY,
361       TranslatePepperFileReadWriteOpenFlagsForTesting(
362           PP_FILEOPENFLAG_EXCLUSIVE));
363 }
364