| Index: sandbox/win/src/sharedmem_ipc_server.cc
|
| diff --git a/sandbox/win/src/sharedmem_ipc_server.cc b/sandbox/win/src/sharedmem_ipc_server.cc
|
| deleted file mode 100644
|
| index cf2d800e5dd6eb068de8b3428129344ce74d2c2a..0000000000000000000000000000000000000000
|
| --- a/sandbox/win/src/sharedmem_ipc_server.cc
|
| +++ /dev/null
|
| @@ -1,430 +0,0 @@
|
| -// 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 "base/callback.h"
|
| -#include "base/logging.h"
|
| -#include "base/memory/scoped_ptr.h"
|
| -#include "base/stl_util.h"
|
| -#include "sandbox/win/src/crosscall_params.h"
|
| -#include "sandbox/win/src/crosscall_server.h"
|
| -#include "sandbox/win/src/sandbox.h"
|
| -#include "sandbox/win/src/sandbox_types.h"
|
| -#include "sandbox/win/src/sharedmem_ipc_client.h"
|
| -#include "sandbox/win/src/sharedmem_ipc_server.h"
|
| -
|
| -namespace {
|
| -// This handle must not be closed.
|
| -volatile HANDLE g_alive_mutex = NULL;
|
| -}
|
| -
|
| -namespace sandbox {
|
| -
|
| -SharedMemIPCServer::ServerControl::ServerControl() {
|
| -}
|
| -
|
| -SharedMemIPCServer::ServerControl::~ServerControl() {
|
| -}
|
| -
|
| -SharedMemIPCServer::SharedMemIPCServer(HANDLE target_process,
|
| - DWORD target_process_id,
|
| - ThreadProvider* thread_provider,
|
| - Dispatcher* dispatcher)
|
| - : client_control_(NULL),
|
| - thread_provider_(thread_provider),
|
| - target_process_(target_process),
|
| - target_process_id_(target_process_id),
|
| - call_dispatcher_(dispatcher) {
|
| - // We create a initially owned mutex. If the server dies unexpectedly,
|
| - // the thread that owns it will fail to release the lock and windows will
|
| - // report to the target (when it tries to acquire it) that the wait was
|
| - // abandoned. Note: We purposely leak the local handle because we want it to
|
| - // be closed by Windows itself so it is properly marked as abandoned if the
|
| - // server dies.
|
| - if (!g_alive_mutex) {
|
| - HANDLE mutex = ::CreateMutexW(NULL, TRUE, NULL);
|
| - if (::InterlockedCompareExchangePointer(&g_alive_mutex, mutex, NULL)) {
|
| - // We lost the race to create the mutex.
|
| - ::CloseHandle(mutex);
|
| - }
|
| - }
|
| -}
|
| -
|
| -SharedMemIPCServer::~SharedMemIPCServer() {
|
| - // Free the wait handles associated with the thread pool.
|
| - if (!thread_provider_->UnRegisterWaits(this)) {
|
| - // Better to leak than to crash.
|
| - return;
|
| - }
|
| - STLDeleteElements(&server_contexts_);
|
| -
|
| - if (client_control_)
|
| - ::UnmapViewOfFile(client_control_);
|
| -}
|
| -
|
| -bool SharedMemIPCServer::Init(void* shared_mem,
|
| - uint32_t shared_size,
|
| - uint32_t channel_size) {
|
| - // The shared memory needs to be at least as big as a channel.
|
| - if (shared_size < channel_size) {
|
| - return false;
|
| - }
|
| - // The channel size should be aligned.
|
| - if (0 != (channel_size % 32)) {
|
| - return false;
|
| - }
|
| -
|
| - // Calculate how many channels we can fit in the shared memory.
|
| - shared_size -= offsetof(IPCControl, channels);
|
| - size_t channel_count = shared_size / (sizeof(ChannelControl) + channel_size);
|
| -
|
| - // If we cannot fit even one channel we bail out.
|
| - if (0 == channel_count) {
|
| - return false;
|
| - }
|
| - // Calculate the start of the first channel.
|
| - size_t base_start = (sizeof(ChannelControl)* channel_count) +
|
| - offsetof(IPCControl, channels);
|
| -
|
| - client_control_ = reinterpret_cast<IPCControl*>(shared_mem);
|
| - client_control_->channels_count = 0;
|
| -
|
| - // This is the initialization that we do per-channel. Basically:
|
| - // 1) make two events (ping & pong)
|
| - // 2) create handles to the events for the client and the server.
|
| - // 3) initialize the channel (client_context) with the state.
|
| - // 4) initialize the server side of the channel (service_context).
|
| - // 5) call the thread provider RegisterWait to register the ping events.
|
| - for (size_t ix = 0; ix != channel_count; ++ix) {
|
| - ChannelControl* client_context = &client_control_->channels[ix];
|
| - ServerControl* service_context = new ServerControl;
|
| - server_contexts_.push_back(service_context);
|
| -
|
| - if (!MakeEvents(&service_context->ping_event,
|
| - &service_context->pong_event,
|
| - &client_context->ping_event,
|
| - &client_context->pong_event)) {
|
| - return false;
|
| - }
|
| -
|
| - client_context->channel_base = base_start;
|
| - client_context->state = kFreeChannel;
|
| -
|
| - // Note that some of these values are available as members of this object
|
| - // but we put them again into the service_context because we will be called
|
| - // on a static method (ThreadPingEventReady). In particular, target_process_
|
| - // is a raw handle that is not owned by this object (it's owned by the
|
| - // owner of this object), and we are storing it in multiple places.
|
| - service_context->shared_base = reinterpret_cast<char*>(shared_mem);
|
| - service_context->channel_size = channel_size;
|
| - service_context->channel = client_context;
|
| - service_context->channel_buffer = service_context->shared_base +
|
| - client_context->channel_base;
|
| - service_context->dispatcher = call_dispatcher_;
|
| - service_context->target_info.process = target_process_;
|
| - service_context->target_info.process_id = target_process_id_;
|
| - // Advance to the next channel.
|
| - base_start += channel_size;
|
| - // Register the ping event with the threadpool.
|
| - thread_provider_->RegisterWait(this, service_context->ping_event.Get(),
|
| - ThreadPingEventReady, service_context);
|
| - }
|
| - if (!::DuplicateHandle(::GetCurrentProcess(), g_alive_mutex,
|
| - target_process_, &client_control_->server_alive,
|
| - SYNCHRONIZE | EVENT_MODIFY_STATE, FALSE, 0)) {
|
| - return false;
|
| - }
|
| - // This last setting indicates to the client all is setup.
|
| - client_control_->channels_count = channel_count;
|
| - return true;
|
| -}
|
| -
|
| -// Releases memory allocated for IPC arguments, if needed.
|
| -void ReleaseArgs(const IPCParams* ipc_params, void* args[kMaxIpcParams]) {
|
| - for (size_t i = 0; i < kMaxIpcParams; i++) {
|
| - switch (ipc_params->args[i]) {
|
| - case WCHAR_TYPE: {
|
| - delete reinterpret_cast<base::string16*>(args[i]);
|
| - args[i] = NULL;
|
| - break;
|
| - }
|
| - case INOUTPTR_TYPE: {
|
| - delete reinterpret_cast<CountedBuffer*>(args[i]);
|
| - args[i] = NULL;
|
| - break;
|
| - }
|
| - default: break;
|
| - }
|
| - }
|
| -}
|
| -
|
| -// Fills up the list of arguments (args and ipc_params) for an IPC call.
|
| -bool GetArgs(CrossCallParamsEx* params, IPCParams* ipc_params,
|
| - void* args[kMaxIpcParams]) {
|
| - if (kMaxIpcParams < params->GetParamsCount())
|
| - return false;
|
| -
|
| - for (uint32_t i = 0; i < params->GetParamsCount(); i++) {
|
| - uint32_t size;
|
| - ArgType type;
|
| - args[i] = params->GetRawParameter(i, &size, &type);
|
| - if (args[i]) {
|
| - ipc_params->args[i] = type;
|
| - switch (type) {
|
| - case WCHAR_TYPE: {
|
| - scoped_ptr<base::string16> data(new base::string16);
|
| - if (!params->GetParameterStr(i, data.get())) {
|
| - args[i] = 0;
|
| - ReleaseArgs(ipc_params, args);
|
| - return false;
|
| - }
|
| - args[i] = data.release();
|
| - break;
|
| - }
|
| - case UINT32_TYPE: {
|
| - uint32_t data;
|
| - if (!params->GetParameter32(i, &data)) {
|
| - ReleaseArgs(ipc_params, args);
|
| - return false;
|
| - }
|
| - IPCInt ipc_int(data);
|
| - args[i] = ipc_int.AsVoidPtr();
|
| - break;
|
| - }
|
| - case VOIDPTR_TYPE : {
|
| - void* data;
|
| - if (!params->GetParameterVoidPtr(i, &data)) {
|
| - ReleaseArgs(ipc_params, args);
|
| - return false;
|
| - }
|
| - args[i] = data;
|
| - break;
|
| - }
|
| - case INOUTPTR_TYPE: {
|
| - if (!args[i]) {
|
| - ReleaseArgs(ipc_params, args);
|
| - return false;
|
| - }
|
| - CountedBuffer* buffer = new CountedBuffer(args[i] , size);
|
| - args[i] = buffer;
|
| - break;
|
| - }
|
| - default: break;
|
| - }
|
| - }
|
| - }
|
| - return true;
|
| -}
|
| -
|
| -bool SharedMemIPCServer::InvokeCallback(const ServerControl* service_context,
|
| - void* ipc_buffer,
|
| - CrossCallReturn* call_result) {
|
| - // Set the default error code;
|
| - SetCallError(SBOX_ERROR_INVALID_IPC, call_result);
|
| - uint32_t output_size = 0;
|
| - // Parse, verify and copy the message. The handler operates on a copy
|
| - // of the message so the client cannot play dirty tricks by changing the
|
| - // data in the channel while the IPC is being processed.
|
| - scoped_ptr<CrossCallParamsEx> params(
|
| - CrossCallParamsEx::CreateFromBuffer(ipc_buffer,
|
| - service_context->channel_size,
|
| - &output_size));
|
| - if (!params.get())
|
| - return false;
|
| -
|
| - uint32_t tag = params->GetTag();
|
| - static_assert(0 == INVALID_TYPE, "incorrect type enum");
|
| - IPCParams ipc_params = {0};
|
| - ipc_params.ipc_tag = tag;
|
| -
|
| - void* args[kMaxIpcParams];
|
| - if (!GetArgs(params.get(), &ipc_params, args))
|
| - return false;
|
| -
|
| - IPCInfo ipc_info = {0};
|
| - ipc_info.ipc_tag = tag;
|
| - ipc_info.client_info = &service_context->target_info;
|
| - Dispatcher* dispatcher = service_context->dispatcher;
|
| - DCHECK(dispatcher);
|
| - bool error = true;
|
| - Dispatcher* handler = NULL;
|
| -
|
| - Dispatcher::CallbackGeneric callback_generic;
|
| - handler = dispatcher->OnMessageReady(&ipc_params, &callback_generic);
|
| - if (handler) {
|
| - switch (params->GetParamsCount()) {
|
| - case 0: {
|
| - // Ask the IPC dispatcher if she can service this IPC.
|
| - Dispatcher::Callback0 callback =
|
| - reinterpret_cast<Dispatcher::Callback0>(callback_generic);
|
| - if (!(handler->*callback)(&ipc_info))
|
| - break;
|
| - error = false;
|
| - break;
|
| - }
|
| - case 1: {
|
| - Dispatcher::Callback1 callback =
|
| - reinterpret_cast<Dispatcher::Callback1>(callback_generic);
|
| - if (!(handler->*callback)(&ipc_info, args[0]))
|
| - break;
|
| - error = false;
|
| - break;
|
| - }
|
| - case 2: {
|
| - Dispatcher::Callback2 callback =
|
| - reinterpret_cast<Dispatcher::Callback2>(callback_generic);
|
| - if (!(handler->*callback)(&ipc_info, args[0], args[1]))
|
| - break;
|
| - error = false;
|
| - break;
|
| - }
|
| - case 3: {
|
| - Dispatcher::Callback3 callback =
|
| - reinterpret_cast<Dispatcher::Callback3>(callback_generic);
|
| - if (!(handler->*callback)(&ipc_info, args[0], args[1], args[2]))
|
| - break;
|
| - error = false;
|
| - break;
|
| - }
|
| - case 4: {
|
| - Dispatcher::Callback4 callback =
|
| - reinterpret_cast<Dispatcher::Callback4>(callback_generic);
|
| - if (!(handler->*callback)(&ipc_info, args[0], args[1], args[2],
|
| - args[3]))
|
| - break;
|
| - error = false;
|
| - break;
|
| - }
|
| - case 5: {
|
| - Dispatcher::Callback5 callback =
|
| - reinterpret_cast<Dispatcher::Callback5>(callback_generic);
|
| - if (!(handler->*callback)(&ipc_info, args[0], args[1], args[2], args[3],
|
| - args[4]))
|
| - break;
|
| - error = false;
|
| - break;
|
| - }
|
| - case 6: {
|
| - Dispatcher::Callback6 callback =
|
| - reinterpret_cast<Dispatcher::Callback6>(callback_generic);
|
| - if (!(handler->*callback)(&ipc_info, args[0], args[1], args[2], args[3],
|
| - args[4], args[5]))
|
| - break;
|
| - error = false;
|
| - break;
|
| - }
|
| - case 7: {
|
| - Dispatcher::Callback7 callback =
|
| - reinterpret_cast<Dispatcher::Callback7>(callback_generic);
|
| - if (!(handler->*callback)(&ipc_info, args[0], args[1], args[2], args[3],
|
| - args[4], args[5], args[6]))
|
| - break;
|
| - error = false;
|
| - break;
|
| - }
|
| - case 8: {
|
| - Dispatcher::Callback8 callback =
|
| - reinterpret_cast<Dispatcher::Callback8>(callback_generic);
|
| - if (!(handler->*callback)(&ipc_info, args[0], args[1], args[2], args[3],
|
| - args[4], args[5], args[6], args[7]))
|
| - break;
|
| - error = false;
|
| - break;
|
| - }
|
| - case 9: {
|
| - Dispatcher::Callback9 callback =
|
| - reinterpret_cast<Dispatcher::Callback9>(callback_generic);
|
| - if (!(handler->*callback)(&ipc_info, args[0], args[1], args[2], args[3],
|
| - args[4], args[5], args[6], args[7], args[8]))
|
| - break;
|
| - error = false;
|
| - break;
|
| - }
|
| - default: {
|
| - NOTREACHED();
|
| - break;
|
| - }
|
| - }
|
| - }
|
| -
|
| - if (error) {
|
| - if (handler)
|
| - SetCallError(SBOX_ERROR_FAILED_IPC, call_result);
|
| - } else {
|
| - memcpy(call_result, &ipc_info.return_info, sizeof(*call_result));
|
| - SetCallSuccess(call_result);
|
| - if (params->IsInOut()) {
|
| - // Maybe the params got changed by the broker. We need to upadte the
|
| - // memory section.
|
| - memcpy(ipc_buffer, params.get(), output_size);
|
| - }
|
| - }
|
| -
|
| - ReleaseArgs(&ipc_params, args);
|
| -
|
| - return !error;
|
| -}
|
| -
|
| -// This function gets called by a thread from the thread pool when a
|
| -// ping event fires. The context is the same as passed in the RegisterWait()
|
| -// call above.
|
| -void __stdcall SharedMemIPCServer::ThreadPingEventReady(void* context,
|
| - unsigned char) {
|
| - if (NULL == context) {
|
| - DCHECK(false);
|
| - return;
|
| - }
|
| - ServerControl* service_context = reinterpret_cast<ServerControl*>(context);
|
| - // Since the event fired, the channel *must* be busy. Change to kAckChannel
|
| - // while we service it.
|
| - LONG last_state =
|
| - ::InterlockedCompareExchange(&service_context->channel->state,
|
| - kAckChannel, kBusyChannel);
|
| - if (kBusyChannel != last_state) {
|
| - DCHECK(false);
|
| - return;
|
| - }
|
| -
|
| - // Prepare the result structure. At this point we will return some result
|
| - // even if the IPC is invalid, malformed or has no handler.
|
| - CrossCallReturn call_result = {0};
|
| - void* buffer = service_context->channel_buffer;
|
| -
|
| - InvokeCallback(service_context, buffer, &call_result);
|
| -
|
| - // Copy the answer back into the channel and signal the pong event. This
|
| - // should wake up the client so he can finish the the ipc cycle.
|
| - CrossCallParams* call_params = reinterpret_cast<CrossCallParams*>(buffer);
|
| - memcpy(call_params->GetCallReturn(), &call_result, sizeof(call_result));
|
| - ::InterlockedExchange(&service_context->channel->state, kAckChannel);
|
| - ::SetEvent(service_context->pong_event.Get());
|
| -}
|
| -
|
| -bool SharedMemIPCServer::MakeEvents(base::win::ScopedHandle* server_ping,
|
| - base::win::ScopedHandle* server_pong,
|
| - HANDLE* client_ping, HANDLE* client_pong) {
|
| - // Note that the IPC client has no right to delete the events. That would
|
| - // cause problems. The server *owns* the events.
|
| - const DWORD kDesiredAccess = SYNCHRONIZE | EVENT_MODIFY_STATE;
|
| -
|
| - // The events are auto reset, and start not signaled.
|
| - server_ping->Set(::CreateEventW(NULL, FALSE, FALSE, NULL));
|
| - if (!::DuplicateHandle(::GetCurrentProcess(), server_ping->Get(),
|
| - target_process_, client_ping, kDesiredAccess, FALSE,
|
| - 0)) {
|
| - return false;
|
| - }
|
| -
|
| - server_pong->Set(::CreateEventW(NULL, FALSE, FALSE, NULL));
|
| - if (!::DuplicateHandle(::GetCurrentProcess(), server_pong->Get(),
|
| - target_process_, client_pong, kDesiredAccess, FALSE,
|
| - 0)) {
|
| - return false;
|
| - }
|
| - return true;
|
| -}
|
| -
|
| -} // namespace sandbox
|
|
|