IDB: Make readonly transactions wait for earlier readwrite transactions
[chromium-blink-merge.git] / sandbox / win / src / sharedmem_ipc_server.cc
blob3b5fe6c2d3a6700cec8c8d98aa51a9b84ba1db85
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 {
16 // This handle must not be closed.
17 volatile HANDLE g_alive_mutex = NULL;
20 namespace sandbox {
22 SharedMemIPCServer::SharedMemIPCServer(HANDLE target_process,
23 DWORD target_process_id,
24 HANDLE target_job,
25 ThreadProvider* thread_provider,
26 Dispatcher* dispatcher)
27 : client_control_(NULL),
28 thread_provider_(thread_provider),
29 target_process_(target_process),
30 target_process_id_(target_process_id),
31 target_job_object_(target_job),
32 call_dispatcher_(dispatcher) {
33 // We create a initially owned mutex. If the server dies unexpectedly,
34 // the thread that owns it will fail to release the lock and windows will
35 // report to the target (when it tries to acquire it) that the wait was
36 // abandoned. Note: We purposely leak the local handle because we want it to
37 // be closed by Windows itself so it is properly marked as abandoned if the
38 // server dies.
39 if (!g_alive_mutex) {
40 HANDLE mutex = ::CreateMutexW(NULL, TRUE, NULL);
41 if (::InterlockedCompareExchangePointer(&g_alive_mutex, mutex, NULL)) {
42 // We lost the race to create the mutex.
43 ::CloseHandle(mutex);
48 SharedMemIPCServer::~SharedMemIPCServer() {
49 // Free the wait handles associated with the thread pool.
50 if (!thread_provider_->UnRegisterWaits(this)) {
51 // Better to leak than to crash.
52 return;
54 // Free the IPC signal events.
55 ServerContexts::iterator it;
56 for (it = server_contexts_.begin(); it != server_contexts_.end(); ++it) {
57 ServerControl* context = (*it);
58 ::CloseHandle(context->ping_event);
59 ::CloseHandle(context->pong_event);
60 delete context;
64 bool SharedMemIPCServer::Init(void* shared_mem, uint32 shared_size,
65 uint32 channel_size) {
66 // The shared memory needs to be at least as big as a channel.
67 if (shared_size < channel_size) {
68 return false;
70 // The channel size should be aligned.
71 if (0 != (channel_size % 32)) {
72 return false;
75 // Calculate how many channels we can fit in the shared memory.
76 shared_size -= offsetof(IPCControl, channels);
77 size_t channel_count = shared_size / (sizeof(ChannelControl) + channel_size);
79 // If we cannot fit even one channel we bail out.
80 if (0 == channel_count) {
81 return false;
83 // Calculate the start of the first channel.
84 size_t base_start = (sizeof(ChannelControl)* channel_count) +
85 offsetof(IPCControl, channels);
87 client_control_ = reinterpret_cast<IPCControl*>(shared_mem);
88 client_control_->channels_count = 0;
90 // This is the initialization that we do per-channel. Basically:
91 // 1) make two events (ping & pong)
92 // 2) create handles to the events for the client and the server.
93 // 3) initialize the channel (client_context) with the state.
94 // 4) initialize the server side of the channel (service_context).
95 // 5) call the thread provider RegisterWait to register the ping events.
96 for (size_t ix = 0; ix != channel_count; ++ix) {
97 ChannelControl* client_context = &client_control_->channels[ix];
98 ServerControl* service_context = new ServerControl;
99 server_contexts_.push_back(service_context);
101 if (!MakeEvents(&service_context->ping_event,
102 &service_context->pong_event,
103 &client_context->ping_event,
104 &client_context->pong_event)) {
105 return false;
108 client_context->channel_base = base_start;
109 client_context->state = kFreeChannel;
111 // Note that some of these values are available as members of this
112 // object but we put them again into the service_context because we
113 // will be called on a static method (ThreadPingEventReady)
114 service_context->shared_base = reinterpret_cast<char*>(shared_mem);
115 service_context->channel_size = channel_size;
116 service_context->channel = client_context;
117 service_context->channel_buffer = service_context->shared_base +
118 client_context->channel_base;
119 service_context->dispatcher = call_dispatcher_;
120 service_context->target_info.process = target_process_;
121 service_context->target_info.process_id = target_process_id_;
122 service_context->target_info.job_object = target_job_object_;
123 // Advance to the next channel.
124 base_start += channel_size;
125 // Register the ping event with the threadpool.
126 thread_provider_->RegisterWait(this, service_context->ping_event,
127 ThreadPingEventReady, service_context);
129 if (!::DuplicateHandle(::GetCurrentProcess(), g_alive_mutex,
130 target_process_, &client_control_->server_alive,
131 SYNCHRONIZE | EVENT_MODIFY_STATE, FALSE, 0)) {
132 return false;
134 // This last setting indicates to the client all is setup.
135 client_control_->channels_count = channel_count;
136 return true;
139 // Releases memory allocated for IPC arguments, if needed.
140 void ReleaseArgs(const IPCParams* ipc_params, void* args[kMaxIpcParams]) {
141 for (size_t i = 0; i < kMaxIpcParams; i++) {
142 switch (ipc_params->args[i]) {
143 case WCHAR_TYPE: {
144 delete reinterpret_cast<base::string16*>(args[i]);
145 args[i] = NULL;
146 break;
148 case INOUTPTR_TYPE: {
149 delete reinterpret_cast<CountedBuffer*>(args[i]);
150 args[i] = NULL;
151 break;
153 default: break;
158 // Fills up the list of arguments (args and ipc_params) for an IPC call.
159 bool GetArgs(CrossCallParamsEx* params, IPCParams* ipc_params,
160 void* args[kMaxIpcParams]) {
161 if (kMaxIpcParams < params->GetParamsCount())
162 return false;
164 for (uint32 i = 0; i < params->GetParamsCount(); i++) {
165 uint32 size;
166 ArgType type;
167 args[i] = params->GetRawParameter(i, &size, &type);
168 if (args[i]) {
169 ipc_params->args[i] = type;
170 switch (type) {
171 case WCHAR_TYPE: {
172 scoped_ptr<base::string16> data(new base::string16);
173 if (!params->GetParameterStr(i, data.get())) {
174 args[i] = 0;
175 ReleaseArgs(ipc_params, args);
176 return false;
178 args[i] = data.release();
179 break;
181 case UINT32_TYPE: {
182 uint32 data;
183 if (!params->GetParameter32(i, &data)) {
184 ReleaseArgs(ipc_params, args);
185 return false;
187 IPCInt ipc_int(data);
188 args[i] = ipc_int.AsVoidPtr();
189 break;
191 case VOIDPTR_TYPE : {
192 void* data;
193 if (!params->GetParameterVoidPtr(i, &data)) {
194 ReleaseArgs(ipc_params, args);
195 return false;
197 args[i] = data;
198 break;
200 case INOUTPTR_TYPE: {
201 if (!args[i]) {
202 ReleaseArgs(ipc_params, args);
203 return false;
205 CountedBuffer* buffer = new CountedBuffer(args[i] , size);
206 args[i] = buffer;
207 break;
209 default: break;
213 return true;
216 bool SharedMemIPCServer::InvokeCallback(const ServerControl* service_context,
217 void* ipc_buffer,
218 CrossCallReturn* call_result) {
219 // Set the default error code;
220 SetCallError(SBOX_ERROR_INVALID_IPC, call_result);
221 uint32 output_size = 0;
222 // Parse, verify and copy the message. The handler operates on a copy
223 // of the message so the client cannot play dirty tricks by changing the
224 // data in the channel while the IPC is being processed.
225 scoped_ptr<CrossCallParamsEx> params(
226 CrossCallParamsEx::CreateFromBuffer(ipc_buffer,
227 service_context->channel_size,
228 &output_size));
229 if (!params.get())
230 return false;
232 uint32 tag = params->GetTag();
233 COMPILE_ASSERT(0 == INVALID_TYPE, Incorrect_type_enum);
234 IPCParams ipc_params = {0};
235 ipc_params.ipc_tag = tag;
237 void* args[kMaxIpcParams];
238 if (!GetArgs(params.get(), &ipc_params, args))
239 return false;
241 IPCInfo ipc_info = {0};
242 ipc_info.ipc_tag = tag;
243 ipc_info.client_info = &service_context->target_info;
244 Dispatcher* dispatcher = service_context->dispatcher;
245 DCHECK(dispatcher);
246 bool error = true;
247 Dispatcher* handler = NULL;
249 Dispatcher::CallbackGeneric callback_generic;
250 handler = dispatcher->OnMessageReady(&ipc_params, &callback_generic);
251 if (handler) {
252 switch (params->GetParamsCount()) {
253 case 0: {
254 // Ask the IPC dispatcher if she can service this IPC.
255 Dispatcher::Callback0 callback =
256 reinterpret_cast<Dispatcher::Callback0>(callback_generic);
257 if (!(handler->*callback)(&ipc_info))
258 break;
259 error = false;
260 break;
262 case 1: {
263 Dispatcher::Callback1 callback =
264 reinterpret_cast<Dispatcher::Callback1>(callback_generic);
265 if (!(handler->*callback)(&ipc_info, args[0]))
266 break;
267 error = false;
268 break;
270 case 2: {
271 Dispatcher::Callback2 callback =
272 reinterpret_cast<Dispatcher::Callback2>(callback_generic);
273 if (!(handler->*callback)(&ipc_info, args[0], args[1]))
274 break;
275 error = false;
276 break;
278 case 3: {
279 Dispatcher::Callback3 callback =
280 reinterpret_cast<Dispatcher::Callback3>(callback_generic);
281 if (!(handler->*callback)(&ipc_info, args[0], args[1], args[2]))
282 break;
283 error = false;
284 break;
286 case 4: {
287 Dispatcher::Callback4 callback =
288 reinterpret_cast<Dispatcher::Callback4>(callback_generic);
289 if (!(handler->*callback)(&ipc_info, args[0], args[1], args[2],
290 args[3]))
291 break;
292 error = false;
293 break;
295 case 5: {
296 Dispatcher::Callback5 callback =
297 reinterpret_cast<Dispatcher::Callback5>(callback_generic);
298 if (!(handler->*callback)(&ipc_info, args[0], args[1], args[2], args[3],
299 args[4]))
300 break;
301 error = false;
302 break;
304 case 6: {
305 Dispatcher::Callback6 callback =
306 reinterpret_cast<Dispatcher::Callback6>(callback_generic);
307 if (!(handler->*callback)(&ipc_info, args[0], args[1], args[2], args[3],
308 args[4], args[5]))
309 break;
310 error = false;
311 break;
313 case 7: {
314 Dispatcher::Callback7 callback =
315 reinterpret_cast<Dispatcher::Callback7>(callback_generic);
316 if (!(handler->*callback)(&ipc_info, args[0], args[1], args[2], args[3],
317 args[4], args[5], args[6]))
318 break;
319 error = false;
320 break;
322 case 8: {
323 Dispatcher::Callback8 callback =
324 reinterpret_cast<Dispatcher::Callback8>(callback_generic);
325 if (!(handler->*callback)(&ipc_info, args[0], args[1], args[2], args[3],
326 args[4], args[5], args[6], args[7]))
327 break;
328 error = false;
329 break;
331 case 9: {
332 Dispatcher::Callback9 callback =
333 reinterpret_cast<Dispatcher::Callback9>(callback_generic);
334 if (!(handler->*callback)(&ipc_info, args[0], args[1], args[2], args[3],
335 args[4], args[5], args[6], args[7], args[8]))
336 break;
337 error = false;
338 break;
340 default: {
341 NOTREACHED();
342 break;
347 if (error) {
348 if (handler)
349 SetCallError(SBOX_ERROR_FAILED_IPC, call_result);
350 } else {
351 memcpy(call_result, &ipc_info.return_info, sizeof(*call_result));
352 SetCallSuccess(call_result);
353 if (params->IsInOut()) {
354 // Maybe the params got changed by the broker. We need to upadte the
355 // memory section.
356 memcpy(ipc_buffer, params.get(), output_size);
360 ReleaseArgs(&ipc_params, args);
362 return !error;
365 // This function gets called by a thread from the thread pool when a
366 // ping event fires. The context is the same as passed in the RegisterWait()
367 // call above.
368 void __stdcall SharedMemIPCServer::ThreadPingEventReady(void* context,
369 unsigned char) {
370 if (NULL == context) {
371 DCHECK(false);
372 return;
374 ServerControl* service_context = reinterpret_cast<ServerControl*>(context);
375 // Since the event fired, the channel *must* be busy. Change to kAckChannel
376 // while we service it.
377 LONG last_state =
378 ::InterlockedCompareExchange(&service_context->channel->state,
379 kAckChannel, kBusyChannel);
380 if (kBusyChannel != last_state) {
381 DCHECK(false);
382 return;
385 // Prepare the result structure. At this point we will return some result
386 // even if the IPC is invalid, malformed or has no handler.
387 CrossCallReturn call_result = {0};
388 void* buffer = service_context->channel_buffer;
390 InvokeCallback(service_context, buffer, &call_result);
392 // Copy the answer back into the channel and signal the pong event. This
393 // should wake up the client so he can finish the the ipc cycle.
394 CrossCallParams* call_params = reinterpret_cast<CrossCallParams*>(buffer);
395 memcpy(call_params->GetCallReturn(), &call_result, sizeof(call_result));
396 ::InterlockedExchange(&service_context->channel->state, kAckChannel);
397 ::SetEvent(service_context->pong_event);
400 bool SharedMemIPCServer::MakeEvents(HANDLE* server_ping, HANDLE* server_pong,
401 HANDLE* client_ping, HANDLE* client_pong) {
402 // Note that the IPC client has no right to delete the events. That would
403 // cause problems. The server *owns* the events.
404 const DWORD kDesiredAccess = SYNCHRONIZE | EVENT_MODIFY_STATE;
406 // The events are auto reset, and start not signaled.
407 *server_ping = ::CreateEventW(NULL, FALSE, FALSE, NULL);
408 if (!::DuplicateHandle(::GetCurrentProcess(), *server_ping, target_process_,
409 client_ping, kDesiredAccess, FALSE, 0)) {
410 return false;
412 *server_pong = ::CreateEventW(NULL, FALSE, FALSE, NULL);
413 if (!::DuplicateHandle(::GetCurrentProcess(), *server_pong, target_process_,
414 client_pong, kDesiredAccess, FALSE, 0)) {
415 return false;
417 return true;
420 } // namespace sandbox