1 /*
2  * Copyright (C) 2020 The Android Open Source Project
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *  * Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  *  * Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in
12  *    the documentation and/or other materials provided with the
13  *    distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
18  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
19  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
22  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
25  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28 
29 #if defined(LIBC_STATIC)
30 #error This file should not be compiled for static targets.
31 #endif
32 
33 #include <fcntl.h>
34 #include <signal.h>
35 #include <string.h>
36 #include <sys/socket.h>
37 #include <sys/stat.h>
38 #include <sys/types.h>
39 #include <sys/ucontext.h>
40 #include <sys/un.h>
41 
42 #include <async_safe/log.h>
43 #include <platform/bionic/malloc.h>
44 #include <platform/bionic/reserved_signals.h>
45 #include <private/ErrnoRestorer.h>
46 #include <private/ScopedFd.h>
47 
48 #include "malloc_heapprofd.h"
49 
50 // This file defines the handler for the reserved signal sent by the Android
51 // platform's profilers. The accompanying signal value discriminates between
52 // specific requestors:
53 //  0: heapprofd heap profiler.
54 //  1: traced_perf perf profiler.
55 static constexpr int kHeapprofdSignalValue = 0;
56 static constexpr int kTracedPerfSignalValue = 1;
57 
58 static void HandleProfilingSignal(int, siginfo_t*, void*);
59 
60 // Called during dynamic libc preinit.
__libc_init_profiling_handlers()61 __LIBC_HIDDEN__ void __libc_init_profiling_handlers() {
62   struct sigaction action = {};
63   action.sa_flags = SA_SIGINFO | SA_RESTART;
64   action.sa_sigaction = HandleProfilingSignal;
65   sigaction(BIONIC_SIGNAL_PROFILER, &action, nullptr);
66 
67   // The perfetto_hprof ART plugin installs a signal handler to handle this signal. That plugin
68   // does not get loaded for a) non-apps, b) non-profilable apps on user. The default signal
69   // disposition is to crash. We do not want the target to crash if we accidentally target a
70   // non-app or non-profilable process.
71   //
72   // This does *not* get run for processes that statically link libc, and those will still crash.
73   signal(BIONIC_SIGNAL_ART_PROFILER, SIG_IGN);
74 }
75 
76 static void HandleSigsysSeccompOverride(int, siginfo_t*, void*);
77 static void HandleTracedPerfSignal();
78 
HandleProfilingSignal(int,siginfo_t * info,void *)79 static void HandleProfilingSignal(int /*signal_number*/, siginfo_t* info, void* /*ucontext*/) {
80   ErrnoRestorer errno_restorer;
81 
82   if (info->si_code != SI_QUEUE) {
83     return;
84   }
85 
86   int signal_value = info->si_value.sival_int;
87   async_safe_format_log(ANDROID_LOG_INFO, "libc", "%s: received profiling signal with si_value: %d",
88                         getprogname(), signal_value);
89 
90   // Proceed only if the process is considered profileable.
91   bool profileable = false;
92   android_mallopt(M_GET_PROCESS_PROFILEABLE, &profileable, sizeof(profileable));
93   if (!profileable) {
94     async_safe_write_log(ANDROID_LOG_ERROR, "libc", "profiling signal rejected (not profileable)");
95     return;
96   }
97 
98   // Temporarily override SIGSYS handling, in a best-effort attempt at not
99   // crashing if we happen to be running in a process with a seccomp filter that
100   // disallows some of the syscalls done by this signal handler. This protects
101   // against SECCOMP_RET_TRAP with a crashing SIGSYS handler (typical of android
102   // minijails). Won't help if the filter is using SECCOMP_RET_KILL_*.
103   // Note: the override is process-wide, but short-lived. The syscalls are still
104   // blocked, but the overridden handler recovers from SIGSYS, and fakes the
105   // syscall return value as ENOSYS.
106   struct sigaction sigsys_override = {};
107   sigsys_override.sa_sigaction = &HandleSigsysSeccompOverride;
108   sigsys_override.sa_flags = SA_SIGINFO;
109 
110   struct sigaction old_act = {};
111   sigaction(SIGSYS, &sigsys_override, &old_act);
112 
113   if (signal_value == kHeapprofdSignalValue) {
114     HandleHeapprofdSignal();
115   } else if (signal_value == kTracedPerfSignalValue) {
116     HandleTracedPerfSignal();
117   } else {
118     async_safe_format_log(ANDROID_LOG_ERROR, "libc", "unrecognized profiling signal si_value: %d",
119                           signal_value);
120   }
121   sigaction(SIGSYS, &old_act, nullptr);
122 }
123 
124 // Open /proc/self/{maps,mem}, connect to traced_perf, send the fds over the
125 // socket. Everything happens synchronously within the signal handler. Socket
126 // is made non-blocking, and we do not retry.
HandleTracedPerfSignal()127 static void HandleTracedPerfSignal() {
128   ScopedFd sock_fd{ socket(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0 /*protocol*/) };
129   if (sock_fd.get() == -1) {
130     async_safe_format_log(ANDROID_LOG_ERROR, "libc", "failed to create socket: %s", strerror(errno));
131     return;
132   }
133 
134   sockaddr_un saddr{ AF_UNIX, "/dev/socket/traced_perf" };
135   size_t addrlen = sizeof(sockaddr_un);
136   if (connect(sock_fd.get(), reinterpret_cast<const struct sockaddr*>(&saddr), addrlen) == -1) {
137     async_safe_format_log(ANDROID_LOG_ERROR, "libc", "failed to connect to traced_perf socket: %s",
138                           strerror(errno));
139     return;
140   }
141 
142   ScopedFd maps_fd{ open("/proc/self/maps", O_RDONLY | O_CLOEXEC) };
143   if (maps_fd.get() == -1) {
144     async_safe_format_log(ANDROID_LOG_ERROR, "libc", "failed to open /proc/self/maps: %s",
145                           strerror(errno));
146     return;
147   }
148   ScopedFd mem_fd{ open("/proc/self/mem", O_RDONLY | O_CLOEXEC) };
149   if (mem_fd.get() == -1) {
150     async_safe_format_log(ANDROID_LOG_ERROR, "libc", "failed to open /proc/self/mem: %s",
151                           strerror(errno));
152     return;
153   }
154 
155   // Send 1 byte with auxiliary data carrying two fds.
156   int send_fds[2] = { maps_fd.get(), mem_fd.get() };
157   int num_fds = 2;
158   char iobuf[1] = {};
159   msghdr msg_hdr = {};
160   iovec iov = { reinterpret_cast<void*>(iobuf), sizeof(iobuf) };
161   msg_hdr.msg_iov = &iov;
162   msg_hdr.msg_iovlen = 1;
163   alignas(cmsghdr) char control_buf[256] = {};
164   const auto raw_ctl_data_sz = num_fds * sizeof(int);
165   const size_t control_buf_len = static_cast<size_t>(CMSG_SPACE(raw_ctl_data_sz));
166   msg_hdr.msg_control = control_buf;
167   msg_hdr.msg_controllen = control_buf_len;  // used by CMSG_FIRSTHDR
168   struct cmsghdr* cmsg = CMSG_FIRSTHDR(&msg_hdr);
169   cmsg->cmsg_level = SOL_SOCKET;
170   cmsg->cmsg_type = SCM_RIGHTS;
171   cmsg->cmsg_len = static_cast<size_t>(CMSG_LEN(raw_ctl_data_sz));
172   memcpy(CMSG_DATA(cmsg), send_fds, num_fds * sizeof(int));
173 
174   if (sendmsg(sock_fd.get(), &msg_hdr, 0) == -1) {
175     async_safe_format_log(ANDROID_LOG_ERROR, "libc", "failed to sendmsg: %s", strerror(errno));
176   }
177 }
178 
HandleSigsysSeccompOverride(int,siginfo_t * info,void * void_context)179 static void HandleSigsysSeccompOverride(int /*signal_number*/, siginfo_t* info,
180                                         void* void_context) {
181   ErrnoRestorer errno_restorer;
182   if (info->si_code != SYS_SECCOMP) {
183     return;
184   }
185 
186   async_safe_format_log(
187       ANDROID_LOG_WARN, "libc",
188       "Profiling setup: trapped seccomp SIGSYS for syscall %d. Returning ENOSYS to caller.",
189       info->si_syscall);
190 
191   // The handler is responsible for setting the return value as if the system
192   // call happened (which is arch-specific). Use a plausible unsuccessful value.
193   auto ret = -ENOSYS;
194   ucontext_t* ctx = reinterpret_cast<ucontext_t*>(void_context);
195 
196 #if defined(__arm__)
197   ctx->uc_mcontext.arm_r0 = ret;
198 #elif defined(__aarch64__)
199   ctx->uc_mcontext.regs[0] = ret;  // x0
200 #elif defined(__i386__)
201   ctx->uc_mcontext.gregs[REG_EAX] = ret;
202 #elif defined(__x86_64__)
203   ctx->uc_mcontext.gregs[REG_RAX] = ret;
204 #else
205 #error "unsupported architecture"
206 #endif
207 }
208