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 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 { 66 explicit DescThunker(NaClIPCAdapter* adapter_arg) 67 : adapter(adapter_arg) { 68 } 69 scoped_refptr<NaClIPCAdapter> adapter; 70 }; 71 72 NaClIPCAdapter* ToAdapter(void* handle) { 73 return static_cast<DescThunker*>(handle)->adapter.get(); 74 } 75 76 // NaClDescCustom implementation. 77 void NaClDescCustomDestroy(void* handle) { 78 delete static_cast<DescThunker*>(handle); 79 } 80 81 ssize_t NaClDescCustomSendMsg(void* handle, const NaClImcTypedMsgHdr* msg, 82 int /* flags */) { 83 return static_cast<ssize_t>(ToAdapter(handle)->Send(msg)); 84 } 85 86 ssize_t NaClDescCustomRecvMsg(void* handle, NaClImcTypedMsgHdr* msg, 87 int /* flags */) { 88 return static_cast<ssize_t>(ToAdapter(handle)->BlockingReceive(msg)); 89 } 90 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 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 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 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 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("a_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 "a_interface->base)) { 176 return &desc->base; 177 } 178 if (desc) 179 NaClDescUnref(reinterpret_cast<NaClDesc*>(desc)); 180 } 181 182 if (quota_interface) 183 NaClDescQuotaInterfaceUnref("a_interface->base); 184 185 return NULL; 186 } 187 188 //------------------------------------------------------------------------------ 189 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. 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: 220 explicit NaClDescWrapper(NaClDesc* desc): desc_(desc) {} 221 ~NaClDescWrapper() { 222 NaClDescUnref(desc_); 223 } 224 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 239 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 246 void AddDescriptor(NaClDescWrapper* desc) { descs_.push_back(desc); } 247 248 size_t desc_count() const { return descs_.size(); } 249 250 private: 251 friend class base::RefCounted<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 265 NaClIPCAdapter::RewrittenMessage::RewrittenMessage() 266 : data_len_(0), 267 data_read_cursor_(0) { 268 } 269 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 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 313 NaClIPCAdapter::LockedData::LockedData() 314 : channel_closed_(false) { 315 } 316 317 NaClIPCAdapter::LockedData::~LockedData() { 318 } 319 320 NaClIPCAdapter::IOThreadData::IOThreadData() { 321 } 322 323 NaClIPCAdapter::IOThreadData::~IOThreadData() { 324 } 325 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 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 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. 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 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 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 456 NaClDesc* NaClIPCAdapter::MakeNaClDesc() { 457 return MakeNaClDescCustom(this); 458 } 459 460 #if defined(OS_POSIX) 461 int NaClIPCAdapter::TakeClientFileDescriptor() { 462 return io_thread_data_.channel_->TakeClientFileDescriptor(); 463 } 464 #endif 465 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 546 void NaClIPCAdapter::OnChannelConnected(int32 peer_pid) { 547 } 548 549 void NaClIPCAdapter::OnChannelError() { 550 CloseChannel(); 551 } 552 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 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 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 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 639 void NaClIPCAdapter::ConnectChannelOnIOThread() { 640 if (!io_thread_data_.channel_->Connect()) 641 NOTREACHED(); 642 } 643 644 void NaClIPCAdapter::CloseChannelOnIOThread() { 645 io_thread_data_.channel_->Close(); 646 } 647 648 void NaClIPCAdapter::SendMessageOnIOThread(scoped_ptr<IPC::Message> message) { 649 io_thread_data_.channel_->Send(message.release()); 650 } 651 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 671 int TranslatePepperFileReadWriteOpenFlagsForTesting(int32_t pp_open_flags) { 672 return TranslatePepperFileReadWriteOpenFlags(pp_open_flags); 673 } 674