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