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