Home | History | Annotate | Download | only in loader
      1 // Copyright 2013 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "components/nacl/loader/nacl_ipc_adapter.h"
      6 
      7 #include <limits.h>
      8 #include <string.h>
      9 
     10 #include "base/basictypes.h"
     11 #include "base/bind.h"
     12 #include "base/location.h"
     13 #include "base/memory/scoped_ptr.h"
     14 #include "base/memory/shared_memory.h"
     15 #include "build/build_config.h"
     16 #include "ipc/ipc_channel.h"
     17 #include "ipc/ipc_platform_file.h"
     18 #include "native_client/src/trusted/desc/nacl_desc_base.h"
     19 #include "native_client/src/trusted/desc/nacl_desc_custom.h"
     20 #include "native_client/src/trusted/desc/nacl_desc_imc_shm.h"
     21 #include "native_client/src/trusted/desc/nacl_desc_io.h"
     22 #include "native_client/src/trusted/desc/nacl_desc_quota.h"
     23 #include "native_client/src/trusted/desc/nacl_desc_quota_interface.h"
     24 #include "native_client/src/trusted/desc/nacl_desc_sync_socket.h"
     25 #include "native_client/src/trusted/desc/nacl_desc_wrapper.h"
     26 #include "native_client/src/trusted/service_runtime/include/sys/fcntl.h"
     27 #include "ppapi/c/ppb_file_io.h"
     28 #include "ppapi/proxy/ppapi_messages.h"
     29 #include "ppapi/proxy/serialized_handle.h"
     30 
     31 using ppapi::proxy::NaClMessageScanner;
     32 
     33 namespace {
     34 
     35 enum BufferSizeStatus {
     36   // The buffer contains a full message with no extra bytes.
     37   MESSAGE_IS_COMPLETE,
     38 
     39   // The message doesn't fit and the buffer contains only some of it.
     40   MESSAGE_IS_TRUNCATED,
     41 
     42   // The buffer contains a full message + extra data.
     43   MESSAGE_HAS_EXTRA_DATA
     44 };
     45 
     46 BufferSizeStatus GetBufferStatus(const char* data, size_t len) {
     47   if (len < sizeof(NaClIPCAdapter::NaClMessageHeader))
     48     return MESSAGE_IS_TRUNCATED;
     49 
     50   const NaClIPCAdapter::NaClMessageHeader* header =
     51       reinterpret_cast<const NaClIPCAdapter::NaClMessageHeader*>(data);
     52   uint32 message_size =
     53       sizeof(NaClIPCAdapter::NaClMessageHeader) + header->payload_size;
     54 
     55   if (len == message_size)
     56     return MESSAGE_IS_COMPLETE;
     57   if (len > message_size)
     58     return MESSAGE_HAS_EXTRA_DATA;
     59   return MESSAGE_IS_TRUNCATED;
     60 }
     61 
     62 //------------------------------------------------------------------------------
     63 // This object allows the NaClDesc to hold a reference to a NaClIPCAdapter and
     64 // forward calls to it.
     65 struct DescThunker {
     66   explicit DescThunker(NaClIPCAdapter* adapter_arg)
     67       : adapter(adapter_arg) {
     68   }
     69   scoped_refptr<NaClIPCAdapter> adapter;
     70 };
     71 
     72 NaClIPCAdapter* ToAdapter(void* handle) {
     73   return static_cast<DescThunker*>(handle)->adapter.get();
     74 }
     75 
     76 // NaClDescCustom implementation.
     77 void NaClDescCustomDestroy(void* handle) {
     78   delete static_cast<DescThunker*>(handle);
     79 }
     80 
     81 ssize_t NaClDescCustomSendMsg(void* handle, const NaClImcTypedMsgHdr* msg,
     82                               int /* flags */) {
     83   return static_cast<ssize_t>(ToAdapter(handle)->Send(msg));
     84 }
     85 
     86 ssize_t NaClDescCustomRecvMsg(void* handle, NaClImcTypedMsgHdr* msg,
     87                               int /* flags */) {
     88   return static_cast<ssize_t>(ToAdapter(handle)->BlockingReceive(msg));
     89 }
     90 
     91 NaClDesc* MakeNaClDescCustom(NaClIPCAdapter* adapter) {
     92   NaClDescCustomFuncs funcs = NACL_DESC_CUSTOM_FUNCS_INITIALIZER;
     93   funcs.Destroy = NaClDescCustomDestroy;
     94   funcs.SendMsg = NaClDescCustomSendMsg;
     95   funcs.RecvMsg = NaClDescCustomRecvMsg;
     96   // NaClDescMakeCustomDesc gives us a reference on the returned NaClDesc.
     97   return NaClDescMakeCustomDesc(new DescThunker(adapter), &funcs);
     98 }
     99 
    100 //------------------------------------------------------------------------------
    101 // This object is passed to a NaClDescQuota to intercept writes and forward them
    102 // to the NaClIPCAdapter, which checks quota. This is a NaCl-style struct. Don't
    103 // add non-trivial fields or virtual methods. Construction should use malloc,
    104 // because this is owned by the NaClDesc, and the NaCl Dtor code will call free.
    105 struct QuotaInterface {
    106   // The "base" struct must be first. NaCl code expects a NaCl style ref-counted
    107   // object, so the "vtable" and other base class fields must be first.
    108   struct NaClDescQuotaInterface base NACL_IS_REFCOUNT_SUBCLASS;
    109 
    110   NaClMessageScanner::FileIO* file_io;
    111 };
    112 
    113 static void QuotaInterfaceDtor(NaClRefCount* nrcp) {
    114   // Trivial class, just pass through to the "base" struct Dtor.
    115   nrcp->vtbl = reinterpret_cast<NaClRefCountVtbl*>(
    116       const_cast<NaClDescQuotaInterfaceVtbl*>(&kNaClDescQuotaInterfaceVtbl));
    117   (*nrcp->vtbl->Dtor)(nrcp);
    118 }
    119 
    120 static int64_t QuotaInterfaceWriteRequest(NaClDescQuotaInterface* ndqi,
    121                                           const uint8_t* /* unused_id */,
    122                                           int64_t offset,
    123                                           int64_t length) {
    124   if (offset < 0 || length < 0)
    125     return 0;
    126   if (std::numeric_limits<int64_t>::max() - length < offset)
    127     return 0;  // offset + length would overflow.
    128   int64_t max_offset = offset + length;
    129   if (max_offset < 0)
    130     return 0;
    131 
    132   QuotaInterface* quota_interface = reinterpret_cast<QuotaInterface*>(ndqi);
    133   NaClMessageScanner::FileIO* file_io = quota_interface->file_io;
    134   int64_t increase = max_offset - file_io->max_written_offset();
    135   if (increase <= 0 || file_io->Grow(increase))
    136     return length;
    137 
    138   return 0;
    139 }
    140 
    141 static int64_t QuotaInterfaceFtruncateRequest(NaClDescQuotaInterface* ndqi,
    142                                               const uint8_t* /* unused_id */,
    143                                               int64_t length) {
    144   // We can't implement SetLength on the plugin side due to sandbox limitations.
    145   // See crbug.com/156077.
    146   NOTREACHED();
    147   return 0;
    148 }
    149 
    150 static const struct NaClDescQuotaInterfaceVtbl kQuotaInterfaceVtbl = {
    151   {
    152     QuotaInterfaceDtor
    153   },
    154   QuotaInterfaceWriteRequest,
    155   QuotaInterfaceFtruncateRequest
    156 };
    157 
    158 NaClDesc* MakeNaClDescQuota(
    159     NaClMessageScanner::FileIO* file_io,
    160     NaClDesc* wrapped_desc) {
    161   // Create the QuotaInterface.
    162   QuotaInterface* quota_interface =
    163       static_cast<QuotaInterface*>(malloc(sizeof *quota_interface));
    164   if (quota_interface && NaClDescQuotaInterfaceCtor(&quota_interface->base)) {
    165     quota_interface->base.base.vtbl =
    166         (struct NaClRefCountVtbl *)(&kQuotaInterfaceVtbl);
    167     // QuotaInterface is a trivial class, so skip the ctor.
    168     quota_interface->file_io = file_io;
    169     // Create the NaClDescQuota.
    170     NaClDescQuota* desc = static_cast<NaClDescQuota*>(malloc(sizeof *desc));
    171     uint8_t unused_id[NACL_DESC_QUOTA_FILE_ID_LEN] = {0};
    172     if (desc && NaClDescQuotaCtor(desc,
    173                                   wrapped_desc,
    174                                   unused_id,
    175                                   &quota_interface->base)) {
    176       return &desc->base;
    177     }
    178     if (desc)
    179       NaClDescUnref(reinterpret_cast<NaClDesc*>(desc));
    180   }
    181 
    182   if (quota_interface)
    183     NaClDescQuotaInterfaceUnref(&quota_interface->base);
    184 
    185   return NULL;
    186 }
    187 
    188 //------------------------------------------------------------------------------
    189 
    190 void DeleteChannel(IPC::Channel* channel) {
    191   delete channel;
    192 }
    193 
    194 // Translates Pepper's read/write open flags into the NaCl equivalents.
    195 // Since the host has already opened the file, flags such as O_CREAT, O_TRUNC,
    196 // and O_EXCL don't make sense, so we filter those out. If no read or write
    197 // flags are set, the function returns NACL_ABI_O_RDONLY as a safe fallback.
    198 int TranslatePepperFileReadWriteOpenFlags(int32_t pp_open_flags) {
    199   bool read = (pp_open_flags & PP_FILEOPENFLAG_READ) != 0;
    200   bool write = (pp_open_flags & PP_FILEOPENFLAG_WRITE) != 0;
    201   bool append = (pp_open_flags & PP_FILEOPENFLAG_APPEND) != 0;
    202 
    203   int nacl_open_flag = NACL_ABI_O_RDONLY;  // NACL_ABI_O_RDONLY == 0.
    204   if (read && (write || append)) {
    205     nacl_open_flag = NACL_ABI_O_RDWR;
    206   } else if (write || append) {
    207     nacl_open_flag = NACL_ABI_O_WRONLY;
    208   } else if (!read) {
    209     DLOG(WARNING) << "One of PP_FILEOPENFLAG_READ, PP_FILEOPENFLAG_WRITE, "
    210                   << "or PP_FILEOPENFLAG_APPEND should be set.";
    211   }
    212   if (append)
    213     nacl_open_flag |= NACL_ABI_O_APPEND;
    214 
    215   return nacl_open_flag;
    216 }
    217 
    218 class NaClDescWrapper {
    219  public:
    220   explicit NaClDescWrapper(NaClDesc* desc): desc_(desc) {}
    221   ~NaClDescWrapper() {
    222     NaClDescUnref(desc_);
    223   }
    224 
    225   NaClDesc* desc() { return desc_; }
    226 
    227  private:
    228   NaClDesc* desc_;
    229   DISALLOW_COPY_AND_ASSIGN(NaClDescWrapper);
    230 };
    231 
    232 }  // namespace
    233 
    234 class NaClIPCAdapter::RewrittenMessage
    235     : public base::RefCounted<RewrittenMessage> {
    236  public:
    237   RewrittenMessage();
    238 
    239   bool is_consumed() const { return data_read_cursor_ == data_len_; }
    240 
    241   void SetData(const NaClIPCAdapter::NaClMessageHeader& header,
    242                const void* payload, size_t payload_length);
    243 
    244   int Read(NaClImcTypedMsgHdr* msg);
    245 
    246   void AddDescriptor(NaClDescWrapper* desc) { descs_.push_back(desc); }
    247 
    248   size_t desc_count() const { return descs_.size(); }
    249 
    250  private:
    251   friend class base::RefCounted<RewrittenMessage>;
    252   ~RewrittenMessage() {}
    253 
    254   scoped_ptr<char[]> data_;
    255   size_t data_len_;
    256 
    257   // Offset into data where the next read will happen. This will be equal to
    258   // data_len_ when all data has been consumed.
    259   size_t data_read_cursor_;
    260 
    261   // Wrapped descriptors for transfer to untrusted code.
    262   ScopedVector<NaClDescWrapper> descs_;
    263 };
    264 
    265 NaClIPCAdapter::RewrittenMessage::RewrittenMessage()
    266     : data_len_(0),
    267       data_read_cursor_(0) {
    268 }
    269 
    270 void NaClIPCAdapter::RewrittenMessage::SetData(
    271     const NaClIPCAdapter::NaClMessageHeader& header,
    272     const void* payload,
    273     size_t payload_length) {
    274   DCHECK(!data_.get() && data_len_ == 0);
    275   size_t header_len = sizeof(NaClIPCAdapter::NaClMessageHeader);
    276   data_len_ = header_len + payload_length;
    277   data_.reset(new char[data_len_]);
    278 
    279   memcpy(data_.get(), &header, sizeof(NaClIPCAdapter::NaClMessageHeader));
    280   memcpy(&data_[header_len], payload, payload_length);
    281 }
    282 
    283 int NaClIPCAdapter::RewrittenMessage::Read(NaClImcTypedMsgHdr* msg) {
    284   CHECK(data_len_ >= data_read_cursor_);
    285   char* dest_buffer = static_cast<char*>(msg->iov[0].base);
    286   size_t dest_buffer_size = msg->iov[0].length;
    287   size_t bytes_to_write = std::min(dest_buffer_size,
    288                                    data_len_ - data_read_cursor_);
    289   if (bytes_to_write == 0)
    290     return 0;
    291 
    292   memcpy(dest_buffer, &data_[data_read_cursor_], bytes_to_write);
    293   data_read_cursor_ += bytes_to_write;
    294 
    295   // Once all data has been consumed, transfer any file descriptors.
    296   if (is_consumed()) {
    297     nacl_abi_size_t desc_count = static_cast<nacl_abi_size_t>(descs_.size());
    298     CHECK(desc_count <= msg->ndesc_length);
    299     msg->ndesc_length = desc_count;
    300     for (nacl_abi_size_t i = 0; i < desc_count; i++) {
    301       // Copy the NaClDesc to the buffer and add a ref so it won't be freed
    302       // when we clear our ScopedVector.
    303       msg->ndescv[i] = descs_[i]->desc();
    304       NaClDescRef(descs_[i]->desc());
    305     }
    306     descs_.clear();
    307   } else {
    308     msg->ndesc_length = 0;
    309   }
    310   return static_cast<int>(bytes_to_write);
    311 }
    312 
    313 NaClIPCAdapter::LockedData::LockedData()
    314     : channel_closed_(false) {
    315 }
    316 
    317 NaClIPCAdapter::LockedData::~LockedData() {
    318 }
    319 
    320 NaClIPCAdapter::IOThreadData::IOThreadData() {
    321 }
    322 
    323 NaClIPCAdapter::IOThreadData::~IOThreadData() {
    324 }
    325 
    326 NaClIPCAdapter::NaClIPCAdapter(const IPC::ChannelHandle& handle,
    327                                base::TaskRunner* runner)
    328     : lock_(),
    329       cond_var_(&lock_),
    330       task_runner_(runner),
    331       locked_data_() {
    332   io_thread_data_.channel_ = IPC::Channel::CreateServer(handle, this);
    333   // Note, we can not PostTask for ConnectChannelOnIOThread here. If we did,
    334   // and that task ran before this constructor completes, the reference count
    335   // would go to 1 and then to 0 because of the Task, before we've been returned
    336   // to the owning scoped_refptr, which is supposed to give us our first
    337   // ref-count.
    338 }
    339 
    340 NaClIPCAdapter::NaClIPCAdapter(scoped_ptr<IPC::Channel> channel,
    341                                base::TaskRunner* runner)
    342     : lock_(),
    343       cond_var_(&lock_),
    344       task_runner_(runner),
    345       locked_data_() {
    346   io_thread_data_.channel_ = channel.Pass();
    347 }
    348 
    349 void NaClIPCAdapter::ConnectChannel() {
    350   task_runner_->PostTask(FROM_HERE,
    351       base::Bind(&NaClIPCAdapter::ConnectChannelOnIOThread, this));
    352 }
    353 
    354 // Note that this message is controlled by the untrusted code. So we should be
    355 // skeptical of anything it contains and quick to give up if anything is fishy.
    356 int NaClIPCAdapter::Send(const NaClImcTypedMsgHdr* msg) {
    357   if (msg->iov_length != 1)
    358     return -1;
    359 
    360   base::AutoLock lock(lock_);
    361 
    362   const char* input_data = static_cast<char*>(msg->iov[0].base);
    363   size_t input_data_len = msg->iov[0].length;
    364   if (input_data_len > IPC::Channel::kMaximumMessageSize) {
    365     ClearToBeSent();
    366     return -1;
    367   }
    368 
    369   // current_message[_len] refers to the total input data received so far.
    370   const char* current_message;
    371   size_t current_message_len;
    372   bool did_append_input_data;
    373   if (locked_data_.to_be_sent_.empty()) {
    374     // No accumulated data, we can avoid a copy by referring to the input
    375     // buffer (the entire message fitting in one call is the common case).
    376     current_message = input_data;
    377     current_message_len = input_data_len;
    378     did_append_input_data = false;
    379   } else {
    380     // We've already accumulated some data, accumulate this new data and
    381     // point to the beginning of the buffer.
    382 
    383     // Make sure our accumulated message size doesn't overflow our max. Since
    384     // we know that data_len < max size (checked above) and our current
    385     // accumulated value is also < max size, we just need to make sure that
    386     // 2x max size can never overflow.
    387     COMPILE_ASSERT(IPC::Channel::kMaximumMessageSize < (UINT_MAX / 2),
    388                    MaximumMessageSizeWillOverflow);
    389     size_t new_size = locked_data_.to_be_sent_.size() + input_data_len;
    390     if (new_size > IPC::Channel::kMaximumMessageSize) {
    391       ClearToBeSent();
    392       return -1;
    393     }
    394 
    395     locked_data_.to_be_sent_.append(input_data, input_data_len);
    396     current_message = &locked_data_.to_be_sent_[0];
    397     current_message_len = locked_data_.to_be_sent_.size();
    398     did_append_input_data = true;
    399   }
    400 
    401   // Check the total data we've accumulated so far to see if it contains a full
    402   // message.
    403   switch (GetBufferStatus(current_message, current_message_len)) {
    404     case MESSAGE_IS_COMPLETE: {
    405       // Got a complete message, can send it out. This will be the common case.
    406       bool success = SendCompleteMessage(current_message, current_message_len);
    407       ClearToBeSent();
    408       return success ? static_cast<int>(input_data_len) : -1;
    409     }
    410     case MESSAGE_IS_TRUNCATED:
    411       // For truncated messages, just accumulate the new data (if we didn't
    412       // already do so above) and go back to waiting for more.
    413       if (!did_append_input_data)
    414         locked_data_.to_be_sent_.append(input_data, input_data_len);
    415       return static_cast<int>(input_data_len);
    416     case MESSAGE_HAS_EXTRA_DATA:
    417     default:
    418       // When the plugin gives us too much data, it's an error.
    419       ClearToBeSent();
    420       return -1;
    421   }
    422 }
    423 
    424 int NaClIPCAdapter::BlockingReceive(NaClImcTypedMsgHdr* msg) {
    425   if (msg->iov_length != 1)
    426     return -1;
    427 
    428   int retval = 0;
    429   {
    430     base::AutoLock lock(lock_);
    431     while (locked_data_.to_be_received_.empty() &&
    432            !locked_data_.channel_closed_)
    433       cond_var_.Wait();
    434     if (locked_data_.channel_closed_) {
    435       retval = -1;
    436     } else {
    437       retval = LockedReceive(msg);
    438       DCHECK(retval > 0);
    439     }
    440   }
    441   cond_var_.Signal();
    442   return retval;
    443 }
    444 
    445 void NaClIPCAdapter::CloseChannel() {
    446   {
    447     base::AutoLock lock(lock_);
    448     locked_data_.channel_closed_ = true;
    449   }
    450   cond_var_.Signal();
    451 
    452   task_runner_->PostTask(FROM_HERE,
    453       base::Bind(&NaClIPCAdapter::CloseChannelOnIOThread, this));
    454 }
    455 
    456 NaClDesc* NaClIPCAdapter::MakeNaClDesc() {
    457   return MakeNaClDescCustom(this);
    458 }
    459 
    460 #if defined(OS_POSIX)
    461 int NaClIPCAdapter::TakeClientFileDescriptor() {
    462   return io_thread_data_.channel_->TakeClientFileDescriptor();
    463 }
    464 #endif
    465 
    466 bool NaClIPCAdapter::OnMessageReceived(const IPC::Message& msg) {
    467   {
    468     base::AutoLock lock(lock_);
    469 
    470     scoped_refptr<RewrittenMessage> rewritten_msg(new RewrittenMessage);
    471 
    472     typedef std::vector<ppapi::proxy::SerializedHandle> Handles;
    473     Handles handles;
    474     scoped_ptr<IPC::Message> new_msg;
    475     if (!locked_data_.nacl_msg_scanner_.ScanMessage(msg, &handles, &new_msg))
    476       return false;
    477 
    478     // Now add any descriptors we found to rewritten_msg. |handles| is usually
    479     // empty, unless we read a message containing a FD or handle.
    480     for (Handles::const_iterator iter = handles.begin();
    481          iter != handles.end();
    482          ++iter) {
    483       scoped_ptr<NaClDescWrapper> nacl_desc;
    484       switch (iter->type()) {
    485         case ppapi::proxy::SerializedHandle::SHARED_MEMORY: {
    486           const base::SharedMemoryHandle& shm_handle = iter->shmem();
    487           uint32_t size = iter->size();
    488           nacl_desc.reset(new NaClDescWrapper(NaClDescImcShmMake(
    489 #if defined(OS_WIN)
    490               shm_handle,
    491 #else
    492               shm_handle.fd,
    493 #endif
    494               static_cast<size_t>(size))));
    495           break;
    496         }
    497         case ppapi::proxy::SerializedHandle::SOCKET: {
    498           nacl_desc.reset(new NaClDescWrapper(NaClDescSyncSocketMake(
    499 #if defined(OS_WIN)
    500               iter->descriptor()
    501 #else
    502               iter->descriptor().fd
    503 #endif
    504           )));
    505           break;
    506         }
    507         case ppapi::proxy::SerializedHandle::FILE: {
    508           // Create the NaClDesc for the file descriptor. If quota checking is
    509           // required, wrap it in a NaClDescQuota.
    510           NaClDesc* desc = NaClDescIoDescFromHandleAllocCtor(
    511 #if defined(OS_WIN)
    512               iter->descriptor(),
    513 #else
    514               iter->descriptor().fd,
    515 #endif
    516               TranslatePepperFileReadWriteOpenFlags(iter->open_flags()));
    517           if (desc && iter->file_io()) {
    518             desc = MakeNaClDescQuota(
    519                 locked_data_.nacl_msg_scanner_.GetFile(iter->file_io()),
    520                 desc);
    521           }
    522           if (desc)
    523             nacl_desc.reset(new NaClDescWrapper(desc));
    524           break;
    525         }
    526 
    527         case ppapi::proxy::SerializedHandle::INVALID: {
    528           // Nothing to do. TODO(dmichael): Should we log this? Or is it
    529           // sometimes okay to pass an INVALID handle?
    530           break;
    531         }
    532         // No default, so the compiler will warn us if new types get added.
    533       }
    534       if (nacl_desc.get())
    535         rewritten_msg->AddDescriptor(nacl_desc.release());
    536     }
    537     if (new_msg)
    538       SaveMessage(*new_msg, rewritten_msg.get());
    539     else
    540       SaveMessage(msg, rewritten_msg.get());
    541   }
    542   cond_var_.Signal();
    543   return true;
    544 }
    545 
    546 void NaClIPCAdapter::OnChannelConnected(int32 peer_pid) {
    547 }
    548 
    549 void NaClIPCAdapter::OnChannelError() {
    550   CloseChannel();
    551 }
    552 
    553 NaClIPCAdapter::~NaClIPCAdapter() {
    554   // Make sure the channel is deleted on the IO thread.
    555   task_runner_->PostTask(FROM_HERE,
    556       base::Bind(&DeleteChannel, io_thread_data_.channel_.release()));
    557 }
    558 
    559 int NaClIPCAdapter::LockedReceive(NaClImcTypedMsgHdr* msg) {
    560   lock_.AssertAcquired();
    561 
    562   if (locked_data_.to_be_received_.empty())
    563     return 0;
    564   scoped_refptr<RewrittenMessage> current =
    565       locked_data_.to_be_received_.front();
    566 
    567   int retval = current->Read(msg);
    568 
    569   // When a message is entirely consumed, remove if from the waiting queue.
    570   if (current->is_consumed())
    571     locked_data_.to_be_received_.pop();
    572 
    573   return retval;
    574 }
    575 
    576 bool NaClIPCAdapter::SendCompleteMessage(const char* buffer,
    577                                          size_t buffer_len) {
    578   lock_.AssertAcquired();
    579   // The message will have already been validated, so we know it's large enough
    580   // for our header.
    581   const NaClMessageHeader* header =
    582       reinterpret_cast<const NaClMessageHeader*>(buffer);
    583 
    584   // Length of the message not including the body. The data passed to us by the
    585   // plugin should match that in the message header. This should have already
    586   // been validated by GetBufferStatus.
    587   int body_len = static_cast<int>(buffer_len - sizeof(NaClMessageHeader));
    588   DCHECK(body_len == static_cast<int>(header->payload_size));
    589 
    590   // We actually discard the flags and only copy the ones we care about. This
    591   // is just because message doesn't have a constructor that takes raw flags.
    592   scoped_ptr<IPC::Message> msg(
    593       new IPC::Message(header->routing, header->type,
    594                        IPC::Message::PRIORITY_NORMAL));
    595   if (header->flags & IPC::Message::SYNC_BIT)
    596     msg->set_sync();
    597   if (header->flags & IPC::Message::REPLY_BIT)
    598     msg->set_reply();
    599   if (header->flags & IPC::Message::REPLY_ERROR_BIT)
    600     msg->set_reply_error();
    601   if (header->flags & IPC::Message::UNBLOCK_BIT)
    602     msg->set_unblock(true);
    603 
    604   msg->WriteBytes(&buffer[sizeof(NaClMessageHeader)], body_len);
    605 
    606   // Technically we didn't have to do any of the previous work in the lock. But
    607   // sometimes our buffer will point to the to_be_sent_ string which is
    608   // protected by the lock, and it's messier to factor Send() such that it can
    609   // unlock for us. Holding the lock for the message construction, which is
    610   // just some memcpys, shouldn't be a big deal.
    611   lock_.AssertAcquired();
    612   if (locked_data_.channel_closed_) {
    613     // If we ever pass handles from the plugin to the host, we should close them
    614     // here before we drop the message.
    615     return false;
    616   }
    617 
    618   // Scan all untrusted messages.
    619   scoped_ptr<IPC::Message> new_msg;
    620   locked_data_.nacl_msg_scanner_.ScanUntrustedMessage(*msg, &new_msg);
    621   if (new_msg)
    622     msg.reset(new_msg.release());
    623 
    624   // Actual send must be done on the I/O thread.
    625   task_runner_->PostTask(FROM_HERE,
    626       base::Bind(&NaClIPCAdapter::SendMessageOnIOThread, this,
    627                  base::Passed(&msg)));
    628   return true;
    629 }
    630 
    631 void NaClIPCAdapter::ClearToBeSent() {
    632   lock_.AssertAcquired();
    633 
    634   // Don't let the string keep its buffer behind our back.
    635   std::string empty;
    636   locked_data_.to_be_sent_.swap(empty);
    637 }
    638 
    639 void NaClIPCAdapter::ConnectChannelOnIOThread() {
    640   if (!io_thread_data_.channel_->Connect())
    641     NOTREACHED();
    642 }
    643 
    644 void NaClIPCAdapter::CloseChannelOnIOThread() {
    645   io_thread_data_.channel_->Close();
    646 }
    647 
    648 void NaClIPCAdapter::SendMessageOnIOThread(scoped_ptr<IPC::Message> message) {
    649   io_thread_data_.channel_->Send(message.release());
    650 }
    651 
    652 void NaClIPCAdapter::SaveMessage(const IPC::Message& msg,
    653                                  RewrittenMessage* rewritten_msg) {
    654   lock_.AssertAcquired();
    655   // There is some padding in this structure (the "padding" member is 16
    656   // bits but this then gets padded to 32 bits). We want to be sure not to
    657   // leak data to the untrusted plugin, so zero everything out first.
    658   NaClMessageHeader header;
    659   memset(&header, 0, sizeof(NaClMessageHeader));
    660 
    661   header.payload_size = static_cast<uint32>(msg.payload_size());
    662   header.routing = msg.routing_id();
    663   header.type = msg.type();
    664   header.flags = msg.flags();
    665   header.num_fds = static_cast<int>(rewritten_msg->desc_count());
    666 
    667   rewritten_msg->SetData(header, msg.payload(), msg.payload_size());
    668   locked_data_.to_be_received_.push(rewritten_msg);
    669 }
    670 
    671 int TranslatePepperFileReadWriteOpenFlagsForTesting(int32_t pp_open_flags) {
    672   return TranslatePepperFileReadWriteOpenFlags(pp_open_flags);
    673 }
    674