| Index: ppapi/proxy/nacl_message_scanner.cc
|
| diff --git a/ppapi/proxy/handle_converter.cc b/ppapi/proxy/nacl_message_scanner.cc
|
| similarity index 43%
|
| rename from ppapi/proxy/handle_converter.cc
|
| rename to ppapi/proxy/nacl_message_scanner.cc
|
| index 587585b53b6e449311721e83f120031beabd7395..4a9018e10a0e2177f02d87ad3472b9778dbaccd4 100644
|
| --- a/ppapi/proxy/handle_converter.cc
|
| +++ b/ppapi/proxy/nacl_message_scanner.cc
|
| @@ -2,7 +2,7 @@
|
| // Use of this source code is governed by a BSD-style license that can be
|
| // found in the LICENSE file.
|
|
|
| -#include "ppapi/proxy/handle_converter.h"
|
| +#include "ppapi/proxy/nacl_message_scanner.h"
|
|
|
| #include <vector>
|
| #include "base/bind.h"
|
| @@ -21,28 +21,40 @@ class Message;
|
|
|
| namespace {
|
|
|
| +typedef std::vector<ppapi::proxy::SerializedHandle> Handles;
|
| +
|
| +struct ScanningResults {
|
| + ScanningResults() : handle_index(0) {}
|
| +
|
| + // Vector to hold handles found in the message.
|
| + Handles handles;
|
| + // Current handle index in the rewritten message. During the scan, it will be
|
| + // be less than or equal to handles.size(). After the scan it should be equal.
|
| + int handle_index;
|
| + // The rewritten message. This may be NULL, so all ScanParam overloads should
|
| + // check for NULL before writing to it.
|
| + scoped_ptr<IPC::Message> new_msg;
|
| +};
|
| +
|
| void WriteHandle(int handle_index,
|
| const ppapi::proxy::SerializedHandle& handle,
|
| - IPC::Message* message) {
|
| - ppapi::proxy::SerializedHandle::WriteHeader(handle.header(), message);
|
| + IPC::Message* msg) {
|
| + ppapi::proxy::SerializedHandle::WriteHeader(handle.header(), msg);
|
|
|
| // Now write the handle itself in POSIX style.
|
| - message->WriteBool(true); // valid == true
|
| - message->WriteInt(handle_index);
|
| + msg->WriteBool(true); // valid == true
|
| + msg->WriteInt(handle_index);
|
| }
|
|
|
| -typedef std::vector<ppapi::proxy::SerializedHandle> Handles;
|
| +// Define overloads for each kind of message parameter that requires special
|
| +// handling. See ScanTuple for how these get used.
|
|
|
| -// We define overloads for catching SerializedHandles so that we can share
|
| -// them correctly to the untrusted side.
|
| -// See ConvertHandlesImpl for how these get used.
|
| -void ConvertHandlesInParam(const ppapi::proxy::SerializedHandle& handle,
|
| - Handles* handles,
|
| - IPC::Message* msg,
|
| - int* handle_index) {
|
| - handles->push_back(handle);
|
| - if (msg)
|
| - WriteHandle((*handle_index)++, handle, msg);
|
| +// Overload to match SerializedHandle.
|
| +void ScanParam(const ppapi::proxy::SerializedHandle& handle,
|
| + ScanningResults* results) {
|
| + results->handles.push_back(handle);
|
| + if (results->new_msg)
|
| + WriteHandle(results->handle_index++, handle, results->new_msg.get());
|
| }
|
|
|
| void HandleWriter(int* handle_index,
|
| @@ -51,129 +63,112 @@ void HandleWriter(int* handle_index,
|
| WriteHandle((*handle_index)++, handle, m);
|
| }
|
|
|
| -void ConvertHandlesInParam(const ppapi::proxy::SerializedVar& var,
|
| - Handles* handles,
|
| - IPC::Message* msg,
|
| - int* handle_index) {
|
| +// Overload to match SerializedVar, which can contain handles.
|
| +void ScanParam(const ppapi::proxy::SerializedVar& var,
|
| + ScanningResults* results) {
|
| std::vector<ppapi::proxy::SerializedHandle*> var_handles = var.GetHandles();
|
| + // TODO(bbudge) Remove this early out, since a subsequent SerializedVar may
|
| + // contain handles, and we will have dropped this one's data.
|
| if (var_handles.empty())
|
| return;
|
|
|
| for (size_t i = 0; i < var_handles.size(); ++i)
|
| - handles->push_back(*var_handles[i]);
|
| - if (msg)
|
| - var.WriteDataToMessage(msg, base::Bind(&HandleWriter, handle_index));
|
| + results->handles.push_back(*var_handles[i]);
|
| + if (results->new_msg)
|
| + var.WriteDataToMessage(results->new_msg.get(),
|
| + base::Bind(&HandleWriter, &results->handle_index));
|
| }
|
|
|
| // For PpapiMsg_ResourceReply and the reply to PpapiHostMsg_ResourceSyncCall,
|
| // the handles are carried inside the ResourceMessageReplyParams.
|
| -// NOTE: We only translate handles from host->NaCl. The only kind of
|
| +// NOTE: We only intercept handles from host->NaCl. The only kind of
|
| // ResourceMessageParams that travels this direction is
|
| // ResourceMessageReplyParams, so that's the only one we need to handle.
|
| -void ConvertHandlesInParam(
|
| - const ppapi::proxy::ResourceMessageReplyParams& params,
|
| - Handles* handles,
|
| - IPC::Message* msg,
|
| - int* handle_index) {
|
| - // First, if we need to rewrite the message parameters, write everything
|
| - // before the handles (there's nothing after the handles).
|
| - if (msg) {
|
| - params.WriteReplyHeader(msg);
|
| +void ScanParam(const ppapi::proxy::ResourceMessageReplyParams& params,
|
| + ScanningResults* results) {
|
| + // If we need to rewrite the message, write everything before the handles
|
| + // (there's nothing after the handles).
|
| + if (results->new_msg) {
|
| + params.WriteReplyHeader(results->new_msg.get());
|
| // IPC writes the vector length as an int before the contents of the
|
| // vector.
|
| - msg->WriteInt(static_cast<int>(params.handles().size()));
|
| + results->new_msg->WriteInt(static_cast<int>(params.handles().size()));
|
| }
|
| for (Handles::const_iterator iter = params.handles().begin();
|
| iter != params.handles().end();
|
| ++iter) {
|
| - // ConvertHandle will write each handle to |msg|, if necessary.
|
| - ConvertHandlesInParam(*iter, handles, msg, handle_index);
|
| + // ScanParam will write each handle to the new message, if necessary.
|
| + ScanParam(*iter, results);
|
| }
|
| // Tell ResourceMessageReplyParams that we have taken the handles, so it
|
| // shouldn't close them. The NaCl runtime will take ownership of them.
|
| params.ConsumeHandles();
|
| }
|
|
|
| -// This overload is to catch all types other than SerializedHandle or
|
| -// ResourceMessageReplyParams. On Windows, |msg| will be a valid pointer, and we
|
| -// must write |param| to it.
|
| +// Overload to match all other types. If we need to rewrite the message,
|
| +// write the parameter.
|
| template <class T>
|
| -void ConvertHandlesInParam(const T& param,
|
| - Handles* /* handles */,
|
| - IPC::Message* msg,
|
| - int* /* handle_index */) {
|
| - // It's not a handle, so just write to the output message, if necessary.
|
| - if (msg)
|
| - IPC::WriteParam(msg, param);
|
| +void ScanParam(const T& param, ScanningResults* results) {
|
| + if (results->new_msg)
|
| + IPC::WriteParam(results->new_msg.get(), param);
|
| }
|
|
|
| -// These just break apart the given tuple and run ConvertHandle over each param.
|
| -// The idea is to extract any handles in the tuple, while writing all data to
|
| -// msg (if msg is valid). The msg will only be valid on Windows, where we need
|
| -// to re-write all of the message parameters, writing the handles in POSIX style
|
| -// for NaCl.
|
| +// These just break apart the given tuple and run ScanParam over each param.
|
| +// The idea is to scan elements in the tuple which require special handling,
|
| +// and write them into the |results| struct.
|
| template <class A>
|
| -void ConvertHandlesImpl(const Tuple1<A>& t1, Handles* handles,
|
| - IPC::Message* msg) {
|
| - int handle_index = 0;
|
| - ConvertHandlesInParam(t1.a, handles, msg, &handle_index);
|
| +void ScanTuple(const Tuple1<A>& t1, ScanningResults* results) {
|
| + ScanParam(t1.a, results);
|
| }
|
| template <class A, class B>
|
| -void ConvertHandlesImpl(const Tuple2<A, B>& t1, Handles* handles,
|
| - IPC::Message* msg) {
|
| - int handle_index = 0;
|
| - ConvertHandlesInParam(t1.a, handles, msg, &handle_index);
|
| - ConvertHandlesInParam(t1.b, handles, msg, &handle_index);
|
| +void ScanTuple(const Tuple2<A, B>& t1, ScanningResults* results) {
|
| + ScanParam(t1.a, results);
|
| + ScanParam(t1.b, results);
|
| }
|
| template <class A, class B, class C>
|
| -void ConvertHandlesImpl(const Tuple3<A, B, C>& t1, Handles* handles,
|
| - IPC::Message* msg) {
|
| - int handle_index = 0;
|
| - ConvertHandlesInParam(t1.a, handles, msg, &handle_index);
|
| - ConvertHandlesInParam(t1.b, handles, msg, &handle_index);
|
| - ConvertHandlesInParam(t1.c, handles, msg, &handle_index);
|
| +void ScanTuple(const Tuple3<A, B, C>& t1, ScanningResults* results) {
|
| + ScanParam(t1.a, results);
|
| + ScanParam(t1.b, results);
|
| + ScanParam(t1.c, results);
|
| }
|
| template <class A, class B, class C, class D>
|
| -void ConvertHandlesImpl(const Tuple4<A, B, C, D>& t1, Handles* handles,
|
| - IPC::Message* msg) {
|
| - int handle_index = 0;
|
| - ConvertHandlesInParam(t1.a, handles, msg, &handle_index);
|
| - ConvertHandlesInParam(t1.b, handles, msg, &handle_index);
|
| - ConvertHandlesInParam(t1.c, handles, msg, &handle_index);
|
| - ConvertHandlesInParam(t1.d, handles, msg, &handle_index);
|
| +void ScanTuple(const Tuple4<A, B, C, D>& t1, ScanningResults* results) {
|
| + ScanParam(t1.a, results);
|
| + ScanParam(t1.b, results);
|
| + ScanParam(t1.c, results);
|
| + ScanParam(t1.d, results);
|
| }
|
|
|
| template <class MessageType>
|
| -class HandleConverterImpl {
|
| +class MessageScannerImpl {
|
| public:
|
| - explicit HandleConverterImpl(const IPC::Message* msg)
|
| + explicit MessageScannerImpl(const IPC::Message* msg)
|
| : msg_(static_cast<const MessageType*>(msg)) {
|
| }
|
| - bool ConvertMessage(Handles* handles, IPC::Message* out_msg) {
|
| + bool ScanMessage(ScanningResults* results) {
|
| typename TupleTypes<typename MessageType::Schema::Param>::ValueTuple params;
|
| if (!MessageType::Read(msg_, ¶ms))
|
| return false;
|
| - ConvertHandlesImpl(params, handles, out_msg);
|
| + ScanTuple(params, results);
|
| return true;
|
| }
|
|
|
| - bool ConvertReply(Handles* handles, IPC::SyncMessage* out_msg) {
|
| + bool ScanReply(ScanningResults* results) {
|
| typename TupleTypes<typename MessageType::Schema::ReplyParam>::ValueTuple
|
| params;
|
| if (!MessageType::ReadReplyParam(msg_, ¶ms))
|
| return false;
|
| - // If we need to rewrite the message (i.e., on Windows), we need to make
|
| - // sure we write the message id first.
|
| - if (out_msg) {
|
| - out_msg->set_reply();
|
| + // If we need to rewrite the message, write the message id first.
|
| + if (results->new_msg) {
|
| + results->new_msg->set_reply();
|
| int id = IPC::SyncMessage::GetMessageId(*msg_);
|
| - out_msg->WriteInt(id);
|
| + results->new_msg->WriteInt(id);
|
| }
|
| - ConvertHandlesImpl(params, handles, out_msg);
|
| + ScanTuple(params, results);
|
| return true;
|
| }
|
| - // TODO(dmichael): Add ConvertSyncMessage for outgoing sync messages, if we
|
| - // ever pass handles in one of those.
|
| + // TODO(dmichael): Add ScanSyncMessage for outgoing sync messages, if we ever
|
| + // need to scan those.
|
|
|
| private:
|
| const MessageType* msg_;
|
| @@ -183,17 +178,21 @@ class HandleConverterImpl {
|
|
|
| #define CASE_FOR_MESSAGE(MESSAGE_TYPE) \
|
| case MESSAGE_TYPE::ID: { \
|
| - HandleConverterImpl<MESSAGE_TYPE> extractor(&msg); \
|
| - if (!extractor.ConvertMessage(handles, new_msg_ptr->get())) \
|
| + MessageScannerImpl<MESSAGE_TYPE> scanner(&msg); \
|
| + if (rewrite_msg) \
|
| + results.new_msg.reset( \
|
| + new IPC::Message(msg.routing_id(), msg.type())); \
|
| + if (!scanner.ScanMessage(&results)) \
|
| return false; \
|
| break; \
|
| }
|
| #define CASE_FOR_REPLY(MESSAGE_TYPE) \
|
| case MESSAGE_TYPE::ID: { \
|
| - HandleConverterImpl<MESSAGE_TYPE> extractor(&msg); \
|
| - if (!extractor.ConvertReply( \
|
| - handles, \
|
| - static_cast<IPC::SyncMessage*>(new_msg_ptr->get()))) \
|
| + MessageScannerImpl<MESSAGE_TYPE> scanner(&msg); \
|
| + if (rewrite_msg) \
|
| + results.new_msg.reset( \
|
| + new IPC::Message(msg.routing_id(), msg.type())); \
|
| + if (!scanner.ScanReply(&results)) \
|
| return false; \
|
| break; \
|
| }
|
| @@ -203,40 +202,37 @@ namespace proxy {
|
|
|
| class SerializedHandle;
|
|
|
| -HandleConverter::HandleConverter() {
|
| +NaClMessageScanner::NaClMessageScanner() {
|
| }
|
|
|
| -bool HandleConverter::ConvertNativeHandlesToPosix(
|
| +// Windows IPC differs from POSIX in that native handles are serialized in the
|
| +// message body, rather than passed in a separate FileDescriptorSet. Therefore,
|
| +// on Windows, any message containing handles must be rewritten in the POSIX
|
| +// format before we can send it to the NaCl plugin.
|
| +//
|
| +// On POSIX and Windows we have to rewrite PpapiMsg_CreateNaClChannel messages.
|
| +// These contain a handle with an invalid (place holder) descriptor. We need to
|
| +// locate this handle so it can be replaced with a valid one when the channel is
|
| +// created.
|
| +bool NaClMessageScanner::ScanMessage(
|
| const IPC::Message& msg,
|
| std::vector<SerializedHandle>* handles,
|
| scoped_ptr<IPC::Message>* new_msg_ptr) {
|
| DCHECK(handles);
|
| + DCHECK(handles->empty());
|
| DCHECK(new_msg_ptr);
|
| DCHECK(!new_msg_ptr->get());
|
|
|
| - // In Windows, we need to re-write the contents of the message. This is
|
| - // because in Windows IPC code, native HANDLE values are serialized in the
|
| - // body of the message.
|
| - //
|
| - // In POSIX, we only serialize an index in to a FileDescriptorSet, and the
|
| - // actual file descriptors are sent out-of-band. So on Windows, to make a
|
| - // message that's compatible with Windows, we need to write a new message that
|
| - // has simple indices in the message body instead of the HANDLEs.
|
| - //
|
| - // NOTE: This means on Windows, new_msg_ptr's serialized contents are not
|
| - // compatible with Windows IPC deserialization code; it is intended to be
|
| - // passed to NaCl.
|
| + bool rewrite_msg =
|
| #if defined(OS_WIN)
|
| - new_msg_ptr->reset(new IPC::Message(msg.routing_id(), msg.type()));
|
| + true;
|
| #else
|
| - // Even on POSIX, we have to rewrite messages to create channels, because
|
| - // these contain a handle with an invalid (place holder) descriptor. The
|
| - // message sending code sees this and doesn't pass the descriptor over
|
| - // correctly.
|
| - if (msg.type() == PpapiMsg_CreateNaClChannel::ID)
|
| - new_msg_ptr->reset(new IPC::Message(msg.routing_id(), msg.type()));
|
| + (msg.type() == PpapiMsg_CreateNaClChannel::ID);
|
| #endif
|
|
|
| + // We can't always tell from the message ID if rewriting is needed. Therefore,
|
| + // scan any message types that might contain a handle.
|
| + ScanningResults results;
|
| switch (msg.type()) {
|
| CASE_FOR_MESSAGE(PpapiMsg_CreateNaClChannel)
|
| CASE_FOR_MESSAGE(PpapiMsg_PPBAudio_NotifyAudioStreamCreated)
|
| @@ -266,10 +262,18 @@ bool HandleConverter::ConvertNativeHandlesToPosix(
|
| // Do nothing for messages we don't know.
|
| break;
|
| }
|
| +
|
| + // Only messages containing handles need to be rewritten. If no handles are
|
| + // found, don't return the rewritten message either. This must be changed if
|
| + // we ever add new param types that also require rewriting.
|
| + if (!results.handles.empty()) {
|
| + handles->swap(results.handles);
|
| + *new_msg_ptr = results.new_msg.Pass();
|
| + }
|
| return true;
|
| }
|
|
|
| -void HandleConverter::RegisterSyncMessageForReply(const IPC::Message& msg) {
|
| +void NaClMessageScanner::RegisterSyncMessageForReply(const IPC::Message& msg) {
|
| DCHECK(msg.is_sync());
|
|
|
| int msg_id = IPC::SyncMessage::GetMessageId(msg);
|
|
|