123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632 |
- // Copyright (c) 2012 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include <stddef.h>
- #include <stdint.h>
- #include "sandbox/win/src/crosscall_client.h"
- #include "sandbox/win/src/crosscall_server.h"
- #include "sandbox/win/src/sharedmem_ipc_client.h"
- #include "sandbox/win/src/sharedmem_ipc_server.h"
- #include "testing/gtest/include/gtest/gtest.h"
- namespace sandbox {
- // Helper function to make the fake shared memory with some
- // basic elements initialized.
- IPCControl* MakeChannels(size_t channel_size,
- size_t total_shared_size,
- size_t* base_start) {
- // Allocate memory
- char* mem = new char[total_shared_size];
- memset(mem, 0, total_shared_size);
- // Calculate how many channels we can fit in the shared memory.
- total_shared_size -= offsetof(IPCControl, channels);
- size_t channel_count =
- total_shared_size / (sizeof(ChannelControl) + channel_size);
- // Calculate the start of the first channel.
- *base_start =
- (sizeof(ChannelControl) * channel_count) + offsetof(IPCControl, channels);
- // Setup client structure.
- IPCControl* client_control = reinterpret_cast<IPCControl*>(mem);
- client_control->channels_count = channel_count;
- return client_control;
- }
- enum TestFixMode { FIX_NO_EVENTS, FIX_PONG_READY, FIX_PONG_NOT_READY };
- void FixChannels(IPCControl* client_control,
- size_t base_start,
- size_t channel_size,
- TestFixMode mode) {
- for (size_t ix = 0; ix != client_control->channels_count; ++ix) {
- ChannelControl& channel = client_control->channels[ix];
- channel.channel_base = base_start;
- channel.state = kFreeChannel;
- if (mode != FIX_NO_EVENTS) {
- bool signaled = (FIX_PONG_READY == mode) ? true : false;
- channel.ping_event = ::CreateEventW(nullptr, false, false, nullptr);
- channel.pong_event = ::CreateEventW(nullptr, false, signaled, nullptr);
- }
- base_start += channel_size;
- }
- }
- void CloseChannelEvents(IPCControl* client_control) {
- for (size_t ix = 0; ix != client_control->channels_count; ++ix) {
- ChannelControl& channel = client_control->channels[ix];
- ::CloseHandle(channel.ping_event);
- ::CloseHandle(channel.pong_event);
- }
- }
- TEST(IPCTest, ChannelMaker) {
- // Test that our testing rig is computing offsets properly. We should have
- // 5 channnels and the offset to the first channel is 108 bytes in 32 bits
- // and 216 in 64 bits.
- size_t channel_start = 0;
- IPCControl* client_control = MakeChannels(12 * 64, 4096, &channel_start);
- ASSERT_TRUE(client_control);
- EXPECT_EQ(5u, client_control->channels_count);
- #if defined(_WIN64)
- EXPECT_EQ(216u, channel_start);
- #else
- EXPECT_EQ(108u, channel_start);
- #endif
- delete[] reinterpret_cast<char*>(client_control);
- }
- TEST(IPCTest, ClientLockUnlock) {
- // Make 7 channels of kIPCChannelSize (1kb) each. Test that we lock and
- // unlock channels properly.
- size_t base_start = 0;
- IPCControl* client_control =
- MakeChannels(kIPCChannelSize, 4096 * 2, &base_start);
- FixChannels(client_control, base_start, kIPCChannelSize, FIX_NO_EVENTS);
- char* mem = reinterpret_cast<char*>(client_control);
- SharedMemIPCClient client(mem);
- // Test that we lock the first 3 channels in sequence.
- void* buff0 = client.GetBuffer();
- EXPECT_TRUE(mem + client_control->channels[0].channel_base == buff0);
- EXPECT_EQ(kBusyChannel, client_control->channels[0].state);
- EXPECT_EQ(kFreeChannel, client_control->channels[1].state);
- EXPECT_EQ(kFreeChannel, client_control->channels[2].state);
- EXPECT_EQ(kFreeChannel, client_control->channels[3].state);
- EXPECT_EQ(kFreeChannel, client_control->channels[4].state);
- EXPECT_EQ(kFreeChannel, client_control->channels[5].state);
- void* buff1 = client.GetBuffer();
- EXPECT_TRUE(mem + client_control->channels[1].channel_base == buff1);
- EXPECT_EQ(kBusyChannel, client_control->channels[0].state);
- EXPECT_EQ(kBusyChannel, client_control->channels[1].state);
- EXPECT_EQ(kFreeChannel, client_control->channels[2].state);
- EXPECT_EQ(kFreeChannel, client_control->channels[3].state);
- EXPECT_EQ(kFreeChannel, client_control->channels[4].state);
- EXPECT_EQ(kFreeChannel, client_control->channels[5].state);
- void* buff2 = client.GetBuffer();
- EXPECT_TRUE(mem + client_control->channels[2].channel_base == buff2);
- EXPECT_EQ(kBusyChannel, client_control->channels[0].state);
- EXPECT_EQ(kBusyChannel, client_control->channels[1].state);
- EXPECT_EQ(kBusyChannel, client_control->channels[2].state);
- EXPECT_EQ(kFreeChannel, client_control->channels[3].state);
- EXPECT_EQ(kFreeChannel, client_control->channels[4].state);
- EXPECT_EQ(kFreeChannel, client_control->channels[5].state);
- // Test that we unlock and re-lock the right channel.
- client.FreeBuffer(buff1);
- EXPECT_EQ(kBusyChannel, client_control->channels[0].state);
- EXPECT_EQ(kFreeChannel, client_control->channels[1].state);
- EXPECT_EQ(kBusyChannel, client_control->channels[2].state);
- EXPECT_EQ(kFreeChannel, client_control->channels[3].state);
- EXPECT_EQ(kFreeChannel, client_control->channels[4].state);
- EXPECT_EQ(kFreeChannel, client_control->channels[5].state);
- void* buff2b = client.GetBuffer();
- EXPECT_TRUE(mem + client_control->channels[1].channel_base == buff2b);
- EXPECT_EQ(kBusyChannel, client_control->channels[0].state);
- EXPECT_EQ(kBusyChannel, client_control->channels[1].state);
- EXPECT_EQ(kBusyChannel, client_control->channels[2].state);
- EXPECT_EQ(kFreeChannel, client_control->channels[3].state);
- EXPECT_EQ(kFreeChannel, client_control->channels[4].state);
- EXPECT_EQ(kFreeChannel, client_control->channels[5].state);
- client.FreeBuffer(buff0);
- EXPECT_EQ(kFreeChannel, client_control->channels[0].state);
- EXPECT_EQ(kBusyChannel, client_control->channels[1].state);
- EXPECT_EQ(kBusyChannel, client_control->channels[2].state);
- EXPECT_EQ(kFreeChannel, client_control->channels[3].state);
- EXPECT_EQ(kFreeChannel, client_control->channels[4].state);
- EXPECT_EQ(kFreeChannel, client_control->channels[5].state);
- delete[] reinterpret_cast<char*>(client_control);
- }
- TEST(IPCTest, CrossCallStrPacking) {
- // This test tries the CrossCall object with null and non-null string
- // combination of parameters, integer types and verifies that the unpacker
- // can read them properly.
- size_t base_start = 0;
- IPCControl* client_control =
- MakeChannels(kIPCChannelSize, 4096 * 4, &base_start);
- client_control->server_alive = HANDLE(1);
- FixChannels(client_control, base_start, kIPCChannelSize, FIX_PONG_READY);
- char* mem = reinterpret_cast<char*>(client_control);
- SharedMemIPCClient client(mem);
- CrossCallReturn answer;
- IpcTag tag1 = IpcTag::PING1;
- const wchar_t* text = L"98765 - 43210";
- std::wstring copied_text;
- CrossCallParamsEx* actual_params;
- CrossCall(client, tag1, text, &answer);
- actual_params = reinterpret_cast<CrossCallParamsEx*>(client.GetBuffer());
- EXPECT_EQ(1u, actual_params->GetParamsCount());
- EXPECT_EQ(tag1, actual_params->GetTag());
- EXPECT_TRUE(actual_params->GetParameterStr(0, &copied_text));
- EXPECT_STREQ(text, copied_text.c_str());
- copied_text.clear();
- // Check with an empty string.
- IpcTag tag2 = IpcTag::PING2;
- const wchar_t* null_text = nullptr;
- CrossCall(client, tag2, null_text, &answer);
- actual_params = reinterpret_cast<CrossCallParamsEx*>(client.GetBuffer());
- EXPECT_EQ(1u, actual_params->GetParamsCount());
- EXPECT_EQ(tag2, actual_params->GetTag());
- uint32_t param_size = 1;
- ArgType type = INVALID_TYPE;
- void* param_addr = actual_params->GetRawParameter(0, ¶m_size, &type);
- EXPECT_TRUE(param_addr);
- EXPECT_EQ(0u, param_size);
- EXPECT_EQ(WCHAR_TYPE, type);
- EXPECT_TRUE(actual_params->GetParameterStr(0, &copied_text));
- EXPECT_TRUE(copied_text.empty());
- IpcTag tag3 = IpcTag::PING1;
- param_size = 1;
- copied_text.clear();
- // Check with an empty string and a non-empty string.
- CrossCall(client, tag3, null_text, text, &answer);
- actual_params = reinterpret_cast<CrossCallParamsEx*>(client.GetBuffer());
- EXPECT_EQ(2u, actual_params->GetParamsCount());
- EXPECT_EQ(tag3, actual_params->GetTag());
- type = INVALID_TYPE;
- param_addr = actual_params->GetRawParameter(0, ¶m_size, &type);
- EXPECT_TRUE(param_addr);
- EXPECT_EQ(0u, param_size);
- EXPECT_EQ(WCHAR_TYPE, type);
- EXPECT_TRUE(actual_params->GetParameterStr(0, &copied_text));
- EXPECT_TRUE(copied_text.empty());
- EXPECT_TRUE(actual_params->GetParameterStr(1, &copied_text));
- EXPECT_STREQ(text, copied_text.c_str());
- param_size = 1;
- std::wstring copied_text_p0, copied_text_p2;
- const wchar_t* text2 = L"AeFG";
- CrossCall(client, tag1, text2, null_text, text, &answer);
- actual_params = reinterpret_cast<CrossCallParamsEx*>(client.GetBuffer());
- EXPECT_EQ(3u, actual_params->GetParamsCount());
- EXPECT_EQ(tag1, actual_params->GetTag());
- EXPECT_TRUE(actual_params->GetParameterStr(0, &copied_text_p0));
- EXPECT_STREQ(text2, copied_text_p0.c_str());
- EXPECT_TRUE(actual_params->GetParameterStr(2, &copied_text_p2));
- EXPECT_STREQ(text, copied_text_p2.c_str());
- type = INVALID_TYPE;
- param_addr = actual_params->GetRawParameter(1, ¶m_size, &type);
- EXPECT_TRUE(param_addr);
- EXPECT_EQ(0u, param_size);
- EXPECT_EQ(WCHAR_TYPE, type);
- CloseChannelEvents(client_control);
- delete[] reinterpret_cast<char*>(client_control);
- }
- TEST(IPCTest, CrossCallIntPacking) {
- // Check handling for regular 32 bit integers used in Windows.
- size_t base_start = 0;
- IPCControl* client_control =
- MakeChannels(kIPCChannelSize, 4096 * 4, &base_start);
- client_control->server_alive = HANDLE(1);
- FixChannels(client_control, base_start, kIPCChannelSize, FIX_PONG_READY);
- IpcTag tag1 = IpcTag::PING1;
- IpcTag tag2 = IpcTag::PING2;
- const wchar_t* text = L"godzilla";
- CrossCallParamsEx* actual_params;
- char* mem = reinterpret_cast<char*>(client_control);
- SharedMemIPCClient client(mem);
- CrossCallReturn answer;
- DWORD dw = 0xE6578;
- CrossCall(client, tag2, dw, &answer);
- actual_params = reinterpret_cast<CrossCallParamsEx*>(client.GetBuffer());
- EXPECT_EQ(1u, actual_params->GetParamsCount());
- EXPECT_EQ(tag2, actual_params->GetTag());
- ArgType type = INVALID_TYPE;
- uint32_t param_size = 1;
- void* param_addr = actual_params->GetRawParameter(0, ¶m_size, &type);
- ASSERT_EQ(sizeof(dw), param_size);
- EXPECT_EQ(UINT32_TYPE, type);
- ASSERT_TRUE(param_addr);
- EXPECT_EQ(0, memcmp(&dw, param_addr, param_size));
- // Check handling for windows HANDLES.
- HANDLE h = HANDLE(0x70000500);
- CrossCall(client, tag1, text, h, &answer);
- actual_params = reinterpret_cast<CrossCallParamsEx*>(client.GetBuffer());
- EXPECT_EQ(2u, actual_params->GetParamsCount());
- EXPECT_EQ(tag1, actual_params->GetTag());
- type = INVALID_TYPE;
- param_addr = actual_params->GetRawParameter(1, ¶m_size, &type);
- ASSERT_EQ(sizeof(h), param_size);
- EXPECT_EQ(VOIDPTR_TYPE, type);
- ASSERT_TRUE(param_addr);
- EXPECT_EQ(0, memcmp(&h, param_addr, param_size));
- // Check combination of 32 and 64 bits.
- CrossCall(client, tag2, h, dw, h, &answer);
- actual_params = reinterpret_cast<CrossCallParamsEx*>(client.GetBuffer());
- EXPECT_EQ(3u, actual_params->GetParamsCount());
- EXPECT_EQ(tag2, actual_params->GetTag());
- type = INVALID_TYPE;
- param_addr = actual_params->GetRawParameter(0, ¶m_size, &type);
- ASSERT_EQ(sizeof(h), param_size);
- EXPECT_EQ(VOIDPTR_TYPE, type);
- ASSERT_TRUE(param_addr);
- EXPECT_EQ(0, memcmp(&h, param_addr, param_size));
- type = INVALID_TYPE;
- param_addr = actual_params->GetRawParameter(1, ¶m_size, &type);
- ASSERT_EQ(sizeof(dw), param_size);
- EXPECT_EQ(UINT32_TYPE, type);
- ASSERT_TRUE(param_addr);
- EXPECT_EQ(0, memcmp(&dw, param_addr, param_size));
- type = INVALID_TYPE;
- param_addr = actual_params->GetRawParameter(2, ¶m_size, &type);
- ASSERT_EQ(sizeof(h), param_size);
- EXPECT_EQ(VOIDPTR_TYPE, type);
- ASSERT_TRUE(param_addr);
- EXPECT_EQ(0, memcmp(&h, param_addr, param_size));
- CloseChannelEvents(client_control);
- delete[] reinterpret_cast<char*>(client_control);
- }
- TEST(IPCTest, CrossCallValidation) {
- // First a sanity test with a well formed parameter object.
- unsigned long value = 124816;
- IpcTag kTag = IpcTag::PING1;
- const uint32_t kBufferSize = 256;
- ActualCallParams<1, kBufferSize> params_1(kTag);
- params_1.CopyParamIn(0, &value, sizeof(value), false, UINT32_TYPE);
- void* buffer = const_cast<void*>(params_1.GetBuffer());
- uint32_t out_size = 0;
- CrossCallParamsEx* ccp = 0;
- ccp = CrossCallParamsEx::CreateFromBuffer(buffer, params_1.GetSize(),
- &out_size);
- ASSERT_TRUE(ccp);
- EXPECT_TRUE(ccp->GetBuffer() != buffer);
- EXPECT_EQ(kTag, ccp->GetTag());
- EXPECT_EQ(1u, ccp->GetParamsCount());
- delete[](reinterpret_cast<char*>(ccp));
- // Test that we handle integer overflow on the number of params
- // correctly. We use a test-only ctor for ActualCallParams that
- // allows to create malformed cross-call buffers.
- const int32_t kPtrDiffSz = sizeof(ptrdiff_t);
- for (int32_t ix = -1; ix != 3; ++ix) {
- uint32_t fake_num_params = (UINT32_MAX / kPtrDiffSz) + ix;
- ActualCallParams<1, kBufferSize> params_2(kTag, fake_num_params);
- params_2.CopyParamIn(0, &value, sizeof(value), false, UINT32_TYPE);
- buffer = const_cast<void*>(params_2.GetBuffer());
- EXPECT_TRUE(buffer);
- ccp = CrossCallParamsEx::CreateFromBuffer(buffer, params_1.GetSize(),
- &out_size);
- // If the buffer is malformed the return is nullptr.
- EXPECT_TRUE(!ccp);
- }
- ActualCallParams<1, kBufferSize> params_3(kTag, 1);
- params_3.CopyParamIn(0, &value, sizeof(value), false, UINT32_TYPE);
- buffer = const_cast<void*>(params_3.GetBuffer());
- EXPECT_TRUE(buffer);
- uint32_t correct_size = params_3.OverrideSize(1);
- ccp = CrossCallParamsEx::CreateFromBuffer(buffer, kBufferSize, &out_size);
- EXPECT_TRUE(!ccp);
- // The correct_size is 8 bytes aligned.
- params_3.OverrideSize(correct_size - 7);
- ccp = CrossCallParamsEx::CreateFromBuffer(buffer, kBufferSize, &out_size);
- EXPECT_TRUE(!ccp);
- params_3.OverrideSize(correct_size);
- ccp = CrossCallParamsEx::CreateFromBuffer(buffer, kBufferSize, &out_size);
- EXPECT_TRUE(ccp);
- // Make sure that two parameters work as expected.
- ActualCallParams<2, kBufferSize> params_4(kTag, 2);
- params_4.CopyParamIn(0, &value, sizeof(value), false, UINT32_TYPE);
- params_4.CopyParamIn(1, buffer, sizeof(buffer), false, VOIDPTR_TYPE);
- buffer = const_cast<void*>(params_4.GetBuffer());
- EXPECT_TRUE(buffer);
- ccp = CrossCallParamsEx::CreateFromBuffer(buffer, kBufferSize, &out_size);
- EXPECT_TRUE(ccp);
- #if defined(_WIN64)
- correct_size = params_4.OverrideSize(1);
- params_4.OverrideSize(correct_size - 1);
- ccp = CrossCallParamsEx::CreateFromBuffer(buffer, kBufferSize, &out_size);
- EXPECT_TRUE(!ccp);
- #endif
- }
- // This structure is passed to the mock server threads to simulate
- // the server side IPC so it has the required kernel objects.
- struct ServerEvents {
- HANDLE ping;
- HANDLE pong;
- volatile LONG* state;
- HANDLE mutex;
- };
- // This is the server thread that quicky answers an IPC and exits.
- DWORD WINAPI QuickResponseServer(PVOID param) {
- ServerEvents* events = reinterpret_cast<ServerEvents*>(param);
- DWORD wait_result = 0;
- wait_result = ::WaitForSingleObject(events->ping, INFINITE);
- ::InterlockedExchange(events->state, kAckChannel);
- ::SetEvent(events->pong);
- return wait_result;
- }
- class CrossCallParamsMock : public CrossCallParams {
- public:
- CrossCallParamsMock(IpcTag tag, uint32_t params_count)
- : CrossCallParams(tag, params_count) {}
- };
- void FakeOkAnswerInChannel(void* channel) {
- CrossCallReturn* answer = reinterpret_cast<CrossCallReturn*>(channel);
- answer->call_outcome = SBOX_ALL_OK;
- }
- // Create two threads that will quickly answer IPCs; the first one
- // using channel 1 (channel 0 is busy) and one using channel 0. No time-out
- // should occur.
- TEST(IPCTest, ClientFastServer) {
- const size_t channel_size = kIPCChannelSize;
- size_t base_start = 0;
- IPCControl* client_control =
- MakeChannels(channel_size, 4096 * 2, &base_start);
- FixChannels(client_control, base_start, kIPCChannelSize, FIX_PONG_NOT_READY);
- client_control->server_alive = ::CreateMutex(nullptr, false, nullptr);
- char* mem = reinterpret_cast<char*>(client_control);
- SharedMemIPCClient client(mem);
- ServerEvents events = {0};
- events.ping = client_control->channels[1].ping_event;
- events.pong = client_control->channels[1].pong_event;
- events.state = &client_control->channels[1].state;
- HANDLE t1 =
- ::CreateThread(nullptr, 0, QuickResponseServer, &events, 0, nullptr);
- ASSERT_TRUE(t1);
- ::CloseHandle(t1);
- void* buff0 = client.GetBuffer();
- EXPECT_TRUE(mem + client_control->channels[0].channel_base == buff0);
- EXPECT_EQ(kBusyChannel, client_control->channels[0].state);
- EXPECT_EQ(kFreeChannel, client_control->channels[1].state);
- EXPECT_EQ(kFreeChannel, client_control->channels[2].state);
- void* buff1 = client.GetBuffer();
- EXPECT_TRUE(mem + client_control->channels[1].channel_base == buff1);
- EXPECT_EQ(kBusyChannel, client_control->channels[0].state);
- EXPECT_EQ(kBusyChannel, client_control->channels[1].state);
- EXPECT_EQ(kFreeChannel, client_control->channels[2].state);
- EXPECT_EQ(IpcTag::UNUSED, client_control->channels[1].ipc_tag);
- IpcTag tag = IpcTag::PING1;
- CrossCallReturn answer;
- CrossCallParamsMock* params1 = new (buff1) CrossCallParamsMock(tag, 1);
- FakeOkAnswerInChannel(buff1);
- ResultCode result = client.DoCall(params1, &answer);
- if (SBOX_ERROR_CHANNEL_ERROR != result)
- client.FreeBuffer(buff1);
- EXPECT_TRUE(SBOX_ALL_OK == result);
- EXPECT_EQ(tag, client_control->channels[1].ipc_tag);
- EXPECT_EQ(kBusyChannel, client_control->channels[0].state);
- EXPECT_EQ(kFreeChannel, client_control->channels[1].state);
- EXPECT_EQ(kFreeChannel, client_control->channels[2].state);
- HANDLE t2 =
- ::CreateThread(nullptr, 0, QuickResponseServer, &events, 0, nullptr);
- ASSERT_TRUE(t2);
- ::CloseHandle(t2);
- client.FreeBuffer(buff0);
- events.ping = client_control->channels[0].ping_event;
- events.pong = client_control->channels[0].pong_event;
- events.state = &client_control->channels[0].state;
- tag = IpcTag::PING2;
- CrossCallParamsMock* params2 = new (buff0) CrossCallParamsMock(tag, 1);
- FakeOkAnswerInChannel(buff0);
- result = client.DoCall(params2, &answer);
- if (SBOX_ERROR_CHANNEL_ERROR != result)
- client.FreeBuffer(buff0);
- EXPECT_TRUE(SBOX_ALL_OK == result);
- EXPECT_EQ(tag, client_control->channels[0].ipc_tag);
- EXPECT_EQ(kFreeChannel, client_control->channels[0].state);
- EXPECT_EQ(kFreeChannel, client_control->channels[1].state);
- EXPECT_EQ(kFreeChannel, client_control->channels[2].state);
- CloseChannelEvents(client_control);
- ::CloseHandle(client_control->server_alive);
- delete[] reinterpret_cast<char*>(client_control);
- }
- // This is the server thread that very slowly answers an IPC and exits. Note
- // that the pong event needs to be signaled twice.
- DWORD WINAPI SlowResponseServer(PVOID param) {
- ServerEvents* events = reinterpret_cast<ServerEvents*>(param);
- DWORD wait_result = 0;
- wait_result = ::WaitForSingleObject(events->ping, INFINITE);
- ::Sleep(kIPCWaitTimeOut1 + kIPCWaitTimeOut2 + 200);
- ::InterlockedExchange(events->state, kAckChannel);
- ::SetEvent(events->pong);
- return wait_result;
- }
- // This thread's job is to keep the mutex locked.
- DWORD WINAPI MainServerThread(PVOID param) {
- ServerEvents* events = reinterpret_cast<ServerEvents*>(param);
- DWORD wait_result = 0;
- wait_result = ::WaitForSingleObject(events->mutex, INFINITE);
- Sleep(kIPCWaitTimeOut1 * 20);
- return wait_result;
- }
- // Creates a server thread that answers the IPC so slow that is guaranteed to
- // trigger the time-out code path in the client. A second thread is created
- // to hold locked the server_alive mutex: this signals the client that the
- // server is not dead and it retries the wait.
- TEST(IPCTest, ClientSlowServer) {
- size_t base_start = 0;
- IPCControl* client_control =
- MakeChannels(kIPCChannelSize, 4096 * 2, &base_start);
- FixChannels(client_control, base_start, kIPCChannelSize, FIX_PONG_NOT_READY);
- client_control->server_alive = ::CreateMutex(nullptr, false, nullptr);
- char* mem = reinterpret_cast<char*>(client_control);
- SharedMemIPCClient client(mem);
- ServerEvents events = {0};
- events.ping = client_control->channels[0].ping_event;
- events.pong = client_control->channels[0].pong_event;
- events.state = &client_control->channels[0].state;
- HANDLE t1 =
- ::CreateThread(nullptr, 0, SlowResponseServer, &events, 0, nullptr);
- ASSERT_TRUE(t1);
- ::CloseHandle(t1);
- ServerEvents events2 = {0};
- events2.pong = events.pong;
- events2.mutex = client_control->server_alive;
- HANDLE t2 =
- ::CreateThread(nullptr, 0, MainServerThread, &events2, 0, nullptr);
- ASSERT_TRUE(t2);
- ::CloseHandle(t2);
- ::Sleep(1);
- void* buff0 = client.GetBuffer();
- IpcTag tag = IpcTag::PING1;
- CrossCallReturn answer;
- CrossCallParamsMock* params1 = new (buff0) CrossCallParamsMock(tag, 1);
- FakeOkAnswerInChannel(buff0);
- ResultCode result = client.DoCall(params1, &answer);
- if (SBOX_ERROR_CHANNEL_ERROR != result)
- client.FreeBuffer(buff0);
- EXPECT_TRUE(SBOX_ALL_OK == result);
- EXPECT_EQ(tag, client_control->channels[0].ipc_tag);
- EXPECT_EQ(kFreeChannel, client_control->channels[0].state);
- CloseChannelEvents(client_control);
- ::CloseHandle(client_control->server_alive);
- delete[] reinterpret_cast<char*>(client_control);
- }
- // This test-only IPC dispatcher has two handlers with the same signature
- // but only CallOneHandler should be used.
- class UnitTestIPCDispatcher : public Dispatcher {
- public:
- UnitTestIPCDispatcher();
- ~UnitTestIPCDispatcher() override {}
- bool SetupService(InterceptionManager* manager, IpcTag service) override {
- return true;
- }
- private:
- bool CallOneHandler(IPCInfo* ipc, HANDLE p1, uint32_t p2) {
- ipc->return_info.extended[0].handle = p1;
- ipc->return_info.extended[1].unsigned_int = p2;
- return true;
- }
- bool CallTwoHandler(IPCInfo* ipc, HANDLE p1, uint32_t p2) { return true; }
- };
- UnitTestIPCDispatcher::UnitTestIPCDispatcher() {
- static const IPCCall call_one = {{IpcTag::PING1, {VOIDPTR_TYPE, UINT32_TYPE}},
- reinterpret_cast<CallbackGeneric>(
- &UnitTestIPCDispatcher::CallOneHandler)};
- static const IPCCall call_two = {{IpcTag::PING2, {VOIDPTR_TYPE, UINT32_TYPE}},
- reinterpret_cast<CallbackGeneric>(
- &UnitTestIPCDispatcher::CallTwoHandler)};
- ipc_calls_.push_back(call_one);
- ipc_calls_.push_back(call_two);
- }
- // This test does most of the shared memory IPC client-server roundtrip
- // and tests the packing, unpacking and call dispatching.
- TEST(IPCTest, SharedMemServerTests) {
- size_t base_start = 0;
- IPCControl* client_control = MakeChannels(kIPCChannelSize, 4096, &base_start);
- client_control->server_alive = HANDLE(1);
- FixChannels(client_control, base_start, kIPCChannelSize, FIX_PONG_READY);
- char* mem = reinterpret_cast<char*>(client_control);
- SharedMemIPCClient client(mem);
- CrossCallReturn answer;
- HANDLE bar = HANDLE(191919);
- DWORD foo = 6767676;
- CrossCall(client, IpcTag::PING1, bar, foo, &answer);
- void* buff = client.GetBuffer();
- ASSERT_TRUE(buff);
- UnitTestIPCDispatcher dispatcher;
- // Since we are directly calling InvokeCallback, most of this structure
- // can be set to nullptr.
- sandbox::SharedMemIPCServer::ServerControl srv_control = {};
- srv_control.channel_size = kIPCChannelSize;
- srv_control.shared_base = reinterpret_cast<char*>(client_control);
- srv_control.dispatcher = &dispatcher;
- sandbox::CrossCallReturn call_return = {0};
- EXPECT_TRUE(
- SharedMemIPCServer::InvokeCallback(&srv_control, buff, &call_return));
- EXPECT_EQ(SBOX_ALL_OK, call_return.call_outcome);
- EXPECT_TRUE(bar == call_return.extended[0].handle);
- EXPECT_EQ(foo, call_return.extended[1].unsigned_int);
- CloseChannelEvents(client_control);
- delete[] reinterpret_cast<char*>(client_control);
- }
- } // namespace sandbox
|