• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
4 
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"
14 
15 namespace {
16 // This handle must not be closed.
17 volatile HANDLE g_alive_mutex = NULL;
18 }
19 
20 namespace sandbox {
21 
SharedMemIPCServer(HANDLE target_process,DWORD target_process_id,HANDLE target_job,ThreadProvider * thread_provider,Dispatcher * dispatcher)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);
44     }
45   }
46 }
47 
~SharedMemIPCServer()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;
53   }
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;
61   }
62 }
63 
Init(void * shared_mem,uint32 shared_size,uint32 channel_size)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;
69   }
70   // The channel size should be aligned.
71   if (0 != (channel_size % 32)) {
72     return false;
73   }
74 
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);
78 
79   // If we cannot fit even one channel we bail out.
80   if (0 == channel_count) {
81     return false;
82   }
83   // Calculate the start of the first channel.
84   size_t base_start = (sizeof(ChannelControl)* channel_count) +
85                        offsetof(IPCControl, channels);
86 
87   client_control_ = reinterpret_cast<IPCControl*>(shared_mem);
88   client_control_->channels_count = 0;
89 
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);
100 
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;
106     }
107 
108     client_context->channel_base = base_start;
109     client_context->state = kFreeChannel;
110 
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);
128   }
129   if (!::DuplicateHandle(::GetCurrentProcess(), g_alive_mutex,
130                          target_process_, &client_control_->server_alive,
131                          SYNCHRONIZE | EVENT_MODIFY_STATE, FALSE, 0)) {
132     return false;
133   }
134   // This last setting indicates to the client all is setup.
135   client_control_->channels_count = channel_count;
136   return true;
137 }
138 
139 // Releases memory allocated for IPC arguments, if needed.
ReleaseArgs(const IPCParams * ipc_params,void * args[kMaxIpcParams])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;
147       }
148       case INOUTPTR_TYPE: {
149         delete reinterpret_cast<CountedBuffer*>(args[i]);
150         args[i] = NULL;
151         break;
152       }
153       default: break;
154     }
155   }
156 }
157 
158 // Fills up the list of arguments (args and ipc_params) for an IPC call.
GetArgs(CrossCallParamsEx * params,IPCParams * ipc_params,void * args[kMaxIpcParams])159 bool GetArgs(CrossCallParamsEx* params, IPCParams* ipc_params,
160              void* args[kMaxIpcParams]) {
161   if (kMaxIpcParams < params->GetParamsCount())
162     return false;
163 
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;
177           }
178           args[i] = data.release();
179           break;
180         }
181         case ULONG_TYPE: {
182           uint32 data;
183           if (!params->GetParameter32(i, &data)) {
184             ReleaseArgs(ipc_params, args);
185             return false;
186           }
187           IPCInt ipc_int(data);
188           args[i] = ipc_int.AsVoidPtr();
189           break;
190         }
191         case VOIDPTR_TYPE : {
192           void* data;
193           if (!params->GetParameterVoidPtr(i, &data)) {
194             ReleaseArgs(ipc_params, args);
195             return false;
196           }
197           args[i] = data;
198           break;
199         }
200         case INOUTPTR_TYPE: {
201           if (!args[i]) {
202             ReleaseArgs(ipc_params, args);
203             return false;
204           }
205           CountedBuffer* buffer = new CountedBuffer(args[i] , size);
206           args[i] = buffer;
207           break;
208         }
209         default: break;
210       }
211     }
212   }
213   return true;
214 }
215 
InvokeCallback(const ServerControl * service_context,void * ipc_buffer,CrossCallReturn * call_result)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;
231 
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;
236 
237   void* args[kMaxIpcParams];
238   if (!GetArgs(params.get(), &ipc_params, args))
239     return false;
240 
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;
248 
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;
261       }
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;
269       }
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;
277       }
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;
285       }
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;
294       }
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;
303       }
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;
312       }
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;
321       }
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;
330       }
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;
339       }
340       default:  {
341         NOTREACHED();
342         break;
343       }
344     }
345   }
346 
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);
357     }
358   }
359 
360   ReleaseArgs(&ipc_params, args);
361 
362   return !error;
363 }
364 
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.
ThreadPingEventReady(void * context,unsigned char)368 void __stdcall SharedMemIPCServer::ThreadPingEventReady(void* context,
369                                                         unsigned char) {
370   if (NULL == context) {
371     DCHECK(false);
372     return;
373   }
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;
383   }
384 
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;
389 
390   InvokeCallback(service_context, buffer, &call_result);
391 
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);
398 }
399 
MakeEvents(HANDLE * server_ping,HANDLE * server_pong,HANDLE * client_ping,HANDLE * client_pong)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;
405 
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;
411   }
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;
416   }
417   return true;
418 }
419 
420 }  // namespace sandbox
421