1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
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 <stddef.h>
6 #include <stdint.h>
7
8 #include "sandbox/win/src/crosscall_client.h"
9 #include "sandbox/win/src/crosscall_server.h"
10 #include "sandbox/win/src/sharedmem_ipc_client.h"
11 #include "sandbox/win/src/sharedmem_ipc_server.h"
12 #include "testing/gtest/include/gtest/gtest.h"
13
14 namespace sandbox {
15
16 // Helper function to make the fake shared memory with some
17 // basic elements initialized.
MakeChannels(size_t channel_size,size_t total_shared_size,size_t * base_start)18 IPCControl* MakeChannels(size_t channel_size,
19 size_t total_shared_size,
20 size_t* base_start) {
21 // Allocate memory
22 char* mem = new char[total_shared_size];
23 memset(mem, 0, total_shared_size);
24 // Calculate how many channels we can fit in the shared memory.
25 total_shared_size -= offsetof(IPCControl, channels);
26 size_t channel_count =
27 total_shared_size / (sizeof(ChannelControl) + channel_size);
28 // Calculate the start of the first channel.
29 *base_start =
30 (sizeof(ChannelControl) * channel_count) + offsetof(IPCControl, channels);
31 // Setup client structure.
32 IPCControl* client_control = reinterpret_cast<IPCControl*>(mem);
33 client_control->channels_count = channel_count;
34 return client_control;
35 }
36
37 enum TestFixMode { FIX_NO_EVENTS, FIX_PONG_READY, FIX_PONG_NOT_READY };
38
FixChannels(IPCControl * client_control,size_t base_start,size_t channel_size,TestFixMode mode)39 void FixChannels(IPCControl* client_control,
40 size_t base_start,
41 size_t channel_size,
42 TestFixMode mode) {
43 for (size_t ix = 0; ix != client_control->channels_count; ++ix) {
44 ChannelControl& channel = client_control->channels[ix];
45 channel.channel_base = base_start;
46 channel.state = kFreeChannel;
47 if (mode != FIX_NO_EVENTS) {
48 bool signaled = (FIX_PONG_READY == mode) ? true : false;
49 channel.ping_event = ::CreateEventW(nullptr, false, false, nullptr);
50 channel.pong_event = ::CreateEventW(nullptr, false, signaled, nullptr);
51 }
52 base_start += channel_size;
53 }
54 }
55
CloseChannelEvents(IPCControl * client_control)56 void CloseChannelEvents(IPCControl* client_control) {
57 for (size_t ix = 0; ix != client_control->channels_count; ++ix) {
58 ChannelControl& channel = client_control->channels[ix];
59 ::CloseHandle(channel.ping_event);
60 ::CloseHandle(channel.pong_event);
61 }
62 }
63
TEST(IPCTest,ChannelMaker)64 TEST(IPCTest, ChannelMaker) {
65 // Test that our testing rig is computing offsets properly. We should have
66 // 5 channnels and the offset to the first channel is 108 bytes in 32 bits
67 // and 216 in 64 bits.
68 size_t channel_start = 0;
69 IPCControl* client_control = MakeChannels(12 * 64, 4096, &channel_start);
70 ASSERT_TRUE(client_control);
71 EXPECT_EQ(5u, client_control->channels_count);
72 #if defined(_WIN64)
73 EXPECT_EQ(216u, channel_start);
74 #else
75 EXPECT_EQ(108u, channel_start);
76 #endif
77 delete[] reinterpret_cast<char*>(client_control);
78 }
79
TEST(IPCTest,ClientLockUnlock)80 TEST(IPCTest, ClientLockUnlock) {
81 // Make 7 channels of kIPCChannelSize (1kb) each. Test that we lock and
82 // unlock channels properly.
83 size_t base_start = 0;
84 IPCControl* client_control =
85 MakeChannels(kIPCChannelSize, 4096 * 2, &base_start);
86 FixChannels(client_control, base_start, kIPCChannelSize, FIX_NO_EVENTS);
87
88 char* mem = reinterpret_cast<char*>(client_control);
89 SharedMemIPCClient client(mem);
90
91 // Test that we lock the first 3 channels in sequence.
92 void* buff0 = client.GetBuffer();
93 EXPECT_TRUE(mem + client_control->channels[0].channel_base == buff0);
94 EXPECT_EQ(kBusyChannel, client_control->channels[0].state);
95 EXPECT_EQ(kFreeChannel, client_control->channels[1].state);
96 EXPECT_EQ(kFreeChannel, client_control->channels[2].state);
97 EXPECT_EQ(kFreeChannel, client_control->channels[3].state);
98 EXPECT_EQ(kFreeChannel, client_control->channels[4].state);
99 EXPECT_EQ(kFreeChannel, client_control->channels[5].state);
100
101 void* buff1 = client.GetBuffer();
102 EXPECT_TRUE(mem + client_control->channels[1].channel_base == buff1);
103 EXPECT_EQ(kBusyChannel, client_control->channels[0].state);
104 EXPECT_EQ(kBusyChannel, client_control->channels[1].state);
105 EXPECT_EQ(kFreeChannel, client_control->channels[2].state);
106 EXPECT_EQ(kFreeChannel, client_control->channels[3].state);
107 EXPECT_EQ(kFreeChannel, client_control->channels[4].state);
108 EXPECT_EQ(kFreeChannel, client_control->channels[5].state);
109
110 void* buff2 = client.GetBuffer();
111 EXPECT_TRUE(mem + client_control->channels[2].channel_base == buff2);
112 EXPECT_EQ(kBusyChannel, client_control->channels[0].state);
113 EXPECT_EQ(kBusyChannel, client_control->channels[1].state);
114 EXPECT_EQ(kBusyChannel, client_control->channels[2].state);
115 EXPECT_EQ(kFreeChannel, client_control->channels[3].state);
116 EXPECT_EQ(kFreeChannel, client_control->channels[4].state);
117 EXPECT_EQ(kFreeChannel, client_control->channels[5].state);
118
119 // Test that we unlock and re-lock the right channel.
120 client.FreeBuffer(buff1);
121 EXPECT_EQ(kBusyChannel, client_control->channels[0].state);
122 EXPECT_EQ(kFreeChannel, client_control->channels[1].state);
123 EXPECT_EQ(kBusyChannel, client_control->channels[2].state);
124 EXPECT_EQ(kFreeChannel, client_control->channels[3].state);
125 EXPECT_EQ(kFreeChannel, client_control->channels[4].state);
126 EXPECT_EQ(kFreeChannel, client_control->channels[5].state);
127
128 void* buff2b = client.GetBuffer();
129 EXPECT_TRUE(mem + client_control->channels[1].channel_base == buff2b);
130 EXPECT_EQ(kBusyChannel, client_control->channels[0].state);
131 EXPECT_EQ(kBusyChannel, client_control->channels[1].state);
132 EXPECT_EQ(kBusyChannel, client_control->channels[2].state);
133 EXPECT_EQ(kFreeChannel, client_control->channels[3].state);
134 EXPECT_EQ(kFreeChannel, client_control->channels[4].state);
135 EXPECT_EQ(kFreeChannel, client_control->channels[5].state);
136
137 client.FreeBuffer(buff0);
138 EXPECT_EQ(kFreeChannel, client_control->channels[0].state);
139 EXPECT_EQ(kBusyChannel, client_control->channels[1].state);
140 EXPECT_EQ(kBusyChannel, client_control->channels[2].state);
141 EXPECT_EQ(kFreeChannel, client_control->channels[3].state);
142 EXPECT_EQ(kFreeChannel, client_control->channels[4].state);
143 EXPECT_EQ(kFreeChannel, client_control->channels[5].state);
144
145 delete[] reinterpret_cast<char*>(client_control);
146 }
147
TEST(IPCTest,CrossCallStrPacking)148 TEST(IPCTest, CrossCallStrPacking) {
149 // This test tries the CrossCall object with null and non-null string
150 // combination of parameters, integer types and verifies that the unpacker
151 // can read them properly.
152 size_t base_start = 0;
153 IPCControl* client_control =
154 MakeChannels(kIPCChannelSize, 4096 * 4, &base_start);
155 client_control->server_alive = HANDLE(1);
156 FixChannels(client_control, base_start, kIPCChannelSize, FIX_PONG_READY);
157
158 char* mem = reinterpret_cast<char*>(client_control);
159 SharedMemIPCClient client(mem);
160
161 CrossCallReturn answer;
162 IpcTag tag1 = IpcTag::PING1;
163 const wchar_t* text = L"98765 - 43210";
164 std::wstring copied_text;
165 CrossCallParamsEx* actual_params;
166
167 CrossCall(client, tag1, text, &answer);
168 actual_params = reinterpret_cast<CrossCallParamsEx*>(client.GetBuffer());
169 EXPECT_EQ(1u, actual_params->GetParamsCount());
170 EXPECT_EQ(tag1, actual_params->GetTag());
171 EXPECT_TRUE(actual_params->GetParameterStr(0, &copied_text));
172 EXPECT_STREQ(text, copied_text.c_str());
173 copied_text.clear();
174
175 // Check with an empty string.
176 IpcTag tag2 = IpcTag::PING2;
177 const wchar_t* null_text = nullptr;
178 CrossCall(client, tag2, null_text, &answer);
179 actual_params = reinterpret_cast<CrossCallParamsEx*>(client.GetBuffer());
180 EXPECT_EQ(1u, actual_params->GetParamsCount());
181 EXPECT_EQ(tag2, actual_params->GetTag());
182 uint32_t param_size = 1;
183 ArgType type = INVALID_TYPE;
184 void* param_addr = actual_params->GetRawParameter(0, ¶m_size, &type);
185 EXPECT_TRUE(param_addr);
186 EXPECT_EQ(0u, param_size);
187 EXPECT_EQ(WCHAR_TYPE, type);
188 EXPECT_TRUE(actual_params->GetParameterStr(0, &copied_text));
189 EXPECT_TRUE(copied_text.empty());
190
191 IpcTag tag3 = IpcTag::PING1;
192 param_size = 1;
193 copied_text.clear();
194
195 // Check with an empty string and a non-empty string.
196 CrossCall(client, tag3, null_text, text, &answer);
197 actual_params = reinterpret_cast<CrossCallParamsEx*>(client.GetBuffer());
198 EXPECT_EQ(2u, actual_params->GetParamsCount());
199 EXPECT_EQ(tag3, actual_params->GetTag());
200 type = INVALID_TYPE;
201 param_addr = actual_params->GetRawParameter(0, ¶m_size, &type);
202 EXPECT_TRUE(param_addr);
203 EXPECT_EQ(0u, param_size);
204 EXPECT_EQ(WCHAR_TYPE, type);
205 EXPECT_TRUE(actual_params->GetParameterStr(0, &copied_text));
206 EXPECT_TRUE(copied_text.empty());
207 EXPECT_TRUE(actual_params->GetParameterStr(1, &copied_text));
208 EXPECT_STREQ(text, copied_text.c_str());
209
210 param_size = 1;
211 std::wstring copied_text_p0, copied_text_p2;
212
213 const wchar_t* text2 = L"AeFG";
214 CrossCall(client, tag1, text2, null_text, text, &answer);
215 actual_params = reinterpret_cast<CrossCallParamsEx*>(client.GetBuffer());
216 EXPECT_EQ(3u, actual_params->GetParamsCount());
217 EXPECT_EQ(tag1, actual_params->GetTag());
218 EXPECT_TRUE(actual_params->GetParameterStr(0, &copied_text_p0));
219 EXPECT_STREQ(text2, copied_text_p0.c_str());
220 EXPECT_TRUE(actual_params->GetParameterStr(2, &copied_text_p2));
221 EXPECT_STREQ(text, copied_text_p2.c_str());
222 type = INVALID_TYPE;
223 param_addr = actual_params->GetRawParameter(1, ¶m_size, &type);
224 EXPECT_TRUE(param_addr);
225 EXPECT_EQ(0u, param_size);
226 EXPECT_EQ(WCHAR_TYPE, type);
227
228 CloseChannelEvents(client_control);
229 delete[] reinterpret_cast<char*>(client_control);
230 }
231
TEST(IPCTest,CrossCallIntPacking)232 TEST(IPCTest, CrossCallIntPacking) {
233 // Check handling for regular 32 bit integers used in Windows.
234 size_t base_start = 0;
235 IPCControl* client_control =
236 MakeChannels(kIPCChannelSize, 4096 * 4, &base_start);
237 client_control->server_alive = HANDLE(1);
238 FixChannels(client_control, base_start, kIPCChannelSize, FIX_PONG_READY);
239
240 IpcTag tag1 = IpcTag::PING1;
241 IpcTag tag2 = IpcTag::PING2;
242 const wchar_t* text = L"godzilla";
243 CrossCallParamsEx* actual_params;
244
245 char* mem = reinterpret_cast<char*>(client_control);
246 SharedMemIPCClient client(mem);
247
248 CrossCallReturn answer;
249 DWORD dw = 0xE6578;
250 CrossCall(client, tag2, dw, &answer);
251 actual_params = reinterpret_cast<CrossCallParamsEx*>(client.GetBuffer());
252 EXPECT_EQ(1u, actual_params->GetParamsCount());
253 EXPECT_EQ(tag2, actual_params->GetTag());
254 ArgType type = INVALID_TYPE;
255 uint32_t param_size = 1;
256 void* param_addr = actual_params->GetRawParameter(0, ¶m_size, &type);
257 ASSERT_EQ(sizeof(dw), param_size);
258 EXPECT_EQ(UINT32_TYPE, type);
259 ASSERT_TRUE(param_addr);
260 EXPECT_EQ(0, memcmp(&dw, param_addr, param_size));
261
262 // Check handling for windows HANDLES.
263 HANDLE h = HANDLE(0x70000500);
264 CrossCall(client, tag1, text, h, &answer);
265 actual_params = reinterpret_cast<CrossCallParamsEx*>(client.GetBuffer());
266 EXPECT_EQ(2u, actual_params->GetParamsCount());
267 EXPECT_EQ(tag1, actual_params->GetTag());
268 type = INVALID_TYPE;
269 param_addr = actual_params->GetRawParameter(1, ¶m_size, &type);
270 ASSERT_EQ(sizeof(h), param_size);
271 EXPECT_EQ(VOIDPTR_TYPE, type);
272 ASSERT_TRUE(param_addr);
273 EXPECT_EQ(0, memcmp(&h, param_addr, param_size));
274
275 // Check combination of 32 and 64 bits.
276 CrossCall(client, tag2, h, dw, h, &answer);
277 actual_params = reinterpret_cast<CrossCallParamsEx*>(client.GetBuffer());
278 EXPECT_EQ(3u, actual_params->GetParamsCount());
279 EXPECT_EQ(tag2, actual_params->GetTag());
280 type = INVALID_TYPE;
281 param_addr = actual_params->GetRawParameter(0, ¶m_size, &type);
282 ASSERT_EQ(sizeof(h), param_size);
283 EXPECT_EQ(VOIDPTR_TYPE, type);
284 ASSERT_TRUE(param_addr);
285 EXPECT_EQ(0, memcmp(&h, param_addr, param_size));
286 type = INVALID_TYPE;
287 param_addr = actual_params->GetRawParameter(1, ¶m_size, &type);
288 ASSERT_EQ(sizeof(dw), param_size);
289 EXPECT_EQ(UINT32_TYPE, type);
290 ASSERT_TRUE(param_addr);
291 EXPECT_EQ(0, memcmp(&dw, param_addr, param_size));
292 type = INVALID_TYPE;
293 param_addr = actual_params->GetRawParameter(2, ¶m_size, &type);
294 ASSERT_EQ(sizeof(h), param_size);
295 EXPECT_EQ(VOIDPTR_TYPE, type);
296 ASSERT_TRUE(param_addr);
297 EXPECT_EQ(0, memcmp(&h, param_addr, param_size));
298
299 CloseChannelEvents(client_control);
300 delete[] reinterpret_cast<char*>(client_control);
301 }
302
TEST(IPCTest,CrossCallValidation)303 TEST(IPCTest, CrossCallValidation) {
304 // First a sanity test with a well formed parameter object.
305 unsigned long value = 124816;
306 IpcTag kTag = IpcTag::PING1;
307 const uint32_t kBufferSize = 256;
308 ActualCallParams<1, kBufferSize> params_1(kTag);
309 params_1.CopyParamIn(0, &value, sizeof(value), false, UINT32_TYPE);
310 void* buffer = const_cast<void*>(params_1.GetBuffer());
311
312 uint32_t out_size = 0;
313 CrossCallParamsEx* ccp = 0;
314 ccp = CrossCallParamsEx::CreateFromBuffer(buffer, params_1.GetSize(),
315 &out_size);
316 ASSERT_TRUE(ccp);
317 EXPECT_TRUE(ccp->GetBuffer() != buffer);
318 EXPECT_EQ(kTag, ccp->GetTag());
319 EXPECT_EQ(1u, ccp->GetParamsCount());
320 delete[](reinterpret_cast<char*>(ccp));
321
322 // Test that we handle integer overflow on the number of params
323 // correctly. We use a test-only ctor for ActualCallParams that
324 // allows to create malformed cross-call buffers.
325 const int32_t kPtrDiffSz = sizeof(ptrdiff_t);
326 for (int32_t ix = -1; ix != 3; ++ix) {
327 uint32_t fake_num_params = (UINT32_MAX / kPtrDiffSz) + ix;
328 ActualCallParams<1, kBufferSize> params_2(kTag, fake_num_params);
329 params_2.CopyParamIn(0, &value, sizeof(value), false, UINT32_TYPE);
330 buffer = const_cast<void*>(params_2.GetBuffer());
331
332 EXPECT_TRUE(buffer);
333 ccp = CrossCallParamsEx::CreateFromBuffer(buffer, params_1.GetSize(),
334 &out_size);
335 // If the buffer is malformed the return is nullptr.
336 EXPECT_TRUE(!ccp);
337 }
338
339 ActualCallParams<1, kBufferSize> params_3(kTag, 1);
340 params_3.CopyParamIn(0, &value, sizeof(value), false, UINT32_TYPE);
341 buffer = const_cast<void*>(params_3.GetBuffer());
342 EXPECT_TRUE(buffer);
343
344 uint32_t correct_size = params_3.OverrideSize(1);
345 ccp = CrossCallParamsEx::CreateFromBuffer(buffer, kBufferSize, &out_size);
346 EXPECT_TRUE(!ccp);
347
348 // The correct_size is 8 bytes aligned.
349 params_3.OverrideSize(correct_size - 7);
350 ccp = CrossCallParamsEx::CreateFromBuffer(buffer, kBufferSize, &out_size);
351 EXPECT_TRUE(!ccp);
352
353 params_3.OverrideSize(correct_size);
354 ccp = CrossCallParamsEx::CreateFromBuffer(buffer, kBufferSize, &out_size);
355 EXPECT_TRUE(ccp);
356
357 // Make sure that two parameters work as expected.
358 ActualCallParams<2, kBufferSize> params_4(kTag, 2);
359 params_4.CopyParamIn(0, &value, sizeof(value), false, UINT32_TYPE);
360 params_4.CopyParamIn(1, buffer, sizeof(buffer), false, VOIDPTR_TYPE);
361 buffer = const_cast<void*>(params_4.GetBuffer());
362 EXPECT_TRUE(buffer);
363
364 ccp = CrossCallParamsEx::CreateFromBuffer(buffer, kBufferSize, &out_size);
365 EXPECT_TRUE(ccp);
366
367 #if defined(_WIN64)
368 correct_size = params_4.OverrideSize(1);
369 params_4.OverrideSize(correct_size - 1);
370 ccp = CrossCallParamsEx::CreateFromBuffer(buffer, kBufferSize, &out_size);
371 EXPECT_TRUE(!ccp);
372 #endif
373 }
374
375 // This structure is passed to the mock server threads to simulate
376 // the server side IPC so it has the required kernel objects.
377 struct ServerEvents {
378 HANDLE ping;
379 HANDLE pong;
380 volatile LONG* state;
381 HANDLE mutex;
382 };
383
384 // This is the server thread that quicky answers an IPC and exits.
QuickResponseServer(PVOID param)385 DWORD WINAPI QuickResponseServer(PVOID param) {
386 ServerEvents* events = reinterpret_cast<ServerEvents*>(param);
387 DWORD wait_result = 0;
388 wait_result = ::WaitForSingleObject(events->ping, INFINITE);
389 ::InterlockedExchange(events->state, kAckChannel);
390 ::SetEvent(events->pong);
391 return wait_result;
392 }
393
394 class CrossCallParamsMock : public CrossCallParams {
395 public:
CrossCallParamsMock(IpcTag tag,uint32_t params_count)396 CrossCallParamsMock(IpcTag tag, uint32_t params_count)
397 : CrossCallParams(tag, params_count) {}
398 };
399
FakeOkAnswerInChannel(void * channel)400 void FakeOkAnswerInChannel(void* channel) {
401 CrossCallReturn* answer = reinterpret_cast<CrossCallReturn*>(channel);
402 answer->call_outcome = SBOX_ALL_OK;
403 }
404
405 // Create two threads that will quickly answer IPCs; the first one
406 // using channel 1 (channel 0 is busy) and one using channel 0. No time-out
407 // should occur.
TEST(IPCTest,ClientFastServer)408 TEST(IPCTest, ClientFastServer) {
409 const size_t channel_size = kIPCChannelSize;
410 size_t base_start = 0;
411 IPCControl* client_control =
412 MakeChannels(channel_size, 4096 * 2, &base_start);
413 FixChannels(client_control, base_start, kIPCChannelSize, FIX_PONG_NOT_READY);
414 client_control->server_alive = ::CreateMutex(nullptr, false, nullptr);
415
416 char* mem = reinterpret_cast<char*>(client_control);
417 SharedMemIPCClient client(mem);
418
419 ServerEvents events = {0};
420 events.ping = client_control->channels[1].ping_event;
421 events.pong = client_control->channels[1].pong_event;
422 events.state = &client_control->channels[1].state;
423
424 HANDLE t1 =
425 ::CreateThread(nullptr, 0, QuickResponseServer, &events, 0, nullptr);
426 ASSERT_TRUE(t1);
427 ::CloseHandle(t1);
428
429 void* buff0 = client.GetBuffer();
430 EXPECT_TRUE(mem + client_control->channels[0].channel_base == buff0);
431 EXPECT_EQ(kBusyChannel, client_control->channels[0].state);
432 EXPECT_EQ(kFreeChannel, client_control->channels[1].state);
433 EXPECT_EQ(kFreeChannel, client_control->channels[2].state);
434
435 void* buff1 = client.GetBuffer();
436 EXPECT_TRUE(mem + client_control->channels[1].channel_base == buff1);
437 EXPECT_EQ(kBusyChannel, client_control->channels[0].state);
438 EXPECT_EQ(kBusyChannel, client_control->channels[1].state);
439 EXPECT_EQ(kFreeChannel, client_control->channels[2].state);
440
441 EXPECT_EQ(IpcTag::UNUSED, client_control->channels[1].ipc_tag);
442
443 IpcTag tag = IpcTag::PING1;
444 CrossCallReturn answer;
445 CrossCallParamsMock* params1 = new (buff1) CrossCallParamsMock(tag, 1);
446 FakeOkAnswerInChannel(buff1);
447
448 ResultCode result = client.DoCall(params1, &answer);
449 if (SBOX_ERROR_CHANNEL_ERROR != result)
450 client.FreeBuffer(buff1);
451
452 EXPECT_TRUE(SBOX_ALL_OK == result);
453 EXPECT_EQ(tag, client_control->channels[1].ipc_tag);
454 EXPECT_EQ(kBusyChannel, client_control->channels[0].state);
455 EXPECT_EQ(kFreeChannel, client_control->channels[1].state);
456 EXPECT_EQ(kFreeChannel, client_control->channels[2].state);
457
458 HANDLE t2 =
459 ::CreateThread(nullptr, 0, QuickResponseServer, &events, 0, nullptr);
460 ASSERT_TRUE(t2);
461 ::CloseHandle(t2);
462
463 client.FreeBuffer(buff0);
464 events.ping = client_control->channels[0].ping_event;
465 events.pong = client_control->channels[0].pong_event;
466 events.state = &client_control->channels[0].state;
467
468 tag = IpcTag::PING2;
469 CrossCallParamsMock* params2 = new (buff0) CrossCallParamsMock(tag, 1);
470 FakeOkAnswerInChannel(buff0);
471
472 result = client.DoCall(params2, &answer);
473 if (SBOX_ERROR_CHANNEL_ERROR != result)
474 client.FreeBuffer(buff0);
475
476 EXPECT_TRUE(SBOX_ALL_OK == result);
477 EXPECT_EQ(tag, client_control->channels[0].ipc_tag);
478 EXPECT_EQ(kFreeChannel, client_control->channels[0].state);
479 EXPECT_EQ(kFreeChannel, client_control->channels[1].state);
480 EXPECT_EQ(kFreeChannel, client_control->channels[2].state);
481
482 CloseChannelEvents(client_control);
483 ::CloseHandle(client_control->server_alive);
484
485 delete[] reinterpret_cast<char*>(client_control);
486 }
487
488 // This is the server thread that very slowly answers an IPC and exits. Note
489 // that the pong event needs to be signaled twice.
SlowResponseServer(PVOID param)490 DWORD WINAPI SlowResponseServer(PVOID param) {
491 ServerEvents* events = reinterpret_cast<ServerEvents*>(param);
492 DWORD wait_result = 0;
493 wait_result = ::WaitForSingleObject(events->ping, INFINITE);
494 ::Sleep(kIPCWaitTimeOut1 + kIPCWaitTimeOut2 + 200);
495 ::InterlockedExchange(events->state, kAckChannel);
496 ::SetEvent(events->pong);
497 return wait_result;
498 }
499
500 // This thread's job is to keep the mutex locked.
MainServerThread(PVOID param)501 DWORD WINAPI MainServerThread(PVOID param) {
502 ServerEvents* events = reinterpret_cast<ServerEvents*>(param);
503 DWORD wait_result = 0;
504 wait_result = ::WaitForSingleObject(events->mutex, INFINITE);
505 Sleep(kIPCWaitTimeOut1 * 20);
506 return wait_result;
507 }
508
509 // Creates a server thread that answers the IPC so slow that is guaranteed to
510 // trigger the time-out code path in the client. A second thread is created
511 // to hold locked the server_alive mutex: this signals the client that the
512 // server is not dead and it retries the wait.
TEST(IPCTest,ClientSlowServer)513 TEST(IPCTest, ClientSlowServer) {
514 size_t base_start = 0;
515 IPCControl* client_control =
516 MakeChannels(kIPCChannelSize, 4096 * 2, &base_start);
517 FixChannels(client_control, base_start, kIPCChannelSize, FIX_PONG_NOT_READY);
518 client_control->server_alive = ::CreateMutex(nullptr, false, nullptr);
519
520 char* mem = reinterpret_cast<char*>(client_control);
521 SharedMemIPCClient client(mem);
522
523 ServerEvents events = {0};
524 events.ping = client_control->channels[0].ping_event;
525 events.pong = client_control->channels[0].pong_event;
526 events.state = &client_control->channels[0].state;
527
528 HANDLE t1 =
529 ::CreateThread(nullptr, 0, SlowResponseServer, &events, 0, nullptr);
530 ASSERT_TRUE(t1);
531 ::CloseHandle(t1);
532
533 ServerEvents events2 = {0};
534 events2.pong = events.pong;
535 events2.mutex = client_control->server_alive;
536
537 HANDLE t2 =
538 ::CreateThread(nullptr, 0, MainServerThread, &events2, 0, nullptr);
539 ASSERT_TRUE(t2);
540 ::CloseHandle(t2);
541
542 ::Sleep(1);
543
544 void* buff0 = client.GetBuffer();
545 IpcTag tag = IpcTag::PING1;
546 CrossCallReturn answer;
547 CrossCallParamsMock* params1 = new (buff0) CrossCallParamsMock(tag, 1);
548 FakeOkAnswerInChannel(buff0);
549
550 ResultCode result = client.DoCall(params1, &answer);
551 if (SBOX_ERROR_CHANNEL_ERROR != result)
552 client.FreeBuffer(buff0);
553
554 EXPECT_TRUE(SBOX_ALL_OK == result);
555 EXPECT_EQ(tag, client_control->channels[0].ipc_tag);
556 EXPECT_EQ(kFreeChannel, client_control->channels[0].state);
557
558 CloseChannelEvents(client_control);
559 ::CloseHandle(client_control->server_alive);
560 delete[] reinterpret_cast<char*>(client_control);
561 }
562
563 // This test-only IPC dispatcher has two handlers with the same signature
564 // but only CallOneHandler should be used.
565 class UnitTestIPCDispatcher : public Dispatcher {
566 public:
567 UnitTestIPCDispatcher();
~UnitTestIPCDispatcher()568 ~UnitTestIPCDispatcher() override {}
569
SetupService(InterceptionManager * manager,IpcTag service)570 bool SetupService(InterceptionManager* manager, IpcTag service) override {
571 return true;
572 }
573
574 private:
CallOneHandler(IPCInfo * ipc,HANDLE p1,uint32_t p2)575 bool CallOneHandler(IPCInfo* ipc, HANDLE p1, uint32_t p2) {
576 ipc->return_info.extended[0].handle = p1;
577 ipc->return_info.extended[1].unsigned_int = p2;
578 return true;
579 }
580
CallTwoHandler(IPCInfo * ipc,HANDLE p1,uint32_t p2)581 bool CallTwoHandler(IPCInfo* ipc, HANDLE p1, uint32_t p2) { return true; }
582 };
583
UnitTestIPCDispatcher()584 UnitTestIPCDispatcher::UnitTestIPCDispatcher() {
585 static const IPCCall call_one = {{IpcTag::PING1, {VOIDPTR_TYPE, UINT32_TYPE}},
586 reinterpret_cast<CallbackGeneric>(
587 &UnitTestIPCDispatcher::CallOneHandler)};
588 static const IPCCall call_two = {{IpcTag::PING2, {VOIDPTR_TYPE, UINT32_TYPE}},
589 reinterpret_cast<CallbackGeneric>(
590 &UnitTestIPCDispatcher::CallTwoHandler)};
591 ipc_calls_.push_back(call_one);
592 ipc_calls_.push_back(call_two);
593 }
594
595 // This test does most of the shared memory IPC client-server roundtrip
596 // and tests the packing, unpacking and call dispatching.
TEST(IPCTest,SharedMemServerTests)597 TEST(IPCTest, SharedMemServerTests) {
598 size_t base_start = 0;
599 IPCControl* client_control = MakeChannels(kIPCChannelSize, 4096, &base_start);
600 client_control->server_alive = HANDLE(1);
601 FixChannels(client_control, base_start, kIPCChannelSize, FIX_PONG_READY);
602
603 char* mem = reinterpret_cast<char*>(client_control);
604 SharedMemIPCClient client(mem);
605
606 CrossCallReturn answer;
607 HANDLE bar = HANDLE(191919);
608 DWORD foo = 6767676;
609 CrossCall(client, IpcTag::PING1, bar, foo, &answer);
610 void* buff = client.GetBuffer();
611 ASSERT_TRUE(buff);
612
613 UnitTestIPCDispatcher dispatcher;
614 // Since we are directly calling InvokeCallback, most of this structure
615 // can be set to nullptr.
616 sandbox::SharedMemIPCServer::ServerControl srv_control = {};
617 srv_control.channel_size = kIPCChannelSize;
618 srv_control.shared_base = reinterpret_cast<char*>(client_control);
619 srv_control.dispatcher = &dispatcher;
620
621 sandbox::CrossCallReturn call_return = {0};
622 EXPECT_TRUE(
623 SharedMemIPCServer::InvokeCallback(&srv_control, buff, &call_return));
624 EXPECT_EQ(SBOX_ALL_OK, call_return.call_outcome);
625 EXPECT_TRUE(bar == call_return.extended[0].handle);
626 EXPECT_EQ(foo, call_return.extended[1].unsigned_int);
627
628 CloseChannelEvents(client_control);
629 delete[] reinterpret_cast<char*>(client_control);
630 }
631
632 } // namespace sandbox
633