Revert "Merged all Chromoting Host code into remoting_core.dll (Windows)."
[chromium-blink-merge.git] / sandbox / win / src / sharedmem_ipc_server.cc
blobe2a30c723662af198929c7695e570db387d19c40
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/callback.h"
6 #include "base/logging.h"
7 #include "base/memory/scoped_ptr.h"
8 #include "sandbox/win/src/sharedmem_ipc_server.h"
9 #include "sandbox/win/src/sharedmem_ipc_client.h"
10 #include "sandbox/win/src/sandbox.h"
11 #include "sandbox/win/src/sandbox_types.h"
12 #include "sandbox/win/src/crosscall_params.h"
13 #include "sandbox/win/src/crosscall_server.h"
15 namespace sandbox {
17 SharedMemIPCServer::SharedMemIPCServer(HANDLE target_process,
18 DWORD target_process_id,
19 HANDLE target_job,
20 ThreadProvider* thread_provider,
21 Dispatcher* dispatcher)
22 : client_control_(NULL),
23 thread_provider_(thread_provider),
24 target_process_(target_process),
25 target_process_id_(target_process_id),
26 target_job_object_(target_job),
27 call_dispatcher_(dispatcher) {
30 SharedMemIPCServer::~SharedMemIPCServer() {
31 // Free the wait handles associated with the thread pool.
32 if (!thread_provider_->UnRegisterWaits(this)) {
33 // Better to leak than to crash.
34 return;
36 // Free the IPC signal events.
37 ServerContexts::iterator it;
38 for (it = server_contexts_.begin(); it != server_contexts_.end(); ++it) {
39 ServerControl* context = (*it);
40 ::CloseHandle(context->ping_event);
41 ::CloseHandle(context->pong_event);
42 delete context;
46 bool SharedMemIPCServer::Init(void* shared_mem, uint32 shared_size,
47 uint32 channel_size) {
48 // The shared memory needs to be at least as big as a channel.
49 if (shared_size < channel_size) {
50 return false;
52 // The channel size should be aligned.
53 if (0 != (channel_size % 32)) {
54 return false;
57 // Calculate how many channels we can fit in the shared memory.
58 shared_size -= offsetof(IPCControl, channels);
59 size_t channel_count = shared_size / (sizeof(ChannelControl) + channel_size);
61 // If we cannot fit even one channel we bail out.
62 if (0 == channel_count) {
63 return false;
65 // Calculate the start of the first channel.
66 size_t base_start = (sizeof(ChannelControl)* channel_count) +
67 offsetof(IPCControl, channels);
69 client_control_ = reinterpret_cast<IPCControl*>(shared_mem);
70 client_control_->channels_count = 0;
72 // This is the initialization that we do per-channel. Basically:
73 // 1) make two events (ping & pong)
74 // 2) create handles to the events for the client and the server.
75 // 3) initialize the channel (client_context) with the state.
76 // 4) initialize the server side of the channel (service_context).
77 // 5) call the thread provider RegisterWait to register the ping events.
78 for (size_t ix = 0; ix != channel_count; ++ix) {
79 ChannelControl* client_context = &client_control_->channels[ix];
80 ServerControl* service_context = new ServerControl;
81 server_contexts_.push_back(service_context);
83 if (!MakeEvents(&service_context->ping_event,
84 &service_context->pong_event,
85 &client_context->ping_event,
86 &client_context->pong_event)) {
87 return false;
90 client_context->channel_base = base_start;
91 client_context->state = kFreeChannel;
93 // Note that some of these values are available as members of this
94 // object but we put them again into the service_context because we
95 // will be called on a static method (ThreadPingEventReady)
96 service_context->shared_base = reinterpret_cast<char*>(shared_mem);
97 service_context->channel_size = channel_size;
98 service_context->channel = client_context;
99 service_context->channel_buffer = service_context->shared_base +
100 client_context->channel_base;
101 service_context->dispatcher = call_dispatcher_;
102 service_context->target_info.process = target_process_;
103 service_context->target_info.process_id = target_process_id_;
104 service_context->target_info.job_object = target_job_object_;
105 // Advance to the next channel.
106 base_start += channel_size;
107 // Register the ping event with the threadpool.
108 thread_provider_->RegisterWait(this, service_context->ping_event,
109 ThreadPingEventReady, service_context);
112 // We create a mutex that the server locks. If the server dies unexpectedly,
113 // the thread that owns it will fail to release the lock and windows will
114 // report to the target (when it tries to acquire it) that the wait was
115 // abandoned. Note: We purposely leak the local handle because we want it to
116 // be closed by Windows itself so it is properly marked as abandoned if the
117 // server dies.
118 if (!::DuplicateHandle(::GetCurrentProcess(),
119 ::CreateMutexW(NULL, TRUE, NULL),
120 target_process_, &client_control_->server_alive,
121 SYNCHRONIZE | EVENT_MODIFY_STATE, FALSE, 0)) {
122 return false;
124 // This last setting indicates to the client all is setup.
125 client_control_->channels_count = channel_count;
126 return true;
129 // Releases memory allocated for IPC arguments, if needed.
130 void ReleaseArgs(const IPCParams* ipc_params, void* args[kMaxIpcParams]) {
131 for (size_t i = 0; i < kMaxIpcParams; i++) {
132 switch (ipc_params->args[i]) {
133 case WCHAR_TYPE: {
134 delete reinterpret_cast<std::wstring*>(args[i]);
135 args[i] = NULL;
136 break;
138 case INOUTPTR_TYPE: {
139 delete reinterpret_cast<CountedBuffer*>(args[i]);
140 args[i] = NULL;
141 break;
143 default: break;
148 // Fills up the list of arguments (args and ipc_params) for an IPC call.
149 bool GetArgs(CrossCallParamsEx* params, IPCParams* ipc_params,
150 void* args[kMaxIpcParams]) {
151 if (kMaxIpcParams < params->GetParamsCount())
152 return false;
154 for (uint32 i = 0; i < params->GetParamsCount(); i++) {
155 uint32 size;
156 ArgType type;
157 args[i] = params->GetRawParameter(i, &size, &type);
158 if (args[i]) {
159 ipc_params->args[i] = type;
160 switch (type) {
161 case WCHAR_TYPE: {
162 scoped_ptr<std::wstring> data(new std::wstring);
163 if (!params->GetParameterStr(i, data.get())) {
164 args[i] = 0;
165 ReleaseArgs(ipc_params, args);
166 return false;
168 args[i] = data.release();
169 break;
171 case ULONG_TYPE: {
172 uint32 data;
173 if (!params->GetParameter32(i, &data)) {
174 ReleaseArgs(ipc_params, args);
175 return false;
177 IPCInt ipc_int(data);
178 args[i] = ipc_int.AsVoidPtr();
179 break;
181 case VOIDPTR_TYPE : {
182 void* data;
183 if (!params->GetParameterVoidPtr(i, &data)) {
184 ReleaseArgs(ipc_params, args);
185 return false;
187 args[i] = data;
188 break;
190 case INOUTPTR_TYPE: {
191 if (!args[i]) {
192 ReleaseArgs(ipc_params, args);
193 return false;
195 CountedBuffer* buffer = new CountedBuffer(args[i] , size);
196 args[i] = buffer;
197 break;
199 default: break;
203 return true;
206 bool SharedMemIPCServer::InvokeCallback(const ServerControl* service_context,
207 void* ipc_buffer,
208 CrossCallReturn* call_result) {
209 // Set the default error code;
210 SetCallError(SBOX_ERROR_INVALID_IPC, call_result);
211 uint32 output_size = 0;
212 // Parse, verify and copy the message. The handler operates on a copy
213 // of the message so the client cannot play dirty tricks by changing the
214 // data in the channel while the IPC is being processed.
215 scoped_ptr<CrossCallParamsEx> params(
216 CrossCallParamsEx::CreateFromBuffer(ipc_buffer,
217 service_context->channel_size,
218 &output_size));
219 if (!params.get())
220 return false;
222 uint32 tag = params->GetTag();
223 COMPILE_ASSERT(0 == INVALID_TYPE, Incorrect_type_enum);
224 IPCParams ipc_params = {0};
225 ipc_params.ipc_tag = tag;
227 void* args[kMaxIpcParams];
228 if (!GetArgs(params.get(), &ipc_params, args))
229 return false;
231 IPCInfo ipc_info = {0};
232 ipc_info.ipc_tag = tag;
233 ipc_info.client_info = &service_context->target_info;
234 Dispatcher* dispatcher = service_context->dispatcher;
235 DCHECK(dispatcher);
236 bool error = true;
237 Dispatcher* handler = NULL;
239 Dispatcher::CallbackGeneric callback_generic;
240 handler = dispatcher->OnMessageReady(&ipc_params, &callback_generic);
241 if (handler) {
242 switch (params->GetParamsCount()) {
243 case 0: {
244 // Ask the IPC dispatcher if she can service this IPC.
245 Dispatcher::Callback0 callback =
246 reinterpret_cast<Dispatcher::Callback0>(callback_generic);
247 if (!(handler->*callback)(&ipc_info))
248 break;
249 error = false;
250 break;
252 case 1: {
253 Dispatcher::Callback1 callback =
254 reinterpret_cast<Dispatcher::Callback1>(callback_generic);
255 if (!(handler->*callback)(&ipc_info, args[0]))
256 break;
257 error = false;
258 break;
260 case 2: {
261 Dispatcher::Callback2 callback =
262 reinterpret_cast<Dispatcher::Callback2>(callback_generic);
263 if (!(handler->*callback)(&ipc_info, args[0], args[1]))
264 break;
265 error = false;
266 break;
268 case 3: {
269 Dispatcher::Callback3 callback =
270 reinterpret_cast<Dispatcher::Callback3>(callback_generic);
271 if (!(handler->*callback)(&ipc_info, args[0], args[1], args[2]))
272 break;
273 error = false;
274 break;
276 case 4: {
277 Dispatcher::Callback4 callback =
278 reinterpret_cast<Dispatcher::Callback4>(callback_generic);
279 if (!(handler->*callback)(&ipc_info, args[0], args[1], args[2],
280 args[3]))
281 break;
282 error = false;
283 break;
285 case 5: {
286 Dispatcher::Callback5 callback =
287 reinterpret_cast<Dispatcher::Callback5>(callback_generic);
288 if (!(handler->*callback)(&ipc_info, args[0], args[1], args[2], args[3],
289 args[4]))
290 break;
291 error = false;
292 break;
294 case 6: {
295 Dispatcher::Callback6 callback =
296 reinterpret_cast<Dispatcher::Callback6>(callback_generic);
297 if (!(handler->*callback)(&ipc_info, args[0], args[1], args[2], args[3],
298 args[4], args[5]))
299 break;
300 error = false;
301 break;
303 case 7: {
304 Dispatcher::Callback7 callback =
305 reinterpret_cast<Dispatcher::Callback7>(callback_generic);
306 if (!(handler->*callback)(&ipc_info, args[0], args[1], args[2], args[3],
307 args[4], args[5], args[6]))
308 break;
309 error = false;
310 break;
312 case 8: {
313 Dispatcher::Callback8 callback =
314 reinterpret_cast<Dispatcher::Callback8>(callback_generic);
315 if (!(handler->*callback)(&ipc_info, args[0], args[1], args[2], args[3],
316 args[4], args[5], args[6], args[7]))
317 break;
318 error = false;
319 break;
321 case 9: {
322 Dispatcher::Callback9 callback =
323 reinterpret_cast<Dispatcher::Callback9>(callback_generic);
324 if (!(handler->*callback)(&ipc_info, args[0], args[1], args[2], args[3],
325 args[4], args[5], args[6], args[7], args[8]))
326 break;
327 error = false;
328 break;
330 default: {
331 NOTREACHED();
332 break;
337 if (error) {
338 if (handler)
339 SetCallError(SBOX_ERROR_FAILED_IPC, call_result);
340 } else {
341 memcpy(call_result, &ipc_info.return_info, sizeof(*call_result));
342 SetCallSuccess(call_result);
343 if (params->IsInOut()) {
344 // Maybe the params got changed by the broker. We need to upadte the
345 // memory section.
346 memcpy(ipc_buffer, params.get(), output_size);
350 ReleaseArgs(&ipc_params, args);
352 return !error;
355 // This function gets called by a thread from the thread pool when a
356 // ping event fires. The context is the same as passed in the RegisterWait()
357 // call above.
358 void __stdcall SharedMemIPCServer::ThreadPingEventReady(void* context,
359 unsigned char) {
360 if (NULL == context) {
361 DCHECK(false);
362 return;
364 ServerControl* service_context = reinterpret_cast<ServerControl*>(context);
365 // Since the event fired, the channel *must* be busy. Change to kAckChannel
366 // while we service it.
367 LONG last_state =
368 ::InterlockedCompareExchange(&service_context->channel->state,
369 kAckChannel, kBusyChannel);
370 if (kBusyChannel != last_state) {
371 DCHECK(false);
372 return;
375 // Prepare the result structure. At this point we will return some result
376 // even if the IPC is invalid, malformed or has no handler.
377 CrossCallReturn call_result = {0};
378 void* buffer = service_context->channel_buffer;
380 InvokeCallback(service_context, buffer, &call_result);
382 // Copy the answer back into the channel and signal the pong event. This
383 // should wake up the client so he can finish the the ipc cycle.
384 CrossCallParams* call_params = reinterpret_cast<CrossCallParams*>(buffer);
385 memcpy(call_params->GetCallReturn(), &call_result, sizeof(call_result));
386 ::InterlockedExchange(&service_context->channel->state, kAckChannel);
387 ::SetEvent(service_context->pong_event);
390 bool SharedMemIPCServer::MakeEvents(HANDLE* server_ping, HANDLE* server_pong,
391 HANDLE* client_ping, HANDLE* client_pong) {
392 // Note that the IPC client has no right to delete the events. That would
393 // cause problems. The server *owns* the events.
394 const DWORD kDesiredAccess = SYNCHRONIZE | EVENT_MODIFY_STATE;
396 // The events are auto reset, and start not signaled.
397 *server_ping = ::CreateEventW(NULL, FALSE, FALSE, NULL);
398 if (!::DuplicateHandle(::GetCurrentProcess(), *server_ping, target_process_,
399 client_ping, kDesiredAccess, FALSE, 0)) {
400 return false;
402 *server_pong = ::CreateEventW(NULL, FALSE, FALSE, NULL);
403 if (!::DuplicateHandle(::GetCurrentProcess(), *server_pong, target_process_,
404 client_pong, kDesiredAccess, FALSE, 0)) {
405 return false;
407 return true;
410 } // namespace sandbox