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