nacl_message_scanner.cc revision 03b57e008b61dfcb1fbad3aea950ae0e001748b0
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ppapi/proxy/nacl_message_scanner.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <vector> 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h" 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ipc/ipc_message.h" 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ipc/ipc_message_macros.h" 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ppapi/proxy/ppapi_messages.h" 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ppapi/proxy/resource_message_params.h" 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ppapi/proxy/serialized_handle.h" 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ppapi/proxy/serialized_var.h" 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class NaClDescImcShm; 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace IPC { 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class Message; 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using ppapi::proxy::ResourceMessageReplyParams; 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using ppapi::proxy::SerializedHandle; 24c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)using ppapi::proxy::SerializedVar; 25c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 26c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)namespace { 27c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 28c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)typedef std::vector<SerializedHandle> Handles; 29c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 30c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)struct ScanningResults { 31c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ScanningResults() : handle_index(0), pp_resource(0) {} 32c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 33c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Vector to hold handles found in the message. 34c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) Handles handles; 35c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Current handle index in the rewritten message. During the scan, it will be 36c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // be less than or equal to handles.size(). After the scan it should be equal. 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int handle_index; 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The rewritten message. This may be NULL, so all ScanParam overloads should 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // check for NULL before writing to it. In some cases, a ScanParam overload 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // may set this to NULL when it can determine that there are no parameters 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // that need conversion. (See the ResourceMessageReplyParams overload.) 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_ptr<IPC::Message> new_msg; 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Resource id for resource messages. Save this when scanning resource replies 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // so when we audit the nested message, we know which resource it is for. 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PP_Resource pp_resource; 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Callback to receive the nested message in a resource message or reply. 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Callback<void(PP_Resource, const IPC::Message&, SerializedHandle*)> 48c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) nested_msg_callback; 49c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}; 50c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 51c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void WriteHandle(int handle_index, 52c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const SerializedHandle& handle, 53c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) IPC::Message* msg) { 54c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) SerializedHandle::WriteHeader(handle.header(), msg); 55c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 56c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Now write the handle itself in POSIX style. 57c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) msg->WriteBool(true); // valid == true 58c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) msg->WriteInt(handle_index); 59c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 60c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Define overloads for each kind of message parameter that requires special 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// handling. See ScanTuple for how these get used. 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Overload to match SerializedHandle. 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ScanParam(const SerializedHandle& handle, ScanningResults* results) { 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) results->handles.push_back(handle); 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (results->new_msg) 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) WriteHandle(results->handle_index++, handle, results->new_msg.get()); 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HandleWriter(int* handle_index, 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IPC::Message* m, 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const SerializedHandle& handle) { 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) WriteHandle((*handle_index)++, handle, m); 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Overload to match SerializedVar, which can contain handles. 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ScanParam(const SerializedVar& var, ScanningResults* results) { 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::vector<SerializedHandle*> var_handles = var.GetHandles(); 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Copy any handles and then rewrite the message. 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (size_t i = 0; i < var_handles.size(); ++i) 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) results->handles.push_back(*var_handles[i]); 83c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (results->new_msg) 84c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) var.WriteDataToMessage(results->new_msg.get(), 85c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) base::Bind(&HandleWriter, &results->handle_index)); 86c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 87c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 88c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// For PpapiMsg_ResourceReply and the reply to PpapiHostMsg_ResourceSyncCall, 89c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// the handles are carried inside the ResourceMessageReplyParams. 90c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// NOTE: We only intercept handles from host->NaCl. The only kind of 91c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// ResourceMessageParams that travels this direction is 92c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// ResourceMessageReplyParams, so that's the only one we need to handle. 93c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void ScanParam(const ResourceMessageReplyParams& params, 94c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ScanningResults* results) { 95c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) results->pp_resource = params.pp_resource(); 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If the resource reply params don't contain handles, NULL the new message 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // pointer to cancel further rewriting. 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // NOTE: This works because only handles currently need rewriting, and we 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // know at this point that this message has none. 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (params.handles().empty()) { 1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) results->new_msg.reset(NULL); 1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // If we need to rewrite the message, write everything before the handles 1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // (there's nothing after the handles). 1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (results->new_msg) { 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) params.WriteReplyHeader(results->new_msg.get()); 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // IPC writes the vector length as an int before the contents of the 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // vector. 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) results->new_msg->WriteInt(static_cast<int>(params.handles().size())); 1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for (Handles::const_iterator iter = params.handles().begin(); 114c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) iter != params.handles().end(); 115c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ++iter) { 116c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // ScanParam will write each handle to the new message, if necessary. 117c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ScanParam(*iter, results); 118c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 119c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Tell ResourceMessageReplyParams that we have taken the handles, so it 120c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // shouldn't close them. The NaCl runtime will take ownership of them. 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) params.ConsumeHandles(); 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Overload to match nested messages. If we need to rewrite the message, write 1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// the parameter. 1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ScanParam(const IPC::Message& param, ScanningResults* results) { 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (results->pp_resource && !results->nested_msg_callback.is_null()) { 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SerializedHandle* handle = NULL; 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (results->handles.size() == 1) 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) handle = &results->handles[0]; 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) results->nested_msg_callback.Run(results->pp_resource, param, handle); 1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (results->new_msg) 134c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) IPC::WriteParam(results->new_msg.get(), param); 135c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 136c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 137c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Overload to match all other types. If we need to rewrite the message, write 138c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// the parameter. 139c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)template <class T> 140c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void ScanParam(const T& param, ScanningResults* results) { 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (results->new_msg) 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IPC::WriteParam(results->new_msg.get(), param); 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// These just break apart the given tuple and run ScanParam over each param. 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The idea is to scan elements in the tuple which require special handling, 147c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// and write them into the |results| struct. 148c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)template <class A> 149c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void ScanTuple(const Tuple1<A>& t1, ScanningResults* results) { 150c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ScanParam(t1.a, results); 151c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 152c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)template <class A, class B> 153c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void ScanTuple(const Tuple2<A, B>& t1, ScanningResults* results) { 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ScanParam(t1.a, results); 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ScanParam(t1.b, results); 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)template <class A, class B, class C> 1582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ScanTuple(const Tuple3<A, B, C>& t1, ScanningResults* results) { 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ScanParam(t1.a, results); 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ScanParam(t1.b, results); 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ScanParam(t1.c, results); 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)template <class A, class B, class C, class D> 1642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ScanTuple(const Tuple4<A, B, C, D>& t1, ScanningResults* results) { 1652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ScanParam(t1.a, results); 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ScanParam(t1.b, results); 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ScanParam(t1.c, results); 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ScanParam(t1.d, results); 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)template <class MessageType> 1722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class MessageScannerImpl { 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public: 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) explicit MessageScannerImpl(const IPC::Message* msg) 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : msg_(static_cast<const MessageType*>(msg)) { 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool ScanMessage(ScanningResults* results) { 1782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) typename TupleTypes<typename MessageType::Schema::Param>::ValueTuple params; 1792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!MessageType::Read(msg_, ¶ms)) 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ScanTuple(params, results); 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) bool ScanReply(ScanningResults* results) { 1862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) typename TupleTypes<typename MessageType::Schema::ReplyParam>::ValueTuple 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) params; 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!MessageType::ReadReplyParam(msg_, ¶ms)) 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If we need to rewrite the message, write the message id first. 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (results->new_msg) { 1922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) results->new_msg->set_reply(); 1932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int id = IPC::SyncMessage::GetMessageId(*msg_); 1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) results->new_msg->WriteInt(id); 1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ScanTuple(params, results); 1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(dmichael): Add ScanSyncMessage for outgoing sync messages, if we ever 2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // need to scan those. 2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private: 2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const MessageType* msg_; 2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace 2072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#define CASE_FOR_MESSAGE(MESSAGE_TYPE) \ 2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case MESSAGE_TYPE::ID: { \ 2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MessageScannerImpl<MESSAGE_TYPE> scanner(&msg); \ 2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (rewrite_msg) \ 2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) results.new_msg.reset( \ 2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) new IPC::Message(msg.routing_id(), msg.type(), \ 2142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) IPC::Message::PRIORITY_NORMAL)); \ 2152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!scanner.ScanMessage(&results)) \ 2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; \ 2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; \ 2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define CASE_FOR_REPLY(MESSAGE_TYPE) \ 2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case MESSAGE_TYPE::ID: { \ 2212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) MessageScannerImpl<MESSAGE_TYPE> scanner(&msg); \ 2222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (rewrite_msg) \ 2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) results.new_msg.reset( \ 2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) new IPC::Message(msg.routing_id(), msg.type(), \ 2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IPC::Message::PRIORITY_NORMAL)); \ 2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!scanner.ScanReply(&results)) \ 227 return false; \ 228 break; \ 229 } 230 231namespace ppapi { 232namespace proxy { 233 234class SerializedHandle; 235 236NaClMessageScanner::FileSystem::FileSystem() 237 : reserved_quota_(0) { 238} 239 240NaClMessageScanner::FileSystem::~FileSystem() { 241} 242 243bool NaClMessageScanner::FileSystem::UpdateReservedQuota(int64_t delta) { 244 base::AutoLock lock(lock_); 245 if (std::numeric_limits<int64_t>::max() - reserved_quota_ < delta) 246 return false; // reserved_quota_ + delta would overflow. 247 if (reserved_quota_ + delta < 0) 248 return false; 249 reserved_quota_ += delta; 250 return true; 251} 252 253NaClMessageScanner::FileIO::FileIO(FileSystem* file_system, 254 int64_t max_written_offset) 255 : file_system_(file_system), 256 max_written_offset_(max_written_offset) { 257} 258 259NaClMessageScanner::FileIO::~FileIO() { 260} 261 262void NaClMessageScanner::FileIO::SetMaxWrittenOffset( 263 int64_t max_written_offset) { 264 base::AutoLock lock(lock_); 265 max_written_offset_ = max_written_offset; 266} 267 268bool NaClMessageScanner::FileIO::Grow(int64_t amount) { 269 base::AutoLock lock(lock_); 270 DCHECK(amount > 0); 271 if (!file_system_->UpdateReservedQuota(-amount)) 272 return false; 273 max_written_offset_ += amount; 274 return true; 275} 276 277NaClMessageScanner::NaClMessageScanner() { 278} 279 280NaClMessageScanner::~NaClMessageScanner() { 281 for (FileSystemMap::iterator it = file_systems_.begin(); 282 it != file_systems_.end(); ++it) 283 delete it->second; 284 for (FileIOMap::iterator it = files_.begin(); it != files_.end(); ++it) 285 delete it->second; 286} 287 288// Windows IPC differs from POSIX in that native handles are serialized in the 289// message body, rather than passed in a separate FileDescriptorSet. Therefore, 290// on Windows, any message containing handles must be rewritten in the POSIX 291// format before we can send it to the NaCl plugin. 292bool NaClMessageScanner::ScanMessage( 293 const IPC::Message& msg, 294 uint32_t type, 295 std::vector<SerializedHandle>* handles, 296 scoped_ptr<IPC::Message>* new_msg_ptr) { 297 DCHECK(handles); 298 DCHECK(handles->empty()); 299 DCHECK(new_msg_ptr); 300 DCHECK(!new_msg_ptr->get()); 301 302 bool rewrite_msg = 303#if defined(OS_WIN) 304 true; 305#else 306 false; 307#endif 308 309 // We can't always tell from the message ID if rewriting is needed. Therefore, 310 // scan any message types that might contain a handle. If we later determine 311 // that there are no handles, we can cancel the rewriting by clearing the 312 // results.new_msg pointer. 313 ScanningResults results; 314 results.nested_msg_callback = 315 base::Bind(&NaClMessageScanner::AuditNestedMessage, 316 base::Unretained(this)); 317 switch (type) { 318 CASE_FOR_MESSAGE(PpapiMsg_PPBAudio_NotifyAudioStreamCreated) 319 CASE_FOR_MESSAGE(PpapiMsg_PPPMessaging_HandleMessage) 320 CASE_FOR_MESSAGE(PpapiPluginMsg_ResourceReply) 321 CASE_FOR_REPLY(PpapiHostMsg_PPBGraphics3D_CreateTransferBuffer) 322 CASE_FOR_REPLY(PpapiHostMsg_PPBImageData_CreateSimple) 323 CASE_FOR_REPLY(PpapiHostMsg_ResourceSyncCall) 324 CASE_FOR_REPLY(PpapiHostMsg_SharedMemory_CreateSharedMemory) 325 default: 326 // Do nothing for messages we don't know. 327 break; 328 } 329 330 // Only messages containing handles need to be rewritten. If no handles are 331 // found, don't return the rewritten message either. This must be changed if 332 // we ever add new param types that also require rewriting. 333 if (!results.handles.empty()) { 334 handles->swap(results.handles); 335 *new_msg_ptr = results.new_msg.Pass(); 336 } 337 return true; 338} 339 340void NaClMessageScanner::ScanUntrustedMessage( 341 const IPC::Message& untrusted_msg, 342 scoped_ptr<IPC::Message>* new_msg_ptr) { 343 // Audit FileIO and FileSystem messages to ensure that the plugin doesn't 344 // exceed its file quota. If we find the message is malformed, just pass it 345 // through - we only care about well formed messages to the host. 346 if (untrusted_msg.type() == PpapiHostMsg_ResourceCall::ID) { 347 ResourceMessageCallParams params; 348 IPC::Message nested_msg; 349 if (!UnpackMessage<PpapiHostMsg_ResourceCall>( 350 untrusted_msg, ¶ms, &nested_msg)) 351 return; 352 353 switch (nested_msg.type()) { 354 case PpapiHostMsg_FileIO_Close::ID: { 355 FileIOMap::iterator it = files_.find(params.pp_resource()); 356 if (it == files_.end()) 357 return; 358 // Audit FileIO Close messages to make sure the plugin reports an 359 // accurate file size. 360 FileGrowth file_growth; 361 if (!UnpackMessage<PpapiHostMsg_FileIO_Close>( 362 nested_msg, &file_growth)) 363 return; 364 365 int64_t trusted_max_written_offset = it->second->max_written_offset(); 366 delete it->second; 367 files_.erase(it); 368 // If the plugin is under-reporting, rewrite the message with the 369 // trusted value. 370 if (trusted_max_written_offset > file_growth.max_written_offset) { 371 new_msg_ptr->reset( 372 new PpapiHostMsg_ResourceCall( 373 params, 374 PpapiHostMsg_FileIO_Close( 375 FileGrowth(trusted_max_written_offset, 0)))); 376 } 377 break; 378 } 379 case PpapiHostMsg_FileIO_SetLength::ID: { 380 FileIOMap::iterator it = files_.find(params.pp_resource()); 381 if (it == files_.end()) 382 return; 383 // Audit FileIO SetLength messages to make sure the plugin is within 384 // the current quota reservation. In addition, deduct the file size 385 // increase from the quota reservation. 386 int64_t length = 0; 387 if (!UnpackMessage<PpapiHostMsg_FileIO_SetLength>( 388 nested_msg, &length)) 389 return; 390 391 // Calculate file size increase, taking care to avoid overflows. 392 if (length < 0) 393 return; 394 int64_t trusted_max_written_offset = it->second->max_written_offset(); 395 int64_t increase = length - trusted_max_written_offset; 396 if (increase <= 0) 397 return; 398 if (!it->second->Grow(increase)) { 399 new_msg_ptr->reset( 400 new PpapiHostMsg_ResourceCall( 401 params, 402 PpapiHostMsg_FileIO_SetLength(-1))); 403 } 404 break; 405 } 406 case PpapiHostMsg_FileSystem_ReserveQuota::ID: { 407 // Audit FileSystem ReserveQuota messages to make sure the plugin 408 // reports accurate file sizes. 409 int64_t amount = 0; 410 FileGrowthMap file_growths; 411 if (!UnpackMessage<PpapiHostMsg_FileSystem_ReserveQuota>( 412 nested_msg, &amount, &file_growths)) 413 return; 414 415 bool audit_failed = false; 416 for (FileGrowthMap::iterator it = file_growths.begin(); 417 it != file_growths.end(); ++it) { 418 FileIOMap::iterator file_it = files_.find(it->first); 419 if (file_it == files_.end()) 420 continue; 421 int64_t trusted_max_written_offset = 422 file_it->second->max_written_offset(); 423 if (trusted_max_written_offset > it->second.max_written_offset) { 424 audit_failed = true; 425 it->second.max_written_offset = trusted_max_written_offset; 426 } 427 if (it->second.append_mode_write_amount < 0) { 428 audit_failed = true; 429 it->second.append_mode_write_amount = 0; 430 } 431 } 432 if (audit_failed) { 433 new_msg_ptr->reset( 434 new PpapiHostMsg_ResourceCall( 435 params, 436 PpapiHostMsg_FileSystem_ReserveQuota( 437 amount, file_growths))); 438 } 439 break; 440 } 441 case PpapiHostMsg_ResourceDestroyed::ID: { 442 // Audit resource destroyed messages to release FileSystems. 443 PP_Resource resource; 444 if (!UnpackMessage<PpapiHostMsg_ResourceDestroyed>( 445 nested_msg, &resource)) 446 return; 447 FileSystemMap::iterator fs_it = file_systems_.find(resource); 448 if (fs_it != file_systems_.end()) { 449 delete fs_it->second; 450 file_systems_.erase(fs_it); 451 } 452 break; 453 } 454 } 455 } 456} 457 458NaClMessageScanner::FileIO* NaClMessageScanner::GetFile( 459 PP_Resource file_io) { 460 FileIOMap::iterator it = files_.find(file_io); 461 DCHECK(it != files_.end()); 462 return it->second; 463} 464 465void NaClMessageScanner::AuditNestedMessage(PP_Resource resource, 466 const IPC::Message& msg, 467 SerializedHandle* handle) { 468 switch (msg.type()) { 469 case PpapiPluginMsg_FileIO_OpenReply::ID: { 470 // A file that requires quota checking was opened. 471 PP_Resource quota_file_system; 472 int64_t max_written_offset = 0; 473 if (ppapi::UnpackMessage<PpapiPluginMsg_FileIO_OpenReply>( 474 msg, "a_file_system, &max_written_offset)) { 475 if (quota_file_system) { 476 // Look up the FileSystem by inserting a new one. If it was already 477 // present, get the existing one, otherwise construct it. 478 FileSystem* file_system = NULL; 479 std::pair<FileSystemMap::iterator, bool> insert_result = 480 file_systems_.insert(std::make_pair(quota_file_system, 481 file_system)); 482 if (insert_result.second) 483 insert_result.first->second = new FileSystem(); 484 file_system = insert_result.first->second; 485 // Create the FileIO. 486 DCHECK(files_.find(resource) == files_.end()); 487 files_.insert(std::make_pair( 488 resource, 489 new FileIO(file_system, max_written_offset))); 490 } 491 } 492 break; 493 } 494 case PpapiPluginMsg_FileSystem_ReserveQuotaReply::ID: { 495 // The amount of reserved quota for a FileSystem was refreshed. 496 int64_t amount = 0; 497 FileSizeMap file_sizes; 498 if (ppapi::UnpackMessage<PpapiPluginMsg_FileSystem_ReserveQuotaReply>( 499 msg, &amount, &file_sizes)) { 500 FileSystemMap::iterator it = file_systems_.find(resource); 501 DCHECK(it != file_systems_.end()); 502 it->second->UpdateReservedQuota(amount); 503 504 FileSizeMap::const_iterator offset_it = file_sizes.begin(); 505 for (; offset_it != file_sizes.end(); ++offset_it) { 506 FileIOMap::iterator fio_it = files_.find(offset_it->first); 507 DCHECK(fio_it != files_.end()); 508 if (fio_it != files_.end()) 509 fio_it->second->SetMaxWrittenOffset(offset_it->second); 510 } 511 } 512 break; 513 } 514 } 515} 516 517} // namespace proxy 518} // namespace ppapi 519