Home | History | Annotate | Download | only in system
      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