security/sandbox/win/src/ipc_unittest.cc

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     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.
     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"
    12 namespace sandbox {
    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 }
    34 enum TestFixMode {
    35   FIX_NO_EVENTS,
    36   FIX_PONG_READY,
    37   FIX_PONG_NOT_READY
    38 };
    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 }
    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 }
    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 }
    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);
    87   char* mem = reinterpret_cast<char*>(client_control);
    88   SharedMemIPCClient client(mem);
    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);
   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);
   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);
   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);
   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);
   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);
   144   delete[] reinterpret_cast<char*>(client_control);
   145 }
   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);
   157   char* mem = reinterpret_cast<char*>(client_control);
   158   SharedMemIPCClient client(mem);
   160   CrossCallReturn answer;
   161   uint32 tag1 = 666;
   162   const wchar_t text[] = L"98765 - 43210";
   163   std::wstring copied_text;
   164   CrossCallParamsEx* actual_params;
   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());
   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, &param_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));
   188   uint32 tag3 = 888;
   189   param_size = 1;
   190   copied_text.clear();
   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, &param_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());
   206   param_size = 1;
   207   std::wstring copied_text_p0, copied_text_p2;
   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, &param_size, &type);
   220   EXPECT_TRUE(NULL != param_addr);
   221   EXPECT_EQ(0, param_size);
   222   EXPECT_EQ(WCHAR_TYPE, type);
   224   CloseChannelEvents(client_control);
   225   delete[] reinterpret_cast<char*>(client_control);
   226 }
   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);
   236   uint32 tag1 = 999;
   237   uint32 tag2 = 111;
   238   const wchar_t text[] = L"godzilla";
   239   CrossCallParamsEx* actual_params;
   241   char* mem = reinterpret_cast<char*>(client_control);
   242   SharedMemIPCClient client(mem);
   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, &param_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));
   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, &param_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));
   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, &param_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, &param_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, &param_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));
   295   CloseChannelEvents(client_control);
   296   delete[] reinterpret_cast<char*>(client_control);
   297 }
   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());
   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));
   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());
   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)
   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);
   342   uint32 correct_size = params_3.OverrideSize(1);
   343   ccp = CrossCallParamsEx::CreateFromBuffer(buffer, kBufferSize, &out_size);
   344   EXPECT_TRUE(NULL == ccp);
   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);
   351   params_3.OverrideSize(correct_size);
   352   ccp = CrossCallParamsEx::CreateFromBuffer(buffer, kBufferSize, &out_size);
   353   EXPECT_TRUE(NULL != ccp);
   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);
   362   ccp = CrossCallParamsEx::CreateFromBuffer(buffer, kBufferSize, &out_size);
   363   EXPECT_TRUE(NULL != ccp);
   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 }
   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 };
   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 }
   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 };
   401 void FakeOkAnswerInChannel(void* channel) {
   402   CrossCallReturn* answer = reinterpret_cast<CrossCallReturn*>(channel);
   403   answer->call_outcome = SBOX_ALL_OK;
   404 }
   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);
   417   char* mem = reinterpret_cast<char*>(client_control);
   418   SharedMemIPCClient client(mem);
   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;
   425   HANDLE t1 = ::CreateThread(NULL, 0, QuickResponseServer, &events, 0, NULL);
   426   ASSERT_TRUE(NULL != t1);
   427   ::CloseHandle(t1);
   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);
   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);
   441   EXPECT_EQ(0, client_control->channels[1].ipc_tag);
   443   uint32 tag = 7654;
   444   CrossCallReturn answer;
   445   CrossCallParamsMock* params1 = new(buff1) CrossCallParamsMock(tag, 1);
   446   FakeOkAnswerInChannel(buff1);
   448   ResultCode result = client.DoCall(params1, &answer);
   449   if (SBOX_ERROR_CHANNEL_ERROR != result)
   450     client.FreeBuffer(buff1);
   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);
   458   HANDLE t2 = ::CreateThread(NULL, 0, QuickResponseServer, &events, 0, NULL);
   459   ASSERT_TRUE(NULL != t2);
   460   ::CloseHandle(t2);
   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;
   467   tag = 4567;
   468   CrossCallParamsMock* params2 = new(buff0) CrossCallParamsMock(tag, 1);
   469   FakeOkAnswerInChannel(buff0);
   471   result = client.DoCall(params2, &answer);
   472   if (SBOX_ERROR_CHANNEL_ERROR != result)
   473     client.FreeBuffer(buff0);
   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);
   481   CloseChannelEvents(client_control);
   482   ::CloseHandle(client_control->server_alive);
   484   delete[] reinterpret_cast<char*>(client_control);
   485 }
   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 }
   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 }
   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);
   519   char* mem = reinterpret_cast<char*>(client_control);
   520   SharedMemIPCClient client(mem);
   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;
   527   HANDLE t1 = ::CreateThread(NULL, 0, SlowResponseServer, &events, 0, NULL);
   528   ASSERT_TRUE(NULL != t1);
   529   ::CloseHandle(t1);
   531   ServerEvents events2 = {0};
   532   events2.pong = events.pong;
   533   events2.mutex = client_control->server_alive;
   535   HANDLE t2 = ::CreateThread(NULL, 0, MainServerThread, &events2, 0, NULL);
   536   ASSERT_TRUE(NULL != t2);
   537   ::CloseHandle(t2);
   539   ::Sleep(1);
   541   void* buff0 = client.GetBuffer();
   542   uint32 tag = 4321;
   543   CrossCallReturn answer;
   544   CrossCallParamsMock* params1 = new(buff0) CrossCallParamsMock(tag, 1);
   545   FakeOkAnswerInChannel(buff0);
   547   ResultCode result = client.DoCall(params1, &answer);
   548   if (SBOX_ERROR_CHANNEL_ERROR != result)
   549     client.FreeBuffer(buff0);
   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);
   555   CloseChannelEvents(client_control);
   556   ::CloseHandle(client_control->server_alive);
   557   delete[] reinterpret_cast<char*>(client_control);
   558 }
   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   };
   569   UnitTestIPCDispatcher();
   570   ~UnitTestIPCDispatcher() {};
   572   virtual bool SetupService(InterceptionManager* manager, int service) {
   573     return true;
   574   }
   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   }
   583   bool CallTwoHandler(IPCInfo* ipc, HANDLE p1, DWORD p2) {
   584     return true;
   585   }
   586 };
   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 }
   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);
   612   char* mem = reinterpret_cast<char*>(client_control);
   613   SharedMemIPCClient client(mem);
   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);
   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} };
   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);
   637   CloseChannelEvents(client_control);
   638   delete[] reinterpret_cast<char*>(client_control);
   639 }
   641 }  // namespace sandbox

mercurial