1 /*
2 * Copyright (C) 2023 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 <atomic>
18 #include <csignal>
19 #include <memory>
20 #include <mutex>
21
22 #if defined(__BIONIC__)
23 #include <platform/bionic/reserved_signals.h>
24 #endif
25
26 #include "berberis/base/checks.h"
27 #include "berberis/base/config_globals.h"
28 #include "berberis/base/tracing.h"
29 #include "berberis/guest_os_primitives/guest_signal.h"
30 #include "berberis/guest_os_primitives/guest_thread.h"
31 #include "berberis/guest_os_primitives/guest_thread_manager.h"
32 #include "berberis/guest_os_primitives/syscall_numbers.h"
33 #include "berberis/guest_state/guest_state_opaque.h"
34 #include "berberis/runtime_primitives/recovery_code.h"
35
36 #include "guest_signal_action.h"
37 #include "guest_thread_manager_impl.h" // AttachCurrentThread, DetachCurrentThread
38 #include "scoped_signal_blocker.h"
39
40 // Glibc didn't define this macro for i386 and x86_64 at the moment of adding
41 // its use below. This condition still stands though.
42 #ifndef SI_FROMKERNEL
43 #define SI_FROMKERNEL(siptr) ((siptr)->si_code > 0)
44 #endif
45
46 namespace berberis {
47
48 namespace {
49
50 // Execution cannot proceed until the next pending signals check for _kernel_ sent
51 // synchronious signals: the faulty instruction will be executed again, leading
52 // to the infinite recursion. So crash immediately to simplify debugging.
53 //
54 // Note that a _user_ sent signal which is typically synchronious, such as SIGSEGV,
55 // can continue until pending signals check.
IsPendingSignalWithoutRecoveryCodeFatal(siginfo_t * info)56 bool IsPendingSignalWithoutRecoveryCodeFatal(siginfo_t* info) {
57 switch (info->si_signo) {
58 case SIGSEGV:
59 case SIGBUS:
60 case SIGILL:
61 case SIGFPE:
62 return SI_FROMKERNEL(info);
63 default:
64 return false;
65 }
66 }
67
68 GuestSignalActionsTable g_signal_actions;
69 // Technically guest threads may work with different signal action tables, so it's possible to
70 // optimize by using different mutexes. But it's rather an exotic corner case, so we keep it simple.
71 std::mutex g_signal_actions_guard_mutex;
72
FindSignalHandler(const GuestSignalActionsTable & signal_actions,int signal)73 const Guest_sigaction* FindSignalHandler(const GuestSignalActionsTable& signal_actions,
74 int signal) {
75 CHECK_GT(signal, 0);
76 CHECK_LE(signal, Guest__KERNEL__NSIG);
77 std::lock_guard<std::mutex> lock(g_signal_actions_guard_mutex);
78 return &signal_actions.at(signal - 1).GetClaimedGuestAction();
79 }
80
81 // Can be interrupted by another HandleHostSignal!
HandleHostSignal(int sig,siginfo_t * info,void * context)82 void HandleHostSignal(int sig, siginfo_t* info, void* context) {
83 TRACE("handle host signal %d", sig);
84
85 bool attached;
86 GuestThread* thread = AttachCurrentThread(false, &attached);
87
88 // If pending signals are enabled, just add this signal to currently pending.
89 // If pending signals are disabled, run handlers for currently pending signals
90 // and for this signal now. While running the handlers, enable nested signals
91 // to be pending.
92 bool prev_pending_signals_enabled = thread->TestAndEnablePendingSignals();
93 thread->SetSignalFromHost(*info);
94 if (!prev_pending_signals_enabled) {
95 CHECK_EQ(GetResidence(*thread->state()), kOutsideGeneratedCode);
96 thread->ProcessAndDisablePendingSignals();
97 if (attached) {
98 DetachCurrentThread();
99 }
100 } else {
101 // We can't make signals pendings as we need to detach the thread!
102 CHECK(!attached);
103
104 #if defined(__i386__)
105 constexpr size_t kHostRegIP = REG_EIP;
106 #elif defined(__x86_64__)
107 constexpr size_t kHostRegIP = REG_RIP;
108 #else
109 #error "Unknown host arch"
110 #endif
111
112 // Run recovery code to restore precise context and exit generated code.
113 ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(context);
114 uintptr_t addr = ucontext->uc_mcontext.gregs[kHostRegIP];
115 uintptr_t recovery_addr = FindRecoveryCode(addr, thread->state());
116
117 if (recovery_addr) {
118 if (!IsConfigFlagSet(kAccurateSigsegv)) {
119 // We often get asynchronious signals at instructions with recovery code.
120 // This is okay when the recovery is accurate, but highly fragile with inaccurate recovery.
121 if (!IsPendingSignalWithoutRecoveryCodeFatal(info)) {
122 TRACE("Skipping imprecise context recovery for non-fatal signal");
123 TRACE("Guest signal handler suspended, continue");
124 return;
125 }
126 TRACE(
127 "Imprecise context at recovery, only guest pc is in sync."
128 " Other registers may be stale.");
129 }
130 ucontext->uc_mcontext.gregs[kHostRegIP] = recovery_addr;
131 TRACE("guest signal handler suspended, run recovery for host pc %p at host pc %p",
132 reinterpret_cast<void*>(addr),
133 reinterpret_cast<void*>(recovery_addr));
134 } else {
135 // Failed to find recovery code.
136 // Translated code should be arranged to continue till
137 // the next pending signals check unless it's fatal.
138 if (IsPendingSignalWithoutRecoveryCodeFatal(info)) {
139 LOG_ALWAYS_FATAL("Cannot process signal %d", sig);
140 }
141 TRACE("guest signal handler suspended, continue");
142 }
143 }
144 }
145
IsReservedSignal(int signal)146 bool IsReservedSignal(int signal) {
147 switch (signal) {
148 // Disallow guest action for SIGABRT to simplify debugging (b/32167022).
149 case SIGABRT:
150 #if defined(__BIONIC__)
151 // Disallow overwriting the host profiler handler from guest code. Otherwise
152 // guest __libc_init_profiling_handlers() would install its own handler, which
153 // is not yet supported for guest code (at least need a proxy for
154 // heapprofd_client.so) and fundamentally cannot be supported for host code.
155 // TODO(b/167966989): Instead intercept __libc_init_profiling_handlers.
156 case BIONIC_SIGNAL_PROFILER:
157 #endif
158 return true;
159 }
160 return false;
161 }
162
163 } // namespace
164
SetDefaultSignalActionsTable()165 void GuestThread::SetDefaultSignalActionsTable() {
166 // We need to initialize shared_ptr, but we don't want to attempt to delete the default
167 // signal actions when guest thread terminates. Hence we specify a void deleter.
168 signal_actions_ = std::shared_ptr<GuestSignalActionsTable>(&g_signal_actions, [](auto) {});
169 }
170
CloneSignalActionsTableFrom(GuestSignalActionsTable * from_table)171 void GuestThread::CloneSignalActionsTableFrom(GuestSignalActionsTable* from_table) {
172 // Need lock to make sure from_table isn't changed concurrently.
173 std::lock_guard<std::mutex> lock(g_signal_actions_guard_mutex);
174 signal_actions_ = std::make_shared<GuestSignalActionsTable>(*from_table);
175 }
176
177 // Can be interrupted by another SetSignal!
SetSignalFromHost(const siginfo_t & host_info)178 void GuestThread::SetSignalFromHost(const siginfo_t& host_info) {
179 siginfo_t* guest_info = pending_signals_.AllocSignal();
180
181 // Convert host siginfo to guest.
182 *guest_info = host_info;
183 switch (host_info.si_signo) {
184 case SIGILL:
185 case SIGFPE: {
186 guest_info->si_addr = ToHostAddr<void>(GetInsnAddr(GetCPUState(*state_)));
187 break;
188 }
189 case SIGSYS: {
190 guest_info->si_syscall = ToGuestSyscallNumber(host_info.si_syscall);
191 break;
192 }
193 }
194
195 // This is never interrupted by code that clears queue or status,
196 // so the order in which to set them is not important.
197 pending_signals_.EnqueueSignal(guest_info);
198 // Check that pending signals are not disabled and mark them as present.
199 uint8_t old_status = GetPendingSignalsStatusAtomic(*state_).exchange(kPendingSignalsPresent,
200 std::memory_order_relaxed);
201 CHECK_NE(kPendingSignalsDisabled, old_status);
202 }
203
SigAltStack(const stack_t * ss,stack_t * old_ss,int * error)204 bool GuestThread::SigAltStack(const stack_t* ss, stack_t* old_ss, int* error) {
205 // The following code is not reentrant!
206 ScopedSignalBlocker signal_blocker;
207
208 if (old_ss) {
209 if (sig_alt_stack_) {
210 old_ss->ss_sp = sig_alt_stack_;
211 old_ss->ss_size = sig_alt_stack_size_;
212 old_ss->ss_flags = IsOnSigAltStack() ? SS_ONSTACK : 0;
213 } else {
214 old_ss->ss_sp = nullptr;
215 old_ss->ss_size = 0;
216 old_ss->ss_flags = SS_DISABLE;
217 }
218 }
219 if (ss) {
220 if (sig_alt_stack_ && IsOnSigAltStack()) {
221 *error = EPERM;
222 return false;
223 }
224 if (ss->ss_flags == SS_DISABLE) {
225 sig_alt_stack_ = nullptr;
226 sig_alt_stack_size_ = 0;
227 return true;
228 }
229 if (ss->ss_flags != 0) {
230 *error = EINVAL;
231 return false;
232 }
233 if (ss->ss_size < GetGuest_MINSIGSTKSZ()) {
234 *error = ENOMEM;
235 return false;
236 }
237 sig_alt_stack_ = ss->ss_sp;
238 sig_alt_stack_size_ = ss->ss_size;
239 }
240 return true;
241 }
242
SwitchToSigAltStack()243 void GuestThread::SwitchToSigAltStack() {
244 if (sig_alt_stack_ && !IsOnSigAltStack()) {
245 // TODO(b/289563835): Try removing `- 16` while ensuring app compatibility.
246 // Reliable context on why we use `- 16` here seems to be lost.
247 SetStackRegister(GetCPUState(*state_), ToGuestAddr(sig_alt_stack_) + sig_alt_stack_size_ - 16);
248 }
249 }
250
IsOnSigAltStack() const251 bool GuestThread::IsOnSigAltStack() const {
252 CHECK_NE(sig_alt_stack_, nullptr);
253 const char* ss_start = static_cast<const char*>(sig_alt_stack_);
254 const char* ss_curr = ToHostAddr<const char>(GetStackRegister(GetCPUState(*state_)));
255 return ss_curr >= ss_start && ss_curr < ss_start + sig_alt_stack_size_;
256 }
257
ProcessPendingSignals()258 void GuestThread::ProcessPendingSignals() {
259 for (;;) {
260 // Process pending signals while present.
261 uint8_t status = GetPendingSignalsStatusAtomic(*state_).load(std::memory_order_acquire);
262 CHECK_NE(kPendingSignalsDisabled, status);
263 if (status == kPendingSignalsEnabled) {
264 return;
265 }
266 ProcessPendingSignalsImpl();
267 }
268 }
269
ProcessAndDisablePendingSignals()270 bool GuestThread::ProcessAndDisablePendingSignals() {
271 for (;;) {
272 // If pending signals are not present, cas should disable them.
273 // Otherwise, process pending signals and try again.
274 uint8_t old_status = kPendingSignalsEnabled;
275 if (GetPendingSignalsStatusAtomic(*state_).compare_exchange_weak(
276 old_status, kPendingSignalsDisabled, std::memory_order_acq_rel)) {
277 return true;
278 }
279 if (old_status == kPendingSignalsDisabled) {
280 return false;
281 }
282 ProcessPendingSignalsImpl();
283 }
284 }
285
TestAndEnablePendingSignals()286 bool GuestThread::TestAndEnablePendingSignals() {
287 // If pending signals are disabled, cas should mark them enabled.
288 // Otherwise, pending signals are already enabled.
289 uint8_t old_status = kPendingSignalsDisabled;
290 return !GetPendingSignalsStatusAtomic(*state_).compare_exchange_strong(
291 old_status, kPendingSignalsEnabled, std::memory_order_acq_rel);
292 }
293
294 // Return if another iteration is needed.
295 // ATTENTION: Can be interrupted by SetSignal!
ProcessPendingSignalsImpl()296 void GuestThread::ProcessPendingSignalsImpl() {
297 // Clear pending signals status and queue.
298 // ATTENTION: It is important to change status before the queue!
299 // Otherwise if interrupted by SetSignal, we might end up with
300 // no pending signals status but with non-empty queue!
301 GetPendingSignalsStatusAtomic(*state_).store(kPendingSignalsEnabled, std::memory_order_relaxed);
302
303 siginfo_t* signal_info;
304 while ((signal_info = pending_signals_.DequeueSignalUnsafe())) {
305 const Guest_sigaction* sa = FindSignalHandler(*signal_actions_.get(), signal_info->si_signo);
306 ProcessGuestSignal(this, sa, signal_info);
307 pending_signals_.FreeSignal(signal_info);
308 }
309 }
310
SetGuestSignalHandler(int signal,const Guest_sigaction * act,Guest_sigaction * old_act,int * error)311 bool SetGuestSignalHandler(int signal,
312 const Guest_sigaction* act,
313 Guest_sigaction* old_act,
314 int* error) {
315 if (signal < 1 || signal > Guest__KERNEL__NSIG) {
316 *error = EINVAL;
317 return false;
318 }
319
320 if (act && IsReservedSignal(signal)) {
321 TRACE("sigaction for reserved signal %d not set", signal);
322 act = nullptr;
323 }
324
325 std::lock_guard<std::mutex> lock(g_signal_actions_guard_mutex);
326 GuestSignalAction& action = GetCurrentGuestThread()->GetSignalActionsTable()->at(signal - 1);
327 return action.Change(signal, act, HandleHostSignal, old_act, error);
328 }
329
330 } // namespace berberis
331