• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 };
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>
CreateMessage(MessageType type,size_t payload_size,size_t num_handles,DataType ** out_data)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>
GetMessagePayload(const void * bytes,size_t num_bytes,DataType ** out_data)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
Create(Delegate * delegate,ScopedPlatformHandle platform_handle,scoped_refptr<base::TaskRunner> io_task_runner,const ProcessErrorCallback & process_error_callback)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
CreatePortsMessage(size_t payload_size,void ** payload,size_t num_handles)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
GetPortsMessageData(Channel::Message * message,void ** data,size_t * num_data_bytes)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 
Start()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 
ShutDown()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 
LeakHandleOnShutdown()211 void NodeChannel::LeakHandleOnShutdown() {
212   base::AutoLock lock(channel_lock_);
213   if (channel_) {
214     channel_->LeakHandle();
215   }
216 }
217 
NotifyBadMessage(const std::string & error)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 
SetRemoteProcessHandle(base::ProcessHandle process_handle)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 
HasRemoteProcessHandle()235 bool NodeChannel::HasRemoteProcessHandle() {
236   base::AutoLock lock(remote_process_handle_lock_);
237   return remote_process_handle_ != base::kNullProcessHandle;
238 }
239 
CopyRemoteProcessHandle()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 
SetRemoteNodeName(const ports::NodeName & name)260 void NodeChannel::SetRemoteNodeName(const ports::NodeName& name) {
261   DCHECK(io_task_runner_->RunsTasksOnCurrentThread());
262   remote_node_name_ = name;
263 }
264 
AcceptChild(const ports::NodeName & parent_name,const ports::NodeName & token)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 
AcceptParent(const ports::NodeName & token,const ports::NodeName & child_name)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 
AddBrokerClient(const ports::NodeName & client_name,base::ProcessHandle process_handle)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 
BrokerClientAdded(const ports::NodeName & client_name,ScopedPlatformHandle broker_channel)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 
AcceptBrokerClient(const ports::NodeName & broker_name,ScopedPlatformHandle broker_channel)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 
PortsMessage(Channel::MessagePtr message)332 void NodeChannel::PortsMessage(Channel::MessagePtr message) {
333   WriteChannelMessage(std::move(message));
334 }
335 
RequestPortMerge(const ports::PortName & connector_port_name,const std::string & token)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 
RequestIntroduction(const ports::NodeName & name)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 
Introduce(const ports::NodeName & name,ScopedPlatformHandle channel_handle)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 
Broadcast(Channel::MessagePtr message)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))
RelayPortsMessage(const ports::NodeName & destination,Channel::MessagePtr message)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 
PortsMessageFromRelay(const ports::NodeName & source,Channel::MessagePtr message)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 
NodeChannel(Delegate * delegate,ScopedPlatformHandle platform_handle,scoped_refptr<base::TaskRunner> io_task_runner,const ProcessErrorCallback & process_error_callback)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 
~NodeChannel()451 NodeChannel::~NodeChannel() {
452   ShutDown();
453 }
454 
OnChannelMessage(const void * payload,size_t payload_size,ScopedPlatformHandleVectorPtr handles)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 
OnChannelError()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)
OnProcessReady(base::ProcessHandle process)753 void NodeChannel::OnProcessReady(base::ProcessHandle process) {
754   io_task_runner_->PostTask(FROM_HERE, base::Bind(
755       &NodeChannel::ProcessPendingMessagesWithMachPorts, this));
756 }
757 
ProcessPendingMessagesWithMachPorts()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 
WriteChannelMessage(Channel::MessagePtr message)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