Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / components / nacl / loader / nacl_ipc_adapter.cc
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 base::ScopedFD 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 }