| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/nacl/nacl_ipc_adapter.h" | 5 #include "chrome/nacl/nacl_ipc_adapter.h" |
| 6 | 6 |
| 7 #include <limits.h> | 7 #include <limits.h> |
| 8 #include <string.h> | 8 #include <string.h> |
| 9 | 9 |
| 10 #include "base/basictypes.h" | 10 #include "base/basictypes.h" |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 82 funcs.SendMsg = NaClDescCustomSendMsg; | 82 funcs.SendMsg = NaClDescCustomSendMsg; |
| 83 funcs.RecvMsg = NaClDescCustomRecvMsg; | 83 funcs.RecvMsg = NaClDescCustomRecvMsg; |
| 84 // NaClDescMakeCustomDesc gives us a reference on the returned NaClDesc. | 84 // NaClDescMakeCustomDesc gives us a reference on the returned NaClDesc. |
| 85 return NaClDescMakeCustomDesc(new DescThunker(adapter), &funcs); | 85 return NaClDescMakeCustomDesc(new DescThunker(adapter), &funcs); |
| 86 } | 86 } |
| 87 | 87 |
| 88 void DeleteChannel(IPC::Channel* channel) { | 88 void DeleteChannel(IPC::Channel* channel) { |
| 89 delete channel; | 89 delete channel; |
| 90 } | 90 } |
| 91 | 91 |
| 92 bool ReadHostResource(PickleIterator* it, int* instance_id, int* resource_id) { | 92 void WriteFileDescriptor(int handle_index, |
| 93 return it->ReadInt(instance_id) && | 93 const ppapi::proxy::SerializedHandle& handle, |
| 94 it->ReadInt(resource_id); | 94 IPC::Message* message) { |
| 95 handle.WriteHeader(message); |
| 96 |
| 97 // Now write the handle itself in POSIX style. |
| 98 message->WriteBool(true); // valid == true |
| 99 message->WriteInt(handle_index); |
| 95 } | 100 } |
| 96 | 101 |
| 97 bool ReadFileDescriptor(const IPC::Message& message, | 102 typedef std::vector<ppapi::proxy::SerializedHandle> Handles; |
| 98 PickleIterator* it, | |
| 99 NaClHandle* handle) { | |
| 100 #if defined(OS_POSIX) | |
| 101 bool valid; | |
| 102 base::FileDescriptor desc; | |
| 103 if (!it->ReadBool(&valid) || | |
| 104 !valid || | |
| 105 !message.ReadFileDescriptor(it, &desc)) | |
| 106 return false; | |
| 107 | 103 |
| 108 *handle = desc.fd; | 104 // We define one overload for catching SerializedHandles, so that we can share |
| 109 return true; | 105 // them correctly to the untrusted side, and another for handling all other |
| 110 #else | 106 // parameters. See ExtractHandlesImpl for how these get used. |
| 111 uint32 value; | 107 void ExtractHandle(const ppapi::proxy::SerializedHandle& handle, |
| 112 if (!it->ReadUInt32(&value)) | 108 Handles* handles, IPC::Message* msg, int* handle_index) { |
| 113 return false; | 109 handles->push_back(handle); |
| 114 | 110 if (msg) |
| 115 *handle = reinterpret_cast<NaClHandle>(value); | 111 WriteFileDescriptor((*handle_index)++, handle, msg); |
| 116 return true; | |
| 117 #endif // defined(OS_POSIX) | |
| 118 } | 112 } |
| 119 | 113 |
| 120 void WriteHostResource(IPC::Message* message, | 114 // This overload is to catch all types other than SerializedHandle. On Windows, |
| 121 int instance_id, | 115 // |msg| will be a valid pointer, and we must write |param| to it |
| 122 int resource_id) { | 116 template <class T> |
| 123 message->WriteInt(instance_id); | 117 void ExtractHandle(const T& param, Handles* /* handles */, IPC::Message* msg, |
| 124 message->WriteInt(resource_id); | 118 int* /* handle_index */) { |
| 119 // It's not a handle, so just write to the output message, if necessary. |
| 120 if (msg) |
| 121 IPC::WriteParam(msg, param); |
| 125 } | 122 } |
| 126 | 123 |
| 127 void WriteFileDescriptor(IPC::Message* message, int index) { | 124 // These just break apart the given tuple and run ExtractHandle over each param. |
| 128 message->WriteBool(true); // valid == true | 125 // The idea is to extract any handles in the tuple, while writing all data to |
| 129 message->WriteInt(index); | 126 // msg (if msg is valid). The msg will only be valid on Windows, where we need |
| 127 // to re-write all of the message parameters, writing the handles in POSIX style |
| 128 // for NaCl. |
| 129 template <class A> |
| 130 void ExtractHandlesImpl(const Tuple1<A>& t1, Handles* handles, |
| 131 IPC::Message* msg) { |
| 132 int handle_index = 0; |
| 133 ExtractHandle(t1.a, handles, msg, &handle_index); |
| 130 } | 134 } |
| 135 template <class A, class B> |
| 136 void ExtractHandlesImpl(const Tuple2<A, B>& t1, Handles* handles, |
| 137 IPC::Message* msg) { |
| 138 int handle_index = 0; |
| 139 ExtractHandle(t1.a, handles, msg, &handle_index); |
| 140 ExtractHandle(t1.b, handles, msg, &handle_index); |
| 141 } |
| 142 template <class A, class B, class C> |
| 143 void ExtractHandlesImpl(const Tuple3<A, B, C>& t1, Handles* handles, |
| 144 IPC::Message* msg) { |
| 145 int handle_index = 0; |
| 146 ExtractHandle(t1.a, handles, msg, &handle_index); |
| 147 ExtractHandle(t1.b, handles, msg, &handle_index); |
| 148 ExtractHandle(t1.c, handles, msg, &handle_index); |
| 149 } |
| 150 template <class A, class B, class C, class D> |
| 151 void ExtractHandlesImpl(const Tuple4<A, B, C, D>& t1, Handles* handles, |
| 152 IPC::Message* msg) { |
| 153 int handle_index = 0; |
| 154 ExtractHandle(t1.a, handles, msg, &handle_index); |
| 155 ExtractHandle(t1.b, handles, msg, &handle_index); |
| 156 ExtractHandle(t1.c, handles, msg, &handle_index); |
| 157 ExtractHandle(t1.d, handles, msg, &handle_index); |
| 158 } |
| 159 |
| 160 template <class MessageType> |
| 161 class HandleExtractor { |
| 162 public: |
| 163 explicit HandleExtractor(const IPC::Message* msg) |
| 164 : msg_(static_cast<const MessageType*>(msg)) { |
| 165 } |
| 166 bool TranslateMessage(Handles* handles, IPC::Message* out_msg) { |
| 167 typename TupleTypes<typename MessageType::Schema::Param>::ValueTuple params; |
| 168 if (!MessageType::Read(msg_, ¶ms)) |
| 169 return false; |
| 170 ExtractHandlesImpl(params, handles, out_msg); |
| 171 return true; |
| 172 } |
| 173 |
| 174 bool TranslateReply(Handles* handles, IPC::SyncMessage* out_msg) { |
| 175 typename TupleTypes<typename MessageType::Schema::ReplyParam>::ValueTuple |
| 176 params; |
| 177 if (!MessageType::ReadReplyParam(msg_, ¶ms)) |
| 178 return false; |
| 179 out_msg->set_reply(); |
| 180 // If we need to rewrite the message (i.e., on Windows), we need to make |
| 181 // sure we write the message id first. |
| 182 if (out_msg) { |
| 183 int id = IPC::SyncMessage::GetMessageId(*msg_); |
| 184 out_msg->WriteInt(id); |
| 185 } |
| 186 ExtractHandlesImpl(params, handles, out_msg); |
| 187 return true; |
| 188 } |
| 189 // TODO(dmichael): Add TranslateSyncMessage for outgoing sync messages, if we |
| 190 // ever pass handles in one of those. |
| 191 |
| 192 private: |
| 193 const MessageType* msg_; |
| 194 }; |
| 131 | 195 |
| 132 } // namespace | 196 } // namespace |
| 133 | 197 |
| 134 class NaClIPCAdapter::RewrittenMessage | 198 class NaClIPCAdapter::RewrittenMessage |
| 135 : public base::RefCounted<RewrittenMessage> { | 199 : public base::RefCounted<RewrittenMessage> { |
| 136 public: | 200 public: |
| 137 RewrittenMessage(); | 201 RewrittenMessage(); |
| 138 | 202 |
| 139 bool is_consumed() const { return data_read_cursor_ == data_len_; } | 203 bool is_consumed() const { return data_read_cursor_ == data_len_; } |
| 140 | 204 |
| (...skipping 206 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 347 NaClDesc* NaClIPCAdapter::MakeNaClDesc() { | 411 NaClDesc* NaClIPCAdapter::MakeNaClDesc() { |
| 348 return MakeNaClDescCustom(this); | 412 return MakeNaClDescCustom(this); |
| 349 } | 413 } |
| 350 | 414 |
| 351 #if defined(OS_POSIX) | 415 #if defined(OS_POSIX) |
| 352 int NaClIPCAdapter::TakeClientFileDescriptor() { | 416 int NaClIPCAdapter::TakeClientFileDescriptor() { |
| 353 return io_thread_data_.channel_->TakeClientFileDescriptor(); | 417 return io_thread_data_.channel_->TakeClientFileDescriptor(); |
| 354 } | 418 } |
| 355 #endif | 419 #endif |
| 356 | 420 |
| 421 #define CASE_FOR_MESSAGE(MESSAGE_TYPE) \ |
| 422 case MESSAGE_TYPE::ID: { \ |
| 423 HandleExtractor<MESSAGE_TYPE> extractor(&msg); \ |
| 424 if (!extractor.TranslateMessage(&handles, new_msg_ptr)) \ |
| 425 return false; \ |
| 426 break; \ |
| 427 } |
| 428 #define CASE_FOR_REPLY(MESSAGE_TYPE) \ |
| 429 case MESSAGE_TYPE::ID: { \ |
| 430 HandleExtractor<MESSAGE_TYPE> extractor(&msg); \ |
| 431 if (!extractor.TranslateReply( \ |
| 432 &handles, \ |
| 433 static_cast<IPC::SyncMessage*>(new_msg_ptr))) \ |
| 434 return false; \ |
| 435 break; \ |
| 436 } |
| 357 bool NaClIPCAdapter::OnMessageReceived(const IPC::Message& msg) { | 437 bool NaClIPCAdapter::OnMessageReceived(const IPC::Message& msg) { |
| 358 { | 438 { |
| 359 base::AutoLock lock(lock_); | 439 base::AutoLock lock(lock_); |
| 360 | 440 |
| 361 scoped_refptr<RewrittenMessage> rewritten_msg(new RewrittenMessage); | 441 scoped_refptr<RewrittenMessage> rewritten_msg(new RewrittenMessage); |
| 362 | 442 |
| 363 PickleIterator it(msg); | 443 // Pointer to the "new" message we will rewrite on Windows. On posix, this |
| 444 // isn't necessary, so it will stay NULL. |
| 445 IPC::Message* new_msg_ptr = NULL; |
| 446 #if defined(OS_WIN) |
| 447 IPC::Message new_msg(msg.routing_id(), msg.type(), msg.priority()); |
| 448 new_msg_ptr = &new_msg; |
| 449 #endif |
| 450 Handles handles; |
| 364 switch (msg.type()) { | 451 switch (msg.type()) { |
| 365 case PpapiMsg_PPBAudio_NotifyAudioStreamCreated::ID: { | 452 CASE_FOR_MESSAGE(PpapiMsg_PPBAudio_NotifyAudioStreamCreated) |
| 366 int instance_id; | 453 CASE_FOR_MESSAGE(PpapiMsg_PPBAudioInput_OpenACK) |
| 367 int resource_id; | 454 case IPC_REPLY_ID: { |
| 368 int result_code; | 455 int id = IPC::SyncMessage::GetMessageId(msg); |
| 369 NaClHandle sock_handle; | 456 // Do I need to skip the ID, or does Params already include it? |
| 370 NaClHandle shm_handle; | 457 // PickleIterator iter(IPC::SyncMessage::GetDataIterator(msg.get())); |
| 371 uint32_t shm_length; | 458 LockedData::PendingSyncMsgMap::iterator iter( |
| 372 if (ReadHostResource(&it, &instance_id, &resource_id) && | 459 locked_data_.pending_sync_msgs_.find(id)); |
| 373 it.ReadInt(&result_code) && | 460 if (iter == locked_data_.pending_sync_msgs_.end()) { |
| 374 ReadFileDescriptor(msg, &it, &sock_handle) && | 461 NOTREACHED(); |
| 375 ReadFileDescriptor(msg, &it, &shm_handle) && | 462 return false; |
| 376 it.ReadUInt32(&shm_length)) { | 463 } |
| 377 // Import the sync socket. | 464 uint32_t type = iter->second; |
| 378 nacl::DescWrapperFactory factory; | 465 locked_data_.pending_sync_msgs_.erase(iter); |
| 379 scoped_ptr<nacl::DescWrapper> socket_wrapper( | 466 switch (type) { |
| 380 factory.ImportSyncSocketHandle(sock_handle)); | 467 CASE_FOR_REPLY(PpapiHostMsg_PPBGraphics3D_GetTransferBuffer) |
| 381 // Import the shared memory handle and increase its size by 4 bytes to | 468 CASE_FOR_REPLY(PpapiHostMsg_PPBImageData_CreateNaCl) |
| 382 // accommodate the length data we write at the end to signal the host. | 469 default: |
| 383 scoped_ptr<nacl::DescWrapper> shm_wrapper( | 470 // Do nothing for messages we don't know. |
| 384 factory.ImportShmHandle(shm_handle, shm_length + sizeof(uint32))); | 471 break; |
| 385 if (shm_wrapper.get() && socket_wrapper.get()) { | |
| 386 rewritten_msg->AddDescriptor(socket_wrapper.release()); | |
| 387 rewritten_msg->AddDescriptor(shm_wrapper.release()); | |
| 388 } | |
| 389 #if defined(OS_POSIX) | |
| 390 SaveMessage(msg, rewritten_msg.get()); | |
| 391 #else | |
| 392 // On Windows we must rewrite the message to match the POSIX form. | |
| 393 IPC::Message new_msg(msg.routing_id(), | |
| 394 PpapiMsg_PPBAudio_NotifyAudioStreamCreated::ID, | |
| 395 msg.priority()); | |
| 396 WriteHostResource(&new_msg, instance_id, resource_id); | |
| 397 new_msg.WriteInt(result_code); | |
| 398 WriteFileDescriptor(&new_msg, 0); // socket handle, index = 0 | |
| 399 WriteFileDescriptor(&new_msg, 1); // shm handle, index = 1 | |
| 400 new_msg.WriteUInt32(shm_length); | |
| 401 SaveMessage(new_msg, rewritten_msg.get()); | |
| 402 #endif | |
| 403 } | 472 } |
| 404 break; | 473 break; |
| 405 } | 474 } |
| 406 default: { | 475 default: |
| 407 SaveMessage(msg, rewritten_msg.get()); | 476 // Do nothing for messages we don't know. |
| 477 break; |
| 478 } |
| 479 // Now add any descriptors we found to rewritten_msg. |handles| is usually |
| 480 // empty, unless we read a message containing a FD or handle. |
| 481 nacl::DescWrapperFactory factory; |
| 482 for (Handles::const_iterator iter = handles.begin(); |
| 483 iter != handles.end(); |
| 484 ++iter) { |
| 485 scoped_ptr<nacl::DescWrapper> nacl_desc; |
| 486 switch (iter->type()) { |
| 487 case ppapi::proxy::SerializedHandle::SHARED_MEMORY: { |
| 488 const base::SharedMemoryHandle& shm_handle = iter->shmem(); |
| 489 uint32_t size = iter->size(); |
| 490 nacl_desc.reset(factory.ImportShmHandle( |
| 491 #if defined(OS_WIN) |
| 492 reinterpret_cast<const NaClHandle>(shm_handle), |
| 493 #else |
| 494 shm_handle.fd, |
| 495 #endif |
| 496 static_cast<size_t>(size))); |
| 497 break; |
| 498 } |
| 499 case ppapi::proxy::SerializedHandle::SOCKET: { |
| 500 nacl_desc.reset(factory.ImportSyncSocketHandle( |
| 501 #if defined(OS_WIN) |
| 502 reinterpret_cast<const NaClHandle>(iter->descriptor()) |
| 503 #else |
| 504 iter->descriptor().fd |
| 505 #endif |
| 506 )); |
| 507 } |
| 508 case ppapi::proxy::SerializedHandle::INVALID: { |
| 509 // Nothing to do. TODO(dmichael): Should we log this? Or is it |
| 510 // sometimes okay to pass an INVALID handle? |
| 511 } |
| 512 // No default, so the compiler will warn us if new types get added. |
| 408 } | 513 } |
| 514 if (nacl_desc.get()) |
| 515 rewritten_msg->AddDescriptor(nacl_desc.release()); |
| 409 } | 516 } |
| 517 if (new_msg_ptr && !handles.empty()) |
| 518 SaveMessage(*new_msg_ptr, rewritten_msg.get()); |
| 519 else |
| 520 SaveMessage(msg, rewritten_msg.get()); |
| 410 } | 521 } |
| 411 cond_var_.Signal(); | 522 cond_var_.Signal(); |
| 412 return true; | 523 return true; |
| 413 } | 524 } |
| 414 | 525 |
| 415 void NaClIPCAdapter::OnChannelConnected(int32 peer_pid) { | 526 void NaClIPCAdapter::OnChannelConnected(int32 peer_pid) { |
| 416 } | 527 } |
| 417 | 528 |
| 418 void NaClIPCAdapter::OnChannelError() { | 529 void NaClIPCAdapter::OnChannelError() { |
| 419 CloseChannel(); | 530 CloseChannel(); |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 473 | 584 |
| 474 // Technically we didn't have to do any of the previous work in the lock. But | 585 // Technically we didn't have to do any of the previous work in the lock. But |
| 475 // sometimes our buffer will point to the to_be_sent_ string which is | 586 // sometimes our buffer will point to the to_be_sent_ string which is |
| 476 // protected by the lock, and it's messier to factor Send() such that it can | 587 // protected by the lock, and it's messier to factor Send() such that it can |
| 477 // unlock for us. Holding the lock for the message construction, which is | 588 // unlock for us. Holding the lock for the message construction, which is |
| 478 // just some memcpys, shouldn't be a big deal. | 589 // just some memcpys, shouldn't be a big deal. |
| 479 lock_.AssertAcquired(); | 590 lock_.AssertAcquired(); |
| 480 if (locked_data_.channel_closed_) | 591 if (locked_data_.channel_closed_) |
| 481 return false; // TODO(brettw) clean up handles here when we add support! | 592 return false; // TODO(brettw) clean up handles here when we add support! |
| 482 | 593 |
| 594 // Store the type of all sync messages so that later we can translate the |
| 595 // reply if necessary. |
| 596 if (msg->is_sync()) { |
| 597 int id = IPC::SyncMessage::GetMessageId(*msg); |
| 598 locked_data_.pending_sync_msgs_[id] = msg->type(); |
| 599 } |
| 483 // Actual send must be done on the I/O thread. | 600 // Actual send must be done on the I/O thread. |
| 484 task_runner_->PostTask(FROM_HERE, | 601 task_runner_->PostTask(FROM_HERE, |
| 485 base::Bind(&NaClIPCAdapter::SendMessageOnIOThread, this, | 602 base::Bind(&NaClIPCAdapter::SendMessageOnIOThread, this, |
| 486 base::Passed(&msg))); | 603 base::Passed(&msg))); |
| 487 return true; | 604 return true; |
| 488 } | 605 } |
| 489 | 606 |
| 490 void NaClIPCAdapter::ClearToBeSent() { | 607 void NaClIPCAdapter::ClearToBeSent() { |
| 491 lock_.AssertAcquired(); | 608 lock_.AssertAcquired(); |
| 492 | 609 |
| (...skipping 27 matching lines...) Expand all Loading... |
| 520 header.payload_size = static_cast<uint32>(msg.payload_size()); | 637 header.payload_size = static_cast<uint32>(msg.payload_size()); |
| 521 header.routing = msg.routing_id(); | 638 header.routing = msg.routing_id(); |
| 522 header.type = msg.type(); | 639 header.type = msg.type(); |
| 523 header.flags = msg.flags(); | 640 header.flags = msg.flags(); |
| 524 header.num_fds = static_cast<int>(rewritten_msg->desc_count()); | 641 header.num_fds = static_cast<int>(rewritten_msg->desc_count()); |
| 525 | 642 |
| 526 rewritten_msg->SetData(header, msg.payload(), msg.payload_size()); | 643 rewritten_msg->SetData(header, msg.payload(), msg.payload_size()); |
| 527 locked_data_.to_be_received_.push(rewritten_msg); | 644 locked_data_.to_be_received_.push(rewritten_msg); |
| 528 } | 645 } |
| 529 | 646 |
| OLD | NEW |