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_, ¶ms)) 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_, ¶ms)) 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