1// Copyright (c) 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/handle_converter.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 16class NaClDescImcShm; 17 18namespace IPC { 19class Message; 20} 21 22namespace { 23 24void WriteHandle(int handle_index, 25 const ppapi::proxy::SerializedHandle& handle, 26 IPC::Message* message) { 27 ppapi::proxy::SerializedHandle::WriteHeader(handle.header(), message); 28 29 // Now write the handle itself in POSIX style. 30 message->WriteBool(true); // valid == true 31 message->WriteInt(handle_index); 32} 33 34typedef std::vector<ppapi::proxy::SerializedHandle> Handles; 35 36// We define overloads for catching SerializedHandles so that we can share 37// them correctly to the untrusted side. 38// See ConvertHandlesImpl for how these get used. 39void ConvertHandlesInParam(const ppapi::proxy::SerializedHandle& handle, 40 Handles* handles, 41 IPC::Message* msg, 42 int* handle_index) { 43 handles->push_back(handle); 44 if (msg) 45 WriteHandle((*handle_index)++, handle, msg); 46} 47 48void HandleWriter(int* handle_index, 49 IPC::Message* m, 50 const ppapi::proxy::SerializedHandle& handle) { 51 WriteHandle((*handle_index)++, handle, m); 52} 53 54void ConvertHandlesInParam(const ppapi::proxy::SerializedVar& var, 55 Handles* handles, 56 IPC::Message* msg, 57 int* handle_index) { 58 std::vector<ppapi::proxy::SerializedHandle*> var_handles = var.GetHandles(); 59 if (var_handles.empty()) 60 return; 61 62 for (size_t i = 0; i < var_handles.size(); ++i) 63 handles->push_back(*var_handles[i]); 64 if (msg) 65 var.WriteDataToMessage(msg, base::Bind(&HandleWriter, handle_index)); 66} 67 68// For PpapiMsg_ResourceReply and the reply to PpapiHostMsg_ResourceSyncCall, 69// the handles are carried inside the ResourceMessageReplyParams. 70// NOTE: We only translate handles from host->NaCl. The only kind of 71// ResourceMessageParams that travels this direction is 72// ResourceMessageReplyParams, so that's the only one we need to handle. 73void ConvertHandlesInParam( 74 const ppapi::proxy::ResourceMessageReplyParams& params, 75 Handles* handles, 76 IPC::Message* msg, 77 int* handle_index) { 78 // First, if we need to rewrite the message parameters, write everything 79 // before the handles (there's nothing after the handles). 80 if (msg) { 81 params.WriteReplyHeader(msg); 82 // IPC writes the vector length as an int before the contents of the 83 // vector. 84 msg->WriteInt(static_cast<int>(params.handles().size())); 85 } 86 for (Handles::const_iterator iter = params.handles().begin(); 87 iter != params.handles().end(); 88 ++iter) { 89 // ConvertHandle will write each handle to |msg|, if necessary. 90 ConvertHandlesInParam(*iter, handles, msg, handle_index); 91 } 92 // Tell ResourceMessageReplyParams that we have taken the handles, so it 93 // shouldn't close them. The NaCl runtime will take ownership of them. 94 params.ConsumeHandles(); 95} 96 97// This overload is to catch all types other than SerializedHandle or 98// ResourceMessageReplyParams. On Windows, |msg| will be a valid pointer, and we 99// must write |param| to it. 100template <class T> 101void ConvertHandlesInParam(const T& param, 102 Handles* /* handles */, 103 IPC::Message* msg, 104 int* /* handle_index */) { 105 // It's not a handle, so just write to the output message, if necessary. 106 if (msg) 107 IPC::WriteParam(msg, param); 108} 109 110// These just break apart the given tuple and run ConvertHandle over each param. 111// The idea is to extract any handles in the tuple, while writing all data to 112// msg (if msg is valid). The msg will only be valid on Windows, where we need 113// to re-write all of the message parameters, writing the handles in POSIX style 114// for NaCl. 115template <class A> 116void ConvertHandlesImpl(const Tuple1<A>& t1, Handles* handles, 117 IPC::Message* msg) { 118 int handle_index = 0; 119 ConvertHandlesInParam(t1.a, handles, msg, &handle_index); 120} 121template <class A, class B> 122void ConvertHandlesImpl(const Tuple2<A, B>& t1, Handles* handles, 123 IPC::Message* msg) { 124 int handle_index = 0; 125 ConvertHandlesInParam(t1.a, handles, msg, &handle_index); 126 ConvertHandlesInParam(t1.b, handles, msg, &handle_index); 127} 128template <class A, class B, class C> 129void ConvertHandlesImpl(const Tuple3<A, B, C>& t1, Handles* handles, 130 IPC::Message* msg) { 131 int handle_index = 0; 132 ConvertHandlesInParam(t1.a, handles, msg, &handle_index); 133 ConvertHandlesInParam(t1.b, handles, msg, &handle_index); 134 ConvertHandlesInParam(t1.c, handles, msg, &handle_index); 135} 136template <class A, class B, class C, class D> 137void ConvertHandlesImpl(const Tuple4<A, B, C, D>& t1, Handles* handles, 138 IPC::Message* msg) { 139 int handle_index = 0; 140 ConvertHandlesInParam(t1.a, handles, msg, &handle_index); 141 ConvertHandlesInParam(t1.b, handles, msg, &handle_index); 142 ConvertHandlesInParam(t1.c, handles, msg, &handle_index); 143 ConvertHandlesInParam(t1.d, handles, msg, &handle_index); 144} 145 146template <class MessageType> 147class HandleConverterImpl { 148 public: 149 explicit HandleConverterImpl(const IPC::Message* msg) 150 : msg_(static_cast<const MessageType*>(msg)) { 151 } 152 bool ConvertMessage(Handles* handles, IPC::Message* out_msg) { 153 typename TupleTypes<typename MessageType::Schema::Param>::ValueTuple params; 154 if (!MessageType::Read(msg_, ¶ms)) 155 return false; 156 ConvertHandlesImpl(params, handles, out_msg); 157 return true; 158 } 159 160 bool ConvertReply(Handles* handles, IPC::SyncMessage* out_msg) { 161 typename TupleTypes<typename MessageType::Schema::ReplyParam>::ValueTuple 162 params; 163 if (!MessageType::ReadReplyParam(msg_, ¶ms)) 164 return false; 165 // If we need to rewrite the message (i.e., on Windows), we need to make 166 // sure we write the message id first. 167 if (out_msg) { 168 out_msg->set_reply(); 169 int id = IPC::SyncMessage::GetMessageId(*msg_); 170 out_msg->WriteInt(id); 171 } 172 ConvertHandlesImpl(params, handles, out_msg); 173 return true; 174 } 175 // TODO(dmichael): Add ConvertSyncMessage for outgoing sync messages, if we 176 // ever pass handles in one of those. 177 178 private: 179 const MessageType* msg_; 180}; 181 182} // namespace 183 184#define CASE_FOR_MESSAGE(MESSAGE_TYPE) \ 185 case MESSAGE_TYPE::ID: { \ 186 HandleConverterImpl<MESSAGE_TYPE> extractor(&msg); \ 187 if (!extractor.ConvertMessage(handles, new_msg_ptr->get())) \ 188 return false; \ 189 break; \ 190 } 191#define CASE_FOR_REPLY(MESSAGE_TYPE) \ 192 case MESSAGE_TYPE::ID: { \ 193 HandleConverterImpl<MESSAGE_TYPE> extractor(&msg); \ 194 if (!extractor.ConvertReply( \ 195 handles, \ 196 static_cast<IPC::SyncMessage*>(new_msg_ptr->get()))) \ 197 return false; \ 198 break; \ 199 } 200 201namespace ppapi { 202namespace proxy { 203 204class SerializedHandle; 205 206HandleConverter::HandleConverter() { 207} 208 209bool HandleConverter::ConvertNativeHandlesToPosix( 210 const IPC::Message& msg, 211 std::vector<SerializedHandle>* handles, 212 scoped_ptr<IPC::Message>* new_msg_ptr) { 213 DCHECK(handles); 214 DCHECK(new_msg_ptr); 215 DCHECK(!new_msg_ptr->get()); 216 217 // In Windows, we need to re-write the contents of the message. This is 218 // because in Windows IPC code, native HANDLE values are serialized in the 219 // body of the message. 220 // 221 // In POSIX, we only serialize an index in to a FileDescriptorSet, and the 222 // actual file descriptors are sent out-of-band. So on Windows, to make a 223 // message that's compatible with Windows, we need to write a new message that 224 // has simple indices in the message body instead of the HANDLEs. 225 // 226 // NOTE: This means on Windows, new_msg_ptr's serialized contents are not 227 // compatible with Windows IPC deserialization code; it is intended to be 228 // passed to NaCl. 229#if defined(OS_WIN) 230 new_msg_ptr->reset( 231 new IPC::Message(msg.routing_id(), msg.type(), msg.priority())); 232#else 233 // Even on POSIX, we have to rewrite messages to create channels, because 234 // these contain a handle with an invalid (place holder) descriptor. The 235 // message sending code sees this and doesn't pass the descriptor over 236 // correctly. 237 if (msg.type() == PpapiMsg_CreateNaClChannel::ID) { 238 new_msg_ptr->reset( 239 new IPC::Message(msg.routing_id(), msg.type(), msg.priority())); 240 } 241#endif 242 243 switch (msg.type()) { 244 CASE_FOR_MESSAGE(PpapiMsg_CreateNaClChannel) 245 CASE_FOR_MESSAGE(PpapiMsg_PPBAudio_NotifyAudioStreamCreated) 246 CASE_FOR_MESSAGE(PpapiMsg_PPPMessaging_HandleMessage) 247 CASE_FOR_MESSAGE(PpapiPluginMsg_ResourceReply) 248 case IPC_REPLY_ID: { 249 int id = IPC::SyncMessage::GetMessageId(msg); 250 PendingSyncMsgMap::iterator iter(pending_sync_msgs_.find(id)); 251 if (iter == pending_sync_msgs_.end()) { 252 NOTREACHED(); 253 return false; 254 } 255 uint32_t type = iter->second; 256 pending_sync_msgs_.erase(iter); 257 switch (type) { 258 CASE_FOR_REPLY(PpapiHostMsg_PPBGraphics3D_GetTransferBuffer) 259 CASE_FOR_REPLY(PpapiHostMsg_PPBImageData_CreateSimple) 260 CASE_FOR_REPLY(PpapiHostMsg_ResourceSyncCall) 261 CASE_FOR_REPLY(PpapiHostMsg_SharedMemory_CreateSharedMemory) 262 default: 263 // Do nothing for messages we don't know. 264 break; 265 } 266 break; 267 } 268 default: 269 // Do nothing for messages we don't know. 270 break; 271 } 272 return true; 273} 274 275void HandleConverter::RegisterSyncMessageForReply(const IPC::Message& msg) { 276 DCHECK(msg.is_sync()); 277 278 int msg_id = IPC::SyncMessage::GetMessageId(msg); 279 DCHECK(pending_sync_msgs_.find(msg_id) == pending_sync_msgs_.end()); 280 281 pending_sync_msgs_[msg_id] = msg.type(); 282} 283 284} // namespace proxy 285} // namespace ppapi 286