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