security/sandbox/win/src/ipc_unittest.cc

changeset 0
6474c204b198
     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, &param_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, &param_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, &param_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, &param_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, &param_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, &param_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, &param_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, &param_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

mercurial