1 /*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "src/ipc/host_impl.h"
18
19 #include <algorithm>
20 #include <cinttypes>
21 #include <utility>
22
23 #include "perfetto/base/build_config.h"
24 #include "perfetto/base/compiler.h"
25 #include "perfetto/base/logging.h"
26 #include "perfetto/base/task_runner.h"
27 #include "perfetto/base/time.h"
28 #include "perfetto/ext/base/crash_keys.h"
29 #include "perfetto/ext/base/sys_types.h"
30 #include "perfetto/ext/base/unix_socket.h"
31 #include "perfetto/ext/base/utils.h"
32 #include "perfetto/ext/ipc/service.h"
33 #include "perfetto/ext/ipc/service_descriptor.h"
34
35 #include "protos/perfetto/ipc/wire_protocol.gen.h"
36
37 // TODO(primiano): put limits on #connections/uid and req. queue (b/69093705).
38
39 namespace perfetto {
40 namespace ipc {
41
42 namespace {
43
44 constexpr base::SockFamily kHostSockFamily =
45 kUseTCPSocket ? base::SockFamily::kInet : base::SockFamily::kUnix;
46
47 base::CrashKey g_crash_key_uid("ipc_uid");
48
GenerateMachineID(base::UnixSocket * sock,const std::string & machine_id_hint)49 base::MachineID GenerateMachineID(base::UnixSocket* sock,
50 const std::string& machine_id_hint) {
51 // The special value of base::kDefaultMachineID is reserved for local
52 // producers.
53 if (!sock->is_connected() || sock->family() == base::SockFamily::kUnix)
54 return base::kDefaultMachineID;
55
56 base::Hasher hasher;
57 // Use the hint from the client, or fallback to hostname if the client
58 // doesn't provide a hint.
59 if (!machine_id_hint.empty()) {
60 hasher.Update(machine_id_hint);
61 } else {
62 // Use the socket address without the port number part as the hint.
63 auto host_id = sock->GetSockAddr();
64 auto pos = std::string::npos;
65 switch (sock->family()) {
66 case base::SockFamily::kInet:
67 PERFETTO_FALLTHROUGH;
68 case base::SockFamily::kInet6:
69 PERFETTO_FALLTHROUGH;
70 case base::SockFamily::kVsock:
71 pos = host_id.rfind(":");
72 if (pos != std::string::npos)
73 host_id.resize(pos);
74 break;
75 case base::SockFamily::kUnspec:
76 PERFETTO_FALLTHROUGH;
77 case base::SockFamily::kUnix:
78 PERFETTO_DFATAL("Should be unreachable.");
79 return base::kDefaultMachineID;
80 }
81 hasher.Update(host_id);
82 }
83
84 // Take the lower 32-bit from the hash.
85 uint32_t digest = static_cast<uint32_t>(hasher.digest());
86 // Avoid the extremely unlikely case that the hasher digest happens to be 0.
87 return digest == base::kDefaultMachineID ? 1 : digest;
88 }
89 } // namespace
90
GetPosixPeerUid() const91 uid_t HostImpl::ClientConnection::GetPosixPeerUid() const {
92 #if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \
93 PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) || \
94 PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE)
95 if (sock->family() == base::SockFamily::kUnix)
96 return sock->peer_uid_posix();
97 #endif
98
99 // For non-unix sockets, check if the UID is set in OnSetPeerIdentity().
100 if (uid_override != base::kInvalidUid)
101 return uid_override;
102 // Must be != kInvalidUid or the PacketValidator will fail.
103 return 0;
104 }
105
GetLinuxPeerPid() const106 pid_t HostImpl::ClientConnection::GetLinuxPeerPid() const {
107 #if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \
108 PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
109 if (sock->family() == base::SockFamily::kUnix)
110 return sock->peer_pid_linux();
111 #endif
112
113 // For non-unix sockets, return the PID set in OnSetPeerIdentity().
114 return pid_override;
115 }
116
117 // static
CreateInstance(const char * socket_name,base::TaskRunner * task_runner)118 std::unique_ptr<Host> Host::CreateInstance(const char* socket_name,
119 base::TaskRunner* task_runner) {
120 std::unique_ptr<HostImpl> host(new HostImpl(socket_name, task_runner));
121 if (!host->sock() || !host->sock()->is_listening())
122 return nullptr;
123 return std::unique_ptr<Host>(std::move(host));
124 }
125
126 // static
CreateInstance(base::ScopedSocketHandle socket_fd,base::TaskRunner * task_runner)127 std::unique_ptr<Host> Host::CreateInstance(base::ScopedSocketHandle socket_fd,
128 base::TaskRunner* task_runner) {
129 std::unique_ptr<HostImpl> host(
130 new HostImpl(std::move(socket_fd), task_runner));
131 if (!host->sock() || !host->sock()->is_listening())
132 return nullptr;
133 return std::unique_ptr<Host>(std::move(host));
134 }
135
136 // static
CreateInstance_Fuchsia(base::TaskRunner * task_runner)137 std::unique_ptr<Host> Host::CreateInstance_Fuchsia(
138 base::TaskRunner* task_runner) {
139 return std::unique_ptr<HostImpl>(new HostImpl(task_runner));
140 }
141
HostImpl(base::ScopedSocketHandle socket_fd,base::TaskRunner * task_runner)142 HostImpl::HostImpl(base::ScopedSocketHandle socket_fd,
143 base::TaskRunner* task_runner)
144 : task_runner_(task_runner), weak_ptr_factory_(this) {
145 PERFETTO_DCHECK_THREAD(thread_checker_);
146 sock_ = base::UnixSocket::Listen(std::move(socket_fd), this, task_runner_,
147 kHostSockFamily, base::SockType::kStream);
148 }
149
HostImpl(const char * socket_name,base::TaskRunner * task_runner)150 HostImpl::HostImpl(const char* socket_name, base::TaskRunner* task_runner)
151 : task_runner_(task_runner), weak_ptr_factory_(this) {
152 PERFETTO_DCHECK_THREAD(thread_checker_);
153 sock_ = base::UnixSocket::Listen(socket_name, this, task_runner_,
154 base::GetSockFamily(socket_name),
155 base::SockType::kStream);
156 if (!sock_) {
157 PERFETTO_PLOG("Failed to create %s", socket_name);
158 }
159 }
160
HostImpl(base::TaskRunner * task_runner)161 HostImpl::HostImpl(base::TaskRunner* task_runner)
162 : task_runner_(task_runner), weak_ptr_factory_(this) {
163 PERFETTO_DCHECK_THREAD(thread_checker_);
164 }
165
166 HostImpl::~HostImpl() = default;
167
ExposeService(std::unique_ptr<Service> service)168 bool HostImpl::ExposeService(std::unique_ptr<Service> service) {
169 PERFETTO_DCHECK_THREAD(thread_checker_);
170 const std::string& service_name = service->GetDescriptor().service_name;
171 if (GetServiceByName(service_name)) {
172 PERFETTO_DLOG("Duplicate ExposeService(): %s", service_name.c_str());
173 return false;
174 }
175 service->use_shmem_emulation_ =
176 sock() && !base::SockShmemSupported(sock()->family());
177 ServiceID sid = ++last_service_id_;
178 ExposedService exposed_service(sid, service_name, std::move(service));
179 services_.emplace(sid, std::move(exposed_service));
180 return true;
181 }
182
AdoptConnectedSocket_Fuchsia(base::ScopedSocketHandle connected_socket,std::function<bool (int)> send_fd_cb)183 void HostImpl::AdoptConnectedSocket_Fuchsia(
184 base::ScopedSocketHandle connected_socket,
185 std::function<bool(int)> send_fd_cb) {
186 PERFETTO_DCHECK_THREAD(thread_checker_);
187 PERFETTO_DCHECK(connected_socket);
188 // Should not be used in conjunction with listen sockets.
189 PERFETTO_DCHECK(!sock_);
190
191 auto unix_socket = base::UnixSocket::AdoptConnected(
192 std::move(connected_socket), this, task_runner_, kHostSockFamily,
193 base::SockType::kStream);
194
195 auto* unix_socket_ptr = unix_socket.get();
196 OnNewIncomingConnection(nullptr, std::move(unix_socket));
197 ClientConnection* client_connection = clients_by_socket_[unix_socket_ptr];
198 client_connection->send_fd_cb_fuchsia = std::move(send_fd_cb);
199 PERFETTO_DCHECK(client_connection->send_fd_cb_fuchsia);
200 }
201
SetSocketSendTimeoutMs(uint32_t timeout_ms)202 void HostImpl::SetSocketSendTimeoutMs(uint32_t timeout_ms) {
203 PERFETTO_DCHECK_THREAD(thread_checker_);
204 // Should be less than the watchdog period (30s).
205 socket_tx_timeout_ms_ = timeout_ms;
206 }
207
OnNewIncomingConnection(base::UnixSocket *,std::unique_ptr<base::UnixSocket> new_conn)208 void HostImpl::OnNewIncomingConnection(
209 base::UnixSocket*,
210 std::unique_ptr<base::UnixSocket> new_conn) {
211 PERFETTO_DCHECK_THREAD(thread_checker_);
212 std::unique_ptr<ClientConnection> client(new ClientConnection());
213 ClientID client_id = ++last_client_id_;
214 clients_by_socket_[new_conn.get()] = client.get();
215 client->id = client_id;
216 client->sock = std::move(new_conn);
217 client->sock->SetTxTimeout(socket_tx_timeout_ms_);
218 clients_[client_id] = std::move(client);
219 }
220
OnDataAvailable(base::UnixSocket * sock)221 void HostImpl::OnDataAvailable(base::UnixSocket* sock) {
222 PERFETTO_DCHECK_THREAD(thread_checker_);
223 auto it = clients_by_socket_.find(sock);
224 if (it == clients_by_socket_.end())
225 return;
226 ClientConnection* client = it->second;
227 BufferedFrameDeserializer& frame_deserializer = client->frame_deserializer;
228
229 auto peer_uid = client->GetPosixPeerUid();
230 auto scoped_key = g_crash_key_uid.SetScoped(static_cast<int64_t>(peer_uid));
231
232 size_t rsize;
233 do {
234 auto buf = frame_deserializer.BeginReceive();
235 base::ScopedFile fd;
236 rsize = client->sock->Receive(buf.data, buf.size, &fd);
237 if (fd) {
238 PERFETTO_DCHECK(!client->received_fd);
239 client->received_fd = std::move(fd);
240 }
241 if (!frame_deserializer.EndReceive(rsize))
242 return OnDisconnect(client->sock.get());
243 } while (rsize > 0);
244
245 for (;;) {
246 std::unique_ptr<Frame> frame = frame_deserializer.PopNextFrame();
247 if (!frame)
248 break;
249 OnReceivedFrame(client, *frame);
250 }
251 }
252
OnReceivedFrame(ClientConnection * client,const Frame & req_frame)253 void HostImpl::OnReceivedFrame(ClientConnection* client,
254 const Frame& req_frame) {
255 if (req_frame.has_msg_bind_service())
256 return OnBindService(client, req_frame);
257 if (req_frame.has_msg_invoke_method())
258 return OnInvokeMethod(client, req_frame);
259 if (req_frame.has_set_peer_identity())
260 return OnSetPeerIdentity(client, req_frame);
261
262 PERFETTO_DLOG("Received invalid RPC frame from client %" PRIu64, client->id);
263 Frame reply_frame;
264 reply_frame.set_request_id(req_frame.request_id());
265 reply_frame.mutable_msg_request_error()->set_error("unknown request");
266 SendFrame(client, reply_frame);
267 }
268
OnBindService(ClientConnection * client,const Frame & req_frame)269 void HostImpl::OnBindService(ClientConnection* client, const Frame& req_frame) {
270 // Binding a service doesn't do anything major. It just returns back the
271 // service id and its method map.
272 const Frame::BindService& req = req_frame.msg_bind_service();
273 Frame reply_frame;
274 reply_frame.set_request_id(req_frame.request_id());
275 auto* reply = reply_frame.mutable_msg_bind_service_reply();
276 const ExposedService* service = GetServiceByName(req.service_name());
277 if (service) {
278 reply->set_success(true);
279 reply->set_service_id(service->id);
280 uint32_t method_id = 1; // method ids start at index 1.
281 for (const auto& desc_method : service->instance->GetDescriptor().methods) {
282 Frame::BindServiceReply::MethodInfo* method_info = reply->add_methods();
283 method_info->set_name(desc_method.name);
284 method_info->set_id(method_id++);
285 }
286 }
287 SendFrame(client, reply_frame);
288 }
289
OnInvokeMethod(ClientConnection * client,const Frame & req_frame)290 void HostImpl::OnInvokeMethod(ClientConnection* client,
291 const Frame& req_frame) {
292 const Frame::InvokeMethod& req = req_frame.msg_invoke_method();
293 Frame reply_frame;
294 RequestID request_id = req_frame.request_id();
295 reply_frame.set_request_id(request_id);
296 reply_frame.mutable_msg_invoke_method_reply()->set_success(false);
297 auto svc_it = services_.find(req.service_id());
298 if (svc_it == services_.end())
299 return SendFrame(client, reply_frame); // |success| == false by default.
300
301 Service* service = svc_it->second.instance.get();
302 const ServiceDescriptor& svc = service->GetDescriptor();
303 const auto& methods = svc.methods;
304 const uint32_t method_id = req.method_id();
305 if (method_id == 0 || method_id > methods.size())
306 return SendFrame(client, reply_frame);
307
308 const ServiceDescriptor::Method& method = methods[method_id - 1];
309 std::unique_ptr<ProtoMessage> decoded_req_args(
310 method.request_proto_decoder(req.args_proto()));
311 if (!decoded_req_args)
312 return SendFrame(client, reply_frame);
313
314 Deferred<ProtoMessage> deferred_reply;
315 base::WeakPtr<HostImpl> host_weak_ptr = weak_ptr_factory_.GetWeakPtr();
316 ClientID client_id = client->id;
317
318 if (!req.drop_reply()) {
319 deferred_reply.Bind([host_weak_ptr, client_id,
320 request_id](AsyncResult<ProtoMessage> reply) {
321 if (!host_weak_ptr)
322 return; // The reply came too late, the HostImpl has gone.
323 host_weak_ptr->ReplyToMethodInvocation(client_id, request_id,
324 std::move(reply));
325 });
326 }
327
328 auto peer_uid = client->GetPosixPeerUid();
329 auto scoped_key = g_crash_key_uid.SetScoped(static_cast<int64_t>(peer_uid));
330 service->client_info_ = ClientInfo(
331 client->id, peer_uid, client->GetLinuxPeerPid(), client->GetMachineID());
332 service->received_fd_ = &client->received_fd;
333 method.invoker(service, *decoded_req_args, std::move(deferred_reply));
334 service->received_fd_ = nullptr;
335 service->client_info_ = ClientInfo();
336 }
337
OnSetPeerIdentity(ClientConnection * client,const Frame & req_frame)338 void HostImpl::OnSetPeerIdentity(ClientConnection* client,
339 const Frame& req_frame) {
340 if (client->sock->family() == base::SockFamily::kUnix) {
341 PERFETTO_DLOG("SetPeerIdentity is ignored for unix socket connections.");
342 return;
343 }
344
345 // This is can only be set once by the relay service.
346 if (client->pid_override != base::kInvalidPid ||
347 client->uid_override != base::kInvalidUid) {
348 PERFETTO_DLOG("Already received SetPeerIdentity.");
349 return;
350 }
351
352 const auto& set_peer_identity = req_frame.set_peer_identity();
353 client->pid_override = set_peer_identity.pid();
354 client->uid_override = static_cast<uid_t>(set_peer_identity.uid());
355
356 client->machine_id = GenerateMachineID(client->sock.get(),
357 set_peer_identity.machine_id_hint());
358 }
359
ReplyToMethodInvocation(ClientID client_id,RequestID request_id,AsyncResult<ProtoMessage> reply)360 void HostImpl::ReplyToMethodInvocation(ClientID client_id,
361 RequestID request_id,
362 AsyncResult<ProtoMessage> reply) {
363 auto client_iter = clients_.find(client_id);
364 if (client_iter == clients_.end())
365 return; // client has disconnected by the time we got the async reply.
366
367 ClientConnection* client = client_iter->second.get();
368 Frame reply_frame;
369 reply_frame.set_request_id(request_id);
370
371 // TODO(fmayer): add a test to guarantee that the reply is consumed within the
372 // same call stack and not kept around. ConsumerIPCService::OnTraceData()
373 // relies on this behavior.
374 auto* reply_frame_data = reply_frame.mutable_msg_invoke_method_reply();
375 reply_frame_data->set_has_more(reply.has_more());
376 if (reply.success()) {
377 std::string reply_proto = reply->SerializeAsString();
378 reply_frame_data->set_reply_proto(reply_proto);
379 reply_frame_data->set_success(true);
380 }
381 SendFrame(client, reply_frame, reply.fd());
382 }
383
384 // static
SendFrame(ClientConnection * client,const Frame & frame,int fd)385 void HostImpl::SendFrame(ClientConnection* client, const Frame& frame, int fd) {
386 auto peer_uid = client->GetPosixPeerUid();
387 auto scoped_key = g_crash_key_uid.SetScoped(static_cast<int64_t>(peer_uid));
388
389 std::string buf = BufferedFrameDeserializer::Serialize(frame);
390
391 // On Fuchsia, |send_fd_cb_fuchsia_| is used to send the FD to the client
392 // and therefore must be set.
393 PERFETTO_DCHECK(!PERFETTO_BUILDFLAG(PERFETTO_OS_FUCHSIA) ||
394 client->send_fd_cb_fuchsia);
395 if (client->send_fd_cb_fuchsia && fd != base::ScopedFile::kInvalid) {
396 if (!client->send_fd_cb_fuchsia(fd)) {
397 client->sock->Shutdown(true);
398 return;
399 }
400 fd = base::ScopedFile::kInvalid;
401 }
402
403 // When a new Client connects in OnNewClientConnection we set a timeout on
404 // Send (see call to SetTxTimeout).
405 //
406 // The old behaviour was to do a blocking I/O call, which caused crashes from
407 // misbehaving producers (see b/169051440).
408 bool res = client->sock->Send(buf.data(), buf.size(), fd);
409 // If we timeout |res| will be false, but the UnixSocket will have called
410 // UnixSocket::ShutDown() and thus |is_connected()| is false.
411 PERFETTO_CHECK(res || !client->sock->is_connected());
412 }
413
OnDisconnect(base::UnixSocket * sock)414 void HostImpl::OnDisconnect(base::UnixSocket* sock) {
415 PERFETTO_DCHECK_THREAD(thread_checker_);
416 auto it = clients_by_socket_.find(sock);
417 if (it == clients_by_socket_.end())
418 return;
419 auto* client = it->second;
420 ClientID client_id = client->id;
421
422 ClientInfo client_info(client_id, client->GetPosixPeerUid(),
423 client->GetLinuxPeerPid(), client->GetMachineID());
424
425 clients_by_socket_.erase(it);
426 PERFETTO_DCHECK(clients_.count(client_id));
427 clients_.erase(client_id);
428
429 for (const auto& service_it : services_) {
430 Service& service = *service_it.second.instance;
431 service.client_info_ = client_info;
432 service.OnClientDisconnected();
433 service.client_info_ = ClientInfo();
434 }
435 }
436
GetServiceByName(const std::string & name)437 const HostImpl::ExposedService* HostImpl::GetServiceByName(
438 const std::string& name) {
439 // This could be optimized by using another map<name,ServiceID>. However this
440 // is used only by Bind/ExposeService that are quite rare (once per client
441 // connection and once per service instance), not worth it.
442 for (const auto& it : services_) {
443 if (it.second.name == name)
444 return &it.second;
445 }
446 return nullptr;
447 }
448
ExposedService(ServiceID id_,const std::string & name_,std::unique_ptr<Service> instance_)449 HostImpl::ExposedService::ExposedService(ServiceID id_,
450 const std::string& name_,
451 std::unique_ptr<Service> instance_)
452 : id(id_), name(name_), instance(std::move(instance_)) {}
453
454 HostImpl::ExposedService::ExposedService(ExposedService&&) noexcept = default;
455 HostImpl::ExposedService& HostImpl::ExposedService::operator=(
456 HostImpl::ExposedService&&) = default;
457 HostImpl::ExposedService::~ExposedService() = default;
458
459 HostImpl::ClientConnection::~ClientConnection() = default;
460
461 } // namespace ipc
462 } // namespace perfetto
463