• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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