Roll src/third_party/WebKit f36d5e0:68b67cd (svn 193299:193303)
[chromium-blink-merge.git] / components / nacl / loader / nacl_ipc_adapter.cc
blob5df92fbe6adb4ef6e1bcf56b2bba334f19bc1469
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 "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/public/nacl_desc.h"
20 #include "native_client/src/trusted/desc/nacl_desc_base.h"
21 #include "native_client/src/trusted/desc/nacl_desc_custom.h"
22 #include "native_client/src/trusted/desc/nacl_desc_imc_shm.h"
23 #include "native_client/src/trusted/desc/nacl_desc_io.h"
24 #include "native_client/src/trusted/desc/nacl_desc_quota.h"
25 #include "native_client/src/trusted/desc/nacl_desc_quota_interface.h"
26 #include "native_client/src/trusted/desc/nacl_desc_sync_socket.h"
27 #include "native_client/src/trusted/service_runtime/include/sys/fcntl.h"
28 #include "ppapi/c/ppb_file_io.h"
29 #include "ppapi/proxy/ppapi_messages.h"
30 #include "ppapi/proxy/serialized_handle.h"
32 using ppapi::proxy::NaClMessageScanner;
34 namespace {
36 enum BufferSizeStatus {
37 // The buffer contains a full message with no extra bytes.
38 MESSAGE_IS_COMPLETE,
40 // The message doesn't fit and the buffer contains only some of it.
41 MESSAGE_IS_TRUNCATED,
43 // The buffer contains a full message + extra data.
44 MESSAGE_HAS_EXTRA_DATA
47 BufferSizeStatus GetBufferStatus(const char* data, size_t len) {
48 if (len < sizeof(NaClIPCAdapter::NaClMessageHeader))
49 return MESSAGE_IS_TRUNCATED;
51 const NaClIPCAdapter::NaClMessageHeader* header =
52 reinterpret_cast<const NaClIPCAdapter::NaClMessageHeader*>(data);
53 uint32 message_size =
54 sizeof(NaClIPCAdapter::NaClMessageHeader) + header->payload_size;
56 if (len == message_size)
57 return MESSAGE_IS_COMPLETE;
58 if (len > message_size)
59 return MESSAGE_HAS_EXTRA_DATA;
60 return MESSAGE_IS_TRUNCATED;
63 //------------------------------------------------------------------------------
64 // This object allows the NaClDesc to hold a reference to a NaClIPCAdapter and
65 // forward calls to it.
66 struct DescThunker {
67 explicit DescThunker(NaClIPCAdapter* adapter_arg)
68 : adapter(adapter_arg) {
70 scoped_refptr<NaClIPCAdapter> adapter;
73 NaClIPCAdapter* ToAdapter(void* handle) {
74 return static_cast<DescThunker*>(handle)->adapter.get();
77 // NaClDescCustom implementation.
78 void NaClDescCustomDestroy(void* handle) {
79 delete static_cast<DescThunker*>(handle);
82 ssize_t NaClDescCustomSendMsg(void* handle, const NaClImcTypedMsgHdr* msg,
83 int /* flags */) {
84 return static_cast<ssize_t>(ToAdapter(handle)->Send(msg));
87 ssize_t NaClDescCustomRecvMsg(void* handle, NaClImcTypedMsgHdr* msg,
88 int /* flags */) {
89 return static_cast<ssize_t>(ToAdapter(handle)->BlockingReceive(msg));
92 NaClDesc* MakeNaClDescCustom(NaClIPCAdapter* adapter) {
93 NaClDescCustomFuncs funcs = NACL_DESC_CUSTOM_FUNCS_INITIALIZER;
94 funcs.Destroy = NaClDescCustomDestroy;
95 funcs.SendMsg = NaClDescCustomSendMsg;
96 funcs.RecvMsg = NaClDescCustomRecvMsg;
97 // NaClDescMakeCustomDesc gives us a reference on the returned NaClDesc.
98 return NaClDescMakeCustomDesc(new DescThunker(adapter), &funcs);
101 //------------------------------------------------------------------------------
102 // This object is passed to a NaClDescQuota to intercept writes and forward them
103 // to the NaClIPCAdapter, which checks quota. This is a NaCl-style struct. Don't
104 // add non-trivial fields or virtual methods. Construction should use malloc,
105 // because this is owned by the NaClDesc, and the NaCl Dtor code will call free.
106 struct QuotaInterface {
107 // The "base" struct must be first. NaCl code expects a NaCl style ref-counted
108 // object, so the "vtable" and other base class fields must be first.
109 struct NaClDescQuotaInterface base NACL_IS_REFCOUNT_SUBCLASS;
111 NaClMessageScanner::FileIO* file_io;
114 static void QuotaInterfaceDtor(NaClRefCount* nrcp) {
115 // Trivial class, just pass through to the "base" struct Dtor.
116 nrcp->vtbl = reinterpret_cast<NaClRefCountVtbl*>(
117 const_cast<NaClDescQuotaInterfaceVtbl*>(&kNaClDescQuotaInterfaceVtbl));
118 (*nrcp->vtbl->Dtor)(nrcp);
121 static int64_t QuotaInterfaceWriteRequest(NaClDescQuotaInterface* ndqi,
122 const uint8_t* /* unused_id */,
123 int64_t offset,
124 int64_t length) {
125 if (offset < 0 || length < 0)
126 return 0;
127 if (std::numeric_limits<int64_t>::max() - length < offset)
128 return 0; // offset + length would overflow.
129 int64_t max_offset = offset + length;
130 if (max_offset < 0)
131 return 0;
133 QuotaInterface* quota_interface = reinterpret_cast<QuotaInterface*>(ndqi);
134 NaClMessageScanner::FileIO* file_io = quota_interface->file_io;
135 int64_t increase = max_offset - file_io->max_written_offset();
136 if (increase <= 0 || file_io->Grow(increase))
137 return length;
139 return 0;
142 static int64_t QuotaInterfaceFtruncateRequest(NaClDescQuotaInterface* ndqi,
143 const uint8_t* /* unused_id */,
144 int64_t length) {
145 // We can't implement SetLength on the plugin side due to sandbox limitations.
146 // See crbug.com/156077.
147 NOTREACHED();
148 return 0;
151 static const struct NaClDescQuotaInterfaceVtbl kQuotaInterfaceVtbl = {
153 QuotaInterfaceDtor
155 QuotaInterfaceWriteRequest,
156 QuotaInterfaceFtruncateRequest
159 NaClDesc* MakeNaClDescQuota(
160 NaClMessageScanner::FileIO* file_io,
161 NaClDesc* wrapped_desc) {
162 // Create the QuotaInterface.
163 QuotaInterface* quota_interface =
164 static_cast<QuotaInterface*>(malloc(sizeof *quota_interface));
165 if (quota_interface && NaClDescQuotaInterfaceCtor(&quota_interface->base)) {
166 quota_interface->base.base.vtbl =
167 (struct NaClRefCountVtbl *)(&kQuotaInterfaceVtbl);
168 // QuotaInterface is a trivial class, so skip the ctor.
169 quota_interface->file_io = file_io;
170 // Create the NaClDescQuota.
171 NaClDescQuota* desc = static_cast<NaClDescQuota*>(malloc(sizeof *desc));
172 uint8_t unused_id[NACL_DESC_QUOTA_FILE_ID_LEN] = {0};
173 if (desc && NaClDescQuotaCtor(desc,
174 wrapped_desc,
175 unused_id,
176 &quota_interface->base)) {
177 return &desc->base;
179 if (desc)
180 NaClDescUnref(reinterpret_cast<NaClDesc*>(desc));
183 if (quota_interface)
184 NaClDescQuotaInterfaceUnref(&quota_interface->base);
186 return NULL;
189 //------------------------------------------------------------------------------
191 void DeleteChannel(IPC::Channel* channel) {
192 delete channel;
195 // Translates Pepper's read/write open flags into the NaCl equivalents.
196 // Since the host has already opened the file, flags such as O_CREAT, O_TRUNC,
197 // and O_EXCL don't make sense, so we filter those out. If no read or write
198 // flags are set, the function returns NACL_ABI_O_RDONLY as a safe fallback.
199 int TranslatePepperFileReadWriteOpenFlags(int32_t pp_open_flags) {
200 bool read = (pp_open_flags & PP_FILEOPENFLAG_READ) != 0;
201 bool write = (pp_open_flags & PP_FILEOPENFLAG_WRITE) != 0;
202 bool append = (pp_open_flags & PP_FILEOPENFLAG_APPEND) != 0;
204 int nacl_open_flag = NACL_ABI_O_RDONLY; // NACL_ABI_O_RDONLY == 0.
205 if (read && (write || append)) {
206 nacl_open_flag = NACL_ABI_O_RDWR;
207 } else if (write || append) {
208 nacl_open_flag = NACL_ABI_O_WRONLY;
209 } else if (!read) {
210 DLOG(WARNING) << "One of PP_FILEOPENFLAG_READ, PP_FILEOPENFLAG_WRITE, "
211 << "or PP_FILEOPENFLAG_APPEND should be set.";
213 if (append)
214 nacl_open_flag |= NACL_ABI_O_APPEND;
216 return nacl_open_flag;
219 class NaClDescWrapper {
220 public:
221 explicit NaClDescWrapper(NaClDesc* desc): desc_(desc) {}
222 ~NaClDescWrapper() {
223 NaClDescUnref(desc_);
226 NaClDesc* desc() { return desc_; }
228 private:
229 NaClDesc* desc_;
230 DISALLOW_COPY_AND_ASSIGN(NaClDescWrapper);
233 } // namespace
235 class NaClIPCAdapter::RewrittenMessage
236 : public base::RefCounted<RewrittenMessage> {
237 public:
238 RewrittenMessage();
240 bool is_consumed() const { return data_read_cursor_ == data_len_; }
242 void SetData(const NaClIPCAdapter::NaClMessageHeader& header,
243 const void* payload, size_t payload_length);
245 int Read(NaClImcTypedMsgHdr* msg);
247 void AddDescriptor(NaClDescWrapper* desc) { descs_.push_back(desc); }
249 size_t desc_count() const { return descs_.size(); }
251 private:
252 friend class base::RefCounted<RewrittenMessage>;
253 ~RewrittenMessage() {}
255 scoped_ptr<char[]> data_;
256 size_t data_len_;
258 // Offset into data where the next read will happen. This will be equal to
259 // data_len_ when all data has been consumed.
260 size_t data_read_cursor_;
262 // Wrapped descriptors for transfer to untrusted code.
263 ScopedVector<NaClDescWrapper> descs_;
266 NaClIPCAdapter::RewrittenMessage::RewrittenMessage()
267 : data_len_(0),
268 data_read_cursor_(0) {
271 void NaClIPCAdapter::RewrittenMessage::SetData(
272 const NaClIPCAdapter::NaClMessageHeader& header,
273 const void* payload,
274 size_t payload_length) {
275 DCHECK(!data_.get() && data_len_ == 0);
276 size_t header_len = sizeof(NaClIPCAdapter::NaClMessageHeader);
277 data_len_ = header_len + payload_length;
278 data_.reset(new char[data_len_]);
280 memcpy(data_.get(), &header, sizeof(NaClIPCAdapter::NaClMessageHeader));
281 memcpy(&data_[header_len], payload, payload_length);
284 int NaClIPCAdapter::RewrittenMessage::Read(NaClImcTypedMsgHdr* msg) {
285 CHECK(data_len_ >= data_read_cursor_);
286 char* dest_buffer = static_cast<char*>(msg->iov[0].base);
287 size_t dest_buffer_size = msg->iov[0].length;
288 size_t bytes_to_write = std::min(dest_buffer_size,
289 data_len_ - data_read_cursor_);
290 if (bytes_to_write == 0)
291 return 0;
293 memcpy(dest_buffer, &data_[data_read_cursor_], bytes_to_write);
294 data_read_cursor_ += bytes_to_write;
296 // Once all data has been consumed, transfer any file descriptors.
297 if (is_consumed()) {
298 nacl_abi_size_t desc_count = static_cast<nacl_abi_size_t>(descs_.size());
299 CHECK(desc_count <= msg->ndesc_length);
300 msg->ndesc_length = desc_count;
301 for (nacl_abi_size_t i = 0; i < desc_count; i++) {
302 // Copy the NaClDesc to the buffer and add a ref so it won't be freed
303 // when we clear our ScopedVector.
304 msg->ndescv[i] = descs_[i]->desc();
305 NaClDescRef(descs_[i]->desc());
307 descs_.clear();
308 } else {
309 msg->ndesc_length = 0;
311 return static_cast<int>(bytes_to_write);
314 NaClIPCAdapter::LockedData::LockedData()
315 : channel_closed_(false) {
318 NaClIPCAdapter::LockedData::~LockedData() {
321 NaClIPCAdapter::IOThreadData::IOThreadData() {
324 NaClIPCAdapter::IOThreadData::~IOThreadData() {
327 NaClIPCAdapter::NaClIPCAdapter(const IPC::ChannelHandle& handle,
328 base::TaskRunner* runner)
329 : lock_(),
330 cond_var_(&lock_),
331 task_runner_(runner),
332 locked_data_() {
333 io_thread_data_.channel_ = IPC::Channel::CreateServer(handle, this);
334 // Note, we can not PostTask for ConnectChannelOnIOThread here. If we did,
335 // and that task ran before this constructor completes, the reference count
336 // would go to 1 and then to 0 because of the Task, before we've been returned
337 // to the owning scoped_refptr, which is supposed to give us our first
338 // ref-count.
341 NaClIPCAdapter::NaClIPCAdapter(scoped_ptr<IPC::Channel> channel,
342 base::TaskRunner* runner)
343 : lock_(),
344 cond_var_(&lock_),
345 task_runner_(runner),
346 locked_data_() {
347 io_thread_data_.channel_ = channel.Pass();
350 void NaClIPCAdapter::ConnectChannel() {
351 task_runner_->PostTask(FROM_HERE,
352 base::Bind(&NaClIPCAdapter::ConnectChannelOnIOThread, this));
355 // Note that this message is controlled by the untrusted code. So we should be
356 // skeptical of anything it contains and quick to give up if anything is fishy.
357 int NaClIPCAdapter::Send(const NaClImcTypedMsgHdr* msg) {
358 if (msg->iov_length != 1)
359 return -1;
361 base::AutoLock lock(lock_);
363 const char* input_data = static_cast<char*>(msg->iov[0].base);
364 size_t input_data_len = msg->iov[0].length;
365 if (input_data_len > IPC::Channel::kMaximumMessageSize) {
366 ClearToBeSent();
367 return -1;
370 // current_message[_len] refers to the total input data received so far.
371 const char* current_message;
372 size_t current_message_len;
373 bool did_append_input_data;
374 if (locked_data_.to_be_sent_.empty()) {
375 // No accumulated data, we can avoid a copy by referring to the input
376 // buffer (the entire message fitting in one call is the common case).
377 current_message = input_data;
378 current_message_len = input_data_len;
379 did_append_input_data = false;
380 } else {
381 // We've already accumulated some data, accumulate this new data and
382 // point to the beginning of the buffer.
384 // Make sure our accumulated message size doesn't overflow our max. Since
385 // we know that data_len < max size (checked above) and our current
386 // accumulated value is also < max size, we just need to make sure that
387 // 2x max size can never overflow.
388 static_assert(IPC::Channel::kMaximumMessageSize < (UINT_MAX / 2),
389 "kMaximumMessageSize is too large, and may overflow");
390 size_t new_size = locked_data_.to_be_sent_.size() + input_data_len;
391 if (new_size > IPC::Channel::kMaximumMessageSize) {
392 ClearToBeSent();
393 return -1;
396 locked_data_.to_be_sent_.append(input_data, input_data_len);
397 current_message = &locked_data_.to_be_sent_[0];
398 current_message_len = locked_data_.to_be_sent_.size();
399 did_append_input_data = true;
402 // Check the total data we've accumulated so far to see if it contains a full
403 // message.
404 switch (GetBufferStatus(current_message, current_message_len)) {
405 case MESSAGE_IS_COMPLETE: {
406 // Got a complete message, can send it out. This will be the common case.
407 bool success = SendCompleteMessage(current_message, current_message_len);
408 ClearToBeSent();
409 return success ? static_cast<int>(input_data_len) : -1;
411 case MESSAGE_IS_TRUNCATED:
412 // For truncated messages, just accumulate the new data (if we didn't
413 // already do so above) and go back to waiting for more.
414 if (!did_append_input_data)
415 locked_data_.to_be_sent_.append(input_data, input_data_len);
416 return static_cast<int>(input_data_len);
417 case MESSAGE_HAS_EXTRA_DATA:
418 default:
419 // When the plugin gives us too much data, it's an error.
420 ClearToBeSent();
421 return -1;
425 int NaClIPCAdapter::BlockingReceive(NaClImcTypedMsgHdr* msg) {
426 if (msg->iov_length != 1)
427 return -1;
429 int retval = 0;
431 base::AutoLock lock(lock_);
432 while (locked_data_.to_be_received_.empty() &&
433 !locked_data_.channel_closed_)
434 cond_var_.Wait();
435 if (locked_data_.channel_closed_) {
436 retval = -1;
437 } else {
438 retval = LockedReceive(msg);
439 DCHECK(retval > 0);
441 cond_var_.Signal();
443 return retval;
446 void NaClIPCAdapter::CloseChannel() {
448 base::AutoLock lock(lock_);
449 locked_data_.channel_closed_ = true;
450 cond_var_.Signal();
453 task_runner_->PostTask(FROM_HERE,
454 base::Bind(&NaClIPCAdapter::CloseChannelOnIOThread, this));
457 NaClDesc* NaClIPCAdapter::MakeNaClDesc() {
458 return MakeNaClDescCustom(this);
461 #if defined(OS_POSIX)
462 base::ScopedFD NaClIPCAdapter::TakeClientFileDescriptor() {
463 return io_thread_data_.channel_->TakeClientFileDescriptor();
465 #endif
467 bool NaClIPCAdapter::OnMessageReceived(const IPC::Message& msg) {
468 uint32_t type = msg.type();
470 if (type == IPC_REPLY_ID) {
471 int id = IPC::SyncMessage::GetMessageId(msg);
472 IOThreadData::PendingSyncMsgMap::iterator it =
473 io_thread_data_.pending_sync_msgs_.find(id);
474 DCHECK(it != io_thread_data_.pending_sync_msgs_.end());
475 if (it != io_thread_data_.pending_sync_msgs_.end()) {
476 type = it->second;
477 io_thread_data_.pending_sync_msgs_.erase(it);
480 // Handle PpapiHostMsg_OpenResource outside the lock as it requires sending
481 // IPC to handle properly.
482 if (type == PpapiHostMsg_OpenResource::ID) {
483 PickleIterator iter = IPC::SyncMessage::GetDataIterator(&msg);
484 ppapi::proxy::SerializedHandle sh;
485 uint64_t token_lo;
486 uint64_t token_hi;
487 if (!IPC::ReadParam(&msg, &iter, &sh) ||
488 !IPC::ReadParam(&msg, &iter, &token_lo) ||
489 !IPC::ReadParam(&msg, &iter, &token_hi)) {
490 return false;
493 if (sh.IsHandleValid() && (token_lo != 0 || token_hi != 0)) {
494 // We've received a valid file token. Instead of using the file
495 // descriptor received, we send the file token to the browser in
496 // exchange for a new file descriptor and file path information.
497 // That file descriptor can be used to construct a NaClDesc with
498 // identity-based validation caching.
500 // We do not use file descriptors from the renderer with validation
501 // caching; a compromised renderer should not be able to run
502 // arbitrary code in a plugin process.
503 DCHECK(!resolve_file_token_cb_.is_null());
505 // resolve_file_token_cb_ must be invoked from the main thread.
506 resolve_file_token_cb_.Run(
507 token_lo,
508 token_hi,
509 base::Bind(&NaClIPCAdapter::OnFileTokenResolved,
510 this,
511 msg));
513 // In this case, we don't release the message to NaCl untrusted code
514 // immediately. We defer it until we get an async message back from the
515 // browser process.
516 return true;
519 return RewriteMessage(msg, type);
522 bool NaClIPCAdapter::RewriteMessage(const IPC::Message& msg, uint32_t type) {
524 base::AutoLock lock(lock_);
525 scoped_refptr<RewrittenMessage> rewritten_msg(new RewrittenMessage);
527 typedef std::vector<ppapi::proxy::SerializedHandle> Handles;
528 Handles handles;
529 scoped_ptr<IPC::Message> new_msg;
531 if (!locked_data_.nacl_msg_scanner_.ScanMessage(
532 msg, type, &handles, &new_msg))
533 return false;
535 // Now add any descriptors we found to rewritten_msg. |handles| is usually
536 // empty, unless we read a message containing a FD or handle.
537 for (Handles::const_iterator iter = handles.begin();
538 iter != handles.end();
539 ++iter) {
540 scoped_ptr<NaClDescWrapper> nacl_desc;
541 switch (iter->type()) {
542 case ppapi::proxy::SerializedHandle::SHARED_MEMORY: {
543 const base::SharedMemoryHandle& shm_handle = iter->shmem();
544 uint32_t size = iter->size();
545 nacl_desc.reset(new NaClDescWrapper(NaClDescImcShmMake(
546 #if defined(OS_WIN)
547 shm_handle,
548 #else
549 shm_handle.fd,
550 #endif
551 static_cast<size_t>(size))));
552 break;
554 case ppapi::proxy::SerializedHandle::SOCKET: {
555 nacl_desc.reset(new NaClDescWrapper(NaClDescSyncSocketMake(
556 #if defined(OS_WIN)
557 iter->descriptor()
558 #else
559 iter->descriptor().fd
560 #endif
561 )));
562 break;
564 case ppapi::proxy::SerializedHandle::FILE: {
565 // Create the NaClDesc for the file descriptor. If quota checking is
566 // required, wrap it in a NaClDescQuota.
567 NaClDesc* desc = NaClDescIoDescFromHandleAllocCtor(
568 #if defined(OS_WIN)
569 iter->descriptor(),
570 #else
571 iter->descriptor().fd,
572 #endif
573 TranslatePepperFileReadWriteOpenFlags(iter->open_flags()));
574 if (desc && iter->file_io()) {
575 desc = MakeNaClDescQuota(
576 locked_data_.nacl_msg_scanner_.GetFile(iter->file_io()),
577 desc);
579 if (desc)
580 nacl_desc.reset(new NaClDescWrapper(desc));
581 break;
584 case ppapi::proxy::SerializedHandle::INVALID: {
585 // Nothing to do.
586 break;
588 // No default, so the compiler will warn us if new types get added.
590 if (nacl_desc.get())
591 rewritten_msg->AddDescriptor(nacl_desc.release());
593 if (new_msg)
594 SaveMessage(*new_msg, rewritten_msg.get());
595 else
596 SaveMessage(msg, rewritten_msg.get());
597 cond_var_.Signal();
599 return true;
602 scoped_ptr<IPC::Message> CreateOpenResourceReply(
603 const IPC::Message& orig_msg,
604 ppapi::proxy::SerializedHandle sh) {
605 // The creation of new_msg must be kept in sync with
606 // SyncMessage::WriteSyncHeader.
607 scoped_ptr<IPC::Message> new_msg(new IPC::Message(
608 orig_msg.routing_id(),
609 orig_msg.type(),
610 IPC::Message::PRIORITY_NORMAL));
611 new_msg->set_reply();
612 new_msg->WriteInt(IPC::SyncMessage::GetMessageId(orig_msg));
614 ppapi::proxy::SerializedHandle::WriteHeader(sh.header(),
615 new_msg.get());
616 new_msg->WriteBool(true); // valid == true
617 // The file descriptor is at index 0. There's only ever one file
618 // descriptor provided for this message type, so this will be correct.
619 new_msg->WriteInt(0);
621 // Write empty file tokens.
622 new_msg->WriteUInt64(0); // token_lo
623 new_msg->WriteUInt64(0); // token_hi
624 return new_msg.Pass();
627 void NaClIPCAdapter::OnFileTokenResolved(const IPC::Message& orig_msg,
628 IPC::PlatformFileForTransit ipc_fd,
629 base::FilePath file_path) {
630 // The path where an invalid ipc_fd is returned isn't currently
631 // covered by any tests.
632 if (ipc_fd == IPC::InvalidPlatformFileForTransit()) {
633 // The file token didn't resolve successfully, so we give the
634 // original FD to the client without making a validated NaClDesc.
635 // However, we must rewrite the message to clear the file tokens.
636 PickleIterator iter = IPC::SyncMessage::GetDataIterator(&orig_msg);
637 ppapi::proxy::SerializedHandle sh;
639 // We know that this can be read safely; see the original read in
640 // OnMessageReceived().
641 CHECK(IPC::ReadParam(&orig_msg, &iter, &sh));
642 scoped_ptr<IPC::Message> new_msg = CreateOpenResourceReply(orig_msg, sh);
644 scoped_ptr<NaClDescWrapper> desc_wrapper(new NaClDescWrapper(
645 NaClDescIoDescFromHandleAllocCtor(
646 #if defined(OS_WIN)
647 sh.descriptor(),
648 #else
649 sh.descriptor().fd,
650 #endif
651 NACL_ABI_O_RDONLY)));
653 scoped_refptr<RewrittenMessage> rewritten_msg(new RewrittenMessage);
654 rewritten_msg->AddDescriptor(desc_wrapper.release());
656 base::AutoLock lock(lock_);
657 SaveMessage(*new_msg, rewritten_msg.get());
658 cond_var_.Signal();
660 return;
663 // The file token was sucessfully resolved.
664 std::string file_path_str = file_path.AsUTF8Unsafe();
665 base::PlatformFile handle =
666 IPC::PlatformFileForTransitToPlatformFile(ipc_fd);
668 ppapi::proxy::SerializedHandle sh;
669 sh.set_file_handle(ipc_fd, PP_FILEOPENFLAG_READ, 0);
670 scoped_ptr<IPC::Message> new_msg = CreateOpenResourceReply(orig_msg, sh);
671 scoped_refptr<RewrittenMessage> rewritten_msg(new RewrittenMessage);
673 struct NaClDesc* desc =
674 NaClDescCreateWithFilePathMetadata(handle, file_path_str.c_str());
675 rewritten_msg->AddDescriptor(new NaClDescWrapper(desc));
677 base::AutoLock lock(lock_);
678 SaveMessage(*new_msg, rewritten_msg.get());
679 cond_var_.Signal();
683 void NaClIPCAdapter::OnChannelConnected(int32 peer_pid) {
686 void NaClIPCAdapter::OnChannelError() {
687 CloseChannel();
690 NaClIPCAdapter::~NaClIPCAdapter() {
691 // Make sure the channel is deleted on the IO thread.
692 task_runner_->PostTask(FROM_HERE,
693 base::Bind(&DeleteChannel, io_thread_data_.channel_.release()));
696 int NaClIPCAdapter::LockedReceive(NaClImcTypedMsgHdr* msg) {
697 lock_.AssertAcquired();
699 if (locked_data_.to_be_received_.empty())
700 return 0;
701 scoped_refptr<RewrittenMessage> current =
702 locked_data_.to_be_received_.front();
704 int retval = current->Read(msg);
706 // When a message is entirely consumed, remove if from the waiting queue.
707 if (current->is_consumed())
708 locked_data_.to_be_received_.pop();
710 return retval;
713 bool NaClIPCAdapter::SendCompleteMessage(const char* buffer,
714 size_t buffer_len) {
715 lock_.AssertAcquired();
716 // The message will have already been validated, so we know it's large enough
717 // for our header.
718 const NaClMessageHeader* header =
719 reinterpret_cast<const NaClMessageHeader*>(buffer);
721 // Length of the message not including the body. The data passed to us by the
722 // plugin should match that in the message header. This should have already
723 // been validated by GetBufferStatus.
724 int body_len = static_cast<int>(buffer_len - sizeof(NaClMessageHeader));
725 DCHECK(body_len == static_cast<int>(header->payload_size));
727 // We actually discard the flags and only copy the ones we care about. This
728 // is just because message doesn't have a constructor that takes raw flags.
729 scoped_ptr<IPC::Message> msg(
730 new IPC::Message(header->routing, header->type,
731 IPC::Message::PRIORITY_NORMAL));
732 if (header->flags & IPC::Message::SYNC_BIT)
733 msg->set_sync();
734 if (header->flags & IPC::Message::REPLY_BIT)
735 msg->set_reply();
736 if (header->flags & IPC::Message::REPLY_ERROR_BIT)
737 msg->set_reply_error();
738 if (header->flags & IPC::Message::UNBLOCK_BIT)
739 msg->set_unblock(true);
741 msg->WriteBytes(&buffer[sizeof(NaClMessageHeader)], body_len);
743 // Technically we didn't have to do any of the previous work in the lock. But
744 // sometimes our buffer will point to the to_be_sent_ string which is
745 // protected by the lock, and it's messier to factor Send() such that it can
746 // unlock for us. Holding the lock for the message construction, which is
747 // just some memcpys, shouldn't be a big deal.
748 lock_.AssertAcquired();
749 if (locked_data_.channel_closed_) {
750 // If we ever pass handles from the plugin to the host, we should close them
751 // here before we drop the message.
752 return false;
755 // Scan all untrusted messages.
756 scoped_ptr<IPC::Message> new_msg;
757 locked_data_.nacl_msg_scanner_.ScanUntrustedMessage(*msg, &new_msg);
758 if (new_msg)
759 msg.reset(new_msg.release());
761 // Actual send must be done on the I/O thread.
762 task_runner_->PostTask(FROM_HERE,
763 base::Bind(&NaClIPCAdapter::SendMessageOnIOThread, this,
764 base::Passed(&msg)));
765 return true;
768 void NaClIPCAdapter::ClearToBeSent() {
769 lock_.AssertAcquired();
771 // Don't let the string keep its buffer behind our back.
772 std::string empty;
773 locked_data_.to_be_sent_.swap(empty);
776 void NaClIPCAdapter::ConnectChannelOnIOThread() {
777 if (!io_thread_data_.channel_->Connect())
778 NOTREACHED();
781 void NaClIPCAdapter::CloseChannelOnIOThread() {
782 io_thread_data_.channel_->Close();
785 void NaClIPCAdapter::SendMessageOnIOThread(scoped_ptr<IPC::Message> message) {
786 int id = IPC::SyncMessage::GetMessageId(*message.get());
787 DCHECK(io_thread_data_.pending_sync_msgs_.find(id) ==
788 io_thread_data_.pending_sync_msgs_.end());
790 if (message->is_sync())
791 io_thread_data_.pending_sync_msgs_[id] = message->type();
792 io_thread_data_.channel_->Send(message.release());
795 void NaClIPCAdapter::SaveMessage(const IPC::Message& msg,
796 RewrittenMessage* rewritten_msg) {
797 lock_.AssertAcquired();
798 // There is some padding in this structure (the "padding" member is 16
799 // bits but this then gets padded to 32 bits). We want to be sure not to
800 // leak data to the untrusted plugin, so zero everything out first.
801 NaClMessageHeader header;
802 memset(&header, 0, sizeof(NaClMessageHeader));
804 header.payload_size = static_cast<uint32>(msg.payload_size());
805 header.routing = msg.routing_id();
806 header.type = msg.type();
807 header.flags = msg.flags();
808 header.num_fds = static_cast<uint16>(rewritten_msg->desc_count());
810 rewritten_msg->SetData(header, msg.payload(), msg.payload_size());
811 locked_data_.to_be_received_.push(rewritten_msg);
814 int TranslatePepperFileReadWriteOpenFlagsForTesting(int32_t pp_open_flags) {
815 return TranslatePepperFileReadWriteOpenFlags(pp_open_flags);