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