1 // Copyright 2016 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 "mojo/edk/system/node_channel.h" 6 7 #include <cstring> 8 #include <limits> 9 #include <sstream> 10 11 #include "base/bind.h" 12 #include "base/location.h" 13 #include "base/logging.h" 14 #include "mojo/edk/system/channel.h" 15 #include "mojo/edk/system/request_context.h" 16 17 #if defined(OS_MACOSX) && !defined(OS_IOS) 18 #include "mojo/edk/system/mach_port_relay.h" 19 #endif 20 21 namespace mojo { 22 namespace edk { 23 24 namespace { 25 26 template <typename T> 27 T Align(T t) { 28 const auto k = kChannelMessageAlignment; 29 return t + (k - (t % k)) % k; 30 } 31 32 // NOTE: Please ONLY append messages to the end of this enum. 33 enum class MessageType : uint32_t { 34 ACCEPT_CHILD, 35 ACCEPT_PARENT, 36 ADD_BROKER_CLIENT, 37 BROKER_CLIENT_ADDED, 38 ACCEPT_BROKER_CLIENT, 39 PORTS_MESSAGE, 40 REQUEST_PORT_MERGE, 41 REQUEST_INTRODUCTION, 42 INTRODUCE, 43 #if defined(OS_WIN) || (defined(OS_MACOSX) && !defined(OS_IOS)) 44 RELAY_PORTS_MESSAGE, 45 #endif 46 BROADCAST, 47 #if defined(OS_WIN) || (defined(OS_MACOSX) && !defined(OS_IOS)) 48 PORTS_MESSAGE_FROM_RELAY, 49 #endif 50 }; 51 52 struct Header { 53 MessageType type; 54 uint32_t padding; 55 }; 56 57 static_assert(sizeof(Header) % kChannelMessageAlignment == 0, 58 "Invalid header size."); 59 60 struct AcceptChildData { 61 ports::NodeName parent_name; 62 ports::NodeName token; 63 }; 64 65 struct AcceptParentData { 66 ports::NodeName token; 67 ports::NodeName child_name; 68 }; 69 70 // This message may include a process handle on plaforms that require it. 71 struct AddBrokerClientData { 72 ports::NodeName client_name; 73 #if !defined(OS_WIN) 74 uint32_t process_handle; 75 uint32_t padding; 76 #endif 77 }; 78 79 #if !defined(OS_WIN) 80 static_assert(sizeof(base::ProcessHandle) == sizeof(uint32_t), 81 "Unexpected pid size"); 82 static_assert(sizeof(AddBrokerClientData) % kChannelMessageAlignment == 0, 83 "Invalid AddBrokerClientData size."); 84 #endif 85 86 // This data is followed by a platform channel handle to the broker. 87 struct BrokerClientAddedData { 88 ports::NodeName client_name; 89 }; 90 91 // This data may be followed by a platform channel handle to the broker. If not, 92 // then the parent is the broker and its channel should be used as such. 93 struct AcceptBrokerClientData { 94 ports::NodeName broker_name; 95 }; 96 97 // This is followed by arbitrary payload data which is interpreted as a token 98 // string for port location. 99 struct RequestPortMergeData { 100 ports::PortName connector_port_name; 101 }; 102 103 // Used for both REQUEST_INTRODUCTION and INTRODUCE. 104 // 105 // For INTRODUCE the message also includes a valid platform handle for a channel 106 // the receiver may use to communicate with the named node directly, or an 107 // invalid platform handle if the node is unknown to the sender or otherwise 108 // cannot be introduced. 109 struct IntroductionData { 110 ports::NodeName name; 111 }; 112 113 #if defined(OS_WIN) || (defined(OS_MACOSX) && !defined(OS_IOS)) 114 // This struct is followed by the full payload of a message to be relayed. 115 struct RelayPortsMessageData { 116 ports::NodeName destination; 117 }; 118 119 // This struct is followed by the full payload of a relayed message. 120 struct PortsMessageFromRelayData { 121 ports::NodeName source; 122 }; 123 #endif 124 125 template <typename DataType> 126 Channel::MessagePtr CreateMessage(MessageType type, 127 size_t payload_size, 128 size_t num_handles, 129 DataType** out_data) { 130 Channel::MessagePtr message( 131 new Channel::Message(sizeof(Header) + payload_size, num_handles)); 132 Header* header = reinterpret_cast<Header*>(message->mutable_payload()); 133 header->type = type; 134 header->padding = 0; 135 *out_data = reinterpret_cast<DataType*>(&header[1]); 136 return message; 137 } 138 139 template <typename DataType> 140 bool GetMessagePayload(const void* bytes, 141 size_t num_bytes, 142 DataType** out_data) { 143 static_assert(sizeof(DataType) > 0, "DataType must have non-zero size."); 144 if (num_bytes < sizeof(Header) + sizeof(DataType)) 145 return false; 146 *out_data = reinterpret_cast<const DataType*>( 147 static_cast<const char*>(bytes) + sizeof(Header)); 148 return true; 149 } 150 151 } // namespace 152 153 // static 154 scoped_refptr<NodeChannel> NodeChannel::Create( 155 Delegate* delegate, 156 ScopedPlatformHandle platform_handle, 157 scoped_refptr<base::TaskRunner> io_task_runner, 158 const ProcessErrorCallback& process_error_callback) { 159 #if defined(OS_NACL_SFI) 160 LOG(FATAL) << "Multi-process not yet supported on NaCl-SFI"; 161 return nullptr; 162 #else 163 return new NodeChannel(delegate, std::move(platform_handle), io_task_runner, 164 process_error_callback); 165 #endif 166 } 167 168 // static 169 Channel::MessagePtr NodeChannel::CreatePortsMessage(size_t payload_size, 170 void** payload, 171 size_t num_handles) { 172 return CreateMessage(MessageType::PORTS_MESSAGE, payload_size, num_handles, 173 payload); 174 } 175 176 // static 177 void NodeChannel::GetPortsMessageData(Channel::Message* message, 178 void** data, 179 size_t* num_data_bytes) { 180 *data = reinterpret_cast<Header*>(message->mutable_payload()) + 1; 181 *num_data_bytes = message->payload_size() - sizeof(Header); 182 } 183 184 void NodeChannel::Start() { 185 #if defined(OS_MACOSX) && !defined(OS_IOS) 186 MachPortRelay* relay = delegate_->GetMachPortRelay(); 187 if (relay) 188 relay->AddObserver(this); 189 #endif 190 191 base::AutoLock lock(channel_lock_); 192 // ShutDown() may have already been called, in which case |channel_| is null. 193 if (channel_) 194 channel_->Start(); 195 } 196 197 void NodeChannel::ShutDown() { 198 #if defined(OS_MACOSX) && !defined(OS_IOS) 199 MachPortRelay* relay = delegate_->GetMachPortRelay(); 200 if (relay) 201 relay->RemoveObserver(this); 202 #endif 203 204 base::AutoLock lock(channel_lock_); 205 if (channel_) { 206 channel_->ShutDown(); 207 channel_ = nullptr; 208 } 209 } 210 211 void NodeChannel::LeakHandleOnShutdown() { 212 base::AutoLock lock(channel_lock_); 213 if (channel_) { 214 channel_->LeakHandle(); 215 } 216 } 217 218 void NodeChannel::NotifyBadMessage(const std::string& error) { 219 if (!process_error_callback_.is_null()) 220 process_error_callback_.Run("Received bad user message: " + error); 221 } 222 223 void NodeChannel::SetRemoteProcessHandle(base::ProcessHandle process_handle) { 224 DCHECK(io_task_runner_->RunsTasksOnCurrentThread()); 225 base::AutoLock lock(remote_process_handle_lock_); 226 DCHECK_EQ(base::kNullProcessHandle, remote_process_handle_); 227 CHECK_NE(remote_process_handle_, base::GetCurrentProcessHandle()); 228 remote_process_handle_ = process_handle; 229 #if defined(OS_WIN) 230 DCHECK(!scoped_remote_process_handle_.is_valid()); 231 scoped_remote_process_handle_.reset(PlatformHandle(process_handle)); 232 #endif 233 } 234 235 bool NodeChannel::HasRemoteProcessHandle() { 236 base::AutoLock lock(remote_process_handle_lock_); 237 return remote_process_handle_ != base::kNullProcessHandle; 238 } 239 240 base::ProcessHandle NodeChannel::CopyRemoteProcessHandle() { 241 base::AutoLock lock(remote_process_handle_lock_); 242 #if defined(OS_WIN) 243 if (remote_process_handle_ != base::kNullProcessHandle) { 244 // Privileged nodes use this to pass their childrens' process handles to the 245 // broker on launch. 246 HANDLE handle = remote_process_handle_; 247 BOOL result = DuplicateHandle( 248 base::GetCurrentProcessHandle(), remote_process_handle_, 249 base::GetCurrentProcessHandle(), &handle, 0, FALSE, 250 DUPLICATE_SAME_ACCESS); 251 DPCHECK(result); 252 return handle; 253 } 254 return base::kNullProcessHandle; 255 #else 256 return remote_process_handle_; 257 #endif 258 } 259 260 void NodeChannel::SetRemoteNodeName(const ports::NodeName& name) { 261 DCHECK(io_task_runner_->RunsTasksOnCurrentThread()); 262 remote_node_name_ = name; 263 } 264 265 void NodeChannel::AcceptChild(const ports::NodeName& parent_name, 266 const ports::NodeName& token) { 267 AcceptChildData* data; 268 Channel::MessagePtr message = CreateMessage( 269 MessageType::ACCEPT_CHILD, sizeof(AcceptChildData), 0, &data); 270 data->parent_name = parent_name; 271 data->token = token; 272 WriteChannelMessage(std::move(message)); 273 } 274 275 void NodeChannel::AcceptParent(const ports::NodeName& token, 276 const ports::NodeName& child_name) { 277 AcceptParentData* data; 278 Channel::MessagePtr message = CreateMessage( 279 MessageType::ACCEPT_PARENT, sizeof(AcceptParentData), 0, &data); 280 data->token = token; 281 data->child_name = child_name; 282 WriteChannelMessage(std::move(message)); 283 } 284 285 void NodeChannel::AddBrokerClient(const ports::NodeName& client_name, 286 base::ProcessHandle process_handle) { 287 AddBrokerClientData* data; 288 ScopedPlatformHandleVectorPtr handles(new PlatformHandleVector()); 289 #if defined(OS_WIN) 290 handles->push_back(PlatformHandle(process_handle)); 291 #endif 292 Channel::MessagePtr message = CreateMessage( 293 MessageType::ADD_BROKER_CLIENT, sizeof(AddBrokerClientData), 294 handles->size(), &data); 295 message->SetHandles(std::move(handles)); 296 data->client_name = client_name; 297 #if !defined(OS_WIN) 298 data->process_handle = process_handle; 299 data->padding = 0; 300 #endif 301 WriteChannelMessage(std::move(message)); 302 } 303 304 void NodeChannel::BrokerClientAdded(const ports::NodeName& client_name, 305 ScopedPlatformHandle broker_channel) { 306 BrokerClientAddedData* data; 307 ScopedPlatformHandleVectorPtr handles(new PlatformHandleVector()); 308 if (broker_channel.is_valid()) 309 handles->push_back(broker_channel.release()); 310 Channel::MessagePtr message = CreateMessage( 311 MessageType::BROKER_CLIENT_ADDED, sizeof(BrokerClientAddedData), 312 handles->size(), &data); 313 message->SetHandles(std::move(handles)); 314 data->client_name = client_name; 315 WriteChannelMessage(std::move(message)); 316 } 317 318 void NodeChannel::AcceptBrokerClient(const ports::NodeName& broker_name, 319 ScopedPlatformHandle broker_channel) { 320 AcceptBrokerClientData* data; 321 ScopedPlatformHandleVectorPtr handles(new PlatformHandleVector()); 322 if (broker_channel.is_valid()) 323 handles->push_back(broker_channel.release()); 324 Channel::MessagePtr message = CreateMessage( 325 MessageType::ACCEPT_BROKER_CLIENT, sizeof(AcceptBrokerClientData), 326 handles->size(), &data); 327 message->SetHandles(std::move(handles)); 328 data->broker_name = broker_name; 329 WriteChannelMessage(std::move(message)); 330 } 331 332 void NodeChannel::PortsMessage(Channel::MessagePtr message) { 333 WriteChannelMessage(std::move(message)); 334 } 335 336 void NodeChannel::RequestPortMerge(const ports::PortName& connector_port_name, 337 const std::string& token) { 338 RequestPortMergeData* data; 339 Channel::MessagePtr message = CreateMessage( 340 MessageType::REQUEST_PORT_MERGE, 341 sizeof(RequestPortMergeData) + token.size(), 0, &data); 342 data->connector_port_name = connector_port_name; 343 memcpy(data + 1, token.data(), token.size()); 344 WriteChannelMessage(std::move(message)); 345 } 346 347 void NodeChannel::RequestIntroduction(const ports::NodeName& name) { 348 IntroductionData* data; 349 Channel::MessagePtr message = CreateMessage( 350 MessageType::REQUEST_INTRODUCTION, sizeof(IntroductionData), 0, &data); 351 data->name = name; 352 WriteChannelMessage(std::move(message)); 353 } 354 355 void NodeChannel::Introduce(const ports::NodeName& name, 356 ScopedPlatformHandle channel_handle) { 357 IntroductionData* data; 358 ScopedPlatformHandleVectorPtr handles(new PlatformHandleVector()); 359 if (channel_handle.is_valid()) 360 handles->push_back(channel_handle.release()); 361 Channel::MessagePtr message = CreateMessage( 362 MessageType::INTRODUCE, sizeof(IntroductionData), handles->size(), &data); 363 message->SetHandles(std::move(handles)); 364 data->name = name; 365 WriteChannelMessage(std::move(message)); 366 } 367 368 void NodeChannel::Broadcast(Channel::MessagePtr message) { 369 DCHECK(!message->has_handles()); 370 void* data; 371 Channel::MessagePtr broadcast_message = CreateMessage( 372 MessageType::BROADCAST, message->data_num_bytes(), 0, &data); 373 memcpy(data, message->data(), message->data_num_bytes()); 374 WriteChannelMessage(std::move(broadcast_message)); 375 } 376 377 #if defined(OS_WIN) || (defined(OS_MACOSX) && !defined(OS_IOS)) 378 void NodeChannel::RelayPortsMessage(const ports::NodeName& destination, 379 Channel::MessagePtr message) { 380 #if defined(OS_WIN) 381 DCHECK(message->has_handles()); 382 383 // Note that this is only used on Windows, and on Windows all platform 384 // handles are included in the message data. We blindly copy all the data 385 // here and the relay node (the parent) will duplicate handles as needed. 386 size_t num_bytes = sizeof(RelayPortsMessageData) + message->data_num_bytes(); 387 RelayPortsMessageData* data; 388 Channel::MessagePtr relay_message = CreateMessage( 389 MessageType::RELAY_PORTS_MESSAGE, num_bytes, 0, &data); 390 data->destination = destination; 391 memcpy(data + 1, message->data(), message->data_num_bytes()); 392 393 // When the handles are duplicated in the parent, the source handles will 394 // be closed. If the parent never receives this message then these handles 395 // will leak, but that means something else has probably broken and the 396 // sending process won't likely be around much longer. 397 ScopedPlatformHandleVectorPtr handles = message->TakeHandles(); 398 handles->clear(); 399 400 #else 401 DCHECK(message->has_mach_ports()); 402 403 // On OSX, the handles are extracted from the relayed message and attached to 404 // the wrapper. The broker then takes the handles attached to the wrapper and 405 // moves them back to the relayed message. This is necessary because the 406 // message may contain fds which need to be attached to the outer message so 407 // that they can be transferred to the broker. 408 ScopedPlatformHandleVectorPtr handles = message->TakeHandles(); 409 size_t num_bytes = sizeof(RelayPortsMessageData) + message->data_num_bytes(); 410 RelayPortsMessageData* data; 411 Channel::MessagePtr relay_message = CreateMessage( 412 MessageType::RELAY_PORTS_MESSAGE, num_bytes, handles->size(), &data); 413 data->destination = destination; 414 memcpy(data + 1, message->data(), message->data_num_bytes()); 415 relay_message->SetHandles(std::move(handles)); 416 #endif // defined(OS_WIN) 417 418 WriteChannelMessage(std::move(relay_message)); 419 } 420 421 void NodeChannel::PortsMessageFromRelay(const ports::NodeName& source, 422 Channel::MessagePtr message) { 423 size_t num_bytes = sizeof(PortsMessageFromRelayData) + 424 message->payload_size(); 425 PortsMessageFromRelayData* data; 426 Channel::MessagePtr relayed_message = CreateMessage( 427 MessageType::PORTS_MESSAGE_FROM_RELAY, num_bytes, message->num_handles(), 428 &data); 429 data->source = source; 430 if (message->payload_size()) 431 memcpy(data + 1, message->payload(), message->payload_size()); 432 relayed_message->SetHandles(message->TakeHandles()); 433 WriteChannelMessage(std::move(relayed_message)); 434 } 435 #endif // defined(OS_WIN) || (defined(OS_MACOSX) && !defined(OS_IOS)) 436 437 NodeChannel::NodeChannel(Delegate* delegate, 438 ScopedPlatformHandle platform_handle, 439 scoped_refptr<base::TaskRunner> io_task_runner, 440 const ProcessErrorCallback& process_error_callback) 441 : delegate_(delegate), 442 io_task_runner_(io_task_runner), 443 process_error_callback_(process_error_callback) 444 #if !defined(OS_NACL_SFI) 445 , channel_( 446 Channel::Create(this, std::move(platform_handle), io_task_runner_)) 447 #endif 448 { 449 } 450 451 NodeChannel::~NodeChannel() { 452 ShutDown(); 453 } 454 455 void NodeChannel::OnChannelMessage(const void* payload, 456 size_t payload_size, 457 ScopedPlatformHandleVectorPtr handles) { 458 DCHECK(io_task_runner_->RunsTasksOnCurrentThread()); 459 460 RequestContext request_context(RequestContext::Source::SYSTEM); 461 462 // Ensure this NodeChannel stays alive through the extent of this method. The 463 // delegate may have the only other reference to this object and it may choose 464 // to drop it here in response to, e.g., a malformed message. 465 scoped_refptr<NodeChannel> keepalive = this; 466 467 #if defined(OS_WIN) 468 // If we receive handles from a known process, rewrite them to our own 469 // process. This can occur when a privileged node receives handles directly 470 // from a privileged descendant. 471 { 472 base::AutoLock lock(remote_process_handle_lock_); 473 if (handles && remote_process_handle_ != base::kNullProcessHandle) { 474 // Note that we explicitly mark the handles as being owned by the sending 475 // process before rewriting them, in order to accommodate RewriteHandles' 476 // internal sanity checks. 477 for (auto& handle : *handles) 478 handle.owning_process = remote_process_handle_; 479 if (!Channel::Message::RewriteHandles(remote_process_handle_, 480 base::GetCurrentProcessHandle(), 481 handles.get())) { 482 DLOG(ERROR) << "Received one or more invalid handles."; 483 } 484 } else if (handles) { 485 // Handles received by an unknown process must already be owned by us. 486 for (auto& handle : *handles) 487 handle.owning_process = base::GetCurrentProcessHandle(); 488 } 489 } 490 #elif defined(OS_MACOSX) && !defined(OS_IOS) 491 // If we're not the root, receive any mach ports from the message. If we're 492 // the root, the only message containing mach ports should be a 493 // RELAY_PORTS_MESSAGE. 494 { 495 MachPortRelay* relay = delegate_->GetMachPortRelay(); 496 if (handles && !relay) { 497 if (!MachPortRelay::ReceivePorts(handles.get())) { 498 LOG(ERROR) << "Error receiving mach ports."; 499 } 500 } 501 } 502 #endif // defined(OS_WIN) 503 504 505 if (payload_size <= sizeof(Header)) { 506 delegate_->OnChannelError(remote_node_name_, this); 507 return; 508 } 509 510 const Header* header = static_cast<const Header*>(payload); 511 switch (header->type) { 512 case MessageType::ACCEPT_CHILD: { 513 const AcceptChildData* data; 514 if (GetMessagePayload(payload, payload_size, &data)) { 515 delegate_->OnAcceptChild(remote_node_name_, data->parent_name, 516 data->token); 517 return; 518 } 519 break; 520 } 521 522 case MessageType::ACCEPT_PARENT: { 523 const AcceptParentData* data; 524 if (GetMessagePayload(payload, payload_size, &data)) { 525 delegate_->OnAcceptParent(remote_node_name_, data->token, 526 data->child_name); 527 return; 528 } 529 break; 530 } 531 532 case MessageType::ADD_BROKER_CLIENT: { 533 const AddBrokerClientData* data; 534 if (GetMessagePayload(payload, payload_size, &data)) { 535 ScopedPlatformHandle process_handle; 536 #if defined(OS_WIN) 537 if (!handles || handles->size() != 1) { 538 DLOG(ERROR) << "Dropping invalid AddBrokerClient message."; 539 break; 540 } 541 process_handle = ScopedPlatformHandle(handles->at(0)); 542 handles->clear(); 543 delegate_->OnAddBrokerClient(remote_node_name_, data->client_name, 544 process_handle.release().handle); 545 #else 546 if (handles && handles->size() != 0) { 547 DLOG(ERROR) << "Dropping invalid AddBrokerClient message."; 548 break; 549 } 550 delegate_->OnAddBrokerClient(remote_node_name_, data->client_name, 551 data->process_handle); 552 #endif 553 return; 554 } 555 break; 556 } 557 558 case MessageType::BROKER_CLIENT_ADDED: { 559 const BrokerClientAddedData* data; 560 if (GetMessagePayload(payload, payload_size, &data)) { 561 ScopedPlatformHandle broker_channel; 562 if (!handles || handles->size() != 1) { 563 DLOG(ERROR) << "Dropping invalid BrokerClientAdded message."; 564 break; 565 } 566 broker_channel = ScopedPlatformHandle(handles->at(0)); 567 handles->clear(); 568 delegate_->OnBrokerClientAdded(remote_node_name_, data->client_name, 569 std::move(broker_channel)); 570 return; 571 } 572 break; 573 } 574 575 case MessageType::ACCEPT_BROKER_CLIENT: { 576 const AcceptBrokerClientData* data; 577 if (GetMessagePayload(payload, payload_size, &data)) { 578 ScopedPlatformHandle broker_channel; 579 if (handles && handles->size() > 1) { 580 DLOG(ERROR) << "Dropping invalid AcceptBrokerClient message."; 581 break; 582 } 583 if (handles && handles->size() == 1) { 584 broker_channel = ScopedPlatformHandle(handles->at(0)); 585 handles->clear(); 586 } 587 delegate_->OnAcceptBrokerClient(remote_node_name_, data->broker_name, 588 std::move(broker_channel)); 589 return; 590 } 591 break; 592 } 593 594 case MessageType::PORTS_MESSAGE: { 595 size_t num_handles = handles ? handles->size() : 0; 596 Channel::MessagePtr message( 597 new Channel::Message(payload_size, num_handles)); 598 message->SetHandles(std::move(handles)); 599 memcpy(message->mutable_payload(), payload, payload_size); 600 delegate_->OnPortsMessage(remote_node_name_, std::move(message)); 601 return; 602 } 603 604 case MessageType::REQUEST_PORT_MERGE: { 605 const RequestPortMergeData* data; 606 if (GetMessagePayload(payload, payload_size, &data)) { 607 // Don't accept an empty token. 608 size_t token_size = payload_size - sizeof(*data) - sizeof(Header); 609 if (token_size == 0) 610 break; 611 std::string token(reinterpret_cast<const char*>(data + 1), token_size); 612 delegate_->OnRequestPortMerge(remote_node_name_, 613 data->connector_port_name, token); 614 return; 615 } 616 break; 617 } 618 619 case MessageType::REQUEST_INTRODUCTION: { 620 const IntroductionData* data; 621 if (GetMessagePayload(payload, payload_size, &data)) { 622 delegate_->OnRequestIntroduction(remote_node_name_, data->name); 623 return; 624 } 625 break; 626 } 627 628 case MessageType::INTRODUCE: { 629 const IntroductionData* data; 630 if (GetMessagePayload(payload, payload_size, &data)) { 631 if (handles && handles->size() > 1) { 632 DLOG(ERROR) << "Dropping invalid introduction message."; 633 break; 634 } 635 ScopedPlatformHandle channel_handle; 636 if (handles && handles->size() == 1) { 637 channel_handle = ScopedPlatformHandle(handles->at(0)); 638 handles->clear(); 639 } 640 delegate_->OnIntroduce(remote_node_name_, data->name, 641 std::move(channel_handle)); 642 return; 643 } 644 break; 645 } 646 647 #if defined(OS_WIN) || (defined(OS_MACOSX) && !defined(OS_IOS)) 648 case MessageType::RELAY_PORTS_MESSAGE: { 649 base::ProcessHandle from_process; 650 { 651 base::AutoLock lock(remote_process_handle_lock_); 652 from_process = remote_process_handle_; 653 } 654 const RelayPortsMessageData* data; 655 if (GetMessagePayload(payload, payload_size, &data)) { 656 // Don't try to relay an empty message. 657 if (payload_size <= sizeof(Header) + sizeof(RelayPortsMessageData)) 658 break; 659 660 const void* message_start = data + 1; 661 Channel::MessagePtr message = Channel::Message::Deserialize( 662 message_start, payload_size - sizeof(Header) - sizeof(*data)); 663 if (!message) { 664 DLOG(ERROR) << "Dropping invalid relay message."; 665 break; 666 } 667 #if defined(OS_MACOSX) && !defined(OS_IOS) 668 message->SetHandles(std::move(handles)); 669 MachPortRelay* relay = delegate_->GetMachPortRelay(); 670 if (!relay) { 671 LOG(ERROR) << "Receiving mach ports without a port relay from " 672 << remote_node_name_ << ". Dropping message."; 673 break; 674 } 675 { 676 base::AutoLock lock(pending_mach_messages_lock_); 677 if (relay->port_provider()->TaskForPid(from_process) == 678 MACH_PORT_NULL) { 679 pending_relay_messages_.push( 680 std::make_pair(data->destination, std::move(message))); 681 break; 682 } 683 } 684 #endif 685 delegate_->OnRelayPortsMessage(remote_node_name_, from_process, 686 data->destination, std::move(message)); 687 return; 688 } 689 break; 690 } 691 #endif 692 693 case MessageType::BROADCAST: { 694 if (payload_size <= sizeof(Header)) 695 break; 696 const void* data = static_cast<const void*>( 697 reinterpret_cast<const Header*>(payload) + 1); 698 Channel::MessagePtr message = 699 Channel::Message::Deserialize(data, payload_size - sizeof(Header)); 700 if (!message || message->has_handles()) { 701 DLOG(ERROR) << "Dropping invalid broadcast message."; 702 break; 703 } 704 delegate_->OnBroadcast(remote_node_name_, std::move(message)); 705 return; 706 } 707 708 #if defined(OS_WIN) || (defined(OS_MACOSX) && !defined(OS_IOS)) 709 case MessageType::PORTS_MESSAGE_FROM_RELAY: 710 const PortsMessageFromRelayData* data; 711 if (GetMessagePayload(payload, payload_size, &data)) { 712 size_t num_bytes = payload_size - sizeof(*data); 713 if (num_bytes < sizeof(Header)) 714 break; 715 num_bytes -= sizeof(Header); 716 717 size_t num_handles = handles ? handles->size() : 0; 718 Channel::MessagePtr message( 719 new Channel::Message(num_bytes, num_handles)); 720 message->SetHandles(std::move(handles)); 721 if (num_bytes) 722 memcpy(message->mutable_payload(), data + 1, num_bytes); 723 delegate_->OnPortsMessageFromRelay( 724 remote_node_name_, data->source, std::move(message)); 725 return; 726 } 727 break; 728 729 #endif // defined(OS_WIN) || (defined(OS_MACOSX) && !defined(OS_IOS)) 730 731 default: 732 break; 733 } 734 735 DLOG(ERROR) << "Received invalid message. Closing channel."; 736 delegate_->OnChannelError(remote_node_name_, this); 737 } 738 739 void NodeChannel::OnChannelError() { 740 DCHECK(io_task_runner_->RunsTasksOnCurrentThread()); 741 742 RequestContext request_context(RequestContext::Source::SYSTEM); 743 744 ShutDown(); 745 // |OnChannelError()| may cause |this| to be destroyed, but still need access 746 // to the name name after that destruction. So may a copy of 747 // |remote_node_name_| so it can be used if |this| becomes destroyed. 748 ports::NodeName node_name = remote_node_name_; 749 delegate_->OnChannelError(node_name, this); 750 } 751 752 #if defined(OS_MACOSX) && !defined(OS_IOS) 753 void NodeChannel::OnProcessReady(base::ProcessHandle process) { 754 io_task_runner_->PostTask(FROM_HERE, base::Bind( 755 &NodeChannel::ProcessPendingMessagesWithMachPorts, this)); 756 } 757 758 void NodeChannel::ProcessPendingMessagesWithMachPorts() { 759 MachPortRelay* relay = delegate_->GetMachPortRelay(); 760 DCHECK(relay); 761 762 base::ProcessHandle remote_process_handle; 763 { 764 base::AutoLock lock(remote_process_handle_lock_); 765 remote_process_handle = remote_process_handle_; 766 } 767 PendingMessageQueue pending_writes; 768 PendingRelayMessageQueue pending_relays; 769 { 770 base::AutoLock lock(pending_mach_messages_lock_); 771 pending_writes.swap(pending_write_messages_); 772 pending_relays.swap(pending_relay_messages_); 773 } 774 DCHECK(pending_writes.empty() && pending_relays.empty()); 775 776 while (!pending_writes.empty()) { 777 Channel::MessagePtr message = std::move(pending_writes.front()); 778 pending_writes.pop(); 779 if (!relay->SendPortsToProcess(message.get(), remote_process_handle)) { 780 LOG(ERROR) << "Error on sending mach ports. Remote process is likely " 781 << "gone. Dropping message."; 782 return; 783 } 784 785 base::AutoLock lock(channel_lock_); 786 if (!channel_) { 787 DLOG(ERROR) << "Dropping message on closed channel."; 788 break; 789 } else { 790 channel_->Write(std::move(message)); 791 } 792 } 793 794 // Ensure this NodeChannel stays alive while flushing relay messages. 795 scoped_refptr<NodeChannel> keepalive = this; 796 797 while (!pending_relays.empty()) { 798 ports::NodeName destination = pending_relays.front().first; 799 Channel::MessagePtr message = std::move(pending_relays.front().second); 800 pending_relays.pop(); 801 delegate_->OnRelayPortsMessage(remote_node_name_, remote_process_handle, 802 destination, std::move(message)); 803 } 804 } 805 #endif 806 807 void NodeChannel::WriteChannelMessage(Channel::MessagePtr message) { 808 #if defined(OS_WIN) 809 // Map handles to the destination process. Note: only messages from a 810 // privileged node should contain handles on Windows. If an unprivileged 811 // node needs to send handles, it should do so via RelayPortsMessage which 812 // stashes the handles in the message in such a way that they go undetected 813 // here (they'll be unpacked and duplicated by a privileged parent.) 814 815 if (message->has_handles()) { 816 base::ProcessHandle remote_process_handle; 817 { 818 base::AutoLock lock(remote_process_handle_lock_); 819 remote_process_handle = remote_process_handle_; 820 } 821 822 // Rewrite outgoing handles if we have a handle to the destination process. 823 if (remote_process_handle != base::kNullProcessHandle) { 824 ScopedPlatformHandleVectorPtr handles = message->TakeHandles(); 825 if (!Channel::Message::RewriteHandles(base::GetCurrentProcessHandle(), 826 remote_process_handle, 827 handles.get())) { 828 DLOG(ERROR) << "Failed to duplicate one or more outgoing handles."; 829 } 830 message->SetHandles(std::move(handles)); 831 } 832 } 833 #elif defined(OS_MACOSX) && !defined(OS_IOS) 834 // On OSX, we need to transfer mach ports to the destination process before 835 // transferring the message itself. 836 if (message->has_mach_ports()) { 837 MachPortRelay* relay = delegate_->GetMachPortRelay(); 838 if (relay) { 839 base::ProcessHandle remote_process_handle; 840 { 841 base::AutoLock lock(remote_process_handle_lock_); 842 // Expect that the receiving node is a child. 843 DCHECK(remote_process_handle_ != base::kNullProcessHandle); 844 remote_process_handle = remote_process_handle_; 845 } 846 { 847 base::AutoLock lock(pending_mach_messages_lock_); 848 if (relay->port_provider()->TaskForPid(remote_process_handle) == 849 MACH_PORT_NULL) { 850 // It is also possible for TaskForPid() to return MACH_PORT_NULL when 851 // the process has started, then died. In that case, the queued 852 // message will never be processed. But that's fine since we're about 853 // to die anyway. 854 pending_write_messages_.push(std::move(message)); 855 return; 856 } 857 } 858 859 if (!relay->SendPortsToProcess(message.get(), remote_process_handle)) { 860 LOG(ERROR) << "Error on sending mach ports. Remote process is likely " 861 << "gone. Dropping message."; 862 return; 863 } 864 } 865 } 866 #endif 867 868 base::AutoLock lock(channel_lock_); 869 if (!channel_) 870 DLOG(ERROR) << "Dropping message on closed channel."; 871 else 872 channel_->Write(std::move(message)); 873 } 874 875 } // namespace edk 876 } // namespace mojo 877