Home | History | Annotate | Download | only in src
      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 sandbox {
     16 
     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) {
     28 }
     29 
     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;
     35   }
     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;
     43   }
     44 }
     45 
     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;
     51   }
     52   // The channel size should be aligned.
     53   if (0 != (channel_size % 32)) {
     54     return false;
     55   }
     56 
     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);
     60 
     61   // If we cannot fit even one channel we bail out.
     62   if (0 == channel_count) {
     63     return false;
     64   }
     65   // Calculate the start of the first channel.
     66   size_t base_start = (sizeof(ChannelControl)* channel_count) +
     67                        offsetof(IPCControl, channels);
     68 
     69   client_control_ = reinterpret_cast<IPCControl*>(shared_mem);
     70   client_control_->channels_count = 0;
     71 
     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);
     82 
     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;
     88     }
     89 
     90     client_context->channel_base = base_start;
     91     client_context->state = kFreeChannel;
     92 
     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);
    110   }
    111 
    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;
    123   }
    124   // This last setting indicates to the client all is setup.
    125   client_control_->channels_count = channel_count;
    126   return true;
    127 }
    128 
    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;
    137       }
    138       case INOUTPTR_TYPE: {
    139         delete reinterpret_cast<CountedBuffer*>(args[i]);
    140         args[i] = NULL;
    141         break;
    142       }
    143       default: break;
    144     }
    145   }
    146 }
    147 
    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;
    153 
    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;
    167           }
    168           args[i] = data.release();
    169           break;
    170         }
    171         case ULONG_TYPE: {
    172           uint32 data;
    173           if (!params->GetParameter32(i, &data)) {
    174             ReleaseArgs(ipc_params, args);
    175             return false;
    176           }
    177           IPCInt ipc_int(data);
    178           args[i] = ipc_int.AsVoidPtr();
    179           break;
    180         }
    181         case VOIDPTR_TYPE : {
    182           void* data;
    183           if (!params->GetParameterVoidPtr(i, &data)) {
    184             ReleaseArgs(ipc_params, args);
    185             return false;
    186           }
    187           args[i] = data;
    188           break;
    189         }
    190         case INOUTPTR_TYPE: {
    191           if (!args[i]) {
    192             ReleaseArgs(ipc_params, args);
    193             return false;
    194           }
    195           CountedBuffer* buffer = new CountedBuffer(args[i] , size);
    196           args[i] = buffer;
    197           break;
    198         }
    199         default: break;
    200       }
    201     }
    202   }
    203   return true;
    204 }
    205 
    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;
    221 
    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;
    226 
    227   void* args[kMaxIpcParams];
    228   if (!GetArgs(params.get(), &ipc_params, args))
    229     return false;
    230 
    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;
    238 
    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;
    251       }
    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;
    259       }
    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;
    267       }
    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;
    275       }
    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;
    284       }
    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;
    293       }
    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;
    302       }
    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;
    311       }
    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;
    320       }
    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;
    329       }
    330       default:  {
    331         NOTREACHED();
    332         break;
    333       }
    334     }
    335   }
    336 
    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);
    347     }
    348   }
    349 
    350   ReleaseArgs(&ipc_params, args);
    351 
    352   return !error;
    353 }
    354 
    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;
    363   }
    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;
    373   }
    374 
    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;
    379 
    380   InvokeCallback(service_context, buffer, &call_result);
    381 
    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);
    388 }
    389 
    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;
    395 
    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;
    401   }
    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;
    406   }
    407   return true;
    408 }
    409 
    410 }  // namespace sandbox
    411