1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/security/sandbox/win/src/ipc_unittest.cc Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,641 @@ 1.4 +// Copyright (c) 2012 The Chromium Authors. All rights reserved. 1.5 +// Use of this source code is governed by a BSD-style license that can be 1.6 +// found in the LICENSE file. 1.7 + 1.8 +#include "base/basictypes.h" 1.9 +#include "sandbox/win/src/crosscall_client.h" 1.10 +#include "sandbox/win/src/crosscall_server.h" 1.11 +#include "sandbox/win/src/sharedmem_ipc_client.h" 1.12 +#include "sandbox/win/src/sharedmem_ipc_server.h" 1.13 +#include "testing/gtest/include/gtest/gtest.h" 1.14 + 1.15 +namespace sandbox { 1.16 + 1.17 +// Helper function to make the fake shared memory with some 1.18 +// basic elements initialized. 1.19 +IPCControl* MakeChannels(size_t channel_size, size_t total_shared_size, 1.20 + size_t* base_start) { 1.21 + // Allocate memory 1.22 + char* mem = new char[total_shared_size]; 1.23 + memset(mem, 0, total_shared_size); 1.24 + // Calculate how many channels we can fit in the shared memory. 1.25 + total_shared_size -= offsetof(IPCControl, channels); 1.26 + size_t channel_count = 1.27 + total_shared_size / (sizeof(ChannelControl) + channel_size); 1.28 + // Calculate the start of the first channel. 1.29 + *base_start = (sizeof(ChannelControl)* channel_count) + 1.30 + offsetof(IPCControl, channels); 1.31 + // Setup client structure. 1.32 + IPCControl* client_control = reinterpret_cast<IPCControl*>(mem); 1.33 + client_control->channels_count = channel_count; 1.34 + return client_control; 1.35 +} 1.36 + 1.37 +enum TestFixMode { 1.38 + FIX_NO_EVENTS, 1.39 + FIX_PONG_READY, 1.40 + FIX_PONG_NOT_READY 1.41 +}; 1.42 + 1.43 +void FixChannels(IPCControl* client_control, size_t base_start, 1.44 + size_t channel_size, TestFixMode mode) { 1.45 + for (size_t ix = 0; ix != client_control->channels_count; ++ix) { 1.46 + ChannelControl& channel = client_control->channels[ix]; 1.47 + channel.channel_base = base_start; 1.48 + channel.state = kFreeChannel; 1.49 + if (mode != FIX_NO_EVENTS) { 1.50 + BOOL signaled = (FIX_PONG_READY == mode)? TRUE : FALSE; 1.51 + channel.ping_event = ::CreateEventW(NULL, FALSE, FALSE, NULL); 1.52 + channel.pong_event = ::CreateEventW(NULL, FALSE, signaled, NULL); 1.53 + } 1.54 + base_start += channel_size; 1.55 + } 1.56 +} 1.57 + 1.58 +void CloseChannelEvents(IPCControl* client_control) { 1.59 + for (size_t ix = 0; ix != client_control->channels_count; ++ix) { 1.60 + ChannelControl& channel = client_control->channels[ix]; 1.61 + ::CloseHandle(channel.ping_event); 1.62 + ::CloseHandle(channel.pong_event); 1.63 + } 1.64 +} 1.65 + 1.66 +TEST(IPCTest, ChannelMaker) { 1.67 + // Test that our testing rig is computing offsets properly. We should have 1.68 + // 5 channnels and the offset to the first channel is 108 bytes in 32 bits 1.69 + // and 216 in 64 bits. 1.70 + size_t channel_start = 0; 1.71 + IPCControl* client_control = MakeChannels(12 * 64, 4096, &channel_start); 1.72 + ASSERT_TRUE(NULL != client_control); 1.73 + EXPECT_EQ(5, client_control->channels_count); 1.74 +#if defined(_WIN64) 1.75 + EXPECT_EQ(216, channel_start); 1.76 +#else 1.77 + EXPECT_EQ(108, channel_start); 1.78 +#endif 1.79 + delete[] reinterpret_cast<char*>(client_control); 1.80 +} 1.81 + 1.82 +TEST(IPCTest, ClientLockUnlock) { 1.83 + // Make 7 channels of kIPCChannelSize (1kb) each. Test that we lock and 1.84 + // unlock channels properly. 1.85 + size_t base_start = 0; 1.86 + IPCControl* client_control = 1.87 + MakeChannels(kIPCChannelSize, 4096 * 2, &base_start); 1.88 + FixChannels(client_control, base_start, kIPCChannelSize, FIX_NO_EVENTS); 1.89 + 1.90 + char* mem = reinterpret_cast<char*>(client_control); 1.91 + SharedMemIPCClient client(mem); 1.92 + 1.93 + // Test that we lock the first 3 channels in sequence. 1.94 + void* buff0 = client.GetBuffer(); 1.95 + EXPECT_TRUE(mem + client_control->channels[0].channel_base == buff0); 1.96 + EXPECT_EQ(kBusyChannel, client_control->channels[0].state); 1.97 + EXPECT_EQ(kFreeChannel, client_control->channels[1].state); 1.98 + EXPECT_EQ(kFreeChannel, client_control->channels[2].state); 1.99 + EXPECT_EQ(kFreeChannel, client_control->channels[3].state); 1.100 + EXPECT_EQ(kFreeChannel, client_control->channels[4].state); 1.101 + EXPECT_EQ(kFreeChannel, client_control->channels[5].state); 1.102 + 1.103 + void* buff1 = client.GetBuffer(); 1.104 + EXPECT_TRUE(mem + client_control->channels[1].channel_base == buff1); 1.105 + EXPECT_EQ(kBusyChannel, client_control->channels[0].state); 1.106 + EXPECT_EQ(kBusyChannel, client_control->channels[1].state); 1.107 + EXPECT_EQ(kFreeChannel, client_control->channels[2].state); 1.108 + EXPECT_EQ(kFreeChannel, client_control->channels[3].state); 1.109 + EXPECT_EQ(kFreeChannel, client_control->channels[4].state); 1.110 + EXPECT_EQ(kFreeChannel, client_control->channels[5].state); 1.111 + 1.112 + void* buff2 = client.GetBuffer(); 1.113 + EXPECT_TRUE(mem + client_control->channels[2].channel_base == buff2); 1.114 + EXPECT_EQ(kBusyChannel, client_control->channels[0].state); 1.115 + EXPECT_EQ(kBusyChannel, client_control->channels[1].state); 1.116 + EXPECT_EQ(kBusyChannel, client_control->channels[2].state); 1.117 + EXPECT_EQ(kFreeChannel, client_control->channels[3].state); 1.118 + EXPECT_EQ(kFreeChannel, client_control->channels[4].state); 1.119 + EXPECT_EQ(kFreeChannel, client_control->channels[5].state); 1.120 + 1.121 + // Test that we unlock and re-lock the right channel. 1.122 + client.FreeBuffer(buff1); 1.123 + EXPECT_EQ(kBusyChannel, client_control->channels[0].state); 1.124 + EXPECT_EQ(kFreeChannel, client_control->channels[1].state); 1.125 + EXPECT_EQ(kBusyChannel, client_control->channels[2].state); 1.126 + EXPECT_EQ(kFreeChannel, client_control->channels[3].state); 1.127 + EXPECT_EQ(kFreeChannel, client_control->channels[4].state); 1.128 + EXPECT_EQ(kFreeChannel, client_control->channels[5].state); 1.129 + 1.130 + void* buff2b = client.GetBuffer(); 1.131 + EXPECT_TRUE(mem + client_control->channels[1].channel_base == buff2b); 1.132 + EXPECT_EQ(kBusyChannel, client_control->channels[0].state); 1.133 + EXPECT_EQ(kBusyChannel, client_control->channels[1].state); 1.134 + EXPECT_EQ(kBusyChannel, client_control->channels[2].state); 1.135 + EXPECT_EQ(kFreeChannel, client_control->channels[3].state); 1.136 + EXPECT_EQ(kFreeChannel, client_control->channels[4].state); 1.137 + EXPECT_EQ(kFreeChannel, client_control->channels[5].state); 1.138 + 1.139 + client.FreeBuffer(buff0); 1.140 + EXPECT_EQ(kFreeChannel, client_control->channels[0].state); 1.141 + EXPECT_EQ(kBusyChannel, client_control->channels[1].state); 1.142 + EXPECT_EQ(kBusyChannel, client_control->channels[2].state); 1.143 + EXPECT_EQ(kFreeChannel, client_control->channels[3].state); 1.144 + EXPECT_EQ(kFreeChannel, client_control->channels[4].state); 1.145 + EXPECT_EQ(kFreeChannel, client_control->channels[5].state); 1.146 + 1.147 + delete[] reinterpret_cast<char*>(client_control); 1.148 +} 1.149 + 1.150 +TEST(IPCTest, CrossCallStrPacking) { 1.151 + // This test tries the CrossCall object with null and non-null string 1.152 + // combination of parameters, integer types and verifies that the unpacker 1.153 + // can read them properly. 1.154 + size_t base_start = 0; 1.155 + IPCControl* client_control = 1.156 + MakeChannels(kIPCChannelSize, 4096 * 4, &base_start); 1.157 + client_control->server_alive = HANDLE(1); 1.158 + FixChannels(client_control, base_start, kIPCChannelSize, FIX_PONG_READY); 1.159 + 1.160 + char* mem = reinterpret_cast<char*>(client_control); 1.161 + SharedMemIPCClient client(mem); 1.162 + 1.163 + CrossCallReturn answer; 1.164 + uint32 tag1 = 666; 1.165 + const wchar_t text[] = L"98765 - 43210"; 1.166 + std::wstring copied_text; 1.167 + CrossCallParamsEx* actual_params; 1.168 + 1.169 + CrossCall(client, tag1, text, &answer); 1.170 + actual_params = reinterpret_cast<CrossCallParamsEx*>(client.GetBuffer()); 1.171 + EXPECT_EQ(1, actual_params->GetParamsCount()); 1.172 + EXPECT_EQ(tag1, actual_params->GetTag()); 1.173 + EXPECT_TRUE(actual_params->GetParameterStr(0, &copied_text)); 1.174 + EXPECT_STREQ(text, copied_text.c_str()); 1.175 + 1.176 + // Check with an empty string. 1.177 + uint32 tag2 = 777; 1.178 + const wchar_t* null_text = NULL; 1.179 + CrossCall(client, tag2, null_text, &answer); 1.180 + actual_params = reinterpret_cast<CrossCallParamsEx*>(client.GetBuffer()); 1.181 + EXPECT_EQ(1, actual_params->GetParamsCount()); 1.182 + EXPECT_EQ(tag2, actual_params->GetTag()); 1.183 + uint32 param_size = 1; 1.184 + ArgType type = INVALID_TYPE; 1.185 + void* param_addr = actual_params->GetRawParameter(0, ¶m_size, &type); 1.186 + EXPECT_TRUE(NULL != param_addr); 1.187 + EXPECT_EQ(0, param_size); 1.188 + EXPECT_EQ(WCHAR_TYPE, type); 1.189 + EXPECT_TRUE(actual_params->GetParameterStr(0, &copied_text)); 1.190 + 1.191 + uint32 tag3 = 888; 1.192 + param_size = 1; 1.193 + copied_text.clear(); 1.194 + 1.195 + // Check with an empty string and a non-empty string. 1.196 + CrossCall(client, tag3, null_text, text, &answer); 1.197 + actual_params = reinterpret_cast<CrossCallParamsEx*>(client.GetBuffer()); 1.198 + EXPECT_EQ(2, actual_params->GetParamsCount()); 1.199 + EXPECT_EQ(tag3, actual_params->GetTag()); 1.200 + type = INVALID_TYPE; 1.201 + param_addr = actual_params->GetRawParameter(0, ¶m_size, &type); 1.202 + EXPECT_TRUE(NULL != param_addr); 1.203 + EXPECT_EQ(0, param_size); 1.204 + EXPECT_EQ(WCHAR_TYPE, type); 1.205 + EXPECT_TRUE(actual_params->GetParameterStr(0, &copied_text)); 1.206 + EXPECT_TRUE(actual_params->GetParameterStr(1, &copied_text)); 1.207 + EXPECT_STREQ(text, copied_text.c_str()); 1.208 + 1.209 + param_size = 1; 1.210 + std::wstring copied_text_p0, copied_text_p2; 1.211 + 1.212 + const wchar_t text2[] = L"AeFG"; 1.213 + CrossCall(client, tag1, text2, null_text, text, &answer); 1.214 + actual_params = reinterpret_cast<CrossCallParamsEx*>(client.GetBuffer()); 1.215 + EXPECT_EQ(3, actual_params->GetParamsCount()); 1.216 + EXPECT_EQ(tag1, actual_params->GetTag()); 1.217 + EXPECT_TRUE(actual_params->GetParameterStr(0, &copied_text_p0)); 1.218 + EXPECT_STREQ(text2, copied_text_p0.c_str()); 1.219 + EXPECT_TRUE(actual_params->GetParameterStr(2, &copied_text_p2)); 1.220 + EXPECT_STREQ(text, copied_text_p2.c_str()); 1.221 + type = INVALID_TYPE; 1.222 + param_addr = actual_params->GetRawParameter(1, ¶m_size, &type); 1.223 + EXPECT_TRUE(NULL != param_addr); 1.224 + EXPECT_EQ(0, param_size); 1.225 + EXPECT_EQ(WCHAR_TYPE, type); 1.226 + 1.227 + CloseChannelEvents(client_control); 1.228 + delete[] reinterpret_cast<char*>(client_control); 1.229 +} 1.230 + 1.231 +TEST(IPCTest, CrossCallIntPacking) { 1.232 + // Check handling for regular 32 bit integers used in Windows. 1.233 + size_t base_start = 0; 1.234 + IPCControl* client_control = 1.235 + MakeChannels(kIPCChannelSize, 4096 * 4, &base_start); 1.236 + client_control->server_alive = HANDLE(1); 1.237 + FixChannels(client_control, base_start, kIPCChannelSize, FIX_PONG_READY); 1.238 + 1.239 + uint32 tag1 = 999; 1.240 + uint32 tag2 = 111; 1.241 + const wchar_t text[] = L"godzilla"; 1.242 + CrossCallParamsEx* actual_params; 1.243 + 1.244 + char* mem = reinterpret_cast<char*>(client_control); 1.245 + SharedMemIPCClient client(mem); 1.246 + 1.247 + CrossCallReturn answer; 1.248 + DWORD dw = 0xE6578; 1.249 + CrossCall(client, tag2, dw, &answer); 1.250 + actual_params = reinterpret_cast<CrossCallParamsEx*>(client.GetBuffer()); 1.251 + EXPECT_EQ(1, actual_params->GetParamsCount()); 1.252 + EXPECT_EQ(tag2, actual_params->GetTag()); 1.253 + ArgType type = INVALID_TYPE; 1.254 + uint32 param_size = 1; 1.255 + void* param_addr = actual_params->GetRawParameter(0, ¶m_size, &type); 1.256 + ASSERT_EQ(sizeof(dw), param_size); 1.257 + EXPECT_EQ(ULONG_TYPE, type); 1.258 + ASSERT_TRUE(NULL != param_addr); 1.259 + EXPECT_EQ(0, memcmp(&dw, param_addr, param_size)); 1.260 + 1.261 + // Check handling for windows HANDLES. 1.262 + HANDLE h = HANDLE(0x70000500); 1.263 + CrossCall(client, tag1, text, h, &answer); 1.264 + actual_params = reinterpret_cast<CrossCallParamsEx*>(client.GetBuffer()); 1.265 + EXPECT_EQ(2, actual_params->GetParamsCount()); 1.266 + EXPECT_EQ(tag1, actual_params->GetTag()); 1.267 + type = INVALID_TYPE; 1.268 + param_addr = actual_params->GetRawParameter(1, ¶m_size, &type); 1.269 + ASSERT_EQ(sizeof(h), param_size); 1.270 + EXPECT_EQ(VOIDPTR_TYPE, type); 1.271 + ASSERT_TRUE(NULL != param_addr); 1.272 + EXPECT_EQ(0, memcmp(&h, param_addr, param_size)); 1.273 + 1.274 + // Check combination of 32 and 64 bits. 1.275 + CrossCall(client, tag2, h, dw, h, &answer); 1.276 + actual_params = reinterpret_cast<CrossCallParamsEx*>(client.GetBuffer()); 1.277 + EXPECT_EQ(3, actual_params->GetParamsCount()); 1.278 + EXPECT_EQ(tag2, actual_params->GetTag()); 1.279 + type = INVALID_TYPE; 1.280 + param_addr = actual_params->GetRawParameter(0, ¶m_size, &type); 1.281 + ASSERT_EQ(sizeof(h), param_size); 1.282 + EXPECT_EQ(VOIDPTR_TYPE, type); 1.283 + ASSERT_TRUE(NULL != param_addr); 1.284 + EXPECT_EQ(0, memcmp(&h, param_addr, param_size)); 1.285 + type = INVALID_TYPE; 1.286 + param_addr = actual_params->GetRawParameter(1, ¶m_size, &type); 1.287 + ASSERT_EQ(sizeof(dw), param_size); 1.288 + EXPECT_EQ(ULONG_TYPE, type); 1.289 + ASSERT_TRUE(NULL != param_addr); 1.290 + EXPECT_EQ(0, memcmp(&dw, param_addr, param_size)); 1.291 + type = INVALID_TYPE; 1.292 + param_addr = actual_params->GetRawParameter(2, ¶m_size, &type); 1.293 + ASSERT_EQ(sizeof(h), param_size); 1.294 + EXPECT_EQ(VOIDPTR_TYPE, type); 1.295 + ASSERT_TRUE(NULL != param_addr); 1.296 + EXPECT_EQ(0, memcmp(&h, param_addr, param_size)); 1.297 + 1.298 + CloseChannelEvents(client_control); 1.299 + delete[] reinterpret_cast<char*>(client_control); 1.300 +} 1.301 + 1.302 +TEST(IPCTest, CrossCallValidation) { 1.303 + // First a sanity test with a well formed parameter object. 1.304 + unsigned long value = 124816; 1.305 + const uint32 kTag = 33; 1.306 + const uint32 kBufferSize = 256; 1.307 + ActualCallParams<1, kBufferSize> params_1(kTag); 1.308 + params_1.CopyParamIn(0, &value, sizeof(value), false, ULONG_TYPE); 1.309 + void* buffer = const_cast<void*>(params_1.GetBuffer()); 1.310 + 1.311 + uint32 out_size = 0; 1.312 + CrossCallParamsEx* ccp = 0; 1.313 + ccp = CrossCallParamsEx::CreateFromBuffer(buffer, params_1.GetSize(), 1.314 + &out_size); 1.315 + ASSERT_TRUE(NULL != ccp); 1.316 + EXPECT_TRUE(ccp->GetBuffer() != buffer); 1.317 + EXPECT_EQ(kTag, ccp->GetTag()); 1.318 + EXPECT_EQ(1, ccp->GetParamsCount()); 1.319 + delete[] (reinterpret_cast<char*>(ccp)); 1.320 + 1.321 +#if defined(NDEBUG) 1.322 + // Test hat we handle integer overflow on the number of params 1.323 + // correctly. We use a test-only ctor for ActualCallParams that 1.324 + // allows to create malformed cross-call buffers. 1.325 + const int32 kPtrDiffSz = sizeof(ptrdiff_t); 1.326 + for (int32 ix = -1; ix != 3; ++ix) { 1.327 + uint32 fake_num_params = (kuint32max / kPtrDiffSz) + ix; 1.328 + ActualCallParams<1, kBufferSize> params_2(kTag, fake_num_params); 1.329 + params_2.CopyParamIn(0, &value, sizeof(value), false, ULONG_TYPE); 1.330 + buffer = const_cast<void*>(params_2.GetBuffer()); 1.331 + 1.332 + EXPECT_TRUE(NULL != buffer); 1.333 + ccp = CrossCallParamsEx::CreateFromBuffer(buffer, params_1.GetSize(), 1.334 + &out_size); 1.335 + // If the buffer is malformed the return is NULL. 1.336 + EXPECT_TRUE(NULL == ccp); 1.337 + } 1.338 +#endif // defined(NDEBUG) 1.339 + 1.340 + ActualCallParams<1, kBufferSize> params_3(kTag, 1); 1.341 + params_3.CopyParamIn(0, &value, sizeof(value), false, ULONG_TYPE); 1.342 + buffer = const_cast<void*>(params_3.GetBuffer()); 1.343 + EXPECT_TRUE(NULL != buffer); 1.344 + 1.345 + uint32 correct_size = params_3.OverrideSize(1); 1.346 + ccp = CrossCallParamsEx::CreateFromBuffer(buffer, kBufferSize, &out_size); 1.347 + EXPECT_TRUE(NULL == ccp); 1.348 + 1.349 + // The correct_size is 8 bytes aligned. 1.350 + params_3.OverrideSize(correct_size - 7); 1.351 + ccp = CrossCallParamsEx::CreateFromBuffer(buffer, kBufferSize, &out_size); 1.352 + EXPECT_TRUE(NULL == ccp); 1.353 + 1.354 + params_3.OverrideSize(correct_size); 1.355 + ccp = CrossCallParamsEx::CreateFromBuffer(buffer, kBufferSize, &out_size); 1.356 + EXPECT_TRUE(NULL != ccp); 1.357 + 1.358 + // Make sure that two parameters work as expected. 1.359 + ActualCallParams<2, kBufferSize> params_4(kTag, 2); 1.360 + params_4.CopyParamIn(0, &value, sizeof(value), false, ULONG_TYPE); 1.361 + params_4.CopyParamIn(1, buffer, sizeof(buffer), false, VOIDPTR_TYPE); 1.362 + buffer = const_cast<void*>(params_4.GetBuffer()); 1.363 + EXPECT_TRUE(NULL != buffer); 1.364 + 1.365 + ccp = CrossCallParamsEx::CreateFromBuffer(buffer, kBufferSize, &out_size); 1.366 + EXPECT_TRUE(NULL != ccp); 1.367 + 1.368 +#if defined(_WIN64) 1.369 + correct_size = params_4.OverrideSize(1); 1.370 + params_4.OverrideSize(correct_size - 1); 1.371 + ccp = CrossCallParamsEx::CreateFromBuffer(buffer, kBufferSize, &out_size); 1.372 + EXPECT_TRUE(NULL == ccp); 1.373 +#endif 1.374 +} 1.375 + 1.376 +// This structure is passed to the mock server threads to simulate 1.377 +// the server side IPC so it has the required kernel objects. 1.378 +struct ServerEvents { 1.379 + HANDLE ping; 1.380 + HANDLE pong; 1.381 + volatile LONG* state; 1.382 + HANDLE mutex; 1.383 +}; 1.384 + 1.385 +// This is the server thread that quicky answers an IPC and exits. 1.386 +DWORD WINAPI QuickResponseServer(PVOID param) { 1.387 + ServerEvents* events = reinterpret_cast<ServerEvents*>(param); 1.388 + DWORD wait_result = 0; 1.389 + wait_result = ::WaitForSingleObject(events->ping, INFINITE); 1.390 + ::InterlockedExchange(events->state, kAckChannel); 1.391 + ::SetEvent(events->pong); 1.392 + return wait_result; 1.393 +} 1.394 + 1.395 +class CrossCallParamsMock : public CrossCallParams { 1.396 + public: 1.397 + CrossCallParamsMock(uint32 tag, uint32 params_count) 1.398 + : CrossCallParams(tag, params_count) { 1.399 + } 1.400 + private: 1.401 + void* params[4]; 1.402 +}; 1.403 + 1.404 +void FakeOkAnswerInChannel(void* channel) { 1.405 + CrossCallReturn* answer = reinterpret_cast<CrossCallReturn*>(channel); 1.406 + answer->call_outcome = SBOX_ALL_OK; 1.407 +} 1.408 + 1.409 +// Create two threads that will quickly answer IPCs; the first one 1.410 +// using channel 1 (channel 0 is busy) and one using channel 0. No time-out 1.411 +// should occur. 1.412 +TEST(IPCTest, ClientFastServer) { 1.413 + const size_t channel_size = kIPCChannelSize; 1.414 + size_t base_start = 0; 1.415 + IPCControl* client_control = 1.416 + MakeChannels(channel_size, 4096 * 2, &base_start); 1.417 + FixChannels(client_control, base_start, kIPCChannelSize, FIX_PONG_NOT_READY); 1.418 + client_control->server_alive = ::CreateMutex(NULL, FALSE, NULL); 1.419 + 1.420 + char* mem = reinterpret_cast<char*>(client_control); 1.421 + SharedMemIPCClient client(mem); 1.422 + 1.423 + ServerEvents events = {0}; 1.424 + events.ping = client_control->channels[1].ping_event; 1.425 + events.pong = client_control->channels[1].pong_event; 1.426 + events.state = &client_control->channels[1].state; 1.427 + 1.428 + HANDLE t1 = ::CreateThread(NULL, 0, QuickResponseServer, &events, 0, NULL); 1.429 + ASSERT_TRUE(NULL != t1); 1.430 + ::CloseHandle(t1); 1.431 + 1.432 + void* buff0 = client.GetBuffer(); 1.433 + EXPECT_TRUE(mem + client_control->channels[0].channel_base == buff0); 1.434 + EXPECT_EQ(kBusyChannel, client_control->channels[0].state); 1.435 + EXPECT_EQ(kFreeChannel, client_control->channels[1].state); 1.436 + EXPECT_EQ(kFreeChannel, client_control->channels[2].state); 1.437 + 1.438 + void* buff1 = client.GetBuffer(); 1.439 + EXPECT_TRUE(mem + client_control->channels[1].channel_base == buff1); 1.440 + EXPECT_EQ(kBusyChannel, client_control->channels[0].state); 1.441 + EXPECT_EQ(kBusyChannel, client_control->channels[1].state); 1.442 + EXPECT_EQ(kFreeChannel, client_control->channels[2].state); 1.443 + 1.444 + EXPECT_EQ(0, client_control->channels[1].ipc_tag); 1.445 + 1.446 + uint32 tag = 7654; 1.447 + CrossCallReturn answer; 1.448 + CrossCallParamsMock* params1 = new(buff1) CrossCallParamsMock(tag, 1); 1.449 + FakeOkAnswerInChannel(buff1); 1.450 + 1.451 + ResultCode result = client.DoCall(params1, &answer); 1.452 + if (SBOX_ERROR_CHANNEL_ERROR != result) 1.453 + client.FreeBuffer(buff1); 1.454 + 1.455 + EXPECT_TRUE(SBOX_ALL_OK == result); 1.456 + EXPECT_EQ(tag, client_control->channels[1].ipc_tag); 1.457 + EXPECT_EQ(kBusyChannel, client_control->channels[0].state); 1.458 + EXPECT_EQ(kFreeChannel, client_control->channels[1].state); 1.459 + EXPECT_EQ(kFreeChannel, client_control->channels[2].state); 1.460 + 1.461 + HANDLE t2 = ::CreateThread(NULL, 0, QuickResponseServer, &events, 0, NULL); 1.462 + ASSERT_TRUE(NULL != t2); 1.463 + ::CloseHandle(t2); 1.464 + 1.465 + client.FreeBuffer(buff0); 1.466 + events.ping = client_control->channels[0].ping_event; 1.467 + events.pong = client_control->channels[0].pong_event; 1.468 + events.state = &client_control->channels[0].state; 1.469 + 1.470 + tag = 4567; 1.471 + CrossCallParamsMock* params2 = new(buff0) CrossCallParamsMock(tag, 1); 1.472 + FakeOkAnswerInChannel(buff0); 1.473 + 1.474 + result = client.DoCall(params2, &answer); 1.475 + if (SBOX_ERROR_CHANNEL_ERROR != result) 1.476 + client.FreeBuffer(buff0); 1.477 + 1.478 + EXPECT_TRUE(SBOX_ALL_OK == result); 1.479 + EXPECT_EQ(tag, client_control->channels[0].ipc_tag); 1.480 + EXPECT_EQ(kFreeChannel, client_control->channels[0].state); 1.481 + EXPECT_EQ(kFreeChannel, client_control->channels[1].state); 1.482 + EXPECT_EQ(kFreeChannel, client_control->channels[2].state); 1.483 + 1.484 + CloseChannelEvents(client_control); 1.485 + ::CloseHandle(client_control->server_alive); 1.486 + 1.487 + delete[] reinterpret_cast<char*>(client_control); 1.488 +} 1.489 + 1.490 +// This is the server thread that very slowly answers an IPC and exits. Note 1.491 +// that the pong event needs to be signaled twice. 1.492 +DWORD WINAPI SlowResponseServer(PVOID param) { 1.493 + ServerEvents* events = reinterpret_cast<ServerEvents*>(param); 1.494 + DWORD wait_result = 0; 1.495 + wait_result = ::WaitForSingleObject(events->ping, INFINITE); 1.496 + ::Sleep(kIPCWaitTimeOut1 + kIPCWaitTimeOut2 + 200); 1.497 + ::InterlockedExchange(events->state, kAckChannel); 1.498 + ::SetEvent(events->pong); 1.499 + return wait_result; 1.500 +} 1.501 + 1.502 +// This thread's job is to keep the mutex locked. 1.503 +DWORD WINAPI MainServerThread(PVOID param) { 1.504 + ServerEvents* events = reinterpret_cast<ServerEvents*>(param); 1.505 + DWORD wait_result = 0; 1.506 + wait_result = ::WaitForSingleObject(events->mutex, INFINITE); 1.507 + Sleep(kIPCWaitTimeOut1 * 20); 1.508 + return wait_result; 1.509 +} 1.510 + 1.511 +// Creates a server thread that answers the IPC so slow that is guaranteed to 1.512 +// trigger the time-out code path in the client. A second thread is created 1.513 +// to hold locked the server_alive mutex: this signals the client that the 1.514 +// server is not dead and it retries the wait. 1.515 +TEST(IPCTest, ClientSlowServer) { 1.516 + size_t base_start = 0; 1.517 + IPCControl* client_control = 1.518 + MakeChannels(kIPCChannelSize, 4096*2, &base_start); 1.519 + FixChannels(client_control, base_start, kIPCChannelSize, FIX_PONG_NOT_READY); 1.520 + client_control->server_alive = ::CreateMutex(NULL, FALSE, NULL); 1.521 + 1.522 + char* mem = reinterpret_cast<char*>(client_control); 1.523 + SharedMemIPCClient client(mem); 1.524 + 1.525 + ServerEvents events = {0}; 1.526 + events.ping = client_control->channels[0].ping_event; 1.527 + events.pong = client_control->channels[0].pong_event; 1.528 + events.state = &client_control->channels[0].state; 1.529 + 1.530 + HANDLE t1 = ::CreateThread(NULL, 0, SlowResponseServer, &events, 0, NULL); 1.531 + ASSERT_TRUE(NULL != t1); 1.532 + ::CloseHandle(t1); 1.533 + 1.534 + ServerEvents events2 = {0}; 1.535 + events2.pong = events.pong; 1.536 + events2.mutex = client_control->server_alive; 1.537 + 1.538 + HANDLE t2 = ::CreateThread(NULL, 0, MainServerThread, &events2, 0, NULL); 1.539 + ASSERT_TRUE(NULL != t2); 1.540 + ::CloseHandle(t2); 1.541 + 1.542 + ::Sleep(1); 1.543 + 1.544 + void* buff0 = client.GetBuffer(); 1.545 + uint32 tag = 4321; 1.546 + CrossCallReturn answer; 1.547 + CrossCallParamsMock* params1 = new(buff0) CrossCallParamsMock(tag, 1); 1.548 + FakeOkAnswerInChannel(buff0); 1.549 + 1.550 + ResultCode result = client.DoCall(params1, &answer); 1.551 + if (SBOX_ERROR_CHANNEL_ERROR != result) 1.552 + client.FreeBuffer(buff0); 1.553 + 1.554 + EXPECT_TRUE(SBOX_ALL_OK == result); 1.555 + EXPECT_EQ(tag, client_control->channels[0].ipc_tag); 1.556 + EXPECT_EQ(kFreeChannel, client_control->channels[0].state); 1.557 + 1.558 + CloseChannelEvents(client_control); 1.559 + ::CloseHandle(client_control->server_alive); 1.560 + delete[] reinterpret_cast<char*>(client_control); 1.561 +} 1.562 + 1.563 +// This test-only IPC dispatcher has two handlers with the same signature 1.564 +// but only CallOneHandler should be used. 1.565 +class UnitTestIPCDispatcher : public Dispatcher { 1.566 + public: 1.567 + enum { 1.568 + CALL_ONE_TAG = 78, 1.569 + CALL_TWO_TAG = 87 1.570 + }; 1.571 + 1.572 + UnitTestIPCDispatcher(); 1.573 + ~UnitTestIPCDispatcher() {}; 1.574 + 1.575 + virtual bool SetupService(InterceptionManager* manager, int service) { 1.576 + return true; 1.577 + } 1.578 + 1.579 + private: 1.580 + bool CallOneHandler(IPCInfo* ipc, HANDLE p1, DWORD p2) { 1.581 + ipc->return_info.extended[0].handle = p1; 1.582 + ipc->return_info.extended[1].unsigned_int = p2; 1.583 + return true; 1.584 + } 1.585 + 1.586 + bool CallTwoHandler(IPCInfo* ipc, HANDLE p1, DWORD p2) { 1.587 + return true; 1.588 + } 1.589 +}; 1.590 + 1.591 +UnitTestIPCDispatcher::UnitTestIPCDispatcher() { 1.592 + static const IPCCall call_one = { 1.593 + {CALL_ONE_TAG, VOIDPTR_TYPE, ULONG_TYPE}, 1.594 + reinterpret_cast<CallbackGeneric>( 1.595 + &UnitTestIPCDispatcher::CallOneHandler) 1.596 + }; 1.597 + static const IPCCall call_two = { 1.598 + {CALL_TWO_TAG, VOIDPTR_TYPE, ULONG_TYPE}, 1.599 + reinterpret_cast<CallbackGeneric>( 1.600 + &UnitTestIPCDispatcher::CallTwoHandler) 1.601 + }; 1.602 + ipc_calls_.push_back(call_one); 1.603 + ipc_calls_.push_back(call_two); 1.604 +} 1.605 + 1.606 +// This test does most of the shared memory IPC client-server roundtrip 1.607 +// and tests the packing, unpacking and call dispatching. 1.608 +TEST(IPCTest, SharedMemServerTests) { 1.609 + size_t base_start = 0; 1.610 + IPCControl* client_control = 1.611 + MakeChannels(kIPCChannelSize, 4096, &base_start); 1.612 + client_control->server_alive = HANDLE(1); 1.613 + FixChannels(client_control, base_start, kIPCChannelSize, FIX_PONG_READY); 1.614 + 1.615 + char* mem = reinterpret_cast<char*>(client_control); 1.616 + SharedMemIPCClient client(mem); 1.617 + 1.618 + CrossCallReturn answer; 1.619 + HANDLE bar = HANDLE(191919); 1.620 + DWORD foo = 6767676; 1.621 + CrossCall(client, UnitTestIPCDispatcher::CALL_ONE_TAG, bar, foo, &answer); 1.622 + void* buff = client.GetBuffer(); 1.623 + ASSERT_TRUE(NULL != buff); 1.624 + 1.625 + UnitTestIPCDispatcher dispatcher; 1.626 + // Since we are directly calling InvokeCallback, most of this structure 1.627 + // can be set to NULL. 1.628 + sandbox::SharedMemIPCServer::ServerControl srv_control = { 1.629 + NULL, NULL, kIPCChannelSize, NULL, 1.630 + reinterpret_cast<char*>(client_control), 1.631 + NULL, &dispatcher, {0} }; 1.632 + 1.633 + sandbox::CrossCallReturn call_return = {0}; 1.634 + EXPECT_TRUE(SharedMemIPCServer::InvokeCallback(&srv_control, buff, 1.635 + &call_return)); 1.636 + EXPECT_EQ(SBOX_ALL_OK, call_return.call_outcome); 1.637 + EXPECT_TRUE(bar == call_return.extended[0].handle); 1.638 + EXPECT_EQ(foo, call_return.extended[1].unsigned_int); 1.639 + 1.640 + CloseChannelEvents(client_control); 1.641 + delete[] reinterpret_cast<char*>(client_control); 1.642 +} 1.643 + 1.644 +} // namespace sandbox