OLD | NEW |
| (Empty) |
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 | |
16 class NaClDescImcShm; | |
17 | |
18 namespace IPC { | |
19 class Message; | |
20 } | |
21 | |
22 namespace { | |
23 | |
24 void 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 | |
34 typedef 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. | |
39 void 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 | |
48 void HandleWriter(int* handle_index, | |
49 IPC::Message* m, | |
50 const ppapi::proxy::SerializedHandle& handle) { | |
51 WriteHandle((*handle_index)++, handle, m); | |
52 } | |
53 | |
54 void 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. | |
73 void 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. | |
100 template <class T> | |
101 void 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. | |
115 template <class A> | |
116 void 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 } | |
121 template <class A, class B> | |
122 void 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 } | |
128 template <class A, class B, class C> | |
129 void 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 } | |
136 template <class A, class B, class C, class D> | |
137 void 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 | |
146 template <class MessageType> | |
147 class 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 | |
201 namespace ppapi { | |
202 namespace proxy { | |
203 | |
204 class SerializedHandle; | |
205 | |
206 HandleConverter::HandleConverter() { | |
207 } | |
208 | |
209 bool 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(new IPC::Message(msg.routing_id(), msg.type())); | |
231 #else | |
232 // Even on POSIX, we have to rewrite messages to create channels, because | |
233 // these contain a handle with an invalid (place holder) descriptor. The | |
234 // message sending code sees this and doesn't pass the descriptor over | |
235 // correctly. | |
236 if (msg.type() == PpapiMsg_CreateNaClChannel::ID) | |
237 new_msg_ptr->reset(new IPC::Message(msg.routing_id(), msg.type())); | |
238 #endif | |
239 | |
240 switch (msg.type()) { | |
241 CASE_FOR_MESSAGE(PpapiMsg_CreateNaClChannel) | |
242 CASE_FOR_MESSAGE(PpapiMsg_PPBAudio_NotifyAudioStreamCreated) | |
243 CASE_FOR_MESSAGE(PpapiMsg_PPPMessaging_HandleMessage) | |
244 CASE_FOR_MESSAGE(PpapiPluginMsg_ResourceReply) | |
245 case IPC_REPLY_ID: { | |
246 int id = IPC::SyncMessage::GetMessageId(msg); | |
247 PendingSyncMsgMap::iterator iter(pending_sync_msgs_.find(id)); | |
248 if (iter == pending_sync_msgs_.end()) { | |
249 NOTREACHED(); | |
250 return false; | |
251 } | |
252 uint32_t type = iter->second; | |
253 pending_sync_msgs_.erase(iter); | |
254 switch (type) { | |
255 CASE_FOR_REPLY(PpapiHostMsg_PPBGraphics3D_GetTransferBuffer) | |
256 CASE_FOR_REPLY(PpapiHostMsg_PPBImageData_CreateSimple) | |
257 CASE_FOR_REPLY(PpapiHostMsg_ResourceSyncCall) | |
258 CASE_FOR_REPLY(PpapiHostMsg_SharedMemory_CreateSharedMemory) | |
259 default: | |
260 // Do nothing for messages we don't know. | |
261 break; | |
262 } | |
263 break; | |
264 } | |
265 default: | |
266 // Do nothing for messages we don't know. | |
267 break; | |
268 } | |
269 return true; | |
270 } | |
271 | |
272 void HandleConverter::RegisterSyncMessageForReply(const IPC::Message& msg) { | |
273 DCHECK(msg.is_sync()); | |
274 | |
275 int msg_id = IPC::SyncMessage::GetMessageId(msg); | |
276 DCHECK(pending_sync_msgs_.find(msg_id) == pending_sync_msgs_.end()); | |
277 | |
278 pending_sync_msgs_[msg_id] = msg.type(); | |
279 } | |
280 | |
281 } // namespace proxy | |
282 } // namespace ppapi | |
OLD | NEW |