blob: c9801cc77c50395fde44a32996c667d52a059050 [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
Peter Boströmfb60ea02021-04-05 21:06:129#include <memory>
tzika0f614d2016-03-08 00:35:1510#include <tuple>
dchengd2b9f612015-12-18 19:08:5111#include <utility>
[email protected]6276b492013-11-02 13:38:3112#include <vector>
dchengd2b9f612015-12-18 19:08:5113
[email protected]6276b492013-11-02 13:38:3114#include "base/bind.h"
avie029c4132015-12-23 06:45:2215#include "build/build_config.h"
[email protected]6276b492013-11-02 13:38:3116#include "ipc/ipc_message.h"
17#include "ipc/ipc_message_macros.h"
18#include "ppapi/proxy/ppapi_messages.h"
19#include "ppapi/proxy/resource_message_params.h"
20#include "ppapi/proxy/serialized_handle.h"
21#include "ppapi/proxy/serialized_var.h"
22
23class NaClDescImcShm;
24
25namespace IPC {
26class Message;
27}
28
[email protected]7a90b852013-12-28 17:54:2729using ppapi::proxy::ResourceMessageReplyParams;
30using ppapi::proxy::SerializedHandle;
31using ppapi::proxy::SerializedVar;
32
[email protected]6276b492013-11-02 13:38:3133namespace {
34
[email protected]7a90b852013-12-28 17:54:2735typedef std::vector<SerializedHandle> Handles;
[email protected]6276b492013-11-02 13:38:3136
37struct ScanningResults {
[email protected]7a90b852013-12-28 17:54:2738 ScanningResults() : handle_index(0), pp_resource(0) {}
[email protected]6276b492013-11-02 13:38:3139
40 // Vector to hold handles found in the message.
41 Handles handles;
42 // Current handle index in the rewritten message. During the scan, it will be
43 // be less than or equal to handles.size(). After the scan it should be equal.
44 int handle_index;
45 // The rewritten message. This may be NULL, so all ScanParam overloads should
[email protected]e74d2d12013-11-02 16:17:3746 // check for NULL before writing to it. In some cases, a ScanParam overload
47 // may set this to NULL when it can determine that there are no parameters
48 // that need conversion. (See the ResourceMessageReplyParams overload.)
dchengced92242016-04-07 00:00:1249 std::unique_ptr<IPC::Message> new_msg;
[email protected]7a90b852013-12-28 17:54:2750 // Resource id for resource messages. Save this when scanning resource replies
51 // so when we audit the nested message, we know which resource it is for.
52 PP_Resource pp_resource;
53 // Callback to receive the nested message in a resource message or reply.
Anand K Mistry483007852021-03-18 22:54:4854 base::RepeatingCallback<
55 void(PP_Resource, const IPC::Message&, SerializedHandle*)>
[email protected]7a90b852013-12-28 17:54:2756 nested_msg_callback;
[email protected]6276b492013-11-02 13:38:3157};
58
59void WriteHandle(int handle_index,
[email protected]7a90b852013-12-28 17:54:2760 const SerializedHandle& handle,
rockot502c94f2016-02-03 20:20:1661 base::Pickle* msg) {
[email protected]7a90b852013-12-28 17:54:2762 SerializedHandle::WriteHeader(handle.header(), msg);
[email protected]6276b492013-11-02 13:38:3163
Matthew Cary36e2ec862019-08-07 23:58:5664 if (handle.type() == SerializedHandle::SHARED_MEMORY_REGION) {
Alexandr Ilinebab9da2018-06-01 02:37:4765 // Write the region in POSIX style.
66 // This serialization must be kept in sync with
67 // ParamTraits<PlatformSharedMemoryRegion>::Write.
68 const auto& region = handle.shmem_region();
69 if (region.IsValid()) {
70 IPC::WriteParam(msg, true); // valid == true
71 IPC::WriteParam(msg, region.GetMode());
72 IPC::WriteParam(msg, static_cast<uint64_t>(region.GetSize()));
73 IPC::WriteParam(msg, region.GetGUID());
74 // Writable regions are not supported, so write only one handle index.
75 DCHECK_NE(region.GetMode(),
76 base::subtle::PlatformSharedMemoryRegion::Mode::kWritable);
77 IPC::WriteParam(msg, handle_index);
78 } else {
79 msg->WriteBool(false); // valid == false
80 }
erikchen14525202017-05-06 19:16:5181 } else if (handle.type() != SerializedHandle::INVALID) {
82 // Now write the handle itself in POSIX style.
83 // This serialization must be kept in sync with
84 // ParamTraits<FileDescriptor>::Write.
Justin TerAvestcffdd032014-09-10 19:21:5685 msg->WriteBool(true); // valid == true
86 msg->WriteInt(handle_index);
87 }
[email protected]6276b492013-11-02 13:38:3188}
89
90// Define overloads for each kind of message parameter that requires special
91// handling. See ScanTuple for how these get used.
92
93// Overload to match SerializedHandle.
Alexandr Ilin1d004102018-05-30 10:55:3294void ScanParam(SerializedHandle&& handle, ScanningResults* results) {
[email protected]6276b492013-11-02 13:38:3195 if (results->new_msg)
96 WriteHandle(results->handle_index++, handle, results->new_msg.get());
Alexandr Ilin1d004102018-05-30 10:55:3297 results->handles.push_back(std::move(handle));
[email protected]6276b492013-11-02 13:38:3198}
99
100void HandleWriter(int* handle_index,
rockot502c94f2016-02-03 20:20:16101 base::Pickle* m,
[email protected]7a90b852013-12-28 17:54:27102 const SerializedHandle& handle) {
[email protected]6276b492013-11-02 13:38:31103 WriteHandle((*handle_index)++, handle, m);
104}
105
106// Overload to match SerializedVar, which can contain handles.
Alexandr Ilin1d004102018-05-30 10:55:32107void ScanParam(SerializedVar&& var, ScanningResults* results) {
108 // Rewrite the message and then copy any handles.
[email protected]6276b492013-11-02 13:38:31109 if (results->new_msg)
Anand K Mistry483007852021-03-18 22:54:48110 var.WriteDataToMessage(
111 results->new_msg.get(),
112 base::BindRepeating(&HandleWriter, &results->handle_index));
Alexandr Ilin1d004102018-05-30 10:55:32113 for (SerializedHandle* var_handle : var.GetHandles())
114 results->handles.push_back(std::move(*var_handle));
[email protected]6276b492013-11-02 13:38:31115}
116
117// For PpapiMsg_ResourceReply and the reply to PpapiHostMsg_ResourceSyncCall,
118// the handles are carried inside the ResourceMessageReplyParams.
119// NOTE: We only intercept handles from host->NaCl. The only kind of
120// ResourceMessageParams that travels this direction is
121// ResourceMessageReplyParams, so that's the only one we need to handle.
Alexandr Ilin1d004102018-05-30 10:55:32122void ScanParam(ResourceMessageReplyParams&& params, ScanningResults* results) {
[email protected]7a90b852013-12-28 17:54:27123 results->pp_resource = params.pp_resource();
[email protected]e74d2d12013-11-02 16:17:37124 // If the resource reply params don't contain handles, NULL the new message
125 // pointer to cancel further rewriting.
126 // NOTE: This works because only handles currently need rewriting, and we
127 // know at this point that this message has none.
128 if (params.handles().empty()) {
129 results->new_msg.reset(NULL);
130 return;
131 }
132
[email protected]6276b492013-11-02 13:38:31133 // If we need to rewrite the message, write everything before the handles
134 // (there's nothing after the handles).
135 if (results->new_msg) {
136 params.WriteReplyHeader(results->new_msg.get());
137 // IPC writes the vector length as an int before the contents of the
138 // vector.
139 results->new_msg->WriteInt(static_cast<int>(params.handles().size()));
140 }
Alexandr Ilin1d004102018-05-30 10:55:32141 std::vector<SerializedHandle> handles;
142 params.TakeAllHandles(&handles);
143 for (SerializedHandle& handle : handles) {
[email protected]6276b492013-11-02 13:38:31144 // ScanParam will write each handle to the new message, if necessary.
Alexandr Ilin1d004102018-05-30 10:55:32145 ScanParam(std::move(handle), results);
[email protected]6276b492013-11-02 13:38:31146 }
[email protected]6276b492013-11-02 13:38:31147}
148
[email protected]7a90b852013-12-28 17:54:27149// Overload to match nested messages. If we need to rewrite the message, write
150// the parameter.
Alexandr Ilin1d004102018-05-30 10:55:32151void ScanParam(IPC::Message&& param, ScanningResults* results) {
[email protected]7a90b852013-12-28 17:54:27152 if (results->pp_resource && !results->nested_msg_callback.is_null()) {
153 SerializedHandle* handle = NULL;
154 if (results->handles.size() == 1)
155 handle = &results->handles[0];
156 results->nested_msg_callback.Run(results->pp_resource, param, handle);
157 }
158 if (results->new_msg)
159 IPC::WriteParam(results->new_msg.get(), param);
160}
161
mseaborn3bedcdc2016-01-04 21:14:13162template <class T>
Alexandr Ilin1d004102018-05-30 10:55:32163void ScanParam(std::vector<T>&& vec, ScanningResults* results) {
mseaborn3bedcdc2016-01-04 21:14:13164 if (results->new_msg)
165 IPC::WriteParam(results->new_msg.get(), static_cast<int>(vec.size()));
Alexandr Ilin1d004102018-05-30 10:55:32166 for (T& element : vec)
167 ScanParam(std::move(element), results);
mseaborn3bedcdc2016-01-04 21:14:13168}
169
[email protected]7a90b852013-12-28 17:54:27170// Overload to match all other types. If we need to rewrite the message, write
171// the parameter.
[email protected]6276b492013-11-02 13:38:31172template <class T>
Alexandr Ilin1d004102018-05-30 10:55:32173void ScanParam(T&& param, ScanningResults* results) {
[email protected]6276b492013-11-02 13:38:31174 if (results->new_msg)
175 IPC::WriteParam(results->new_msg.get(), param);
176}
177
178// These just break apart the given tuple and run ScanParam over each param.
179// The idea is to scan elements in the tuple which require special handling,
180// and write them into the |results| struct.
181template <class A>
Alexandr Ilin1d004102018-05-30 10:55:32182void ScanTuple(std::tuple<A>&& t1, ScanningResults* results) {
183 ScanParam(std::move(std::get<0>(t1)), results);
[email protected]6276b492013-11-02 13:38:31184}
185template <class A, class B>
Alexandr Ilin1d004102018-05-30 10:55:32186void ScanTuple(std::tuple<A, B>&& t1, ScanningResults* results) {
187 ScanParam(std::move(std::get<0>(t1)), results);
188 ScanParam(std::move(std::get<1>(t1)), results);
[email protected]6276b492013-11-02 13:38:31189}
190template <class A, class B, class C>
Alexandr Ilin1d004102018-05-30 10:55:32191void ScanTuple(std::tuple<A, B, C>&& t1, ScanningResults* results) {
192 ScanParam(std::move(std::get<0>(t1)), results);
193 ScanParam(std::move(std::get<1>(t1)), results);
194 ScanParam(std::move(std::get<2>(t1)), results);
[email protected]6276b492013-11-02 13:38:31195}
196template <class A, class B, class C, class D>
Alexandr Ilin1d004102018-05-30 10:55:32197void ScanTuple(std::tuple<A, B, C, D>&& t1, ScanningResults* results) {
198 ScanParam(std::move(std::get<0>(t1)), results);
199 ScanParam(std::move(std::get<1>(t1)), results);
200 ScanParam(std::move(std::get<2>(t1)), results);
201 ScanParam(std::move(std::get<3>(t1)), results);
[email protected]6276b492013-11-02 13:38:31202}
203
204template <class MessageType>
205class MessageScannerImpl {
206 public:
David Benjaminbf3962f2018-10-25 16:46:20207 explicit MessageScannerImpl(const IPC::Message* msg) : msg_(msg) {}
[email protected]6276b492013-11-02 13:38:31208 bool ScanMessage(ScanningResults* results) {
mdempsky390ab1e2016-03-07 22:18:35209 typename MessageType::Param params;
[email protected]6276b492013-11-02 13:38:31210 if (!MessageType::Read(msg_, &params))
211 return false;
Alexandr Ilin1d004102018-05-30 10:55:32212 ScanTuple(std::move(params), results);
[email protected]6276b492013-11-02 13:38:31213 return true;
214 }
215
mseaborn3bedcdc2016-01-04 21:14:13216 bool ScanSyncMessage(ScanningResults* results) {
mdempsky390ab1e2016-03-07 22:18:35217 typename MessageType::SendParam params;
mseaborn3bedcdc2016-01-04 21:14:13218 if (!MessageType::ReadSendParam(msg_, &params))
219 return false;
220 // If we need to rewrite the message, write the message id first.
221 if (results->new_msg) {
222 results->new_msg->set_sync();
223 int id = IPC::SyncMessage::GetMessageId(*msg_);
224 results->new_msg->WriteInt(id);
225 }
Alexandr Ilin1d004102018-05-30 10:55:32226 ScanTuple(std::move(params), results);
mseaborn3bedcdc2016-01-04 21:14:13227 return true;
228 }
229
[email protected]6276b492013-11-02 13:38:31230 bool ScanReply(ScanningResults* results) {
mdempsky390ab1e2016-03-07 22:18:35231 typename MessageType::ReplyParam params;
[email protected]6276b492013-11-02 13:38:31232 if (!MessageType::ReadReplyParam(msg_, &params))
233 return false;
234 // If we need to rewrite the message, write the message id first.
235 if (results->new_msg) {
236 results->new_msg->set_reply();
237 int id = IPC::SyncMessage::GetMessageId(*msg_);
238 results->new_msg->WriteInt(id);
239 }
Alexandr Ilin1d004102018-05-30 10:55:32240 ScanTuple(std::move(params), results);
[email protected]6276b492013-11-02 13:38:31241 return true;
242 }
[email protected]6276b492013-11-02 13:38:31243
244 private:
David Benjaminbf3962f2018-10-25 16:46:20245 const IPC::Message* msg_;
[email protected]6276b492013-11-02 13:38:31246};
247
248} // namespace
249
250#define CASE_FOR_MESSAGE(MESSAGE_TYPE) \
251 case MESSAGE_TYPE::ID: { \
252 MessageScannerImpl<MESSAGE_TYPE> scanner(&msg); \
253 if (rewrite_msg) \
254 results.new_msg.reset( \
[email protected]753bb252013-11-04 22:28:12255 new IPC::Message(msg.routing_id(), msg.type(), \
256 IPC::Message::PRIORITY_NORMAL)); \
[email protected]6276b492013-11-02 13:38:31257 if (!scanner.ScanMessage(&results)) \
258 return false; \
259 break; \
260 }
mseaborn3bedcdc2016-01-04 21:14:13261#define CASE_FOR_SYNC_MESSAGE(MESSAGE_TYPE) \
262 case MESSAGE_TYPE::ID: { \
263 MessageScannerImpl<MESSAGE_TYPE> scanner(&msg); \
264 if (rewrite_msg) \
265 results.new_msg.reset( \
266 new IPC::Message(msg.routing_id(), msg.type(), \
267 IPC::Message::PRIORITY_NORMAL)); \
268 if (!scanner.ScanSyncMessage(&results)) \
269 return false; \
270 break; \
271 }
[email protected]6276b492013-11-02 13:38:31272#define CASE_FOR_REPLY(MESSAGE_TYPE) \
273 case MESSAGE_TYPE::ID: { \
274 MessageScannerImpl<MESSAGE_TYPE> scanner(&msg); \
275 if (rewrite_msg) \
276 results.new_msg.reset( \
[email protected]753bb252013-11-04 22:28:12277 new IPC::Message(msg.routing_id(), msg.type(), \
278 IPC::Message::PRIORITY_NORMAL)); \
[email protected]6276b492013-11-02 13:38:31279 if (!scanner.ScanReply(&results)) \
280 return false; \
281 break; \
282 }
283
284namespace ppapi {
285namespace proxy {
286
287class SerializedHandle;
288
[email protected]7a90b852013-12-28 17:54:27289NaClMessageScanner::FileSystem::FileSystem()
290 : reserved_quota_(0) {
291}
292
293NaClMessageScanner::FileSystem::~FileSystem() {
294}
295
296bool NaClMessageScanner::FileSystem::UpdateReservedQuota(int64_t delta) {
297 base::AutoLock lock(lock_);
298 if (std::numeric_limits<int64_t>::max() - reserved_quota_ < delta)
299 return false; // reserved_quota_ + delta would overflow.
300 if (reserved_quota_ + delta < 0)
301 return false;
302 reserved_quota_ += delta;
303 return true;
304}
305
306NaClMessageScanner::FileIO::FileIO(FileSystem* file_system,
307 int64_t max_written_offset)
308 : file_system_(file_system),
309 max_written_offset_(max_written_offset) {
310}
311
312NaClMessageScanner::FileIO::~FileIO() {
313}
314
315void NaClMessageScanner::FileIO::SetMaxWrittenOffset(
316 int64_t max_written_offset) {
317 base::AutoLock lock(lock_);
318 max_written_offset_ = max_written_offset;
319}
320
321bool NaClMessageScanner::FileIO::Grow(int64_t amount) {
322 base::AutoLock lock(lock_);
323 DCHECK(amount > 0);
324 if (!file_system_->UpdateReservedQuota(-amount))
325 return false;
326 max_written_offset_ += amount;
327 return true;
328}
329
[email protected]6276b492013-11-02 13:38:31330NaClMessageScanner::NaClMessageScanner() {
331}
332
[email protected]7a90b852013-12-28 17:54:27333NaClMessageScanner::~NaClMessageScanner() {
334 for (FileSystemMap::iterator it = file_systems_.begin();
335 it != file_systems_.end(); ++it)
336 delete it->second;
337 for (FileIOMap::iterator it = files_.begin(); it != files_.end(); ++it)
338 delete it->second;
339}
340
[email protected]6276b492013-11-02 13:38:31341// Windows IPC differs from POSIX in that native handles are serialized in the
342// message body, rather than passed in a separate FileDescriptorSet. Therefore,
343// on Windows, any message containing handles must be rewritten in the POSIX
344// format before we can send it to the NaCl plugin.
scottmgd19b4f72015-06-19 22:51:00345// On Mac, base::SharedMemoryHandle has a different serialization than
346// base::FileDescriptor (which base::SharedMemoryHandle is typedef-ed to in
347// OS_NACL).
[email protected]6276b492013-11-02 13:38:31348bool NaClMessageScanner::ScanMessage(
349 const IPC::Message& msg,
[email protected]c8f326a2014-08-21 23:19:07350 uint32_t type,
[email protected]6276b492013-11-02 13:38:31351 std::vector<SerializedHandle>* handles,
dchengced92242016-04-07 00:00:12352 std::unique_ptr<IPC::Message>* new_msg_ptr) {
[email protected]6276b492013-11-02 13:38:31353 DCHECK(handles);
354 DCHECK(handles->empty());
355 DCHECK(new_msg_ptr);
356 DCHECK(!new_msg_ptr->get());
357
358 bool rewrite_msg =
Xiaohan Wang0fd6e56a2022-01-13 20:26:11359#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC)
[email protected]6276b492013-11-02 13:38:31360 true;
361#else
[email protected]73af6332014-02-06 23:28:10362 false;
[email protected]6276b492013-11-02 13:38:31363#endif
364
365 // We can't always tell from the message ID if rewriting is needed. Therefore,
[email protected]e74d2d12013-11-02 16:17:37366 // scan any message types that might contain a handle. If we later determine
367 // that there are no handles, we can cancel the rewriting by clearing the
368 // results.new_msg pointer.
[email protected]6276b492013-11-02 13:38:31369 ScanningResults results;
Anand K Mistry483007852021-03-18 22:54:48370 results.nested_msg_callback = base::BindRepeating(
371 &NaClMessageScanner::AuditNestedMessage, base::Unretained(this));
[email protected]c8f326a2014-08-21 23:19:07372 switch (type) {
[email protected]6276b492013-11-02 13:38:31373 CASE_FOR_MESSAGE(PpapiMsg_PPBAudio_NotifyAudioStreamCreated)
374 CASE_FOR_MESSAGE(PpapiMsg_PPPMessaging_HandleMessage)
375 CASE_FOR_MESSAGE(PpapiPluginMsg_ResourceReply)
dmichael822ba8f2016-01-11 17:54:52376 CASE_FOR_SYNC_MESSAGE(PpapiMsg_PPPMessageHandler_HandleBlockingMessage)
mseaborn98d206ca2016-01-08 11:43:28377 CASE_FOR_SYNC_MESSAGE(PpapiMsg_PnaclTranslatorCompileInit)
mseaborn3bedcdc2016-01-04 21:14:13378 CASE_FOR_SYNC_MESSAGE(PpapiMsg_PnaclTranslatorLink)
Justin TerAvestcffdd032014-09-10 19:21:56379 CASE_FOR_REPLY(PpapiHostMsg_OpenResource)
penghuanga206fb492014-09-09 21:27:32380 CASE_FOR_REPLY(PpapiHostMsg_PPBGraphics3D_Create)
[email protected]c8f326a2014-08-21 23:19:07381 CASE_FOR_REPLY(PpapiHostMsg_PPBGraphics3D_CreateTransferBuffer)
382 CASE_FOR_REPLY(PpapiHostMsg_PPBImageData_CreateSimple)
383 CASE_FOR_REPLY(PpapiHostMsg_ResourceSyncCall)
384 CASE_FOR_REPLY(PpapiHostMsg_SharedMemory_CreateSharedMemory)
[email protected]6276b492013-11-02 13:38:31385 default:
386 // Do nothing for messages we don't know.
387 break;
388 }
389
390 // Only messages containing handles need to be rewritten. If no handles are
391 // found, don't return the rewritten message either. This must be changed if
392 // we ever add new param types that also require rewriting.
393 if (!results.handles.empty()) {
394 handles->swap(results.handles);
dchengd2b9f612015-12-18 19:08:51395 *new_msg_ptr = std::move(results.new_msg);
[email protected]6276b492013-11-02 13:38:31396 }
397 return true;
398}
399
[email protected]c586216c2013-12-18 21:59:17400void NaClMessageScanner::ScanUntrustedMessage(
401 const IPC::Message& untrusted_msg,
dchengced92242016-04-07 00:00:12402 std::unique_ptr<IPC::Message>* new_msg_ptr) {
[email protected]7a90b852013-12-28 17:54:27403 // Audit FileIO and FileSystem messages to ensure that the plugin doesn't
404 // exceed its file quota. If we find the message is malformed, just pass it
405 // through - we only care about well formed messages to the host.
406 if (untrusted_msg.type() == PpapiHostMsg_ResourceCall::ID) {
407 ResourceMessageCallParams params;
408 IPC::Message nested_msg;
409 if (!UnpackMessage<PpapiHostMsg_ResourceCall>(
410 untrusted_msg, &params, &nested_msg))
411 return;
412
413 switch (nested_msg.type()) {
414 case PpapiHostMsg_FileIO_Close::ID: {
415 FileIOMap::iterator it = files_.find(params.pp_resource());
416 if (it == files_.end())
417 return;
418 // Audit FileIO Close messages to make sure the plugin reports an
419 // accurate file size.
[email protected]540d6af42014-01-28 21:19:03420 FileGrowth file_growth;
[email protected]7a90b852013-12-28 17:54:27421 if (!UnpackMessage<PpapiHostMsg_FileIO_Close>(
[email protected]540d6af42014-01-28 21:19:03422 nested_msg, &file_growth))
[email protected]7a90b852013-12-28 17:54:27423 return;
424
425 int64_t trusted_max_written_offset = it->second->max_written_offset();
426 delete it->second;
427 files_.erase(it);
428 // If the plugin is under-reporting, rewrite the message with the
429 // trusted value.
[email protected]540d6af42014-01-28 21:19:03430 if (trusted_max_written_offset > file_growth.max_written_offset) {
Peter Boströmfb60ea02021-04-05 21:06:12431 *new_msg_ptr = std::make_unique<PpapiHostMsg_ResourceCall>(
432 params, PpapiHostMsg_FileIO_Close(
433 FileGrowth(trusted_max_written_offset, 0)));
[email protected]7a90b852013-12-28 17:54:27434 }
[email protected]2d585cbd2014-06-03 02:13:22435 break;
[email protected]7a90b852013-12-28 17:54:27436 }
437 case PpapiHostMsg_FileIO_SetLength::ID: {
438 FileIOMap::iterator it = files_.find(params.pp_resource());
439 if (it == files_.end())
440 return;
441 // Audit FileIO SetLength messages to make sure the plugin is within
442 // the current quota reservation. In addition, deduct the file size
443 // increase from the quota reservation.
444 int64_t length = 0;
445 if (!UnpackMessage<PpapiHostMsg_FileIO_SetLength>(
446 nested_msg, &length))
447 return;
448
449 // Calculate file size increase, taking care to avoid overflows.
450 if (length < 0)
451 return;
452 int64_t trusted_max_written_offset = it->second->max_written_offset();
453 int64_t increase = length - trusted_max_written_offset;
454 if (increase <= 0)
455 return;
456 if (!it->second->Grow(increase)) {
Peter Boströmfb60ea02021-04-05 21:06:12457 *new_msg_ptr = std::make_unique<PpapiHostMsg_ResourceCall>(
458 params, PpapiHostMsg_FileIO_SetLength(-1));
[email protected]7a90b852013-12-28 17:54:27459 }
460 break;
461 }
462 case PpapiHostMsg_FileSystem_ReserveQuota::ID: {
463 // Audit FileSystem ReserveQuota messages to make sure the plugin
464 // reports accurate file sizes.
465 int64_t amount = 0;
[email protected]540d6af42014-01-28 21:19:03466 FileGrowthMap file_growths;
[email protected]7a90b852013-12-28 17:54:27467 if (!UnpackMessage<PpapiHostMsg_FileSystem_ReserveQuota>(
[email protected]540d6af42014-01-28 21:19:03468 nested_msg, &amount, &file_growths))
[email protected]7a90b852013-12-28 17:54:27469 return;
470
471 bool audit_failed = false;
[email protected]540d6af42014-01-28 21:19:03472 for (FileGrowthMap::iterator it = file_growths.begin();
473 it != file_growths.end(); ++it) {
[email protected]7a90b852013-12-28 17:54:27474 FileIOMap::iterator file_it = files_.find(it->first);
475 if (file_it == files_.end())
476 continue;
477 int64_t trusted_max_written_offset =
478 file_it->second->max_written_offset();
[email protected]540d6af42014-01-28 21:19:03479 if (trusted_max_written_offset > it->second.max_written_offset) {
[email protected]7a90b852013-12-28 17:54:27480 audit_failed = true;
[email protected]540d6af42014-01-28 21:19:03481 it->second.max_written_offset = trusted_max_written_offset;
482 }
483 if (it->second.append_mode_write_amount < 0) {
484 audit_failed = true;
485 it->second.append_mode_write_amount = 0;
[email protected]7a90b852013-12-28 17:54:27486 }
487 }
488 if (audit_failed) {
Peter Boströmfb60ea02021-04-05 21:06:12489 *new_msg_ptr = std::make_unique<PpapiHostMsg_ResourceCall>(
490 params,
491 PpapiHostMsg_FileSystem_ReserveQuota(amount, file_growths));
[email protected]7a90b852013-12-28 17:54:27492 }
493 break;
494 }
495 case PpapiHostMsg_ResourceDestroyed::ID: {
496 // Audit resource destroyed messages to release FileSystems.
497 PP_Resource resource;
498 if (!UnpackMessage<PpapiHostMsg_ResourceDestroyed>(
499 nested_msg, &resource))
500 return;
501 FileSystemMap::iterator fs_it = file_systems_.find(resource);
502 if (fs_it != file_systems_.end()) {
503 delete fs_it->second;
504 file_systems_.erase(fs_it);
505 }
[email protected]2d585cbd2014-06-03 02:13:22506 break;
[email protected]7a90b852013-12-28 17:54:27507 }
508 }
509 }
[email protected]c586216c2013-12-18 21:59:17510}
[email protected]6276b492013-11-02 13:38:31511
[email protected]7a90b852013-12-28 17:54:27512NaClMessageScanner::FileIO* NaClMessageScanner::GetFile(
513 PP_Resource file_io) {
514 FileIOMap::iterator it = files_.find(file_io);
515 DCHECK(it != files_.end());
516 return it->second;
517}
518
519void NaClMessageScanner::AuditNestedMessage(PP_Resource resource,
520 const IPC::Message& msg,
521 SerializedHandle* handle) {
522 switch (msg.type()) {
523 case PpapiPluginMsg_FileIO_OpenReply::ID: {
524 // A file that requires quota checking was opened.
525 PP_Resource quota_file_system;
526 int64_t max_written_offset = 0;
527 if (ppapi::UnpackMessage<PpapiPluginMsg_FileIO_OpenReply>(
528 msg, &quota_file_system, &max_written_offset)) {
529 if (quota_file_system) {
530 // Look up the FileSystem by inserting a new one. If it was already
531 // present, get the existing one, otherwise construct it.
532 FileSystem* file_system = NULL;
533 std::pair<FileSystemMap::iterator, bool> insert_result =
534 file_systems_.insert(std::make_pair(quota_file_system,
535 file_system));
536 if (insert_result.second)
537 insert_result.first->second = new FileSystem();
538 file_system = insert_result.first->second;
539 // Create the FileIO.
540 DCHECK(files_.find(resource) == files_.end());
541 files_.insert(std::make_pair(
542 resource,
543 new FileIO(file_system, max_written_offset)));
544 }
545 }
546 break;
547 }
548 case PpapiPluginMsg_FileSystem_ReserveQuotaReply::ID: {
549 // The amount of reserved quota for a FileSystem was refreshed.
550 int64_t amount = 0;
[email protected]540d6af42014-01-28 21:19:03551 FileSizeMap file_sizes;
[email protected]7a90b852013-12-28 17:54:27552 if (ppapi::UnpackMessage<PpapiPluginMsg_FileSystem_ReserveQuotaReply>(
[email protected]540d6af42014-01-28 21:19:03553 msg, &amount, &file_sizes)) {
[email protected]7a90b852013-12-28 17:54:27554 FileSystemMap::iterator it = file_systems_.find(resource);
555 DCHECK(it != file_systems_.end());
556 it->second->UpdateReservedQuota(amount);
557
[email protected]540d6af42014-01-28 21:19:03558 FileSizeMap::const_iterator offset_it = file_sizes.begin();
559 for (; offset_it != file_sizes.end(); ++offset_it) {
[email protected]7a90b852013-12-28 17:54:27560 FileIOMap::iterator fio_it = files_.find(offset_it->first);
561 DCHECK(fio_it != files_.end());
562 if (fio_it != files_.end())
563 fio_it->second->SetMaxWrittenOffset(offset_it->second);
564 }
565 }
566 break;
567 }
568 }
569}
570
[email protected]6276b492013-11-02 13:38:31571} // namespace proxy
572} // namespace ppapi