blob: 4fae6974ee67dc3b3e51b07777d645f07a697bd6 [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
avie029c4132015-12-23 06:45:227#include <stddef.h>
8
tzika0f614d2016-03-08 00:35:159#include <tuple>
dchengd2b9f612015-12-18 19:08:5110#include <utility>
[email protected]6276b492013-11-02 13:38:3111#include <vector>
dchengd2b9f612015-12-18 19:08:5112
[email protected]6276b492013-11-02 13:38:3113#include "base/bind.h"
avie029c4132015-12-23 06:45:2214#include "build/build_config.h"
[email protected]6276b492013-11-02 13:38:3115#include "ipc/ipc_message.h"
16#include "ipc/ipc_message_macros.h"
17#include "ppapi/proxy/ppapi_messages.h"
18#include "ppapi/proxy/resource_message_params.h"
19#include "ppapi/proxy/serialized_handle.h"
20#include "ppapi/proxy/serialized_var.h"
21
22class NaClDescImcShm;
23
24namespace IPC {
25class Message;
26}
27
[email protected]7a90b852013-12-28 17:54:2728using ppapi::proxy::ResourceMessageReplyParams;
29using ppapi::proxy::SerializedHandle;
30using ppapi::proxy::SerializedVar;
31
[email protected]6276b492013-11-02 13:38:3132namespace {
33
[email protected]7a90b852013-12-28 17:54:2734typedef std::vector<SerializedHandle> Handles;
[email protected]6276b492013-11-02 13:38:3135
36struct ScanningResults {
[email protected]7a90b852013-12-28 17:54:2737 ScanningResults() : handle_index(0), pp_resource(0) {}
[email protected]6276b492013-11-02 13:38:3138
39 // Vector to hold handles found in the message.
40 Handles handles;
41 // Current handle index in the rewritten message. During the scan, it will be
42 // be less than or equal to handles.size(). After the scan it should be equal.
43 int handle_index;
44 // The rewritten message. This may be NULL, so all ScanParam overloads should
[email protected]e74d2d12013-11-02 16:17:3745 // check for NULL before writing to it. In some cases, a ScanParam overload
46 // may set this to NULL when it can determine that there are no parameters
47 // that need conversion. (See the ResourceMessageReplyParams overload.)
dchengced92242016-04-07 00:00:1248 std::unique_ptr<IPC::Message> new_msg;
[email protected]7a90b852013-12-28 17:54:2749 // Resource id for resource messages. Save this when scanning resource replies
50 // so when we audit the nested message, we know which resource it is for.
51 PP_Resource pp_resource;
52 // Callback to receive the nested message in a resource message or reply.
53 base::Callback<void(PP_Resource, const IPC::Message&, SerializedHandle*)>
54 nested_msg_callback;
[email protected]6276b492013-11-02 13:38:3155};
56
57void WriteHandle(int handle_index,
[email protected]7a90b852013-12-28 17:54:2758 const SerializedHandle& handle,
rockot502c94f2016-02-03 20:20:1659 base::Pickle* msg) {
[email protected]7a90b852013-12-28 17:54:2760 SerializedHandle::WriteHeader(handle.header(), msg);
[email protected]6276b492013-11-02 13:38:3161
erikchen14525202017-05-06 19:16:5162 if (handle.type() == SerializedHandle::SHARED_MEMORY) {
Justin TerAvestcffdd032014-09-10 19:21:5663 // Now write the handle itself in POSIX style.
erikchen14525202017-05-06 19:16:5164 // This serialization must be kept in sync with
Alexandr Ilinebab9da2018-06-01 02:37:4765 // ParamTraits<SharedMemoryHandle>::Write.
erikchen14525202017-05-06 19:16:5166 if (handle.shmem().IsValid()) {
67 msg->WriteBool(true); // valid == true
68 msg->WriteInt(handle_index);
Alexandr Ilinebab9da2018-06-01 02:37:4769 IPC::WriteParam(msg, handle.shmem().GetGUID());
erikchen9d6afd712017-05-18 17:49:0670 msg->WriteUInt64(handle.shmem().GetSize());
erikchen14525202017-05-06 19:16:5171 } else {
72 msg->WriteBool(false); // valid == false
73 }
Alexandr Ilinebab9da2018-06-01 02:37:4774 } else if (handle.type() == SerializedHandle::SHARED_MEMORY_REGION) {
75 // Write the region in POSIX style.
76 // This serialization must be kept in sync with
77 // ParamTraits<PlatformSharedMemoryRegion>::Write.
78 const auto& region = handle.shmem_region();
79 if (region.IsValid()) {
80 IPC::WriteParam(msg, true); // valid == true
81 IPC::WriteParam(msg, region.GetMode());
82 IPC::WriteParam(msg, static_cast<uint64_t>(region.GetSize()));
83 IPC::WriteParam(msg, region.GetGUID());
84 // Writable regions are not supported, so write only one handle index.
85 DCHECK_NE(region.GetMode(),
86 base::subtle::PlatformSharedMemoryRegion::Mode::kWritable);
87 IPC::WriteParam(msg, handle_index);
88 } else {
89 msg->WriteBool(false); // valid == false
90 }
erikchen14525202017-05-06 19:16:5191 } else if (handle.type() != SerializedHandle::INVALID) {
92 // Now write the handle itself in POSIX style.
93 // This serialization must be kept in sync with
94 // ParamTraits<FileDescriptor>::Write.
Justin TerAvestcffdd032014-09-10 19:21:5695 msg->WriteBool(true); // valid == true
96 msg->WriteInt(handle_index);
97 }
[email protected]6276b492013-11-02 13:38:3198}
99
100// Define overloads for each kind of message parameter that requires special
101// handling. See ScanTuple for how these get used.
102
103// Overload to match SerializedHandle.
Alexandr Ilin1d004102018-05-30 10:55:32104void ScanParam(SerializedHandle&& handle, ScanningResults* results) {
[email protected]6276b492013-11-02 13:38:31105 if (results->new_msg)
106 WriteHandle(results->handle_index++, handle, results->new_msg.get());
Alexandr Ilin1d004102018-05-30 10:55:32107 results->handles.push_back(std::move(handle));
[email protected]6276b492013-11-02 13:38:31108}
109
110void HandleWriter(int* handle_index,
rockot502c94f2016-02-03 20:20:16111 base::Pickle* m,
[email protected]7a90b852013-12-28 17:54:27112 const SerializedHandle& handle) {
[email protected]6276b492013-11-02 13:38:31113 WriteHandle((*handle_index)++, handle, m);
114}
115
116// Overload to match SerializedVar, which can contain handles.
Alexandr Ilin1d004102018-05-30 10:55:32117void ScanParam(SerializedVar&& var, ScanningResults* results) {
118 // Rewrite the message and then copy any handles.
[email protected]6276b492013-11-02 13:38:31119 if (results->new_msg)
120 var.WriteDataToMessage(results->new_msg.get(),
121 base::Bind(&HandleWriter, &results->handle_index));
Alexandr Ilin1d004102018-05-30 10:55:32122 for (SerializedHandle* var_handle : var.GetHandles())
123 results->handles.push_back(std::move(*var_handle));
[email protected]6276b492013-11-02 13:38:31124}
125
126// For PpapiMsg_ResourceReply and the reply to PpapiHostMsg_ResourceSyncCall,
127// the handles are carried inside the ResourceMessageReplyParams.
128// NOTE: We only intercept handles from host->NaCl. The only kind of
129// ResourceMessageParams that travels this direction is
130// ResourceMessageReplyParams, so that's the only one we need to handle.
Alexandr Ilin1d004102018-05-30 10:55:32131void ScanParam(ResourceMessageReplyParams&& params, ScanningResults* results) {
[email protected]7a90b852013-12-28 17:54:27132 results->pp_resource = params.pp_resource();
[email protected]e74d2d12013-11-02 16:17:37133 // If the resource reply params don't contain handles, NULL the new message
134 // pointer to cancel further rewriting.
135 // NOTE: This works because only handles currently need rewriting, and we
136 // know at this point that this message has none.
137 if (params.handles().empty()) {
138 results->new_msg.reset(NULL);
139 return;
140 }
141
[email protected]6276b492013-11-02 13:38:31142 // If we need to rewrite the message, write everything before the handles
143 // (there's nothing after the handles).
144 if (results->new_msg) {
145 params.WriteReplyHeader(results->new_msg.get());
146 // IPC writes the vector length as an int before the contents of the
147 // vector.
148 results->new_msg->WriteInt(static_cast<int>(params.handles().size()));
149 }
Alexandr Ilin1d004102018-05-30 10:55:32150 std::vector<SerializedHandle> handles;
151 params.TakeAllHandles(&handles);
152 for (SerializedHandle& handle : handles) {
[email protected]6276b492013-11-02 13:38:31153 // ScanParam will write each handle to the new message, if necessary.
Alexandr Ilin1d004102018-05-30 10:55:32154 ScanParam(std::move(handle), results);
[email protected]6276b492013-11-02 13:38:31155 }
[email protected]6276b492013-11-02 13:38:31156}
157
[email protected]7a90b852013-12-28 17:54:27158// Overload to match nested messages. If we need to rewrite the message, write
159// the parameter.
Alexandr Ilin1d004102018-05-30 10:55:32160void ScanParam(IPC::Message&& param, ScanningResults* results) {
[email protected]7a90b852013-12-28 17:54:27161 if (results->pp_resource && !results->nested_msg_callback.is_null()) {
162 SerializedHandle* handle = NULL;
163 if (results->handles.size() == 1)
164 handle = &results->handles[0];
165 results->nested_msg_callback.Run(results->pp_resource, param, handle);
166 }
167 if (results->new_msg)
168 IPC::WriteParam(results->new_msg.get(), param);
169}
170
mseaborn3bedcdc2016-01-04 21:14:13171template <class T>
Alexandr Ilin1d004102018-05-30 10:55:32172void ScanParam(std::vector<T>&& vec, ScanningResults* results) {
mseaborn3bedcdc2016-01-04 21:14:13173 if (results->new_msg)
174 IPC::WriteParam(results->new_msg.get(), static_cast<int>(vec.size()));
Alexandr Ilin1d004102018-05-30 10:55:32175 for (T& element : vec)
176 ScanParam(std::move(element), results);
mseaborn3bedcdc2016-01-04 21:14:13177}
178
[email protected]7a90b852013-12-28 17:54:27179// Overload to match all other types. If we need to rewrite the message, write
180// the parameter.
[email protected]6276b492013-11-02 13:38:31181template <class T>
Alexandr Ilin1d004102018-05-30 10:55:32182void ScanParam(T&& param, ScanningResults* results) {
[email protected]6276b492013-11-02 13:38:31183 if (results->new_msg)
184 IPC::WriteParam(results->new_msg.get(), param);
185}
186
187// These just break apart the given tuple and run ScanParam over each param.
188// The idea is to scan elements in the tuple which require special handling,
189// and write them into the |results| struct.
190template <class A>
Alexandr Ilin1d004102018-05-30 10:55:32191void ScanTuple(std::tuple<A>&& t1, ScanningResults* results) {
192 ScanParam(std::move(std::get<0>(t1)), results);
[email protected]6276b492013-11-02 13:38:31193}
194template <class A, class B>
Alexandr Ilin1d004102018-05-30 10:55:32195void ScanTuple(std::tuple<A, B>&& t1, ScanningResults* results) {
196 ScanParam(std::move(std::get<0>(t1)), results);
197 ScanParam(std::move(std::get<1>(t1)), results);
[email protected]6276b492013-11-02 13:38:31198}
199template <class A, class B, class C>
Alexandr Ilin1d004102018-05-30 10:55:32200void ScanTuple(std::tuple<A, B, C>&& t1, ScanningResults* results) {
201 ScanParam(std::move(std::get<0>(t1)), results);
202 ScanParam(std::move(std::get<1>(t1)), results);
203 ScanParam(std::move(std::get<2>(t1)), results);
[email protected]6276b492013-11-02 13:38:31204}
205template <class A, class B, class C, class D>
Alexandr Ilin1d004102018-05-30 10:55:32206void ScanTuple(std::tuple<A, B, C, D>&& t1, ScanningResults* results) {
207 ScanParam(std::move(std::get<0>(t1)), results);
208 ScanParam(std::move(std::get<1>(t1)), results);
209 ScanParam(std::move(std::get<2>(t1)), results);
210 ScanParam(std::move(std::get<3>(t1)), results);
[email protected]6276b492013-11-02 13:38:31211}
212
213template <class MessageType>
214class MessageScannerImpl {
215 public:
216 explicit MessageScannerImpl(const IPC::Message* msg)
krasin86a5a182016-02-23 09:59:09217 // The cast below is invalid. See https://crbug.com/520760.
[email protected]6276b492013-11-02 13:38:31218 : msg_(static_cast<const MessageType*>(msg)) {
219 }
220 bool ScanMessage(ScanningResults* results) {
mdempsky390ab1e2016-03-07 22:18:35221 typename MessageType::Param params;
[email protected]6276b492013-11-02 13:38:31222 if (!MessageType::Read(msg_, &params))
223 return false;
Alexandr Ilin1d004102018-05-30 10:55:32224 ScanTuple(std::move(params), results);
[email protected]6276b492013-11-02 13:38:31225 return true;
226 }
227
mseaborn3bedcdc2016-01-04 21:14:13228 bool ScanSyncMessage(ScanningResults* results) {
mdempsky390ab1e2016-03-07 22:18:35229 typename MessageType::SendParam params;
mseaborn3bedcdc2016-01-04 21:14:13230 if (!MessageType::ReadSendParam(msg_, &params))
231 return false;
232 // If we need to rewrite the message, write the message id first.
233 if (results->new_msg) {
234 results->new_msg->set_sync();
235 int id = IPC::SyncMessage::GetMessageId(*msg_);
236 results->new_msg->WriteInt(id);
237 }
Alexandr Ilin1d004102018-05-30 10:55:32238 ScanTuple(std::move(params), results);
mseaborn3bedcdc2016-01-04 21:14:13239 return true;
240 }
241
[email protected]6276b492013-11-02 13:38:31242 bool ScanReply(ScanningResults* results) {
mdempsky390ab1e2016-03-07 22:18:35243 typename MessageType::ReplyParam params;
[email protected]6276b492013-11-02 13:38:31244 if (!MessageType::ReadReplyParam(msg_, &params))
245 return false;
246 // If we need to rewrite the message, write the message id first.
247 if (results->new_msg) {
248 results->new_msg->set_reply();
249 int id = IPC::SyncMessage::GetMessageId(*msg_);
250 results->new_msg->WriteInt(id);
251 }
Alexandr Ilin1d004102018-05-30 10:55:32252 ScanTuple(std::move(params), results);
[email protected]6276b492013-11-02 13:38:31253 return true;
254 }
[email protected]6276b492013-11-02 13:38:31255
256 private:
257 const MessageType* msg_;
258};
259
260} // namespace
261
262#define CASE_FOR_MESSAGE(MESSAGE_TYPE) \
263 case MESSAGE_TYPE::ID: { \
264 MessageScannerImpl<MESSAGE_TYPE> scanner(&msg); \
265 if (rewrite_msg) \
266 results.new_msg.reset( \
[email protected]753bb252013-11-04 22:28:12267 new IPC::Message(msg.routing_id(), msg.type(), \
268 IPC::Message::PRIORITY_NORMAL)); \
[email protected]6276b492013-11-02 13:38:31269 if (!scanner.ScanMessage(&results)) \
270 return false; \
271 break; \
272 }
mseaborn3bedcdc2016-01-04 21:14:13273#define CASE_FOR_SYNC_MESSAGE(MESSAGE_TYPE) \
274 case MESSAGE_TYPE::ID: { \
275 MessageScannerImpl<MESSAGE_TYPE> scanner(&msg); \
276 if (rewrite_msg) \
277 results.new_msg.reset( \
278 new IPC::Message(msg.routing_id(), msg.type(), \
279 IPC::Message::PRIORITY_NORMAL)); \
280 if (!scanner.ScanSyncMessage(&results)) \
281 return false; \
282 break; \
283 }
[email protected]6276b492013-11-02 13:38:31284#define CASE_FOR_REPLY(MESSAGE_TYPE) \
285 case MESSAGE_TYPE::ID: { \
286 MessageScannerImpl<MESSAGE_TYPE> scanner(&msg); \
287 if (rewrite_msg) \
288 results.new_msg.reset( \
[email protected]753bb252013-11-04 22:28:12289 new IPC::Message(msg.routing_id(), msg.type(), \
290 IPC::Message::PRIORITY_NORMAL)); \
[email protected]6276b492013-11-02 13:38:31291 if (!scanner.ScanReply(&results)) \
292 return false; \
293 break; \
294 }
295
296namespace ppapi {
297namespace proxy {
298
299class SerializedHandle;
300
[email protected]7a90b852013-12-28 17:54:27301NaClMessageScanner::FileSystem::FileSystem()
302 : reserved_quota_(0) {
303}
304
305NaClMessageScanner::FileSystem::~FileSystem() {
306}
307
308bool NaClMessageScanner::FileSystem::UpdateReservedQuota(int64_t delta) {
309 base::AutoLock lock(lock_);
310 if (std::numeric_limits<int64_t>::max() - reserved_quota_ < delta)
311 return false; // reserved_quota_ + delta would overflow.
312 if (reserved_quota_ + delta < 0)
313 return false;
314 reserved_quota_ += delta;
315 return true;
316}
317
318NaClMessageScanner::FileIO::FileIO(FileSystem* file_system,
319 int64_t max_written_offset)
320 : file_system_(file_system),
321 max_written_offset_(max_written_offset) {
322}
323
324NaClMessageScanner::FileIO::~FileIO() {
325}
326
327void NaClMessageScanner::FileIO::SetMaxWrittenOffset(
328 int64_t max_written_offset) {
329 base::AutoLock lock(lock_);
330 max_written_offset_ = max_written_offset;
331}
332
333bool NaClMessageScanner::FileIO::Grow(int64_t amount) {
334 base::AutoLock lock(lock_);
335 DCHECK(amount > 0);
336 if (!file_system_->UpdateReservedQuota(-amount))
337 return false;
338 max_written_offset_ += amount;
339 return true;
340}
341
[email protected]6276b492013-11-02 13:38:31342NaClMessageScanner::NaClMessageScanner() {
343}
344
[email protected]7a90b852013-12-28 17:54:27345NaClMessageScanner::~NaClMessageScanner() {
346 for (FileSystemMap::iterator it = file_systems_.begin();
347 it != file_systems_.end(); ++it)
348 delete it->second;
349 for (FileIOMap::iterator it = files_.begin(); it != files_.end(); ++it)
350 delete it->second;
351}
352
[email protected]6276b492013-11-02 13:38:31353// Windows IPC differs from POSIX in that native handles are serialized in the
354// message body, rather than passed in a separate FileDescriptorSet. Therefore,
355// on Windows, any message containing handles must be rewritten in the POSIX
356// format before we can send it to the NaCl plugin.
scottmgd19b4f72015-06-19 22:51:00357// On Mac, base::SharedMemoryHandle has a different serialization than
358// base::FileDescriptor (which base::SharedMemoryHandle is typedef-ed to in
359// OS_NACL).
[email protected]6276b492013-11-02 13:38:31360bool NaClMessageScanner::ScanMessage(
361 const IPC::Message& msg,
[email protected]c8f326a2014-08-21 23:19:07362 uint32_t type,
[email protected]6276b492013-11-02 13:38:31363 std::vector<SerializedHandle>* handles,
dchengced92242016-04-07 00:00:12364 std::unique_ptr<IPC::Message>* new_msg_ptr) {
[email protected]6276b492013-11-02 13:38:31365 DCHECK(handles);
366 DCHECK(handles->empty());
367 DCHECK(new_msg_ptr);
368 DCHECK(!new_msg_ptr->get());
369
370 bool rewrite_msg =
scottmgd19b4f72015-06-19 22:51:00371#if defined(OS_WIN) || defined(OS_MACOSX)
[email protected]6276b492013-11-02 13:38:31372 true;
373#else
[email protected]73af6332014-02-06 23:28:10374 false;
[email protected]6276b492013-11-02 13:38:31375#endif
376
377 // We can't always tell from the message ID if rewriting is needed. Therefore,
[email protected]e74d2d12013-11-02 16:17:37378 // scan any message types that might contain a handle. If we later determine
379 // that there are no handles, we can cancel the rewriting by clearing the
380 // results.new_msg pointer.
[email protected]6276b492013-11-02 13:38:31381 ScanningResults results;
[email protected]7a90b852013-12-28 17:54:27382 results.nested_msg_callback =
383 base::Bind(&NaClMessageScanner::AuditNestedMessage,
384 base::Unretained(this));
[email protected]c8f326a2014-08-21 23:19:07385 switch (type) {
[email protected]6276b492013-11-02 13:38:31386 CASE_FOR_MESSAGE(PpapiMsg_PPBAudio_NotifyAudioStreamCreated)
387 CASE_FOR_MESSAGE(PpapiMsg_PPPMessaging_HandleMessage)
388 CASE_FOR_MESSAGE(PpapiPluginMsg_ResourceReply)
dmichael822ba8f2016-01-11 17:54:52389 CASE_FOR_SYNC_MESSAGE(PpapiMsg_PPPMessageHandler_HandleBlockingMessage)
mseaborn98d206ca2016-01-08 11:43:28390 CASE_FOR_SYNC_MESSAGE(PpapiMsg_PnaclTranslatorCompileInit)
mseaborn3bedcdc2016-01-04 21:14:13391 CASE_FOR_SYNC_MESSAGE(PpapiMsg_PnaclTranslatorLink)
Justin TerAvestcffdd032014-09-10 19:21:56392 CASE_FOR_REPLY(PpapiHostMsg_OpenResource)
penghuanga206fb492014-09-09 21:27:32393 CASE_FOR_REPLY(PpapiHostMsg_PPBGraphics3D_Create)
[email protected]c8f326a2014-08-21 23:19:07394 CASE_FOR_REPLY(PpapiHostMsg_PPBGraphics3D_CreateTransferBuffer)
395 CASE_FOR_REPLY(PpapiHostMsg_PPBImageData_CreateSimple)
396 CASE_FOR_REPLY(PpapiHostMsg_ResourceSyncCall)
397 CASE_FOR_REPLY(PpapiHostMsg_SharedMemory_CreateSharedMemory)
[email protected]6276b492013-11-02 13:38:31398 default:
399 // Do nothing for messages we don't know.
400 break;
401 }
402
403 // Only messages containing handles need to be rewritten. If no handles are
404 // found, don't return the rewritten message either. This must be changed if
405 // we ever add new param types that also require rewriting.
406 if (!results.handles.empty()) {
407 handles->swap(results.handles);
dchengd2b9f612015-12-18 19:08:51408 *new_msg_ptr = std::move(results.new_msg);
[email protected]6276b492013-11-02 13:38:31409 }
410 return true;
411}
412
[email protected]c586216c2013-12-18 21:59:17413void NaClMessageScanner::ScanUntrustedMessage(
414 const IPC::Message& untrusted_msg,
dchengced92242016-04-07 00:00:12415 std::unique_ptr<IPC::Message>* new_msg_ptr) {
[email protected]7a90b852013-12-28 17:54:27416 // Audit FileIO and FileSystem messages to ensure that the plugin doesn't
417 // exceed its file quota. If we find the message is malformed, just pass it
418 // through - we only care about well formed messages to the host.
419 if (untrusted_msg.type() == PpapiHostMsg_ResourceCall::ID) {
420 ResourceMessageCallParams params;
421 IPC::Message nested_msg;
422 if (!UnpackMessage<PpapiHostMsg_ResourceCall>(
423 untrusted_msg, &params, &nested_msg))
424 return;
425
426 switch (nested_msg.type()) {
427 case PpapiHostMsg_FileIO_Close::ID: {
428 FileIOMap::iterator it = files_.find(params.pp_resource());
429 if (it == files_.end())
430 return;
431 // Audit FileIO Close messages to make sure the plugin reports an
432 // accurate file size.
[email protected]540d6af42014-01-28 21:19:03433 FileGrowth file_growth;
[email protected]7a90b852013-12-28 17:54:27434 if (!UnpackMessage<PpapiHostMsg_FileIO_Close>(
[email protected]540d6af42014-01-28 21:19:03435 nested_msg, &file_growth))
[email protected]7a90b852013-12-28 17:54:27436 return;
437
438 int64_t trusted_max_written_offset = it->second->max_written_offset();
439 delete it->second;
440 files_.erase(it);
441 // If the plugin is under-reporting, rewrite the message with the
442 // trusted value.
[email protected]540d6af42014-01-28 21:19:03443 if (trusted_max_written_offset > file_growth.max_written_offset) {
[email protected]7a90b852013-12-28 17:54:27444 new_msg_ptr->reset(
445 new PpapiHostMsg_ResourceCall(
446 params,
[email protected]540d6af42014-01-28 21:19:03447 PpapiHostMsg_FileIO_Close(
448 FileGrowth(trusted_max_written_offset, 0))));
[email protected]7a90b852013-12-28 17:54:27449 }
[email protected]2d585cbd2014-06-03 02:13:22450 break;
[email protected]7a90b852013-12-28 17:54:27451 }
452 case PpapiHostMsg_FileIO_SetLength::ID: {
453 FileIOMap::iterator it = files_.find(params.pp_resource());
454 if (it == files_.end())
455 return;
456 // Audit FileIO SetLength messages to make sure the plugin is within
457 // the current quota reservation. In addition, deduct the file size
458 // increase from the quota reservation.
459 int64_t length = 0;
460 if (!UnpackMessage<PpapiHostMsg_FileIO_SetLength>(
461 nested_msg, &length))
462 return;
463
464 // Calculate file size increase, taking care to avoid overflows.
465 if (length < 0)
466 return;
467 int64_t trusted_max_written_offset = it->second->max_written_offset();
468 int64_t increase = length - trusted_max_written_offset;
469 if (increase <= 0)
470 return;
471 if (!it->second->Grow(increase)) {
472 new_msg_ptr->reset(
473 new PpapiHostMsg_ResourceCall(
474 params,
475 PpapiHostMsg_FileIO_SetLength(-1)));
476 }
477 break;
478 }
479 case PpapiHostMsg_FileSystem_ReserveQuota::ID: {
480 // Audit FileSystem ReserveQuota messages to make sure the plugin
481 // reports accurate file sizes.
482 int64_t amount = 0;
[email protected]540d6af42014-01-28 21:19:03483 FileGrowthMap file_growths;
[email protected]7a90b852013-12-28 17:54:27484 if (!UnpackMessage<PpapiHostMsg_FileSystem_ReserveQuota>(
[email protected]540d6af42014-01-28 21:19:03485 nested_msg, &amount, &file_growths))
[email protected]7a90b852013-12-28 17:54:27486 return;
487
488 bool audit_failed = false;
[email protected]540d6af42014-01-28 21:19:03489 for (FileGrowthMap::iterator it = file_growths.begin();
490 it != file_growths.end(); ++it) {
[email protected]7a90b852013-12-28 17:54:27491 FileIOMap::iterator file_it = files_.find(it->first);
492 if (file_it == files_.end())
493 continue;
494 int64_t trusted_max_written_offset =
495 file_it->second->max_written_offset();
[email protected]540d6af42014-01-28 21:19:03496 if (trusted_max_written_offset > it->second.max_written_offset) {
[email protected]7a90b852013-12-28 17:54:27497 audit_failed = true;
[email protected]540d6af42014-01-28 21:19:03498 it->second.max_written_offset = trusted_max_written_offset;
499 }
500 if (it->second.append_mode_write_amount < 0) {
501 audit_failed = true;
502 it->second.append_mode_write_amount = 0;
[email protected]7a90b852013-12-28 17:54:27503 }
504 }
505 if (audit_failed) {
506 new_msg_ptr->reset(
507 new PpapiHostMsg_ResourceCall(
508 params,
509 PpapiHostMsg_FileSystem_ReserveQuota(
[email protected]540d6af42014-01-28 21:19:03510 amount, file_growths)));
[email protected]7a90b852013-12-28 17:54:27511 }
512 break;
513 }
514 case PpapiHostMsg_ResourceDestroyed::ID: {
515 // Audit resource destroyed messages to release FileSystems.
516 PP_Resource resource;
517 if (!UnpackMessage<PpapiHostMsg_ResourceDestroyed>(
518 nested_msg, &resource))
519 return;
520 FileSystemMap::iterator fs_it = file_systems_.find(resource);
521 if (fs_it != file_systems_.end()) {
522 delete fs_it->second;
523 file_systems_.erase(fs_it);
524 }
[email protected]2d585cbd2014-06-03 02:13:22525 break;
[email protected]7a90b852013-12-28 17:54:27526 }
527 }
528 }
[email protected]c586216c2013-12-18 21:59:17529}
[email protected]6276b492013-11-02 13:38:31530
[email protected]7a90b852013-12-28 17:54:27531NaClMessageScanner::FileIO* NaClMessageScanner::GetFile(
532 PP_Resource file_io) {
533 FileIOMap::iterator it = files_.find(file_io);
534 DCHECK(it != files_.end());
535 return it->second;
536}
537
538void NaClMessageScanner::AuditNestedMessage(PP_Resource resource,
539 const IPC::Message& msg,
540 SerializedHandle* handle) {
541 switch (msg.type()) {
542 case PpapiPluginMsg_FileIO_OpenReply::ID: {
543 // A file that requires quota checking was opened.
544 PP_Resource quota_file_system;
545 int64_t max_written_offset = 0;
546 if (ppapi::UnpackMessage<PpapiPluginMsg_FileIO_OpenReply>(
547 msg, &quota_file_system, &max_written_offset)) {
548 if (quota_file_system) {
549 // Look up the FileSystem by inserting a new one. If it was already
550 // present, get the existing one, otherwise construct it.
551 FileSystem* file_system = NULL;
552 std::pair<FileSystemMap::iterator, bool> insert_result =
553 file_systems_.insert(std::make_pair(quota_file_system,
554 file_system));
555 if (insert_result.second)
556 insert_result.first->second = new FileSystem();
557 file_system = insert_result.first->second;
558 // Create the FileIO.
559 DCHECK(files_.find(resource) == files_.end());
560 files_.insert(std::make_pair(
561 resource,
562 new FileIO(file_system, max_written_offset)));
563 }
564 }
565 break;
566 }
567 case PpapiPluginMsg_FileSystem_ReserveQuotaReply::ID: {
568 // The amount of reserved quota for a FileSystem was refreshed.
569 int64_t amount = 0;
[email protected]540d6af42014-01-28 21:19:03570 FileSizeMap file_sizes;
[email protected]7a90b852013-12-28 17:54:27571 if (ppapi::UnpackMessage<PpapiPluginMsg_FileSystem_ReserveQuotaReply>(
[email protected]540d6af42014-01-28 21:19:03572 msg, &amount, &file_sizes)) {
[email protected]7a90b852013-12-28 17:54:27573 FileSystemMap::iterator it = file_systems_.find(resource);
574 DCHECK(it != file_systems_.end());
575 it->second->UpdateReservedQuota(amount);
576
[email protected]540d6af42014-01-28 21:19:03577 FileSizeMap::const_iterator offset_it = file_sizes.begin();
578 for (; offset_it != file_sizes.end(); ++offset_it) {
[email protected]7a90b852013-12-28 17:54:27579 FileIOMap::iterator fio_it = files_.find(offset_it->first);
580 DCHECK(fio_it != files_.end());
581 if (fio_it != files_.end())
582 fio_it->second->SetMaxWrittenOffset(offset_it->second);
583 }
584 }
585 break;
586 }
587 }
588}
589
[email protected]6276b492013-11-02 13:38:31590} // namespace proxy
591} // namespace ppapi