Home | History | Annotate | Download | only in proxy
      1 // Copyright 2013 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 "ppapi/proxy/nacl_message_scanner.h"
      6 
      7 #include <vector>
      8 #include "base/bind.h"
      9 #include "ipc/ipc_message.h"
     10 #include "ipc/ipc_message_macros.h"
     11 #include "ppapi/proxy/ppapi_messages.h"
     12 #include "ppapi/proxy/resource_message_params.h"
     13 #include "ppapi/proxy/serialized_handle.h"
     14 #include "ppapi/proxy/serialized_var.h"
     15 
     16 class NaClDescImcShm;
     17 
     18 namespace IPC {
     19 class Message;
     20 }
     21 
     22 namespace {
     23 
     24 typedef std::vector<ppapi::proxy::SerializedHandle> Handles;
     25 
     26 struct ScanningResults {
     27   ScanningResults() : handle_index(0) {}
     28 
     29   // Vector to hold handles found in the message.
     30   Handles handles;
     31   // Current handle index in the rewritten message. During the scan, it will be
     32   // be less than or equal to handles.size(). After the scan it should be equal.
     33   int handle_index;
     34   // The rewritten message. This may be NULL, so all ScanParam overloads should
     35   // check for NULL before writing to it. In some cases, a ScanParam overload
     36   // may set this to NULL when it can determine that there are no parameters
     37   // that need conversion. (See the ResourceMessageReplyParams overload.)
     38   scoped_ptr<IPC::Message> new_msg;
     39 };
     40 
     41 void WriteHandle(int handle_index,
     42                  const ppapi::proxy::SerializedHandle& handle,
     43                  IPC::Message* msg) {
     44   ppapi::proxy::SerializedHandle::WriteHeader(handle.header(), msg);
     45 
     46   // Now write the handle itself in POSIX style.
     47   msg->WriteBool(true);  // valid == true
     48   msg->WriteInt(handle_index);
     49 }
     50 
     51 // Define overloads for each kind of message parameter that requires special
     52 // handling. See ScanTuple for how these get used.
     53 
     54 // Overload to match SerializedHandle.
     55 void ScanParam(const ppapi::proxy::SerializedHandle& handle,
     56                ScanningResults* results) {
     57   results->handles.push_back(handle);
     58   if (results->new_msg)
     59     WriteHandle(results->handle_index++, handle, results->new_msg.get());
     60 }
     61 
     62 void HandleWriter(int* handle_index,
     63                   IPC::Message* m,
     64                   const ppapi::proxy::SerializedHandle& handle) {
     65   WriteHandle((*handle_index)++, handle, m);
     66 }
     67 
     68 // Overload to match SerializedVar, which can contain handles.
     69 void ScanParam(const ppapi::proxy::SerializedVar& var,
     70                ScanningResults* results) {
     71   std::vector<ppapi::proxy::SerializedHandle*> var_handles = var.GetHandles();
     72   // Copy any handles and then rewrite the message.
     73   for (size_t i = 0; i < var_handles.size(); ++i)
     74     results->handles.push_back(*var_handles[i]);
     75   if (results->new_msg)
     76     var.WriteDataToMessage(results->new_msg.get(),
     77                            base::Bind(&HandleWriter, &results->handle_index));
     78 }
     79 
     80 // For PpapiMsg_ResourceReply and the reply to PpapiHostMsg_ResourceSyncCall,
     81 // the handles are carried inside the ResourceMessageReplyParams.
     82 // NOTE: We only intercept handles from host->NaCl. The only kind of
     83 //       ResourceMessageParams that travels this direction is
     84 //       ResourceMessageReplyParams, so that's the only one we need to handle.
     85 void ScanParam(const ppapi::proxy::ResourceMessageReplyParams& params,
     86                ScanningResults* results) {
     87   // If the resource reply params don't contain handles, NULL the new message
     88   // pointer to cancel further rewriting.
     89   // NOTE: This works because only handles currently need rewriting, and we
     90   //       know at this point that this message has none.
     91   if (params.handles().empty()) {
     92     results->new_msg.reset(NULL);
     93     return;
     94   }
     95 
     96   // If we need to rewrite the message, write everything before the handles
     97   // (there's nothing after the handles).
     98   if (results->new_msg) {
     99     params.WriteReplyHeader(results->new_msg.get());
    100     // IPC writes the vector length as an int before the contents of the
    101     // vector.
    102     results->new_msg->WriteInt(static_cast<int>(params.handles().size()));
    103   }
    104   for (Handles::const_iterator iter = params.handles().begin();
    105        iter != params.handles().end();
    106        ++iter) {
    107     // ScanParam will write each handle to the new message, if necessary.
    108     ScanParam(*iter, results);
    109   }
    110   // Tell ResourceMessageReplyParams that we have taken the handles, so it
    111   // shouldn't close them. The NaCl runtime will take ownership of them.
    112   params.ConsumeHandles();
    113 }
    114 
    115 // Overload to match all other types. If we need to rewrite the message,
    116 // write the parameter.
    117 template <class T>
    118 void ScanParam(const T& param, ScanningResults* results) {
    119   if (results->new_msg)
    120     IPC::WriteParam(results->new_msg.get(), param);
    121 }
    122 
    123 // These just break apart the given tuple and run ScanParam over each param.
    124 // The idea is to scan elements in the tuple which require special handling,
    125 // and write them into the |results| struct.
    126 template <class A>
    127 void ScanTuple(const Tuple1<A>& t1, ScanningResults* results) {
    128   ScanParam(t1.a, results);
    129 }
    130 template <class A, class B>
    131 void ScanTuple(const Tuple2<A, B>& t1, ScanningResults* results) {
    132   ScanParam(t1.a, results);
    133   ScanParam(t1.b, results);
    134 }
    135 template <class A, class B, class C>
    136 void ScanTuple(const Tuple3<A, B, C>& t1, ScanningResults* results) {
    137   ScanParam(t1.a, results);
    138   ScanParam(t1.b, results);
    139   ScanParam(t1.c, results);
    140 }
    141 template <class A, class B, class C, class D>
    142 void ScanTuple(const Tuple4<A, B, C, D>& t1, ScanningResults* results) {
    143   ScanParam(t1.a, results);
    144   ScanParam(t1.b, results);
    145   ScanParam(t1.c, results);
    146   ScanParam(t1.d, results);
    147 }
    148 
    149 template <class MessageType>
    150 class MessageScannerImpl {
    151  public:
    152   explicit MessageScannerImpl(const IPC::Message* msg)
    153       : msg_(static_cast<const MessageType*>(msg)) {
    154   }
    155   bool ScanMessage(ScanningResults* results) {
    156     typename TupleTypes<typename MessageType::Schema::Param>::ValueTuple params;
    157     if (!MessageType::Read(msg_, &params))
    158       return false;
    159     ScanTuple(params, results);
    160     return true;
    161   }
    162 
    163   bool ScanReply(ScanningResults* results) {
    164     typename TupleTypes<typename MessageType::Schema::ReplyParam>::ValueTuple
    165         params;
    166     if (!MessageType::ReadReplyParam(msg_, &params))
    167       return false;
    168     // If we need to rewrite the message, write the message id first.
    169     if (results->new_msg) {
    170       results->new_msg->set_reply();
    171       int id = IPC::SyncMessage::GetMessageId(*msg_);
    172       results->new_msg->WriteInt(id);
    173     }
    174     ScanTuple(params, results);
    175     return true;
    176   }
    177   // TODO(dmichael): Add ScanSyncMessage for outgoing sync messages, if we ever
    178   //                 need to scan those.
    179 
    180  private:
    181   const MessageType* msg_;
    182 };
    183 
    184 }  // namespace
    185 
    186 #define CASE_FOR_MESSAGE(MESSAGE_TYPE) \
    187       case MESSAGE_TYPE::ID: { \
    188         MessageScannerImpl<MESSAGE_TYPE> scanner(&msg); \
    189         if (rewrite_msg) \
    190           results.new_msg.reset( \
    191               new IPC::Message(msg.routing_id(), msg.type(), \
    192                                IPC::Message::PRIORITY_NORMAL)); \
    193         if (!scanner.ScanMessage(&results)) \
    194           return false; \
    195         break; \
    196       }
    197 #define CASE_FOR_REPLY(MESSAGE_TYPE) \
    198       case MESSAGE_TYPE::ID: { \
    199         MessageScannerImpl<MESSAGE_TYPE> scanner(&msg); \
    200         if (rewrite_msg) \
    201           results.new_msg.reset( \
    202               new IPC::Message(msg.routing_id(), msg.type(), \
    203                                IPC::Message::PRIORITY_NORMAL)); \
    204         if (!scanner.ScanReply(&results)) \
    205           return false; \
    206         break; \
    207       }
    208 
    209 namespace ppapi {
    210 namespace proxy {
    211 
    212 class SerializedHandle;
    213 
    214 NaClMessageScanner::NaClMessageScanner() {
    215 }
    216 
    217 // Windows IPC differs from POSIX in that native handles are serialized in the
    218 // message body, rather than passed in a separate FileDescriptorSet. Therefore,
    219 // on Windows, any message containing handles must be rewritten in the POSIX
    220 // format before we can send it to the NaCl plugin.
    221 //
    222 // On POSIX and Windows we have to rewrite PpapiMsg_CreateNaClChannel messages.
    223 // These contain a handle with an invalid (place holder) descriptor. We need to
    224 // locate this handle so it can be replaced with a valid one when the channel is
    225 // created.
    226 bool NaClMessageScanner::ScanMessage(
    227     const IPC::Message& msg,
    228     std::vector<SerializedHandle>* handles,
    229     scoped_ptr<IPC::Message>* new_msg_ptr) {
    230   DCHECK(handles);
    231   DCHECK(handles->empty());
    232   DCHECK(new_msg_ptr);
    233   DCHECK(!new_msg_ptr->get());
    234 
    235   bool rewrite_msg =
    236 #if defined(OS_WIN)
    237       true;
    238 #else
    239       (msg.type() == PpapiMsg_CreateNaClChannel::ID);
    240 #endif
    241 
    242 
    243   // We can't always tell from the message ID if rewriting is needed. Therefore,
    244   // scan any message types that might contain a handle. If we later determine
    245   // that there are no handles, we can cancel the rewriting by clearing the
    246   // results.new_msg pointer.
    247   ScanningResults results;
    248   switch (msg.type()) {
    249     CASE_FOR_MESSAGE(PpapiMsg_CreateNaClChannel)
    250     CASE_FOR_MESSAGE(PpapiMsg_PPBAudio_NotifyAudioStreamCreated)
    251     CASE_FOR_MESSAGE(PpapiMsg_PPPMessaging_HandleMessage)
    252     CASE_FOR_MESSAGE(PpapiPluginMsg_ResourceReply)
    253     case IPC_REPLY_ID: {
    254       int id = IPC::SyncMessage::GetMessageId(msg);
    255       PendingSyncMsgMap::iterator iter(pending_sync_msgs_.find(id));
    256       if (iter == pending_sync_msgs_.end()) {
    257         NOTREACHED();
    258         return false;
    259       }
    260       uint32_t type = iter->second;
    261       pending_sync_msgs_.erase(iter);
    262       switch (type) {
    263         CASE_FOR_REPLY(PpapiHostMsg_PPBGraphics3D_GetTransferBuffer)
    264         CASE_FOR_REPLY(PpapiHostMsg_PPBImageData_CreateSimple)
    265         CASE_FOR_REPLY(PpapiHostMsg_ResourceSyncCall)
    266         CASE_FOR_REPLY(PpapiHostMsg_SharedMemory_CreateSharedMemory)
    267         default:
    268           // Do nothing for messages we don't know.
    269           break;
    270       }
    271       break;
    272     }
    273     default:
    274       // Do nothing for messages we don't know.
    275       break;
    276   }
    277 
    278   // Only messages containing handles need to be rewritten. If no handles are
    279   // found, don't return the rewritten message either. This must be changed if
    280   // we ever add new param types that also require rewriting.
    281   if (!results.handles.empty()) {
    282     handles->swap(results.handles);
    283     *new_msg_ptr = results.new_msg.Pass();
    284   }
    285   return true;
    286 }
    287 
    288 void NaClMessageScanner::RegisterSyncMessageForReply(const IPC::Message& msg) {
    289   DCHECK(msg.is_sync());
    290 
    291   int msg_id = IPC::SyncMessage::GetMessageId(msg);
    292   DCHECK(pending_sync_msgs_.find(msg_id) == pending_sync_msgs_.end());
    293 
    294   pending_sync_msgs_[msg_id] = msg.type();
    295 }
    296 
    297 }  // namespace proxy
    298 }  // namespace ppapi
    299