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
33using ppapi::proxy::NaClMessageScanner;
34
35namespace {
36
37enum 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
48BufferSizeStatus 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.
67struct DescThunker {
68  explicit DescThunker(NaClIPCAdapter* adapter_arg)
69      : adapter(adapter_arg) {
70  }
71  scoped_refptr<NaClIPCAdapter> adapter;
72};
73
74NaClIPCAdapter* ToAdapter(void* handle) {
75  return static_cast<DescThunker*>(handle)->adapter.get();
76}
77
78// NaClDescCustom implementation.
79void NaClDescCustomDestroy(void* handle) {
80  delete static_cast<DescThunker*>(handle);
81}
82
83ssize_t NaClDescCustomSendMsg(void* handle, const NaClImcTypedMsgHdr* msg,
84                              int /* flags */) {
85  return static_cast<ssize_t>(ToAdapter(handle)->Send(msg));
86}
87
88ssize_t NaClDescCustomRecvMsg(void* handle, NaClImcTypedMsgHdr* msg,
89                              int /* flags */) {
90  return static_cast<ssize_t>(ToAdapter(handle)->BlockingReceive(msg));
91}
92
93NaClDesc* 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.
107struct 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
115static 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
122static 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
143static 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
152static const struct NaClDescQuotaInterfaceVtbl kQuotaInterfaceVtbl = {
153  {
154    QuotaInterfaceDtor
155  },
156  QuotaInterfaceWriteRequest,
157  QuotaInterfaceFtruncateRequest
158};
159
160NaClDesc* 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
192void 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.
200int 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
220class 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
236class 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
267NaClIPCAdapter::RewrittenMessage::RewrittenMessage()
268    : data_len_(0),
269      data_read_cursor_(0) {
270}
271
272void 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
285int 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
315NaClIPCAdapter::LockedData::LockedData()
316    : channel_closed_(false) {
317}
318
319NaClIPCAdapter::LockedData::~LockedData() {
320}
321
322NaClIPCAdapter::IOThreadData::IOThreadData() {
323}
324
325NaClIPCAdapter::IOThreadData::~IOThreadData() {
326}
327
328NaClIPCAdapter::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
342NaClIPCAdapter::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
351void 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.
358int 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
426int 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
447void 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
458NaClDesc* NaClIPCAdapter::MakeNaClDesc() {
459  return MakeNaClDescCustom(this);
460}
461
462#if defined(OS_POSIX)
463int NaClIPCAdapter::TakeClientFileDescriptor() {
464  return io_thread_data_.channel_->TakeClientFileDescriptor();
465}
466#endif
467
468bool 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
523bool 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
603scoped_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
628void 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
702void NaClIPCAdapter::OnChannelConnected(int32 peer_pid) {
703}
704
705void NaClIPCAdapter::OnChannelError() {
706  CloseChannel();
707}
708
709NaClIPCAdapter::~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
715int 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
732bool 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
787void 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
795void NaClIPCAdapter::ConnectChannelOnIOThread() {
796  if (!io_thread_data_.channel_->Connect())
797    NOTREACHED();
798}
799
800void NaClIPCAdapter::CloseChannelOnIOThread() {
801  io_thread_data_.channel_->Close();
802}
803
804void 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
814void 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
833int TranslatePepperFileReadWriteOpenFlagsForTesting(int32_t pp_open_flags) {
834  return TranslatePepperFileReadWriteOpenFlags(pp_open_flags);
835}
836