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