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