blob: 602b18e3a932ba6022e8f1d5e66f91d0cd4a61eb [file] [log] [blame]
[email protected]6276b492013-11-02 13:38:311// 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
16class NaClDescImcShm;
17
18namespace IPC {
19class Message;
20}
21
22namespace {
23
24typedef std::vector<ppapi::proxy::SerializedHandle> Handles;
25
26struct 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
[email protected]e74d2d12013-11-02 16:17:3735 // 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.)
[email protected]6276b492013-11-02 13:38:3138 scoped_ptr<IPC::Message> new_msg;
39};
40
41void 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.
55void 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
62void 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.
69void ScanParam(const ppapi::proxy::SerializedVar& var,
70 ScanningResults* results) {
71 std::vector<ppapi::proxy::SerializedHandle*> var_handles = var.GetHandles();
[email protected]e74d2d12013-11-02 16:17:3772 // Copy any handles and then rewrite the message.
[email protected]6276b492013-11-02 13:38:3173 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.
85void ScanParam(const ppapi::proxy::ResourceMessageReplyParams& params,
86 ScanningResults* results) {
[email protected]e74d2d12013-11-02 16:17:3787 // 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
[email protected]6276b492013-11-02 13:38:3196 // 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.
117template <class T>
118void 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.
126template <class A>
127void ScanTuple(const Tuple1<A>& t1, ScanningResults* results) {
128 ScanParam(t1.a, results);
129}
130template <class A, class B>
131void ScanTuple(const Tuple2<A, B>& t1, ScanningResults* results) {
132 ScanParam(t1.a, results);
133 ScanParam(t1.b, results);
134}
135template <class A, class B, class C>
136void 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}
141template <class A, class B, class C, class D>
142void 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
149template <class MessageType>
150class 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( \
[email protected]753bb252013-11-04 22:28:12191 new IPC::Message(msg.routing_id(), msg.type(), \
192 IPC::Message::PRIORITY_NORMAL)); \
[email protected]6276b492013-11-02 13:38:31193 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( \
[email protected]753bb252013-11-04 22:28:12202 new IPC::Message(msg.routing_id(), msg.type(), \
203 IPC::Message::PRIORITY_NORMAL)); \
[email protected]6276b492013-11-02 13:38:31204 if (!scanner.ScanReply(&results)) \
205 return false; \
206 break; \
207 }
208
209namespace ppapi {
210namespace proxy {
211
212class SerializedHandle;
213
214NaClMessageScanner::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.
226bool 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
[email protected]e74d2d12013-11-02 16:17:37242
[email protected]6276b492013-11-02 13:38:31243 // We can't always tell from the message ID if rewriting is needed. Therefore,
[email protected]e74d2d12013-11-02 16:17:37244 // 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.
[email protected]6276b492013-11-02 13:38:31247 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
[email protected]c586216c2013-12-18 21:59:17288void NaClMessageScanner::ScanUntrustedMessage(
289 const IPC::Message& untrusted_msg,
290 scoped_ptr<IPC::Message>* new_msg_ptr) {
291 if (untrusted_msg.is_sync())
292 RegisterSyncMessageForReply(untrusted_msg);
293 // TODO(bbudge) Add message auditing for FileSystem and FileIO resources when
294 // we implement Write on the plugin side of the proxy. See crbug.com/194304.
295}
[email protected]6276b492013-11-02 13:38:31296
[email protected]c586216c2013-12-18 21:59:17297void NaClMessageScanner::RegisterSyncMessageForReply(const IPC::Message& msg) {
[email protected]6276b492013-11-02 13:38:31298 int msg_id = IPC::SyncMessage::GetMessageId(msg);
299 DCHECK(pending_sync_msgs_.find(msg_id) == pending_sync_msgs_.end());
300
301 pending_sync_msgs_[msg_id] = msg.type();
302}
303
304} // namespace proxy
305} // namespace ppapi