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 "base/task_runner_util.h"
     16 #include "build/build_config.h"
     17 #include "ipc/ipc_channel.h"
     18 #include "ipc/ipc_platform_file.h"
     19 #include "native_client/src/trusted/desc/nacl_desc_base.h"
     20 #include "native_client/src/trusted/desc/nacl_desc_custom.h"
     21 #include "native_client/src/trusted/desc/nacl_desc_imc_shm.h"
     22 #include "native_client/src/trusted/desc/nacl_desc_io.h"
     23 #include "native_client/src/trusted/desc/nacl_desc_quota.h"
     24 #include "native_client/src/trusted/desc/nacl_desc_quota_interface.h"
     25 #include "native_client/src/trusted/desc/nacl_desc_sync_socket.h"
     26 #include "native_client/src/trusted/desc/nacl_desc_wrapper.h"
     27 #include "native_client/src/trusted/service_runtime/include/sys/fcntl.h"
     28 #include "native_client/src/trusted/validator/rich_file_info.h"
     29 #include "ppapi/c/ppb_file_io.h"
     30 #include "ppapi/proxy/ppapi_messages.h"
     31 #include "ppapi/proxy/serialized_handle.h"
     32 
     33 using ppapi::proxy::NaClMessageScanner;
     34 
     35 namespace {
     36 
     37 enum BufferSizeStatus {
     38   // The buffer contains a full message with no extra bytes.
     39   MESSAGE_IS_COMPLETE,
     40 
     41   // The message doesn't fit and the buffer contains only some of it.
     42   MESSAGE_IS_TRUNCATED,
     43 
     44   // The buffer contains a full message + extra data.
     45   MESSAGE_HAS_EXTRA_DATA
     46 };
     47 
     48 BufferSizeStatus GetBufferStatus(const char* data, size_t len) {
     49   if (len < sizeof(NaClIPCAdapter::NaClMessageHeader))
     50     return MESSAGE_IS_TRUNCATED;
     51 
     52   const NaClIPCAdapter::NaClMessageHeader* header =
     53       reinterpret_cast<const NaClIPCAdapter::NaClMessageHeader*>(data);
     54   uint32 message_size =
     55       sizeof(NaClIPCAdapter::NaClMessageHeader) + header->payload_size;
     56 
     57   if (len == message_size)
     58     return MESSAGE_IS_COMPLETE;
     59   if (len > message_size)
     60     return MESSAGE_HAS_EXTRA_DATA;
     61   return MESSAGE_IS_TRUNCATED;
     62 }
     63 
     64 //------------------------------------------------------------------------------
     65 // This object allows the NaClDesc to hold a reference to a NaClIPCAdapter and
     66 // forward calls to it.
     67 struct DescThunker {
     68   explicit DescThunker(NaClIPCAdapter* adapter_arg)
     69       : adapter(adapter_arg) {
     70   }
     71   scoped_refptr<NaClIPCAdapter> adapter;
     72 };
     73 
     74 NaClIPCAdapter* ToAdapter(void* handle) {
     75   return static_cast<DescThunker*>(handle)->adapter.get();
     76 }
     77 
     78 // NaClDescCustom implementation.
     79 void NaClDescCustomDestroy(void* handle) {
     80   delete static_cast<DescThunker*>(handle);
     81 }
     82 
     83 ssize_t NaClDescCustomSendMsg(void* handle, const NaClImcTypedMsgHdr* msg,
     84                               int /* flags */) {
     85   return static_cast<ssize_t>(ToAdapter(handle)->Send(msg));
     86 }
     87 
     88 ssize_t NaClDescCustomRecvMsg(void* handle, NaClImcTypedMsgHdr* msg,
     89                               int /* flags */) {
     90   return static_cast<ssize_t>(ToAdapter(handle)->BlockingReceive(msg));
     91 }
     92 
     93 NaClDesc* MakeNaClDescCustom(NaClIPCAdapter* adapter) {
     94   NaClDescCustomFuncs funcs = NACL_DESC_CUSTOM_FUNCS_INITIALIZER;
     95   funcs.Destroy = NaClDescCustomDestroy;
     96   funcs.SendMsg = NaClDescCustomSendMsg;
     97   funcs.RecvMsg = NaClDescCustomRecvMsg;
     98   // NaClDescMakeCustomDesc gives us a reference on the returned NaClDesc.
     99   return NaClDescMakeCustomDesc(new DescThunker(adapter), &funcs);
    100 }
    101 
    102 //------------------------------------------------------------------------------
    103 // This object is passed to a NaClDescQuota to intercept writes and forward them
    104 // to the NaClIPCAdapter, which checks quota. This is a NaCl-style struct. Don't
    105 // add non-trivial fields or virtual methods. Construction should use malloc,
    106 // because this is owned by the NaClDesc, and the NaCl Dtor code will call free.
    107 struct QuotaInterface {
    108   // The "base" struct must be first. NaCl code expects a NaCl style ref-counted
    109   // object, so the "vtable" and other base class fields must be first.
    110   struct NaClDescQuotaInterface base NACL_IS_REFCOUNT_SUBCLASS;
    111 
    112   NaClMessageScanner::FileIO* file_io;
    113 };
    114 
    115 static void QuotaInterfaceDtor(NaClRefCount* nrcp) {
    116   // Trivial class, just pass through to the "base" struct Dtor.
    117   nrcp->vtbl = reinterpret_cast<NaClRefCountVtbl*>(
    118       const_cast<NaClDescQuotaInterfaceVtbl*>(&kNaClDescQuotaInterfaceVtbl));
    119   (*nrcp->vtbl->Dtor)(nrcp);
    120 }
    121 
    122 static int64_t QuotaInterfaceWriteRequest(NaClDescQuotaInterface* ndqi,
    123                                           const uint8_t* /* unused_id */,
    124                                           int64_t offset,
    125                                           int64_t length) {
    126   if (offset < 0 || length < 0)
    127     return 0;
    128   if (std::numeric_limits<int64_t>::max() - length < offset)
    129     return 0;  // offset + length would overflow.
    130   int64_t max_offset = offset + length;
    131   if (max_offset < 0)
    132     return 0;
    133 
    134   QuotaInterface* quota_interface = reinterpret_cast<QuotaInterface*>(ndqi);
    135   NaClMessageScanner::FileIO* file_io = quota_interface->file_io;
    136   int64_t increase = max_offset - file_io->max_written_offset();
    137   if (increase <= 0 || file_io->Grow(increase))
    138     return length;
    139 
    140   return 0;
    141 }
    142 
    143 static int64_t QuotaInterfaceFtruncateRequest(NaClDescQuotaInterface* ndqi,
    144                                               const uint8_t* /* unused_id */,
    145                                               int64_t length) {
    146   // We can't implement SetLength on the plugin side due to sandbox limitations.
    147   // See crbug.com/156077.
    148   NOTREACHED();
    149   return 0;
    150 }
    151 
    152 static const struct NaClDescQuotaInterfaceVtbl kQuotaInterfaceVtbl = {
    153   {
    154     QuotaInterfaceDtor
    155   },
    156   QuotaInterfaceWriteRequest,
    157   QuotaInterfaceFtruncateRequest
    158 };
    159 
    160 NaClDesc* MakeNaClDescQuota(
    161     NaClMessageScanner::FileIO* file_io,
    162     NaClDesc* wrapped_desc) {
    163   // Create the QuotaInterface.
    164   QuotaInterface* quota_interface =
    165       static_cast<QuotaInterface*>(malloc(sizeof *quota_interface));
    166   if (quota_interface && NaClDescQuotaInterfaceCtor(&quota_interface->base)) {
    167     quota_interface->base.base.vtbl =
    168         (struct NaClRefCountVtbl *)(&kQuotaInterfaceVtbl);
    169     // QuotaInterface is a trivial class, so skip the ctor.
    170     quota_interface->file_io = file_io;
    171     // Create the NaClDescQuota.
    172     NaClDescQuota* desc = static_cast<NaClDescQuota*>(malloc(sizeof *desc));
    173     uint8_t unused_id[NACL_DESC_QUOTA_FILE_ID_LEN] = {0};
    174     if (desc && NaClDescQuotaCtor(desc,
    175                                   wrapped_desc,
    176                                   unused_id,
    177                                   &quota_interface->base)) {
    178       return &desc->base;
    179     }
    180     if (desc)
    181       NaClDescUnref(reinterpret_cast<NaClDesc*>(desc));
    182   }
    183 
    184   if (quota_interface)
    185     NaClDescQuotaInterfaceUnref(&quota_interface->base);
    186 
    187   return NULL;
    188 }
    189 
    190 //------------------------------------------------------------------------------
    191 
    192 void DeleteChannel(IPC::Channel* channel) {
    193   delete channel;
    194 }
    195 
    196 // Translates Pepper's read/write open flags into the NaCl equivalents.
    197 // Since the host has already opened the file, flags such as O_CREAT, O_TRUNC,
    198 // and O_EXCL don't make sense, so we filter those out. If no read or write
    199 // flags are set, the function returns NACL_ABI_O_RDONLY as a safe fallback.
    200 int TranslatePepperFileReadWriteOpenFlags(int32_t pp_open_flags) {
    201   bool read = (pp_open_flags & PP_FILEOPENFLAG_READ) != 0;
    202   bool write = (pp_open_flags & PP_FILEOPENFLAG_WRITE) != 0;
    203   bool append = (pp_open_flags & PP_FILEOPENFLAG_APPEND) != 0;
    204 
    205   int nacl_open_flag = NACL_ABI_O_RDONLY;  // NACL_ABI_O_RDONLY == 0.
    206   if (read && (write || append)) {
    207     nacl_open_flag = NACL_ABI_O_RDWR;
    208   } else if (write || append) {
    209     nacl_open_flag = NACL_ABI_O_WRONLY;
    210   } else if (!read) {
    211     DLOG(WARNING) << "One of PP_FILEOPENFLAG_READ, PP_FILEOPENFLAG_WRITE, "
    212                   << "or PP_FILEOPENFLAG_APPEND should be set.";
    213   }
    214   if (append)
    215     nacl_open_flag |= NACL_ABI_O_APPEND;
    216 
    217   return nacl_open_flag;
    218 }
    219 
    220 class NaClDescWrapper {
    221  public:
    222   explicit NaClDescWrapper(NaClDesc* desc): desc_(desc) {}
    223   ~NaClDescWrapper() {
    224     NaClDescUnref(desc_);
    225   }
    226 
    227   NaClDesc* desc() { return desc_; }
    228 
    229  private:
    230   NaClDesc* desc_;
    231   DISALLOW_COPY_AND_ASSIGN(NaClDescWrapper);
    232 };
    233 
    234 }  // namespace
    235 
    236 class NaClIPCAdapter::RewrittenMessage
    237     : public base::RefCounted<RewrittenMessage> {
    238  public:
    239   RewrittenMessage();
    240 
    241   bool is_consumed() const { return data_read_cursor_ == data_len_; }
    242 
    243   void SetData(const NaClIPCAdapter::NaClMessageHeader& header,
    244                const void* payload, size_t payload_length);
    245 
    246   int Read(NaClImcTypedMsgHdr* msg);
    247 
    248   void AddDescriptor(NaClDescWrapper* desc) { descs_.push_back(desc); }
    249 
    250   size_t desc_count() const { return descs_.size(); }
    251 
    252  private:
    253   friend class base::RefCounted<RewrittenMessage>;
    254   ~RewrittenMessage() {}
    255 
    256   scoped_ptr<char[]> data_;
    257   size_t data_len_;
    258 
    259   // Offset into data where the next read will happen. This will be equal to
    260   // data_len_ when all data has been consumed.
    261   size_t data_read_cursor_;
    262 
    263   // Wrapped descriptors for transfer to untrusted code.
    264   ScopedVector<NaClDescWrapper> descs_;
    265 };
    266 
    267 NaClIPCAdapter::RewrittenMessage::RewrittenMessage()
    268     : data_len_(0),
    269       data_read_cursor_(0) {
    270 }
    271 
    272 void NaClIPCAdapter::RewrittenMessage::SetData(
    273     const NaClIPCAdapter::NaClMessageHeader& header,
    274     const void* payload,
    275     size_t payload_length) {
    276   DCHECK(!data_.get() && data_len_ == 0);
    277   size_t header_len = sizeof(NaClIPCAdapter::NaClMessageHeader);
    278   data_len_ = header_len + payload_length;
    279   data_.reset(new char[data_len_]);
    280 
    281   memcpy(data_.get(), &header, sizeof(NaClIPCAdapter::NaClMessageHeader));
    282   memcpy(&data_[header_len], payload, payload_length);
    283 }
    284 
    285 int NaClIPCAdapter::RewrittenMessage::Read(NaClImcTypedMsgHdr* msg) {
    286   CHECK(data_len_ >= data_read_cursor_);
    287   char* dest_buffer = static_cast<char*>(msg->iov[0].base);
    288   size_t dest_buffer_size = msg->iov[0].length;
    289   size_t bytes_to_write = std::min(dest_buffer_size,
    290                                    data_len_ - data_read_cursor_);
    291   if (bytes_to_write == 0)
    292     return 0;
    293 
    294   memcpy(dest_buffer, &data_[data_read_cursor_], bytes_to_write);
    295   data_read_cursor_ += bytes_to_write;
    296 
    297   // Once all data has been consumed, transfer any file descriptors.
    298   if (is_consumed()) {
    299     nacl_abi_size_t desc_count = static_cast<nacl_abi_size_t>(descs_.size());
    300     CHECK(desc_count <= msg->ndesc_length);
    301     msg->ndesc_length = desc_count;
    302     for (nacl_abi_size_t i = 0; i < desc_count; i++) {
    303       // Copy the NaClDesc to the buffer and add a ref so it won't be freed
    304       // when we clear our ScopedVector.
    305       msg->ndescv[i] = descs_[i]->desc();
    306       NaClDescRef(descs_[i]->desc());
    307     }
    308     descs_.clear();
    309   } else {
    310     msg->ndesc_length = 0;
    311   }
    312   return static_cast<int>(bytes_to_write);
    313 }
    314 
    315 NaClIPCAdapter::LockedData::LockedData()
    316     : channel_closed_(false) {
    317 }
    318 
    319 NaClIPCAdapter::LockedData::~LockedData() {
    320 }
    321 
    322 NaClIPCAdapter::IOThreadData::IOThreadData() {
    323 }
    324 
    325 NaClIPCAdapter::IOThreadData::~IOThreadData() {
    326 }
    327 
    328 NaClIPCAdapter::NaClIPCAdapter(const IPC::ChannelHandle& handle,
    329                                base::TaskRunner* runner)
    330     : lock_(),
    331       cond_var_(&lock_),
    332       task_runner_(runner),
    333       locked_data_() {
    334   io_thread_data_.channel_ = IPC::Channel::CreateServer(handle, this);
    335   // Note, we can not PostTask for ConnectChannelOnIOThread here. If we did,
    336   // and that task ran before this constructor completes, the reference count
    337   // would go to 1 and then to 0 because of the Task, before we've been returned
    338   // to the owning scoped_refptr, which is supposed to give us our first
    339   // ref-count.
    340 }
    341 
    342 NaClIPCAdapter::NaClIPCAdapter(scoped_ptr<IPC::Channel> channel,
    343                                base::TaskRunner* runner)
    344     : lock_(),
    345       cond_var_(&lock_),
    346       task_runner_(runner),
    347       locked_data_() {
    348   io_thread_data_.channel_ = channel.Pass();
    349 }
    350 
    351 void NaClIPCAdapter::ConnectChannel() {
    352   task_runner_->PostTask(FROM_HERE,
    353       base::Bind(&NaClIPCAdapter::ConnectChannelOnIOThread, this));
    354 }
    355 
    356 // Note that this message is controlled by the untrusted code. So we should be
    357 // skeptical of anything it contains and quick to give up if anything is fishy.
    358 int NaClIPCAdapter::Send(const NaClImcTypedMsgHdr* msg) {
    359   if (msg->iov_length != 1)
    360     return -1;
    361 
    362   base::AutoLock lock(lock_);
    363 
    364   const char* input_data = static_cast<char*>(msg->iov[0].base);
    365   size_t input_data_len = msg->iov[0].length;
    366   if (input_data_len > IPC::Channel::kMaximumMessageSize) {
    367     ClearToBeSent();
    368     return -1;
    369   }
    370 
    371   // current_message[_len] refers to the total input data received so far.
    372   const char* current_message;
    373   size_t current_message_len;
    374   bool did_append_input_data;
    375   if (locked_data_.to_be_sent_.empty()) {
    376     // No accumulated data, we can avoid a copy by referring to the input
    377     // buffer (the entire message fitting in one call is the common case).
    378     current_message = input_data;
    379     current_message_len = input_data_len;
    380     did_append_input_data = false;
    381   } else {
    382     // We've already accumulated some data, accumulate this new data and
    383     // point to the beginning of the buffer.
    384 
    385     // Make sure our accumulated message size doesn't overflow our max. Since
    386     // we know that data_len < max size (checked above) and our current
    387     // accumulated value is also < max size, we just need to make sure that
    388     // 2x max size can never overflow.
    389     COMPILE_ASSERT(IPC::Channel::kMaximumMessageSize < (UINT_MAX / 2),
    390                    MaximumMessageSizeWillOverflow);
    391     size_t new_size = locked_data_.to_be_sent_.size() + input_data_len;
    392     if (new_size > IPC::Channel::kMaximumMessageSize) {
    393       ClearToBeSent();
    394       return -1;
    395     }
    396 
    397     locked_data_.to_be_sent_.append(input_data, input_data_len);
    398     current_message = &locked_data_.to_be_sent_[0];
    399     current_message_len = locked_data_.to_be_sent_.size();
    400     did_append_input_data = true;
    401   }
    402 
    403   // Check the total data we've accumulated so far to see if it contains a full
    404   // message.
    405   switch (GetBufferStatus(current_message, current_message_len)) {
    406     case MESSAGE_IS_COMPLETE: {
    407       // Got a complete message, can send it out. This will be the common case.
    408       bool success = SendCompleteMessage(current_message, current_message_len);
    409       ClearToBeSent();
    410       return success ? static_cast<int>(input_data_len) : -1;
    411     }
    412     case MESSAGE_IS_TRUNCATED:
    413       // For truncated messages, just accumulate the new data (if we didn't
    414       // already do so above) and go back to waiting for more.
    415       if (!did_append_input_data)
    416         locked_data_.to_be_sent_.append(input_data, input_data_len);
    417       return static_cast<int>(input_data_len);
    418     case MESSAGE_HAS_EXTRA_DATA:
    419     default:
    420       // When the plugin gives us too much data, it's an error.
    421       ClearToBeSent();
    422       return -1;
    423   }
    424 }
    425 
    426 int NaClIPCAdapter::BlockingReceive(NaClImcTypedMsgHdr* msg) {
    427   if (msg->iov_length != 1)
    428     return -1;
    429 
    430   int retval = 0;
    431   {
    432     base::AutoLock lock(lock_);
    433     while (locked_data_.to_be_received_.empty() &&
    434            !locked_data_.channel_closed_)
    435       cond_var_.Wait();
    436     if (locked_data_.channel_closed_) {
    437       retval = -1;
    438     } else {
    439       retval = LockedReceive(msg);
    440       DCHECK(retval > 0);
    441     }
    442     cond_var_.Signal();
    443   }
    444   return retval;
    445 }
    446 
    447 void NaClIPCAdapter::CloseChannel() {
    448   {
    449     base::AutoLock lock(lock_);
    450     locked_data_.channel_closed_ = true;
    451     cond_var_.Signal();
    452   }
    453 
    454   task_runner_->PostTask(FROM_HERE,
    455       base::Bind(&NaClIPCAdapter::CloseChannelOnIOThread, this));
    456 }
    457 
    458 NaClDesc* NaClIPCAdapter::MakeNaClDesc() {
    459   return MakeNaClDescCustom(this);
    460 }
    461 
    462 #if defined(OS_POSIX)
    463 int NaClIPCAdapter::TakeClientFileDescriptor() {
    464   return io_thread_data_.channel_->TakeClientFileDescriptor();
    465 }
    466 #endif
    467 
    468 bool NaClIPCAdapter::OnMessageReceived(const IPC::Message& msg) {
    469   uint32_t type = msg.type();
    470 
    471   if (type == IPC_REPLY_ID) {
    472     int id = IPC::SyncMessage::GetMessageId(msg);
    473     IOThreadData::PendingSyncMsgMap::iterator it =
    474         io_thread_data_.pending_sync_msgs_.find(id);
    475     DCHECK(it != io_thread_data_.pending_sync_msgs_.end());
    476     if (it != io_thread_data_.pending_sync_msgs_.end()) {
    477       type = it->second;
    478       io_thread_data_.pending_sync_msgs_.erase(it);
    479     }
    480   }
    481   // Handle PpapiHostMsg_OpenResource outside the lock as it requires sending
    482   // IPC to handle properly.
    483   if (type == PpapiHostMsg_OpenResource::ID) {
    484     PickleIterator iter = IPC::SyncMessage::GetDataIterator(&msg);
    485     ppapi::proxy::SerializedHandle sh;
    486     uint64_t token_lo;
    487     uint64_t token_hi;
    488     if (!IPC::ReadParam(&msg, &iter, &sh) ||
    489         !IPC::ReadParam(&msg, &iter, &token_lo) ||
    490         !IPC::ReadParam(&msg, &iter, &token_hi)) {
    491       return false;
    492     }
    493 
    494     if (sh.IsHandleValid() && (token_lo != 0 || token_hi != 0)) {
    495       // We've received a valid file token. Instead of using the file
    496       // descriptor received, we send the file token to the browser in
    497       // exchange for a new file descriptor and file path information.
    498       // That file descriptor can be used to construct a NaClDesc with
    499       // identity-based validation caching.
    500       //
    501       // We do not use file descriptors from the renderer with validation
    502       // caching; a compromised renderer should not be able to run
    503       // arbitrary code in a plugin process.
    504       DCHECK(!resolve_file_token_cb_.is_null());
    505 
    506       // resolve_file_token_cb_ must be invoked from the main thread.
    507       resolve_file_token_cb_.Run(
    508           token_lo,
    509           token_hi,
    510           base::Bind(&NaClIPCAdapter::OnFileTokenResolved,
    511                      this,
    512                      msg));
    513 
    514       // In this case, we don't release the message to NaCl untrusted code
    515       // immediately. We defer it until we get an async message back from the
    516       // browser process.
    517       return true;
    518     }
    519   }
    520   return RewriteMessage(msg, type);
    521 }
    522 
    523 bool NaClIPCAdapter::RewriteMessage(const IPC::Message& msg, uint32_t type) {
    524   {
    525     base::AutoLock lock(lock_);
    526     scoped_refptr<RewrittenMessage> rewritten_msg(new RewrittenMessage);
    527 
    528     typedef std::vector<ppapi::proxy::SerializedHandle> Handles;
    529     Handles handles;
    530     scoped_ptr<IPC::Message> new_msg;
    531 
    532     if (!locked_data_.nacl_msg_scanner_.ScanMessage(
    533             msg, type, &handles, &new_msg))
    534       return false;
    535 
    536     // Now add any descriptors we found to rewritten_msg. |handles| is usually
    537     // empty, unless we read a message containing a FD or handle.
    538     for (Handles::const_iterator iter = handles.begin();
    539          iter != handles.end();
    540          ++iter) {
    541       scoped_ptr<NaClDescWrapper> nacl_desc;
    542       switch (iter->type()) {
    543         case ppapi::proxy::SerializedHandle::SHARED_MEMORY: {
    544           const base::SharedMemoryHandle& shm_handle = iter->shmem();
    545           uint32_t size = iter->size();
    546           nacl_desc.reset(new NaClDescWrapper(NaClDescImcShmMake(
    547 #if defined(OS_WIN)
    548               shm_handle,
    549 #else
    550               shm_handle.fd,
    551 #endif
    552               static_cast<size_t>(size))));
    553           break;
    554         }
    555         case ppapi::proxy::SerializedHandle::SOCKET: {
    556           nacl_desc.reset(new NaClDescWrapper(NaClDescSyncSocketMake(
    557 #if defined(OS_WIN)
    558               iter->descriptor()
    559 #else
    560               iter->descriptor().fd
    561 #endif
    562           )));
    563           break;
    564         }
    565         case ppapi::proxy::SerializedHandle::FILE: {
    566           // Create the NaClDesc for the file descriptor. If quota checking is
    567           // required, wrap it in a NaClDescQuota.
    568           NaClDesc* desc = NaClDescIoDescFromHandleAllocCtor(
    569 #if defined(OS_WIN)
    570               iter->descriptor(),
    571 #else
    572               iter->descriptor().fd,
    573 #endif
    574               TranslatePepperFileReadWriteOpenFlags(iter->open_flags()));
    575           if (desc && iter->file_io()) {
    576             desc = MakeNaClDescQuota(
    577                 locked_data_.nacl_msg_scanner_.GetFile(iter->file_io()),
    578                 desc);
    579           }
    580           if (desc)
    581             nacl_desc.reset(new NaClDescWrapper(desc));
    582           break;
    583         }
    584 
    585         case ppapi::proxy::SerializedHandle::INVALID: {
    586           // Nothing to do.
    587           break;
    588         }
    589         // No default, so the compiler will warn us if new types get added.
    590       }
    591       if (nacl_desc.get())
    592         rewritten_msg->AddDescriptor(nacl_desc.release());
    593     }
    594     if (new_msg)
    595       SaveMessage(*new_msg, rewritten_msg.get());
    596     else
    597       SaveMessage(msg, rewritten_msg.get());
    598     cond_var_.Signal();
    599   }
    600   return true;
    601 }
    602 
    603 scoped_ptr<IPC::Message> CreateOpenResourceReply(
    604     const IPC::Message& orig_msg,
    605     ppapi::proxy::SerializedHandle sh) {
    606   // The creation of new_msg must be kept in sync with
    607   // SyncMessage::WriteSyncHeader.
    608   scoped_ptr<IPC::Message> new_msg(new IPC::Message(
    609       orig_msg.routing_id(),
    610       orig_msg.type(),
    611       IPC::Message::PRIORITY_NORMAL));
    612   new_msg->set_reply();
    613   new_msg->WriteInt(IPC::SyncMessage::GetMessageId(orig_msg));
    614 
    615   ppapi::proxy::SerializedHandle::WriteHeader(sh.header(),
    616                                               new_msg.get());
    617   new_msg->WriteBool(true);  // valid == true
    618   // The file descriptor is at index 0. There's only ever one file
    619   // descriptor provided for this message type, so this will be correct.
    620   new_msg->WriteInt(0);
    621 
    622   // Write empty file tokens.
    623   new_msg->WriteUInt64(0);  // token_lo
    624   new_msg->WriteUInt64(0);  // token_hi
    625   return new_msg.Pass();
    626 }
    627 
    628 void NaClIPCAdapter::OnFileTokenResolved(const IPC::Message& orig_msg,
    629                                          IPC::PlatformFileForTransit ipc_fd,
    630                                          base::FilePath file_path) {
    631   // The path where an invalid ipc_fd is returned isn't currently
    632   // covered by any tests.
    633   if (ipc_fd == IPC::InvalidPlatformFileForTransit()) {
    634     // The file token didn't resolve successfully, so we give the
    635     // original FD to the client without making a validated NaClDesc.
    636     // However, we must rewrite the message to clear the file tokens.
    637     PickleIterator iter = IPC::SyncMessage::GetDataIterator(&orig_msg);
    638     ppapi::proxy::SerializedHandle sh;
    639 
    640     // We know that this can be read safely; see the original read in
    641     // OnMessageReceived().
    642     CHECK(IPC::ReadParam(&orig_msg, &iter, &sh));
    643     scoped_ptr<IPC::Message> new_msg = CreateOpenResourceReply(orig_msg, sh);
    644 
    645     scoped_ptr<NaClDescWrapper> desc_wrapper(new NaClDescWrapper(
    646         NaClDescIoDescFromHandleAllocCtor(
    647 #if defined(OS_WIN)
    648             sh.descriptor(),
    649 #else
    650             sh.descriptor().fd,
    651 #endif
    652             NACL_ABI_O_RDONLY)));
    653 
    654     scoped_refptr<RewrittenMessage> rewritten_msg(new RewrittenMessage);
    655     rewritten_msg->AddDescriptor(desc_wrapper.release());
    656     {
    657       base::AutoLock lock(lock_);
    658       SaveMessage(*new_msg, rewritten_msg.get());
    659       cond_var_.Signal();
    660     }
    661     return;
    662   }
    663 
    664   // The file token was sucessfully resolved.
    665   std::string file_path_str = file_path.AsUTF8Unsafe();
    666   base::PlatformFile handle =
    667       IPC::PlatformFileForTransitToPlatformFile(ipc_fd);
    668   // The file token was resolved successfully, so we populate the new
    669   // NaClDesc with that information.
    670   char* alloc_file_path = static_cast<char*>(
    671       malloc(file_path_str.length() + 1));
    672   strcpy(alloc_file_path, file_path_str.c_str());
    673   scoped_ptr<NaClDescWrapper> desc_wrapper(new NaClDescWrapper(
    674       NaClDescIoDescFromHandleAllocCtor(handle, NACL_ABI_O_RDONLY)));
    675 
    676   // Mark the desc as OK for mapping as executable memory.
    677   NaClDescMarkSafeForMmap(desc_wrapper->desc());
    678 
    679   // Provide metadata for validation.
    680   struct NaClRichFileInfo info;
    681   NaClRichFileInfoCtor(&info);
    682   info.known_file = 1;
    683   info.file_path = alloc_file_path;  // Takes ownership.
    684   info.file_path_length =
    685       static_cast<uint32_t>(file_path_str.length());
    686   NaClSetFileOriginInfo(desc_wrapper->desc(), &info);
    687   NaClRichFileInfoDtor(&info);
    688 
    689   ppapi::proxy::SerializedHandle sh;
    690   sh.set_file_handle(ipc_fd, PP_FILEOPENFLAG_READ, 0);
    691   scoped_ptr<IPC::Message> new_msg = CreateOpenResourceReply(orig_msg, sh);
    692   scoped_refptr<RewrittenMessage> rewritten_msg(new RewrittenMessage);
    693 
    694   rewritten_msg->AddDescriptor(desc_wrapper.release());
    695   {
    696     base::AutoLock lock(lock_);
    697     SaveMessage(*new_msg, rewritten_msg.get());
    698     cond_var_.Signal();
    699   }
    700 }
    701 
    702 void NaClIPCAdapter::OnChannelConnected(int32 peer_pid) {
    703 }
    704 
    705 void NaClIPCAdapter::OnChannelError() {
    706   CloseChannel();
    707 }
    708 
    709 NaClIPCAdapter::~NaClIPCAdapter() {
    710   // Make sure the channel is deleted on the IO thread.
    711   task_runner_->PostTask(FROM_HERE,
    712       base::Bind(&DeleteChannel, io_thread_data_.channel_.release()));
    713 }
    714 
    715 int NaClIPCAdapter::LockedReceive(NaClImcTypedMsgHdr* msg) {
    716   lock_.AssertAcquired();
    717 
    718   if (locked_data_.to_be_received_.empty())
    719     return 0;
    720   scoped_refptr<RewrittenMessage> current =
    721       locked_data_.to_be_received_.front();
    722 
    723   int retval = current->Read(msg);
    724 
    725   // When a message is entirely consumed, remove if from the waiting queue.
    726   if (current->is_consumed())
    727     locked_data_.to_be_received_.pop();
    728 
    729   return retval;
    730 }
    731 
    732 bool NaClIPCAdapter::SendCompleteMessage(const char* buffer,
    733                                          size_t buffer_len) {
    734   lock_.AssertAcquired();
    735   // The message will have already been validated, so we know it's large enough
    736   // for our header.
    737   const NaClMessageHeader* header =
    738       reinterpret_cast<const NaClMessageHeader*>(buffer);
    739 
    740   // Length of the message not including the body. The data passed to us by the
    741   // plugin should match that in the message header. This should have already
    742   // been validated by GetBufferStatus.
    743   int body_len = static_cast<int>(buffer_len - sizeof(NaClMessageHeader));
    744   DCHECK(body_len == static_cast<int>(header->payload_size));
    745 
    746   // We actually discard the flags and only copy the ones we care about. This
    747   // is just because message doesn't have a constructor that takes raw flags.
    748   scoped_ptr<IPC::Message> msg(
    749       new IPC::Message(header->routing, header->type,
    750                        IPC::Message::PRIORITY_NORMAL));
    751   if (header->flags & IPC::Message::SYNC_BIT)
    752     msg->set_sync();
    753   if (header->flags & IPC::Message::REPLY_BIT)
    754     msg->set_reply();
    755   if (header->flags & IPC::Message::REPLY_ERROR_BIT)
    756     msg->set_reply_error();
    757   if (header->flags & IPC::Message::UNBLOCK_BIT)
    758     msg->set_unblock(true);
    759 
    760   msg->WriteBytes(&buffer[sizeof(NaClMessageHeader)], body_len);
    761 
    762   // Technically we didn't have to do any of the previous work in the lock. But
    763   // sometimes our buffer will point to the to_be_sent_ string which is
    764   // protected by the lock, and it's messier to factor Send() such that it can
    765   // unlock for us. Holding the lock for the message construction, which is
    766   // just some memcpys, shouldn't be a big deal.
    767   lock_.AssertAcquired();
    768   if (locked_data_.channel_closed_) {
    769     // If we ever pass handles from the plugin to the host, we should close them
    770     // here before we drop the message.
    771     return false;
    772   }
    773 
    774   // Scan all untrusted messages.
    775   scoped_ptr<IPC::Message> new_msg;
    776   locked_data_.nacl_msg_scanner_.ScanUntrustedMessage(*msg, &new_msg);
    777   if (new_msg)
    778     msg.reset(new_msg.release());
    779 
    780   // Actual send must be done on the I/O thread.
    781   task_runner_->PostTask(FROM_HERE,
    782       base::Bind(&NaClIPCAdapter::SendMessageOnIOThread, this,
    783                  base::Passed(&msg)));
    784   return true;
    785 }
    786 
    787 void NaClIPCAdapter::ClearToBeSent() {
    788   lock_.AssertAcquired();
    789 
    790   // Don't let the string keep its buffer behind our back.
    791   std::string empty;
    792   locked_data_.to_be_sent_.swap(empty);
    793 }
    794 
    795 void NaClIPCAdapter::ConnectChannelOnIOThread() {
    796   if (!io_thread_data_.channel_->Connect())
    797     NOTREACHED();
    798 }
    799 
    800 void NaClIPCAdapter::CloseChannelOnIOThread() {
    801   io_thread_data_.channel_->Close();
    802 }
    803 
    804 void NaClIPCAdapter::SendMessageOnIOThread(scoped_ptr<IPC::Message> message) {
    805   int id = IPC::SyncMessage::GetMessageId(*message.get());
    806   DCHECK(io_thread_data_.pending_sync_msgs_.find(id) ==
    807          io_thread_data_.pending_sync_msgs_.end());
    808 
    809   if (message->is_sync())
    810     io_thread_data_.pending_sync_msgs_[id] = message->type();
    811   io_thread_data_.channel_->Send(message.release());
    812 }
    813 
    814 void NaClIPCAdapter::SaveMessage(const IPC::Message& msg,
    815                                  RewrittenMessage* rewritten_msg) {
    816   lock_.AssertAcquired();
    817   // There is some padding in this structure (the "padding" member is 16
    818   // bits but this then gets padded to 32 bits). We want to be sure not to
    819   // leak data to the untrusted plugin, so zero everything out first.
    820   NaClMessageHeader header;
    821   memset(&header, 0, sizeof(NaClMessageHeader));
    822 
    823   header.payload_size = static_cast<uint32>(msg.payload_size());
    824   header.routing = msg.routing_id();
    825   header.type = msg.type();
    826   header.flags = msg.flags();
    827   header.num_fds = static_cast<int>(rewritten_msg->desc_count());
    828 
    829   rewritten_msg->SetData(header, msg.payload(), msg.payload_size());
    830   locked_data_.to_be_received_.push(rewritten_msg);
    831 }
    832 
    833 int TranslatePepperFileReadWriteOpenFlagsForTesting(int32_t pp_open_flags) {
    834   return TranslatePepperFileReadWriteOpenFlags(pp_open_flags);
    835 }
    836