1 // Copyright 2018 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/public/cpp/system/invitation.h"
6 
7 #include "base/numerics/safe_conversions.h"
8 #include "build/build_config.h"
9 #include "mojo/public/c/system/invitation.h"
10 #include "mojo/public/c/system/platform_handle.h"
11 #include "mojo/public/cpp/system/platform_handle.h"
12 
13 namespace mojo {
14 
15 namespace {
16 
17 static constexpr base::StringPiece kIsolatedPipeName = {"\0\0\0\0", 4};
18 
ProcessHandleToMojoProcessHandle(base::ProcessHandle target_process,MojoPlatformProcessHandle * handle)19 void ProcessHandleToMojoProcessHandle(base::ProcessHandle target_process,
20                                       MojoPlatformProcessHandle* handle) {
21   handle->struct_size = sizeof(*handle);
22 #if defined(OS_WIN)
23   handle->value =
24       static_cast<uint64_t>(reinterpret_cast<uintptr_t>(target_process));
25 #else
26   handle->value = static_cast<uint64_t>(target_process);
27 #endif
28 }
29 
PlatformHandleToTransportEndpoint(PlatformHandle platform_handle,MojoPlatformHandle * endpoint_handle,MojoInvitationTransportEndpoint * endpoint)30 void PlatformHandleToTransportEndpoint(
31     PlatformHandle platform_handle,
32     MojoPlatformHandle* endpoint_handle,
33     MojoInvitationTransportEndpoint* endpoint) {
34   PlatformHandle::ToMojoPlatformHandle(std::move(platform_handle),
35                                        endpoint_handle);
36   CHECK_NE(endpoint_handle->type, MOJO_PLATFORM_HANDLE_TYPE_INVALID);
37 
38   endpoint->struct_size = sizeof(*endpoint);
39   endpoint->num_platform_handles = 1;
40   endpoint->platform_handles = endpoint_handle;
41 }
42 
RunErrorCallback(uintptr_t context,const MojoProcessErrorDetails * details)43 void RunErrorCallback(uintptr_t context,
44                       const MojoProcessErrorDetails* details) {
45   auto* callback = reinterpret_cast<ProcessErrorCallback*>(context);
46   std::string error_message;
47   if (details->error_message) {
48     error_message =
49         std::string(details->error_message, details->error_message_length);
50     callback->Run(error_message);
51   } else if (details->flags & MOJO_PROCESS_ERROR_FLAG_DISCONNECTED) {
52     delete callback;
53   }
54 }
55 
SendInvitation(ScopedInvitationHandle invitation,base::ProcessHandle target_process,PlatformHandle endpoint_handle,MojoInvitationTransportType transport_type,MojoSendInvitationFlags flags,const ProcessErrorCallback & error_callback,base::StringPiece isolated_connection_name)56 void SendInvitation(ScopedInvitationHandle invitation,
57                     base::ProcessHandle target_process,
58                     PlatformHandle endpoint_handle,
59                     MojoInvitationTransportType transport_type,
60                     MojoSendInvitationFlags flags,
61                     const ProcessErrorCallback& error_callback,
62                     base::StringPiece isolated_connection_name) {
63   MojoPlatformProcessHandle process_handle;
64   ProcessHandleToMojoProcessHandle(target_process, &process_handle);
65 
66   MojoPlatformHandle platform_handle;
67   MojoInvitationTransportEndpoint endpoint;
68   PlatformHandleToTransportEndpoint(std::move(endpoint_handle),
69                                     &platform_handle, &endpoint);
70   endpoint.type = transport_type;
71 
72   MojoProcessErrorHandler error_handler = nullptr;
73   uintptr_t error_handler_context = 0;
74   if (error_callback) {
75     error_handler = &RunErrorCallback;
76 
77     // NOTE: The allocated callback is effectively owned by the error handler,
78     // which will delete it on the final invocation for this context (i.e.
79     // process disconnection).
80     error_handler_context =
81         reinterpret_cast<uintptr_t>(new ProcessErrorCallback(error_callback));
82   }
83 
84   MojoSendInvitationOptions options;
85   options.struct_size = sizeof(options);
86   options.flags = flags;
87   if (flags & MOJO_SEND_INVITATION_FLAG_ISOLATED) {
88     options.isolated_connection_name = isolated_connection_name.data();
89     options.isolated_connection_name_length =
90         static_cast<uint32_t>(isolated_connection_name.size());
91   }
92   MojoResult result =
93       MojoSendInvitation(invitation.get().value(), &process_handle, &endpoint,
94                          error_handler, error_handler_context, &options);
95   // If successful, the invitation handle is already closed for us.
96   if (result == MOJO_RESULT_OK)
97     ignore_result(invitation.release());
98 }
99 
100 }  // namespace
101 
OutgoingInvitation()102 OutgoingInvitation::OutgoingInvitation() {
103   MojoHandle invitation_handle;
104   MojoResult result = MojoCreateInvitation(nullptr, &invitation_handle);
105   DCHECK_EQ(result, MOJO_RESULT_OK);
106 
107   handle_.reset(InvitationHandle(invitation_handle));
108 }
109 
110 OutgoingInvitation::OutgoingInvitation(OutgoingInvitation&& other) = default;
111 
112 OutgoingInvitation::~OutgoingInvitation() = default;
113 
114 OutgoingInvitation& OutgoingInvitation::operator=(OutgoingInvitation&& other) =
115     default;
116 
AttachMessagePipe(base::StringPiece name)117 ScopedMessagePipeHandle OutgoingInvitation::AttachMessagePipe(
118     base::StringPiece name) {
119   DCHECK(!name.empty());
120   DCHECK(base::IsValueInRangeForNumericType<uint32_t>(name.size()));
121   MojoHandle message_pipe_handle;
122   MojoResult result = MojoAttachMessagePipeToInvitation(
123       handle_.get().value(), name.data(), static_cast<uint32_t>(name.size()),
124       nullptr, &message_pipe_handle);
125   DCHECK_EQ(MOJO_RESULT_OK, result);
126   return ScopedMessagePipeHandle(MessagePipeHandle(message_pipe_handle));
127 }
128 
AttachMessagePipe(uint64_t name)129 ScopedMessagePipeHandle OutgoingInvitation::AttachMessagePipe(uint64_t name) {
130   return AttachMessagePipe(
131       base::StringPiece(reinterpret_cast<const char*>(&name), sizeof(name)));
132 }
133 
ExtractMessagePipe(base::StringPiece name)134 ScopedMessagePipeHandle OutgoingInvitation::ExtractMessagePipe(
135     base::StringPiece name) {
136   DCHECK(!name.empty());
137   DCHECK(base::IsValueInRangeForNumericType<uint32_t>(name.size()));
138   MojoHandle message_pipe_handle;
139   MojoResult result = MojoExtractMessagePipeFromInvitation(
140       handle_.get().value(), name.data(), static_cast<uint32_t>(name.size()),
141       nullptr, &message_pipe_handle);
142   DCHECK_EQ(MOJO_RESULT_OK, result);
143   return ScopedMessagePipeHandle(MessagePipeHandle(message_pipe_handle));
144 }
145 
ExtractMessagePipe(uint64_t name)146 ScopedMessagePipeHandle OutgoingInvitation::ExtractMessagePipe(uint64_t name) {
147   return ExtractMessagePipe(
148       base::StringPiece(reinterpret_cast<const char*>(&name), sizeof(name)));
149 }
150 
151 // static
Send(OutgoingInvitation invitation,base::ProcessHandle target_process,PlatformChannelEndpoint channel_endpoint,const ProcessErrorCallback & error_callback)152 void OutgoingInvitation::Send(OutgoingInvitation invitation,
153                               base::ProcessHandle target_process,
154                               PlatformChannelEndpoint channel_endpoint,
155                               const ProcessErrorCallback& error_callback) {
156   SendInvitation(std::move(invitation.handle_), target_process,
157                  channel_endpoint.TakePlatformHandle(),
158                  MOJO_INVITATION_TRANSPORT_TYPE_CHANNEL,
159                  MOJO_SEND_INVITATION_FLAG_NONE, error_callback, "");
160 }
161 
162 // static
Send(OutgoingInvitation invitation,base::ProcessHandle target_process,PlatformChannelServerEndpoint server_endpoint,const ProcessErrorCallback & error_callback)163 void OutgoingInvitation::Send(OutgoingInvitation invitation,
164                               base::ProcessHandle target_process,
165                               PlatformChannelServerEndpoint server_endpoint,
166                               const ProcessErrorCallback& error_callback) {
167   SendInvitation(std::move(invitation.handle_), target_process,
168                  server_endpoint.TakePlatformHandle(),
169                  MOJO_INVITATION_TRANSPORT_TYPE_CHANNEL_SERVER,
170                  MOJO_SEND_INVITATION_FLAG_NONE, error_callback, "");
171 }
172 
173 // static
SendAsync(OutgoingInvitation invitation,base::ProcessHandle target_process,PlatformChannelEndpoint channel_endpoint,const ProcessErrorCallback & error_callback)174 void OutgoingInvitation::SendAsync(OutgoingInvitation invitation,
175                                    base::ProcessHandle target_process,
176                                    PlatformChannelEndpoint channel_endpoint,
177                                    const ProcessErrorCallback& error_callback) {
178   SendInvitation(std::move(invitation.handle_), target_process,
179                  channel_endpoint.TakePlatformHandle(),
180                  MOJO_INVITATION_TRANSPORT_TYPE_CHANNEL_ASYNC,
181                  MOJO_SEND_INVITATION_FLAG_NONE, error_callback, "");
182 }
183 
184 // static
SendIsolated(PlatformChannelEndpoint channel_endpoint,base::StringPiece connection_name)185 ScopedMessagePipeHandle OutgoingInvitation::SendIsolated(
186     PlatformChannelEndpoint channel_endpoint,
187     base::StringPiece connection_name) {
188   mojo::OutgoingInvitation invitation;
189   ScopedMessagePipeHandle pipe =
190       invitation.AttachMessagePipe(kIsolatedPipeName);
191   SendInvitation(std::move(invitation.handle_), base::kNullProcessHandle,
192                  channel_endpoint.TakePlatformHandle(),
193                  MOJO_INVITATION_TRANSPORT_TYPE_CHANNEL,
194                  MOJO_SEND_INVITATION_FLAG_ISOLATED, ProcessErrorCallback(),
195                  connection_name);
196   return pipe;
197 }
198 
199 // static
SendIsolated(PlatformChannelServerEndpoint server_endpoint,base::StringPiece connection_name)200 ScopedMessagePipeHandle OutgoingInvitation::SendIsolated(
201     PlatformChannelServerEndpoint server_endpoint,
202     base::StringPiece connection_name) {
203   mojo::OutgoingInvitation invitation;
204   ScopedMessagePipeHandle pipe =
205       invitation.AttachMessagePipe(kIsolatedPipeName);
206   SendInvitation(std::move(invitation.handle_), base::kNullProcessHandle,
207                  server_endpoint.TakePlatformHandle(),
208                  MOJO_INVITATION_TRANSPORT_TYPE_CHANNEL_SERVER,
209                  MOJO_SEND_INVITATION_FLAG_ISOLATED, ProcessErrorCallback(),
210                  connection_name);
211   return pipe;
212 }
213 
214 IncomingInvitation::IncomingInvitation() = default;
215 
216 IncomingInvitation::IncomingInvitation(IncomingInvitation&& other) = default;
217 
IncomingInvitation(ScopedInvitationHandle handle)218 IncomingInvitation::IncomingInvitation(ScopedInvitationHandle handle)
219     : handle_(std::move(handle)) {}
220 
221 IncomingInvitation::~IncomingInvitation() = default;
222 
223 IncomingInvitation& IncomingInvitation::operator=(IncomingInvitation&& other) =
224     default;
225 
226 // static
Accept(PlatformChannelEndpoint channel_endpoint,MojoAcceptInvitationFlags flags)227 IncomingInvitation IncomingInvitation::Accept(
228     PlatformChannelEndpoint channel_endpoint,
229     MojoAcceptInvitationFlags flags) {
230   MojoPlatformHandle endpoint_handle;
231   PlatformHandle::ToMojoPlatformHandle(channel_endpoint.TakePlatformHandle(),
232                                        &endpoint_handle);
233   CHECK_NE(endpoint_handle.type, MOJO_PLATFORM_HANDLE_TYPE_INVALID);
234 
235   MojoInvitationTransportEndpoint transport_endpoint;
236   transport_endpoint.struct_size = sizeof(transport_endpoint);
237   transport_endpoint.type = MOJO_INVITATION_TRANSPORT_TYPE_CHANNEL;
238   transport_endpoint.num_platform_handles = 1;
239   transport_endpoint.platform_handles = &endpoint_handle;
240 
241   MojoAcceptInvitationOptions options;
242   options.struct_size = sizeof(options);
243   options.flags = flags;
244 
245   MojoHandle invitation_handle;
246   MojoResult result =
247       MojoAcceptInvitation(&transport_endpoint, &options, &invitation_handle);
248   if (result != MOJO_RESULT_OK)
249     return IncomingInvitation();
250 
251   return IncomingInvitation(
252       ScopedInvitationHandle(InvitationHandle(invitation_handle)));
253 }
254 
255 // static
AcceptAsync(PlatformChannelEndpoint channel_endpoint)256 IncomingInvitation IncomingInvitation::AcceptAsync(
257     PlatformChannelEndpoint channel_endpoint) {
258   MojoPlatformHandle endpoint_handle;
259   PlatformHandle::ToMojoPlatformHandle(channel_endpoint.TakePlatformHandle(),
260                                        &endpoint_handle);
261   CHECK_NE(endpoint_handle.type, MOJO_PLATFORM_HANDLE_TYPE_INVALID);
262 
263   MojoInvitationTransportEndpoint transport_endpoint;
264   transport_endpoint.struct_size = sizeof(transport_endpoint);
265   transport_endpoint.type = MOJO_INVITATION_TRANSPORT_TYPE_CHANNEL_ASYNC;
266   transport_endpoint.num_platform_handles = 1;
267   transport_endpoint.platform_handles = &endpoint_handle;
268 
269   MojoHandle invitation_handle;
270   MojoResult result =
271       MojoAcceptInvitation(&transport_endpoint, nullptr, &invitation_handle);
272   if (result != MOJO_RESULT_OK)
273     return IncomingInvitation();
274 
275   return IncomingInvitation(
276       ScopedInvitationHandle(InvitationHandle(invitation_handle)));
277 }
278 
279 // static
AcceptIsolated(PlatformChannelEndpoint channel_endpoint)280 ScopedMessagePipeHandle IncomingInvitation::AcceptIsolated(
281     PlatformChannelEndpoint channel_endpoint) {
282   MojoPlatformHandle endpoint_handle;
283   PlatformHandle::ToMojoPlatformHandle(channel_endpoint.TakePlatformHandle(),
284                                        &endpoint_handle);
285   CHECK_NE(endpoint_handle.type, MOJO_PLATFORM_HANDLE_TYPE_INVALID);
286 
287   MojoInvitationTransportEndpoint transport_endpoint;
288   transport_endpoint.struct_size = sizeof(transport_endpoint);
289   transport_endpoint.type = MOJO_INVITATION_TRANSPORT_TYPE_CHANNEL;
290   transport_endpoint.num_platform_handles = 1;
291   transport_endpoint.platform_handles = &endpoint_handle;
292 
293   MojoAcceptInvitationOptions options;
294   options.struct_size = sizeof(options);
295   options.flags = MOJO_ACCEPT_INVITATION_FLAG_ISOLATED;
296 
297   MojoHandle invitation_handle;
298   MojoResult result =
299       MojoAcceptInvitation(&transport_endpoint, &options, &invitation_handle);
300   if (result != MOJO_RESULT_OK)
301     return ScopedMessagePipeHandle();
302 
303   IncomingInvitation invitation{
304       ScopedInvitationHandle(InvitationHandle(invitation_handle))};
305   return invitation.ExtractMessagePipe(kIsolatedPipeName);
306 }
307 
ExtractMessagePipe(base::StringPiece name)308 ScopedMessagePipeHandle IncomingInvitation::ExtractMessagePipe(
309     base::StringPiece name) {
310   DCHECK(!name.empty());
311   DCHECK(base::IsValueInRangeForNumericType<uint32_t>(name.size()));
312   DCHECK(handle_.is_valid());
313   MojoHandle message_pipe_handle;
314   MojoResult result = MojoExtractMessagePipeFromInvitation(
315       handle_.get().value(), name.data(), static_cast<uint32_t>(name.size()),
316       nullptr, &message_pipe_handle);
317   DCHECK_EQ(MOJO_RESULT_OK, result);
318   return ScopedMessagePipeHandle(MessagePipeHandle(message_pipe_handle));
319 }
320 
ExtractMessagePipe(uint64_t name)321 ScopedMessagePipeHandle IncomingInvitation::ExtractMessagePipe(uint64_t name) {
322   return ExtractMessagePipe(
323       base::StringPiece(reinterpret_cast<const char*>(&name), sizeof(name)));
324 }
325 
326 }  // namespace mojo
327