Support for unpacked ARM packed relocations.
[chromium-blink-merge.git] / components / nacl / loader / nacl_ipc_adapter.cc
blobd3160e4e51e09b7fd27baa4a3d1c47f041e60a5b
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.
5 #include "components/nacl/loader/nacl_ipc_adapter.h"
7 #include <limits.h>
8 #include <string.h>
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"
31 using ppapi::proxy::NaClMessageScanner;
33 namespace {
35 enum BufferSizeStatus {
36 // The buffer contains a full message with no extra bytes.
37 MESSAGE_IS_COMPLETE,
39 // The message doesn't fit and the buffer contains only some of it.
40 MESSAGE_IS_TRUNCATED,
42 // The buffer contains a full message + extra data.
43 MESSAGE_HAS_EXTRA_DATA
46 BufferSizeStatus GetBufferStatus(const char* data, size_t len) {
47 if (len < sizeof(NaClIPCAdapter::NaClMessageHeader))
48 return MESSAGE_IS_TRUNCATED;
50 const NaClIPCAdapter::NaClMessageHeader* header =
51 reinterpret_cast<const NaClIPCAdapter::NaClMessageHeader*>(data);
52 uint32 message_size =
53 sizeof(NaClIPCAdapter::NaClMessageHeader) + header->payload_size;
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;
62 //------------------------------------------------------------------------------
63 // This object allows the NaClDesc to hold a reference to a NaClIPCAdapter and
64 // forward calls to it.
65 struct DescThunker {
66 explicit DescThunker(NaClIPCAdapter* adapter_arg)
67 : adapter(adapter_arg) {
69 scoped_refptr<NaClIPCAdapter> adapter;
72 NaClIPCAdapter* ToAdapter(void* handle) {
73 return static_cast<DescThunker*>(handle)->adapter.get();
76 // NaClDescCustom implementation.
77 void NaClDescCustomDestroy(void* handle) {
78 delete static_cast<DescThunker*>(handle);
81 ssize_t NaClDescCustomSendMsg(void* handle, const NaClImcTypedMsgHdr* msg,
82 int /* flags */) {
83 return static_cast<ssize_t>(ToAdapter(handle)->Send(msg));
86 ssize_t NaClDescCustomRecvMsg(void* handle, NaClImcTypedMsgHdr* msg,
87 int /* flags */) {
88 return static_cast<ssize_t>(ToAdapter(handle)->BlockingReceive(msg));
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);
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;
110 NaClMessageScanner::FileIO* file_io;
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);
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;
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;
138 return 0;
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;
150 static const struct NaClDescQuotaInterfaceVtbl kQuotaInterfaceVtbl = {
152 QuotaInterfaceDtor
154 QuotaInterfaceWriteRequest,
155 QuotaInterfaceFtruncateRequest
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;
178 if (desc)
179 NaClDescUnref(reinterpret_cast<NaClDesc*>(desc));
182 if (quota_interface)
183 NaClDescQuotaInterfaceUnref(&quota_interface->base);
185 return NULL;
188 //------------------------------------------------------------------------------
190 void DeleteChannel(IPC::Channel* channel) {
191 delete channel;
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.
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;
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.";
212 if (append)
213 nacl_open_flag |= NACL_ABI_O_APPEND;
215 return nacl_open_flag;
218 class NaClDescWrapper {
219 public:
220 explicit NaClDescWrapper(NaClDesc* desc): desc_(desc) {}
221 ~NaClDescWrapper() {
222 NaClDescUnref(desc_);
225 NaClDesc* desc() { return desc_; }
227 private:
228 NaClDesc* desc_;
229 DISALLOW_COPY_AND_ASSIGN(NaClDescWrapper);
232 } // namespace
234 class NaClIPCAdapter::RewrittenMessage
235 : public base::RefCounted<RewrittenMessage> {
236 public:
237 RewrittenMessage();
239 bool is_consumed() const { return data_read_cursor_ == data_len_; }
241 void SetData(const NaClIPCAdapter::NaClMessageHeader& header,
242 const void* payload, size_t payload_length);
244 int Read(NaClImcTypedMsgHdr* msg);
246 void AddDescriptor(NaClDescWrapper* desc) { descs_.push_back(desc); }
248 size_t desc_count() const { return descs_.size(); }
250 private:
251 friend class base::RefCounted<RewrittenMessage>;
252 ~RewrittenMessage() {}
254 scoped_ptr<char[]> data_;
255 size_t data_len_;
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_;
261 // Wrapped descriptors for transfer to untrusted code.
262 ScopedVector<NaClDescWrapper> descs_;
265 NaClIPCAdapter::RewrittenMessage::RewrittenMessage()
266 : data_len_(0),
267 data_read_cursor_(0) {
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_]);
279 memcpy(data_.get(), &header, sizeof(NaClIPCAdapter::NaClMessageHeader));
280 memcpy(&data_[header_len], payload, payload_length);
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;
292 memcpy(dest_buffer, &data_[data_read_cursor_], bytes_to_write);
293 data_read_cursor_ += bytes_to_write;
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());
306 descs_.clear();
307 } else {
308 msg->ndesc_length = 0;
310 return static_cast<int>(bytes_to_write);
313 NaClIPCAdapter::LockedData::LockedData()
314 : channel_closed_(false) {
317 NaClIPCAdapter::LockedData::~LockedData() {
320 NaClIPCAdapter::IOThreadData::IOThreadData() {
323 NaClIPCAdapter::IOThreadData::~IOThreadData() {
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.
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();
349 void NaClIPCAdapter::ConnectChannel() {
350 task_runner_->PostTask(FROM_HERE,
351 base::Bind(&NaClIPCAdapter::ConnectChannelOnIOThread, this));
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.
356 int NaClIPCAdapter::Send(const NaClImcTypedMsgHdr* msg) {
357 if (msg->iov_length != 1)
358 return -1;
360 base::AutoLock lock(lock_);
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;
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.
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;
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;
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;
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;
424 int NaClIPCAdapter::BlockingReceive(NaClImcTypedMsgHdr* msg) {
425 if (msg->iov_length != 1)
426 return -1;
428 int retval = 0;
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);
441 cond_var_.Signal();
442 return retval;
445 void NaClIPCAdapter::CloseChannel() {
447 base::AutoLock lock(lock_);
448 locked_data_.channel_closed_ = true;
450 cond_var_.Signal();
452 task_runner_->PostTask(FROM_HERE,
453 base::Bind(&NaClIPCAdapter::CloseChannelOnIOThread, this));
456 NaClDesc* NaClIPCAdapter::MakeNaClDesc() {
457 return MakeNaClDescCustom(this);
460 #if defined(OS_POSIX)
461 int NaClIPCAdapter::TakeClientFileDescriptor() {
462 return io_thread_data_.channel_->TakeClientFileDescriptor();
464 #endif
466 bool NaClIPCAdapter::OnMessageReceived(const IPC::Message& msg) {
468 base::AutoLock lock(lock_);
470 scoped_refptr<RewrittenMessage> rewritten_msg(new RewrittenMessage);
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;
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;
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;
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);
522 if (desc)
523 nacl_desc.reset(new NaClDescWrapper(desc));
524 break;
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;
532 // No default, so the compiler will warn us if new types get added.
534 if (nacl_desc.get())
535 rewritten_msg->AddDescriptor(nacl_desc.release());
537 if (new_msg)
538 SaveMessage(*new_msg, rewritten_msg.get());
539 else
540 SaveMessage(msg, rewritten_msg.get());
542 cond_var_.Signal();
543 return true;
546 void NaClIPCAdapter::OnChannelConnected(int32 peer_pid) {
549 void NaClIPCAdapter::OnChannelError() {
550 CloseChannel();
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()));
559 int NaClIPCAdapter::LockedReceive(NaClImcTypedMsgHdr* msg) {
560 lock_.AssertAcquired();
562 if (locked_data_.to_be_received_.empty())
563 return 0;
564 scoped_refptr<RewrittenMessage> current =
565 locked_data_.to_be_received_.front();
567 int retval = current->Read(msg);
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();
573 return retval;
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);
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));
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);
604 msg->WriteBytes(&buffer[sizeof(NaClMessageHeader)], body_len);
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;
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());
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;
631 void NaClIPCAdapter::ClearToBeSent() {
632 lock_.AssertAcquired();
634 // Don't let the string keep its buffer behind our back.
635 std::string empty;
636 locked_data_.to_be_sent_.swap(empty);
639 void NaClIPCAdapter::ConnectChannelOnIOThread() {
640 if (!io_thread_data_.channel_->Connect())
641 NOTREACHED();
644 void NaClIPCAdapter::CloseChannelOnIOThread() {
645 io_thread_data_.channel_->Close();
648 void NaClIPCAdapter::SendMessageOnIOThread(scoped_ptr<IPC::Message> message) {
649 io_thread_data_.channel_->Send(message.release());
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));
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());
667 rewritten_msg->SetData(header, msg.payload(), msg.payload_size());
668 locked_data_.to_be_received_.push(rewritten_msg);
671 int TranslatePepperFileReadWriteOpenFlagsForTesting(int32_t pp_open_flags) {
672 return TranslatePepperFileReadWriteOpenFlags(pp_open_flags);