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 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 { 61 explicit DescThunker(NaClIPCAdapter* adapter_param) 62 : adapter(adapter_param) { 63 } 64 scoped_refptr<NaClIPCAdapter> adapter; 65 }; 66 67 NaClIPCAdapter* ToAdapter(void* handle) { 68 return static_cast<DescThunker*>(handle)->adapter.get(); 69 } 70 71 // NaClDescCustom implementation. 72 void NaClDescCustomDestroy(void* handle) { 73 delete static_cast<DescThunker*>(handle); 74 } 75 76 ssize_t NaClDescCustomSendMsg(void* handle, const NaClImcTypedMsgHdr* msg, 77 int /* flags */) { 78 return static_cast<ssize_t>(ToAdapter(handle)->Send(msg)); 79 } 80 81 ssize_t NaClDescCustomRecvMsg(void* handle, NaClImcTypedMsgHdr* msg, 82 int /* flags */) { 83 return static_cast<ssize_t>(ToAdapter(handle)->BlockingReceive(msg)); 84 } 85 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 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. 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: 125 explicit NaClDescWrapper(NaClDesc* desc): desc_(desc) {} 126 ~NaClDescWrapper() { 127 NaClDescUnref(desc_); 128 } 129 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 144 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 151 void AddDescriptor(NaClDescWrapper* desc) { descs_.push_back(desc); } 152 153 size_t desc_count() const { return descs_.size(); } 154 155 private: 156 friend class base::RefCounted<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 170 NaClIPCAdapter::RewrittenMessage::RewrittenMessage() 171 : data_len_(0), 172 data_read_cursor_(0) { 173 } 174 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 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 218 NaClIPCAdapter::LockedData::LockedData() 219 : channel_closed_(false) { 220 } 221 222 NaClIPCAdapter::LockedData::~LockedData() { 223 } 224 225 NaClIPCAdapter::IOThreadData::IOThreadData() { 226 } 227 228 NaClIPCAdapter::IOThreadData::~IOThreadData() { 229 } 230 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 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 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. 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 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 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 362 NaClDesc* NaClIPCAdapter::MakeNaClDesc() { 363 return MakeNaClDescCustom(this); 364 } 365 366 #if defined(OS_POSIX) 367 int NaClIPCAdapter::TakeClientFileDescriptor() { 368 return io_thread_data_.channel_->TakeClientFileDescriptor(); 369 } 370 #endif 371 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_ptr; 381 bool success = locked_data_.handle_converter_.ConvertNativeHandlesToPosix( 382 msg, &handles, &new_msg_ptr); 383 if (!success) 384 return false; 385 386 // Now add any descriptors we found to rewritten_msg. |handles| is usually 387 // empty, unless we read a message containing a FD or handle. 388 for (Handles::const_iterator iter = handles.begin(); 389 iter != handles.end(); 390 ++iter) { 391 scoped_ptr<NaClDescWrapper> nacl_desc; 392 switch (iter->type()) { 393 case ppapi::proxy::SerializedHandle::SHARED_MEMORY: { 394 const base::SharedMemoryHandle& shm_handle = iter->shmem(); 395 uint32_t size = iter->size(); 396 nacl_desc.reset(new NaClDescWrapper(NaClDescImcShmMake( 397 #if defined(OS_WIN) 398 shm_handle, 399 #else 400 shm_handle.fd, 401 #endif 402 static_cast<size_t>(size)))); 403 break; 404 } 405 case ppapi::proxy::SerializedHandle::SOCKET: { 406 nacl_desc.reset(new NaClDescWrapper(NaClDescSyncSocketMake( 407 #if defined(OS_WIN) 408 iter->descriptor() 409 #else 410 iter->descriptor().fd 411 #endif 412 ))); 413 break; 414 } 415 case ppapi::proxy::SerializedHandle::CHANNEL_HANDLE: { 416 // Check that this came from a PpapiMsg_CreateNaClChannel message. 417 // This code here is only appropriate for that message. 418 DCHECK(msg.type() == PpapiMsg_CreateNaClChannel::ID); 419 IPC::ChannelHandle channel_handle = 420 IPC::Channel::GenerateVerifiedChannelID("nacl"); 421 scoped_refptr<NaClIPCAdapter> ipc_adapter( 422 new NaClIPCAdapter(channel_handle, task_runner_.get())); 423 ipc_adapter->ConnectChannel(); 424 #if defined(OS_POSIX) 425 channel_handle.socket = base::FileDescriptor( 426 ipc_adapter->TakeClientFileDescriptor(), true); 427 #endif 428 nacl_desc.reset(new NaClDescWrapper(ipc_adapter->MakeNaClDesc())); 429 // Send back a message that the channel was created. 430 scoped_ptr<IPC::Message> response( 431 new PpapiHostMsg_ChannelCreated(channel_handle)); 432 task_runner_->PostTask(FROM_HERE, 433 base::Bind(&NaClIPCAdapter::SendMessageOnIOThread, this, 434 base::Passed(&response))); 435 break; 436 } 437 case ppapi::proxy::SerializedHandle::FILE: 438 // IMPORTANT: The NaClDescIoDescFromHandleAllocCtor function creates 439 // a NaClDesc that checks file flags before reading and writing. This 440 // is essential since PPB_FileIO now sends a file descriptor to the 441 // plugin which may have write capabilities. We can't allow the plugin 442 // to write with it since it could bypass quota checks, which still 443 // happen in the host. 444 nacl_desc.reset(new NaClDescWrapper(NaClDescIoDescFromHandleAllocCtor( 445 #if defined(OS_WIN) 446 iter->descriptor(), 447 #else 448 iter->descriptor().fd, 449 #endif 450 TranslatePepperFileReadWriteOpenFlags(iter->open_flag())))); 451 break; 452 case ppapi::proxy::SerializedHandle::INVALID: { 453 // Nothing to do. TODO(dmichael): Should we log this? Or is it 454 // sometimes okay to pass an INVALID handle? 455 break; 456 } 457 // No default, so the compiler will warn us if new types get added. 458 } 459 if (nacl_desc.get()) 460 rewritten_msg->AddDescriptor(nacl_desc.release()); 461 } 462 if (new_msg_ptr && !handles.empty()) 463 SaveMessage(*new_msg_ptr, rewritten_msg.get()); 464 else 465 SaveMessage(msg, rewritten_msg.get()); 466 } 467 cond_var_.Signal(); 468 return true; 469 } 470 471 void NaClIPCAdapter::OnChannelConnected(int32 peer_pid) { 472 } 473 474 void NaClIPCAdapter::OnChannelError() { 475 CloseChannel(); 476 } 477 478 NaClIPCAdapter::~NaClIPCAdapter() { 479 // Make sure the channel is deleted on the IO thread. 480 task_runner_->PostTask(FROM_HERE, 481 base::Bind(&DeleteChannel, io_thread_data_.channel_.release())); 482 } 483 484 int NaClIPCAdapter::LockedReceive(NaClImcTypedMsgHdr* msg) { 485 lock_.AssertAcquired(); 486 487 if (locked_data_.to_be_received_.empty()) 488 return 0; 489 scoped_refptr<RewrittenMessage> current = 490 locked_data_.to_be_received_.front(); 491 492 int retval = current->Read(msg); 493 494 // When a message is entirely consumed, remove if from the waiting queue. 495 if (current->is_consumed()) 496 locked_data_.to_be_received_.pop(); 497 498 return retval; 499 } 500 501 bool NaClIPCAdapter::SendCompleteMessage(const char* buffer, 502 size_t buffer_len) { 503 lock_.AssertAcquired(); 504 // The message will have already been validated, so we know it's large enough 505 // for our header. 506 const NaClMessageHeader* header = 507 reinterpret_cast<const NaClMessageHeader*>(buffer); 508 509 // Length of the message not including the body. The data passed to us by the 510 // plugin should match that in the message header. This should have already 511 // been validated by GetBufferStatus. 512 int body_len = static_cast<int>(buffer_len - sizeof(NaClMessageHeader)); 513 DCHECK(body_len == static_cast<int>(header->payload_size)); 514 515 // We actually discard the flags and only copy the ones we care about. This 516 // is just because message doesn't have a constructor that takes raw flags. 517 scoped_ptr<IPC::Message> msg( 518 new IPC::Message(header->routing, header->type, 519 IPC::Message::PRIORITY_NORMAL)); 520 if (header->flags & IPC::Message::SYNC_BIT) 521 msg->set_sync(); 522 if (header->flags & IPC::Message::REPLY_BIT) 523 msg->set_reply(); 524 if (header->flags & IPC::Message::REPLY_ERROR_BIT) 525 msg->set_reply_error(); 526 if (header->flags & IPC::Message::UNBLOCK_BIT) 527 msg->set_unblock(true); 528 529 msg->WriteBytes(&buffer[sizeof(NaClMessageHeader)], body_len); 530 531 // Technically we didn't have to do any of the previous work in the lock. But 532 // sometimes our buffer will point to the to_be_sent_ string which is 533 // protected by the lock, and it's messier to factor Send() such that it can 534 // unlock for us. Holding the lock for the message construction, which is 535 // just some memcpys, shouldn't be a big deal. 536 lock_.AssertAcquired(); 537 if (locked_data_.channel_closed_) 538 return false; // TODO(brettw) clean up handles here when we add support! 539 540 if (msg->is_sync()) { 541 locked_data_.handle_converter_.RegisterSyncMessageForReply(*msg); 542 } 543 // Actual send must be done on the I/O thread. 544 task_runner_->PostTask(FROM_HERE, 545 base::Bind(&NaClIPCAdapter::SendMessageOnIOThread, this, 546 base::Passed(&msg))); 547 return true; 548 } 549 550 void NaClIPCAdapter::ClearToBeSent() { 551 lock_.AssertAcquired(); 552 553 // Don't let the string keep its buffer behind our back. 554 std::string empty; 555 locked_data_.to_be_sent_.swap(empty); 556 } 557 558 void NaClIPCAdapter::ConnectChannelOnIOThread() { 559 if (!io_thread_data_.channel_->Connect()) 560 NOTREACHED(); 561 } 562 563 void NaClIPCAdapter::CloseChannelOnIOThread() { 564 io_thread_data_.channel_->Close(); 565 } 566 567 void NaClIPCAdapter::SendMessageOnIOThread(scoped_ptr<IPC::Message> message) { 568 io_thread_data_.channel_->Send(message.release()); 569 } 570 571 void NaClIPCAdapter::SaveMessage(const IPC::Message& msg, 572 RewrittenMessage* rewritten_msg) { 573 lock_.AssertAcquired(); 574 // There is some padding in this structure (the "padding" member is 16 575 // bits but this then gets padded to 32 bits). We want to be sure not to 576 // leak data to the untrusted plugin, so zero everything out first. 577 NaClMessageHeader header; 578 memset(&header, 0, sizeof(NaClMessageHeader)); 579 580 header.payload_size = static_cast<uint32>(msg.payload_size()); 581 header.routing = msg.routing_id(); 582 header.type = msg.type(); 583 header.flags = msg.flags(); 584 header.num_fds = static_cast<int>(rewritten_msg->desc_count()); 585 586 rewritten_msg->SetData(header, msg.payload(), msg.payload_size()); 587 locked_data_.to_be_received_.push(rewritten_msg); 588 } 589 590 int TranslatePepperFileReadWriteOpenFlagsForTesting(int32_t pp_open_flags) { 591 return TranslatePepperFileReadWriteOpenFlags(pp_open_flags); 592 } 593