1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/security/sandbox/win/src/sharedmem_ipc_server.cc Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,410 @@ 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/callback.h" 1.9 +#include "base/logging.h" 1.10 +#include "base/memory/scoped_ptr.h" 1.11 +#include "sandbox/win/src/sharedmem_ipc_server.h" 1.12 +#include "sandbox/win/src/sharedmem_ipc_client.h" 1.13 +#include "sandbox/win/src/sandbox.h" 1.14 +#include "sandbox/win/src/sandbox_types.h" 1.15 +#include "sandbox/win/src/crosscall_params.h" 1.16 +#include "sandbox/win/src/crosscall_server.h" 1.17 + 1.18 +namespace sandbox { 1.19 + 1.20 +SharedMemIPCServer::SharedMemIPCServer(HANDLE target_process, 1.21 + DWORD target_process_id, 1.22 + HANDLE target_job, 1.23 + ThreadProvider* thread_provider, 1.24 + Dispatcher* dispatcher) 1.25 + : client_control_(NULL), 1.26 + thread_provider_(thread_provider), 1.27 + target_process_(target_process), 1.28 + target_process_id_(target_process_id), 1.29 + target_job_object_(target_job), 1.30 + call_dispatcher_(dispatcher) { 1.31 +} 1.32 + 1.33 +SharedMemIPCServer::~SharedMemIPCServer() { 1.34 + // Free the wait handles associated with the thread pool. 1.35 + if (!thread_provider_->UnRegisterWaits(this)) { 1.36 + // Better to leak than to crash. 1.37 + return; 1.38 + } 1.39 + // Free the IPC signal events. 1.40 + ServerContexts::iterator it; 1.41 + for (it = server_contexts_.begin(); it != server_contexts_.end(); ++it) { 1.42 + ServerControl* context = (*it); 1.43 + ::CloseHandle(context->ping_event); 1.44 + ::CloseHandle(context->pong_event); 1.45 + delete context; 1.46 + } 1.47 +} 1.48 + 1.49 +bool SharedMemIPCServer::Init(void* shared_mem, uint32 shared_size, 1.50 + uint32 channel_size) { 1.51 + // The shared memory needs to be at least as big as a channel. 1.52 + if (shared_size < channel_size) { 1.53 + return false; 1.54 + } 1.55 + // The channel size should be aligned. 1.56 + if (0 != (channel_size % 32)) { 1.57 + return false; 1.58 + } 1.59 + 1.60 + // Calculate how many channels we can fit in the shared memory. 1.61 + shared_size -= offsetof(IPCControl, channels); 1.62 + size_t channel_count = shared_size / (sizeof(ChannelControl) + channel_size); 1.63 + 1.64 + // If we cannot fit even one channel we bail out. 1.65 + if (0 == channel_count) { 1.66 + return false; 1.67 + } 1.68 + // Calculate the start of the first channel. 1.69 + size_t base_start = (sizeof(ChannelControl)* channel_count) + 1.70 + offsetof(IPCControl, channels); 1.71 + 1.72 + client_control_ = reinterpret_cast<IPCControl*>(shared_mem); 1.73 + client_control_->channels_count = 0; 1.74 + 1.75 + // This is the initialization that we do per-channel. Basically: 1.76 + // 1) make two events (ping & pong) 1.77 + // 2) create handles to the events for the client and the server. 1.78 + // 3) initialize the channel (client_context) with the state. 1.79 + // 4) initialize the server side of the channel (service_context). 1.80 + // 5) call the thread provider RegisterWait to register the ping events. 1.81 + for (size_t ix = 0; ix != channel_count; ++ix) { 1.82 + ChannelControl* client_context = &client_control_->channels[ix]; 1.83 + ServerControl* service_context = new ServerControl; 1.84 + server_contexts_.push_back(service_context); 1.85 + 1.86 + if (!MakeEvents(&service_context->ping_event, 1.87 + &service_context->pong_event, 1.88 + &client_context->ping_event, 1.89 + &client_context->pong_event)) { 1.90 + return false; 1.91 + } 1.92 + 1.93 + client_context->channel_base = base_start; 1.94 + client_context->state = kFreeChannel; 1.95 + 1.96 + // Note that some of these values are available as members of this 1.97 + // object but we put them again into the service_context because we 1.98 + // will be called on a static method (ThreadPingEventReady) 1.99 + service_context->shared_base = reinterpret_cast<char*>(shared_mem); 1.100 + service_context->channel_size = channel_size; 1.101 + service_context->channel = client_context; 1.102 + service_context->channel_buffer = service_context->shared_base + 1.103 + client_context->channel_base; 1.104 + service_context->dispatcher = call_dispatcher_; 1.105 + service_context->target_info.process = target_process_; 1.106 + service_context->target_info.process_id = target_process_id_; 1.107 + service_context->target_info.job_object = target_job_object_; 1.108 + // Advance to the next channel. 1.109 + base_start += channel_size; 1.110 + // Register the ping event with the threadpool. 1.111 + thread_provider_->RegisterWait(this, service_context->ping_event, 1.112 + ThreadPingEventReady, service_context); 1.113 + } 1.114 + 1.115 + // We create a mutex that the server locks. If the server dies unexpectedly, 1.116 + // the thread that owns it will fail to release the lock and windows will 1.117 + // report to the target (when it tries to acquire it) that the wait was 1.118 + // abandoned. Note: We purposely leak the local handle because we want it to 1.119 + // be closed by Windows itself so it is properly marked as abandoned if the 1.120 + // server dies. 1.121 + if (!::DuplicateHandle(::GetCurrentProcess(), 1.122 + ::CreateMutexW(NULL, TRUE, NULL), 1.123 + target_process_, &client_control_->server_alive, 1.124 + SYNCHRONIZE | EVENT_MODIFY_STATE, FALSE, 0)) { 1.125 + return false; 1.126 + } 1.127 + // This last setting indicates to the client all is setup. 1.128 + client_control_->channels_count = channel_count; 1.129 + return true; 1.130 +} 1.131 + 1.132 +// Releases memory allocated for IPC arguments, if needed. 1.133 +void ReleaseArgs(const IPCParams* ipc_params, void* args[kMaxIpcParams]) { 1.134 + for (size_t i = 0; i < kMaxIpcParams; i++) { 1.135 + switch (ipc_params->args[i]) { 1.136 + case WCHAR_TYPE: { 1.137 + delete reinterpret_cast<std::wstring*>(args[i]); 1.138 + args[i] = NULL; 1.139 + break; 1.140 + } 1.141 + case INOUTPTR_TYPE: { 1.142 + delete reinterpret_cast<CountedBuffer*>(args[i]); 1.143 + args[i] = NULL; 1.144 + break; 1.145 + } 1.146 + default: break; 1.147 + } 1.148 + } 1.149 +} 1.150 + 1.151 +// Fills up the list of arguments (args and ipc_params) for an IPC call. 1.152 +bool GetArgs(CrossCallParamsEx* params, IPCParams* ipc_params, 1.153 + void* args[kMaxIpcParams]) { 1.154 + if (kMaxIpcParams < params->GetParamsCount()) 1.155 + return false; 1.156 + 1.157 + for (uint32 i = 0; i < params->GetParamsCount(); i++) { 1.158 + uint32 size; 1.159 + ArgType type; 1.160 + args[i] = params->GetRawParameter(i, &size, &type); 1.161 + if (args[i]) { 1.162 + ipc_params->args[i] = type; 1.163 + switch (type) { 1.164 + case WCHAR_TYPE: { 1.165 + scoped_ptr<std::wstring> data(new std::wstring); 1.166 + if (!params->GetParameterStr(i, data.get())) { 1.167 + args[i] = 0; 1.168 + ReleaseArgs(ipc_params, args); 1.169 + return false; 1.170 + } 1.171 + args[i] = data.release(); 1.172 + break; 1.173 + } 1.174 + case ULONG_TYPE: { 1.175 + uint32 data; 1.176 + if (!params->GetParameter32(i, &data)) { 1.177 + ReleaseArgs(ipc_params, args); 1.178 + return false; 1.179 + } 1.180 + IPCInt ipc_int(data); 1.181 + args[i] = ipc_int.AsVoidPtr(); 1.182 + break; 1.183 + } 1.184 + case VOIDPTR_TYPE : { 1.185 + void* data; 1.186 + if (!params->GetParameterVoidPtr(i, &data)) { 1.187 + ReleaseArgs(ipc_params, args); 1.188 + return false; 1.189 + } 1.190 + args[i] = data; 1.191 + break; 1.192 + } 1.193 + case INOUTPTR_TYPE: { 1.194 + if (!args[i]) { 1.195 + ReleaseArgs(ipc_params, args); 1.196 + return false; 1.197 + } 1.198 + CountedBuffer* buffer = new CountedBuffer(args[i] , size); 1.199 + args[i] = buffer; 1.200 + break; 1.201 + } 1.202 + default: break; 1.203 + } 1.204 + } 1.205 + } 1.206 + return true; 1.207 +} 1.208 + 1.209 +bool SharedMemIPCServer::InvokeCallback(const ServerControl* service_context, 1.210 + void* ipc_buffer, 1.211 + CrossCallReturn* call_result) { 1.212 + // Set the default error code; 1.213 + SetCallError(SBOX_ERROR_INVALID_IPC, call_result); 1.214 + uint32 output_size = 0; 1.215 + // Parse, verify and copy the message. The handler operates on a copy 1.216 + // of the message so the client cannot play dirty tricks by changing the 1.217 + // data in the channel while the IPC is being processed. 1.218 + scoped_ptr<CrossCallParamsEx> params( 1.219 + CrossCallParamsEx::CreateFromBuffer(ipc_buffer, 1.220 + service_context->channel_size, 1.221 + &output_size)); 1.222 + if (!params.get()) 1.223 + return false; 1.224 + 1.225 + uint32 tag = params->GetTag(); 1.226 + COMPILE_ASSERT(0 == INVALID_TYPE, Incorrect_type_enum); 1.227 + IPCParams ipc_params = {0}; 1.228 + ipc_params.ipc_tag = tag; 1.229 + 1.230 + void* args[kMaxIpcParams]; 1.231 + if (!GetArgs(params.get(), &ipc_params, args)) 1.232 + return false; 1.233 + 1.234 + IPCInfo ipc_info = {0}; 1.235 + ipc_info.ipc_tag = tag; 1.236 + ipc_info.client_info = &service_context->target_info; 1.237 + Dispatcher* dispatcher = service_context->dispatcher; 1.238 + DCHECK(dispatcher); 1.239 + bool error = true; 1.240 + Dispatcher* handler = NULL; 1.241 + 1.242 + Dispatcher::CallbackGeneric callback_generic; 1.243 + handler = dispatcher->OnMessageReady(&ipc_params, &callback_generic); 1.244 + if (handler) { 1.245 + switch (params->GetParamsCount()) { 1.246 + case 0: { 1.247 + // Ask the IPC dispatcher if she can service this IPC. 1.248 + Dispatcher::Callback0 callback = 1.249 + reinterpret_cast<Dispatcher::Callback0>(callback_generic); 1.250 + if (!(handler->*callback)(&ipc_info)) 1.251 + break; 1.252 + error = false; 1.253 + break; 1.254 + } 1.255 + case 1: { 1.256 + Dispatcher::Callback1 callback = 1.257 + reinterpret_cast<Dispatcher::Callback1>(callback_generic); 1.258 + if (!(handler->*callback)(&ipc_info, args[0])) 1.259 + break; 1.260 + error = false; 1.261 + break; 1.262 + } 1.263 + case 2: { 1.264 + Dispatcher::Callback2 callback = 1.265 + reinterpret_cast<Dispatcher::Callback2>(callback_generic); 1.266 + if (!(handler->*callback)(&ipc_info, args[0], args[1])) 1.267 + break; 1.268 + error = false; 1.269 + break; 1.270 + } 1.271 + case 3: { 1.272 + Dispatcher::Callback3 callback = 1.273 + reinterpret_cast<Dispatcher::Callback3>(callback_generic); 1.274 + if (!(handler->*callback)(&ipc_info, args[0], args[1], args[2])) 1.275 + break; 1.276 + error = false; 1.277 + break; 1.278 + } 1.279 + case 4: { 1.280 + Dispatcher::Callback4 callback = 1.281 + reinterpret_cast<Dispatcher::Callback4>(callback_generic); 1.282 + if (!(handler->*callback)(&ipc_info, args[0], args[1], args[2], 1.283 + args[3])) 1.284 + break; 1.285 + error = false; 1.286 + break; 1.287 + } 1.288 + case 5: { 1.289 + Dispatcher::Callback5 callback = 1.290 + reinterpret_cast<Dispatcher::Callback5>(callback_generic); 1.291 + if (!(handler->*callback)(&ipc_info, args[0], args[1], args[2], args[3], 1.292 + args[4])) 1.293 + break; 1.294 + error = false; 1.295 + break; 1.296 + } 1.297 + case 6: { 1.298 + Dispatcher::Callback6 callback = 1.299 + reinterpret_cast<Dispatcher::Callback6>(callback_generic); 1.300 + if (!(handler->*callback)(&ipc_info, args[0], args[1], args[2], args[3], 1.301 + args[4], args[5])) 1.302 + break; 1.303 + error = false; 1.304 + break; 1.305 + } 1.306 + case 7: { 1.307 + Dispatcher::Callback7 callback = 1.308 + reinterpret_cast<Dispatcher::Callback7>(callback_generic); 1.309 + if (!(handler->*callback)(&ipc_info, args[0], args[1], args[2], args[3], 1.310 + args[4], args[5], args[6])) 1.311 + break; 1.312 + error = false; 1.313 + break; 1.314 + } 1.315 + case 8: { 1.316 + Dispatcher::Callback8 callback = 1.317 + reinterpret_cast<Dispatcher::Callback8>(callback_generic); 1.318 + if (!(handler->*callback)(&ipc_info, args[0], args[1], args[2], args[3], 1.319 + args[4], args[5], args[6], args[7])) 1.320 + break; 1.321 + error = false; 1.322 + break; 1.323 + } 1.324 + case 9: { 1.325 + Dispatcher::Callback9 callback = 1.326 + reinterpret_cast<Dispatcher::Callback9>(callback_generic); 1.327 + if (!(handler->*callback)(&ipc_info, args[0], args[1], args[2], args[3], 1.328 + args[4], args[5], args[6], args[7], args[8])) 1.329 + break; 1.330 + error = false; 1.331 + break; 1.332 + } 1.333 + default: { 1.334 + NOTREACHED(); 1.335 + break; 1.336 + } 1.337 + } 1.338 + } 1.339 + 1.340 + if (error) { 1.341 + if (handler) 1.342 + SetCallError(SBOX_ERROR_FAILED_IPC, call_result); 1.343 + } else { 1.344 + memcpy(call_result, &ipc_info.return_info, sizeof(*call_result)); 1.345 + SetCallSuccess(call_result); 1.346 + if (params->IsInOut()) { 1.347 + // Maybe the params got changed by the broker. We need to upadte the 1.348 + // memory section. 1.349 + memcpy(ipc_buffer, params.get(), output_size); 1.350 + } 1.351 + } 1.352 + 1.353 + ReleaseArgs(&ipc_params, args); 1.354 + 1.355 + return !error; 1.356 +} 1.357 + 1.358 +// This function gets called by a thread from the thread pool when a 1.359 +// ping event fires. The context is the same as passed in the RegisterWait() 1.360 +// call above. 1.361 +void __stdcall SharedMemIPCServer::ThreadPingEventReady(void* context, 1.362 + unsigned char) { 1.363 + if (NULL == context) { 1.364 + DCHECK(false); 1.365 + return; 1.366 + } 1.367 + ServerControl* service_context = reinterpret_cast<ServerControl*>(context); 1.368 + // Since the event fired, the channel *must* be busy. Change to kAckChannel 1.369 + // while we service it. 1.370 + LONG last_state = 1.371 + ::InterlockedCompareExchange(&service_context->channel->state, 1.372 + kAckChannel, kBusyChannel); 1.373 + if (kBusyChannel != last_state) { 1.374 + DCHECK(false); 1.375 + return; 1.376 + } 1.377 + 1.378 + // Prepare the result structure. At this point we will return some result 1.379 + // even if the IPC is invalid, malformed or has no handler. 1.380 + CrossCallReturn call_result = {0}; 1.381 + void* buffer = service_context->channel_buffer; 1.382 + 1.383 + InvokeCallback(service_context, buffer, &call_result); 1.384 + 1.385 + // Copy the answer back into the channel and signal the pong event. This 1.386 + // should wake up the client so he can finish the the ipc cycle. 1.387 + CrossCallParams* call_params = reinterpret_cast<CrossCallParams*>(buffer); 1.388 + memcpy(call_params->GetCallReturn(), &call_result, sizeof(call_result)); 1.389 + ::InterlockedExchange(&service_context->channel->state, kAckChannel); 1.390 + ::SetEvent(service_context->pong_event); 1.391 +} 1.392 + 1.393 +bool SharedMemIPCServer::MakeEvents(HANDLE* server_ping, HANDLE* server_pong, 1.394 + HANDLE* client_ping, HANDLE* client_pong) { 1.395 + // Note that the IPC client has no right to delete the events. That would 1.396 + // cause problems. The server *owns* the events. 1.397 + const DWORD kDesiredAccess = SYNCHRONIZE | EVENT_MODIFY_STATE; 1.398 + 1.399 + // The events are auto reset, and start not signaled. 1.400 + *server_ping = ::CreateEventW(NULL, FALSE, FALSE, NULL); 1.401 + if (!::DuplicateHandle(::GetCurrentProcess(), *server_ping, target_process_, 1.402 + client_ping, kDesiredAccess, FALSE, 0)) { 1.403 + return false; 1.404 + } 1.405 + *server_pong = ::CreateEventW(NULL, FALSE, FALSE, NULL); 1.406 + if (!::DuplicateHandle(::GetCurrentProcess(), *server_pong, target_process_, 1.407 + client_pong, kDesiredAccess, FALSE, 0)) { 1.408 + return false; 1.409 + } 1.410 + return true; 1.411 +} 1.412 + 1.413 +} // namespace sandbox