nacl_message_scanner.cc revision 5d1f7b1de12d16ceb2c938c56701a3e8bfa558f7
10f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved.
20f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
30f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)// found in the LICENSE file.
40f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
50f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)#include "ppapi/proxy/nacl_message_scanner.h"
60f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
70f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)#include <vector>
80f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)#include "base/bind.h"
90f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)#include "ipc/ipc_message.h"
100f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)#include "ipc/ipc_message_macros.h"
110f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)#include "ppapi/proxy/ppapi_messages.h"
120f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)#include "ppapi/proxy/resource_message_params.h"
130f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)#include "ppapi/proxy/serialized_handle.h"
140f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)#include "ppapi/proxy/serialized_var.h"
150f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
160f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)class NaClDescImcShm;
170f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
180f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)namespace IPC {
190f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)class Message;
200f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)}
210f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)using ppapi::proxy::ResourceMessageReplyParams;
235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)using ppapi::proxy::SerializedHandle;
245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)using ppapi::proxy::SerializedVar;
255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
260f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)namespace {
270f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)typedef std::vector<SerializedHandle> Handles;
290f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
300f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)struct ScanningResults {
315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ScanningResults() : handle_index(0), pp_resource(0) {}
320f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
330f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  // Vector to hold handles found in the message.
340f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  Handles handles;
350f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  // Current handle index in the rewritten message. During the scan, it will be
360f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  // be less than or equal to handles.size(). After the scan it should be equal.
370f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  int handle_index;
380f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  // The rewritten message. This may be NULL, so all ScanParam overloads should
390f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  // check for NULL before writing to it. In some cases, a ScanParam overload
400f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  // may set this to NULL when it can determine that there are no parameters
410f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  // that need conversion. (See the ResourceMessageReplyParams overload.)
420f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  scoped_ptr<IPC::Message> new_msg;
435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Resource id for resource messages. Save this when scanning resource replies
445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // so when we audit the nested message, we know which resource it is for.
455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  PP_Resource pp_resource;
465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Callback to receive the nested message in a resource message or reply.
475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::Callback<void(PP_Resource, const IPC::Message&, SerializedHandle*)>
485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      nested_msg_callback;
490f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)};
500f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
510f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)void WriteHandle(int handle_index,
525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 const SerializedHandle& handle,
530f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)                 IPC::Message* msg) {
545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  SerializedHandle::WriteHeader(handle.header(), msg);
550f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
560f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  // Now write the handle itself in POSIX style.
570f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  msg->WriteBool(true);  // valid == true
580f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  msg->WriteInt(handle_index);
590f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)}
600f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
610f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)// Define overloads for each kind of message parameter that requires special
620f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)// handling. See ScanTuple for how these get used.
630f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
640f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)// Overload to match SerializedHandle.
655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void ScanParam(const SerializedHandle& handle, ScanningResults* results) {
660f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  results->handles.push_back(handle);
670f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  if (results->new_msg)
680f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    WriteHandle(results->handle_index++, handle, results->new_msg.get());
690f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)}
700f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
710f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)void HandleWriter(int* handle_index,
720f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)                  IPC::Message* m,
735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                  const SerializedHandle& handle) {
740f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  WriteHandle((*handle_index)++, handle, m);
750f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)}
760f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
770f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)// Overload to match SerializedVar, which can contain handles.
785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void ScanParam(const SerializedVar& var, ScanningResults* results) {
795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::vector<SerializedHandle*> var_handles = var.GetHandles();
800f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  // Copy any handles and then rewrite the message.
810f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  for (size_t i = 0; i < var_handles.size(); ++i)
820f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    results->handles.push_back(*var_handles[i]);
830f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  if (results->new_msg)
840f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    var.WriteDataToMessage(results->new_msg.get(),
850f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)                           base::Bind(&HandleWriter, &results->handle_index));
860f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)}
870f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
880f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)// For PpapiMsg_ResourceReply and the reply to PpapiHostMsg_ResourceSyncCall,
890f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)// the handles are carried inside the ResourceMessageReplyParams.
900f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)// NOTE: We only intercept handles from host->NaCl. The only kind of
910f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)//       ResourceMessageParams that travels this direction is
920f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)//       ResourceMessageReplyParams, so that's the only one we need to handle.
935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void ScanParam(const ResourceMessageReplyParams& params,
940f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)               ScanningResults* results) {
955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  results->pp_resource = params.pp_resource();
960f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  // If the resource reply params don't contain handles, NULL the new message
970f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  // pointer to cancel further rewriting.
980f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  // NOTE: This works because only handles currently need rewriting, and we
990f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  //       know at this point that this message has none.
1000f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  if (params.handles().empty()) {
1010f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    results->new_msg.reset(NULL);
1020f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    return;
1030f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  }
1040f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
1050f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  // If we need to rewrite the message, write everything before the handles
1060f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  // (there's nothing after the handles).
1070f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  if (results->new_msg) {
1080f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    params.WriteReplyHeader(results->new_msg.get());
1090f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    // IPC writes the vector length as an int before the contents of the
1100f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    // vector.
1110f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    results->new_msg->WriteInt(static_cast<int>(params.handles().size()));
1120f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  }
1130f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  for (Handles::const_iterator iter = params.handles().begin();
1140f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)       iter != params.handles().end();
1150f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)       ++iter) {
1160f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    // ScanParam will write each handle to the new message, if necessary.
1170f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    ScanParam(*iter, results);
1180f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  }
1190f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  // Tell ResourceMessageReplyParams that we have taken the handles, so it
1200f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  // shouldn't close them. The NaCl runtime will take ownership of them.
1210f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  params.ConsumeHandles();
1220f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)}
1230f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
1245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Overload to match nested messages. If we need to rewrite the message, write
1255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// the parameter.
1265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void ScanParam(const IPC::Message& param, ScanningResults* results) {
1275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (results->pp_resource && !results->nested_msg_callback.is_null()) {
1285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    SerializedHandle* handle = NULL;
1295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (results->handles.size() == 1)
1305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      handle = &results->handles[0];
1315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    results->nested_msg_callback.Run(results->pp_resource, param, handle);
1325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (results->new_msg)
1345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    IPC::WriteParam(results->new_msg.get(), param);
1355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Overload to match all other types. If we need to rewrite the message, write
1385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// the parameter.
1390f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)template <class T>
1400f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)void ScanParam(const T& param, ScanningResults* results) {
1410f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  if (results->new_msg)
1420f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    IPC::WriteParam(results->new_msg.get(), param);
1430f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)}
1440f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
1450f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)// These just break apart the given tuple and run ScanParam over each param.
1460f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)// The idea is to scan elements in the tuple which require special handling,
1470f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)// and write them into the |results| struct.
1480f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)template <class A>
1490f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)void ScanTuple(const Tuple1<A>& t1, ScanningResults* results) {
1500f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  ScanParam(t1.a, results);
1510f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)}
1520f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)template <class A, class B>
1530f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)void ScanTuple(const Tuple2<A, B>& t1, ScanningResults* results) {
1540f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  ScanParam(t1.a, results);
1550f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  ScanParam(t1.b, results);
1560f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)}
1570f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)template <class A, class B, class C>
1580f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)void ScanTuple(const Tuple3<A, B, C>& t1, ScanningResults* results) {
1590f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  ScanParam(t1.a, results);
1600f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  ScanParam(t1.b, results);
1610f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  ScanParam(t1.c, results);
1620f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)}
1630f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)template <class A, class B, class C, class D>
1640f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)void ScanTuple(const Tuple4<A, B, C, D>& t1, ScanningResults* results) {
1650f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  ScanParam(t1.a, results);
1660f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  ScanParam(t1.b, results);
1670f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  ScanParam(t1.c, results);
1680f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  ScanParam(t1.d, results);
1690f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)}
1700f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
1710f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)template <class MessageType>
1720f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)class MessageScannerImpl {
1730f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) public:
1740f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  explicit MessageScannerImpl(const IPC::Message* msg)
1750f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      : msg_(static_cast<const MessageType*>(msg)) {
1760f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  }
1770f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  bool ScanMessage(ScanningResults* results) {
1780f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    typename TupleTypes<typename MessageType::Schema::Param>::ValueTuple params;
1790f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    if (!MessageType::Read(msg_, &params))
1800f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      return false;
1810f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    ScanTuple(params, results);
1820f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    return true;
1830f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  }
1840f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
1850f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  bool ScanReply(ScanningResults* results) {
1860f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    typename TupleTypes<typename MessageType::Schema::ReplyParam>::ValueTuple
1870f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)        params;
1880f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    if (!MessageType::ReadReplyParam(msg_, &params))
1890f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      return false;
1900f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    // If we need to rewrite the message, write the message id first.
1910f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    if (results->new_msg) {
1920f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      results->new_msg->set_reply();
1930f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      int id = IPC::SyncMessage::GetMessageId(*msg_);
1940f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      results->new_msg->WriteInt(id);
1950f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    }
1960f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    ScanTuple(params, results);
1970f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    return true;
1980f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  }
1990f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  // TODO(dmichael): Add ScanSyncMessage for outgoing sync messages, if we ever
2000f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  //                 need to scan those.
2010f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
2020f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) private:
2030f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  const MessageType* msg_;
2040f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)};
2050f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
2060f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)}  // namespace
2070f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
2080f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)#define CASE_FOR_MESSAGE(MESSAGE_TYPE) \
2090f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      case MESSAGE_TYPE::ID: { \
2100f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)        MessageScannerImpl<MESSAGE_TYPE> scanner(&msg); \
2110f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)        if (rewrite_msg) \
2120f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)          results.new_msg.reset( \
2130f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)              new IPC::Message(msg.routing_id(), msg.type(), \
2140f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)                               IPC::Message::PRIORITY_NORMAL)); \
2150f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)        if (!scanner.ScanMessage(&results)) \
2160f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)          return false; \
2170f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)        break; \
2180f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      }
2190f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)#define CASE_FOR_REPLY(MESSAGE_TYPE) \
2200f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      case MESSAGE_TYPE::ID: { \
2210f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)        MessageScannerImpl<MESSAGE_TYPE> scanner(&msg); \
2220f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)        if (rewrite_msg) \
2230f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)          results.new_msg.reset( \
2240f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)              new IPC::Message(msg.routing_id(), msg.type(), \
2250f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)                               IPC::Message::PRIORITY_NORMAL)); \
2260f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)        if (!scanner.ScanReply(&results)) \
2270f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)          return false; \
2280f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)        break; \
2290f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      }
2300f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
2310f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)namespace ppapi {
2320f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)namespace proxy {
2330f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
2340f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)class SerializedHandle;
2350f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
2365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)NaClMessageScanner::FileSystem::FileSystem()
2375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    : reserved_quota_(0) {
2385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)NaClMessageScanner::FileSystem::~FileSystem() {
2415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool NaClMessageScanner::FileSystem::UpdateReservedQuota(int64_t delta) {
2445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::AutoLock lock(lock_);
2455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (std::numeric_limits<int64_t>::max() - reserved_quota_ < delta)
2465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return false;  // reserved_quota_ + delta would overflow.
2475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (reserved_quota_ + delta < 0)
2485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return false;
2495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  reserved_quota_ += delta;
2505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return true;
2515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)NaClMessageScanner::FileIO::FileIO(FileSystem* file_system,
2545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                   int64_t max_written_offset)
2555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    : file_system_(file_system),
2565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      max_written_offset_(max_written_offset) {
2575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)NaClMessageScanner::FileIO::~FileIO() {
2605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void NaClMessageScanner::FileIO::SetMaxWrittenOffset(
2635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    int64_t max_written_offset) {
2645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::AutoLock lock(lock_);
2655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  max_written_offset_ = max_written_offset;
2665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool NaClMessageScanner::FileIO::Grow(int64_t amount) {
2695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::AutoLock lock(lock_);
2705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(amount > 0);
2715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!file_system_->UpdateReservedQuota(-amount))
2725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return false;
2735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  max_written_offset_ += amount;
2745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return true;
2755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2770f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)NaClMessageScanner::NaClMessageScanner() {
2780f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)}
2790f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
2805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)NaClMessageScanner::~NaClMessageScanner() {
2815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (FileSystemMap::iterator it = file_systems_.begin();
2825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      it != file_systems_.end(); ++it)
2835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    delete it->second;
2845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (FileIOMap::iterator it = files_.begin(); it != files_.end(); ++it)
2855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    delete it->second;
2865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2880f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)// Windows IPC differs from POSIX in that native handles are serialized in the
2890f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)// message body, rather than passed in a separate FileDescriptorSet. Therefore,
2900f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)// on Windows, any message containing handles must be rewritten in the POSIX
2910f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)// format before we can send it to the NaCl plugin.
2920f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)bool NaClMessageScanner::ScanMessage(
2930f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    const IPC::Message& msg,
2940f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    std::vector<SerializedHandle>* handles,
2950f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    scoped_ptr<IPC::Message>* new_msg_ptr) {
2960f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  DCHECK(handles);
2970f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  DCHECK(handles->empty());
2980f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  DCHECK(new_msg_ptr);
2990f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  DCHECK(!new_msg_ptr->get());
3000f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
3010f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  bool rewrite_msg =
3020f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)#if defined(OS_WIN)
3030f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      true;
3040f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)#else
3055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      false;
3060f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)#endif
3070f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
3080f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  // We can't always tell from the message ID if rewriting is needed. Therefore,
3090f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  // scan any message types that might contain a handle. If we later determine
3100f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  // that there are no handles, we can cancel the rewriting by clearing the
3110f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  // results.new_msg pointer.
3120f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  ScanningResults results;
3135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  results.nested_msg_callback =
3145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      base::Bind(&NaClMessageScanner::AuditNestedMessage,
3155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 base::Unretained(this));
3160f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  switch (msg.type()) {
3170f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    CASE_FOR_MESSAGE(PpapiMsg_PPBAudio_NotifyAudioStreamCreated)
3180f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    CASE_FOR_MESSAGE(PpapiMsg_PPPMessaging_HandleMessage)
3190f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    CASE_FOR_MESSAGE(PpapiPluginMsg_ResourceReply)
3200f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    case IPC_REPLY_ID: {
3210f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      int id = IPC::SyncMessage::GetMessageId(msg);
3220f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      PendingSyncMsgMap::iterator iter(pending_sync_msgs_.find(id));
3230f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      if (iter == pending_sync_msgs_.end()) {
3240f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)        NOTREACHED();
3250f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)        return false;
3260f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      }
3270f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      uint32_t type = iter->second;
3280f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      pending_sync_msgs_.erase(iter);
3290f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      switch (type) {
3300f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)        CASE_FOR_REPLY(PpapiHostMsg_PPBGraphics3D_GetTransferBuffer)
3310f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)        CASE_FOR_REPLY(PpapiHostMsg_PPBImageData_CreateSimple)
3320f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)        CASE_FOR_REPLY(PpapiHostMsg_ResourceSyncCall)
3330f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)        CASE_FOR_REPLY(PpapiHostMsg_SharedMemory_CreateSharedMemory)
3340f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)        default:
3350f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)          // Do nothing for messages we don't know.
3360f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)          break;
3370f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      }
3380f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      break;
3390f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    }
3400f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    default:
3410f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      // Do nothing for messages we don't know.
3420f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      break;
3430f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  }
3440f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
3450f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  // Only messages containing handles need to be rewritten. If no handles are
3460f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  // found, don't return the rewritten message either. This must be changed if
3470f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  // we ever add new param types that also require rewriting.
3480f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  if (!results.handles.empty()) {
3490f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    handles->swap(results.handles);
3500f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    *new_msg_ptr = results.new_msg.Pass();
3510f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  }
3520f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  return true;
3530f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)}
3540f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
3555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void NaClMessageScanner::ScanUntrustedMessage(
3565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const IPC::Message& untrusted_msg,
3575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    scoped_ptr<IPC::Message>* new_msg_ptr) {
3585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (untrusted_msg.is_sync())
3595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    RegisterSyncMessageForReply(untrusted_msg);
3605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Audit FileIO and FileSystem messages to ensure that the plugin doesn't
3625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // exceed its file quota. If we find the message is malformed, just pass it
3635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // through - we only care about well formed messages to the host.
3645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (untrusted_msg.type() == PpapiHostMsg_ResourceCall::ID) {
3655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    ResourceMessageCallParams params;
3665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    IPC::Message nested_msg;
3675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (!UnpackMessage<PpapiHostMsg_ResourceCall>(
3685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            untrusted_msg, &params, &nested_msg))
3695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return;
3705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    switch (nested_msg.type()) {
3725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      case PpapiHostMsg_FileIO_Close::ID: {
3735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        FileIOMap::iterator it = files_.find(params.pp_resource());
3745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        if (it == files_.end())
3755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          return;
3765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        // Audit FileIO Close messages to make sure the plugin reports an
3775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        // accurate file size.
3785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        FileGrowth file_growth;
3795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        if (!UnpackMessage<PpapiHostMsg_FileIO_Close>(
3805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                nested_msg, &file_growth))
3815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          return;
3825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        int64_t trusted_max_written_offset = it->second->max_written_offset();
3845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        delete it->second;
3855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        files_.erase(it);
3865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        // If the plugin is under-reporting, rewrite the message with the
3875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        // trusted value.
3885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        if (trusted_max_written_offset > file_growth.max_written_offset) {
3895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          new_msg_ptr->reset(
3905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)              new PpapiHostMsg_ResourceCall(
3915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                  params,
3925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                  PpapiHostMsg_FileIO_Close(
3935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                      FileGrowth(trusted_max_written_offset, 0))));
3945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        }
3955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      }
3965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      case PpapiHostMsg_FileIO_SetLength::ID: {
3975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        FileIOMap::iterator it = files_.find(params.pp_resource());
3985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        if (it == files_.end())
3995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          return;
4005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        // Audit FileIO SetLength messages to make sure the plugin is within
4015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        // the current quota reservation. In addition, deduct the file size
4025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        // increase from the quota reservation.
4035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        int64_t length = 0;
4045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        if (!UnpackMessage<PpapiHostMsg_FileIO_SetLength>(
4055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                nested_msg, &length))
4065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          return;
4075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        // Calculate file size increase, taking care to avoid overflows.
4095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        if (length < 0)
4105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          return;
4115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        int64_t trusted_max_written_offset = it->second->max_written_offset();
4125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        int64_t increase = length - trusted_max_written_offset;
4135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        if (increase <= 0)
4145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          return;
4155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        if (!it->second->Grow(increase)) {
4165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          new_msg_ptr->reset(
4175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)              new PpapiHostMsg_ResourceCall(
4185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                  params,
4195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                  PpapiHostMsg_FileIO_SetLength(-1)));
4205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        }
4215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        break;
4225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      }
4235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      case PpapiHostMsg_FileSystem_ReserveQuota::ID: {
4245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        // Audit FileSystem ReserveQuota messages to make sure the plugin
4255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        // reports accurate file sizes.
4265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        int64_t amount = 0;
4275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        FileGrowthMap file_growths;
4285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        if (!UnpackMessage<PpapiHostMsg_FileSystem_ReserveQuota>(
4295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                nested_msg, &amount, &file_growths))
4305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          return;
4315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        bool audit_failed = false;
4335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        for (FileGrowthMap::iterator it = file_growths.begin();
4345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            it != file_growths.end(); ++it) {
4355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          FileIOMap::iterator file_it = files_.find(it->first);
4365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          if (file_it == files_.end())
4375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            continue;
4385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          int64_t trusted_max_written_offset =
4395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)              file_it->second->max_written_offset();
4405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          if (trusted_max_written_offset > it->second.max_written_offset) {
4415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            audit_failed = true;
4425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            it->second.max_written_offset = trusted_max_written_offset;
4435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          }
4445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          if (it->second.append_mode_write_amount < 0) {
4455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            audit_failed = true;
4465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            it->second.append_mode_write_amount = 0;
4475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          }
4485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        }
4495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        if (audit_failed) {
4505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          new_msg_ptr->reset(
4515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)              new PpapiHostMsg_ResourceCall(
4525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                  params,
4535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                  PpapiHostMsg_FileSystem_ReserveQuota(
4545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                      amount, file_growths)));
4555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        }
4565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        break;
4575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      }
4585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      case PpapiHostMsg_ResourceDestroyed::ID: {
4595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        // Audit resource destroyed messages to release FileSystems.
4605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        PP_Resource resource;
4615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        if (!UnpackMessage<PpapiHostMsg_ResourceDestroyed>(
4625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                nested_msg, &resource))
4635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          return;
4645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        FileSystemMap::iterator fs_it = file_systems_.find(resource);
4655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        if (fs_it != file_systems_.end()) {
4665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          delete fs_it->second;
4675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          file_systems_.erase(fs_it);
4685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        }
4695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      }
4705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
4715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
4725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
4730f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
4745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void NaClMessageScanner::RegisterSyncMessageForReply(const IPC::Message& msg) {
4750f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  int msg_id = IPC::SyncMessage::GetMessageId(msg);
4760f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  DCHECK(pending_sync_msgs_.find(msg_id) == pending_sync_msgs_.end());
4770f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
4780f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  pending_sync_msgs_[msg_id] = msg.type();
4790f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)}
4800f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
4815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)NaClMessageScanner::FileIO* NaClMessageScanner::GetFile(
4825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    PP_Resource file_io) {
4835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  FileIOMap::iterator it = files_.find(file_io);
4845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(it != files_.end());
4855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return it->second;
4865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
4875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void NaClMessageScanner::AuditNestedMessage(PP_Resource resource,
4895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                            const IPC::Message& msg,
4905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                            SerializedHandle* handle) {
4915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  switch (msg.type()) {
4925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    case PpapiPluginMsg_FileIO_OpenReply::ID: {
4935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      // A file that requires quota checking was opened.
4945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      PP_Resource quota_file_system;
4955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      int64_t max_written_offset = 0;
4965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      if (ppapi::UnpackMessage<PpapiPluginMsg_FileIO_OpenReply>(
4975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)              msg, &quota_file_system, &max_written_offset)) {
4985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        if (quota_file_system) {
4995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          // Look up the FileSystem by inserting a new one. If it was already
5005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          // present, get the existing one, otherwise construct it.
5015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          FileSystem* file_system = NULL;
5025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          std::pair<FileSystemMap::iterator, bool> insert_result =
5035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)              file_systems_.insert(std::make_pair(quota_file_system,
5045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                                  file_system));
5055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          if (insert_result.second)
5065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            insert_result.first->second = new FileSystem();
5075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          file_system = insert_result.first->second;
5085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          // Create the FileIO.
5095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          DCHECK(files_.find(resource) == files_.end());
5105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          files_.insert(std::make_pair(
5115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)              resource,
5125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)              new FileIO(file_system, max_written_offset)));
5135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        }
5145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      }
5155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      break;
5165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
5175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    case PpapiPluginMsg_FileSystem_ReserveQuotaReply::ID: {
5185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      // The amount of reserved quota for a FileSystem was refreshed.
5195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      int64_t amount = 0;
5205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      FileSizeMap file_sizes;
5215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      if (ppapi::UnpackMessage<PpapiPluginMsg_FileSystem_ReserveQuotaReply>(
5225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          msg, &amount, &file_sizes)) {
5235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        FileSystemMap::iterator it = file_systems_.find(resource);
5245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        DCHECK(it != file_systems_.end());
5255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        it->second->UpdateReservedQuota(amount);
5265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
5275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        FileSizeMap::const_iterator offset_it = file_sizes.begin();
5285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        for (; offset_it != file_sizes.end(); ++offset_it) {
5295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          FileIOMap::iterator fio_it = files_.find(offset_it->first);
5305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          DCHECK(fio_it != files_.end());
5315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          if (fio_it != files_.end())
5325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            fio_it->second->SetMaxWrittenOffset(offset_it->second);
5335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        }
5345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      }
5355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      break;
5365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
5375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
5385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
5395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
5400f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)}  // namespace proxy
5410f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)}  // namespace ppapi
542