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