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 // Generic implementation that relies on guest arch-specific headers. This file must be compiled
18 // separately for each guest architecture.
19 
20 #include "berberis/guest_os_primitives/guest_signal.h"
21 
22 #include "berberis/base/host_signal.h"
23 #include "berberis/base/tracing.h"
24 #include "berberis/guest_abi/guest_call.h"
25 #include "berberis/guest_os_primitives/guest_signal_arch.h"
26 #include "berberis/guest_os_primitives/guest_thread.h"
27 
28 #include "guest_context_arch.h"
29 #include "scoped_signal_blocker.h"
30 
31 namespace berberis {
32 
ProcessGuestSignal(GuestThread * thread,const Guest_sigaction * sa,Guest_siginfo_t * info)33 void ProcessGuestSignal(GuestThread* thread, const Guest_sigaction* sa, Guest_siginfo_t* info) {
34   // ATTENTION: action mask is ADDED to currently blocked signals!
35   // Should be no-op if invoked from HandleHostSignal, as it must run under guest action mask!
36   HostSigset block_mask;
37   ConvertToBigSigset(sa->sa_mask, &block_mask);
38   if ((sa->sa_flags & SA_NODEFER) == 0u) {
39     HostSigaddset(&block_mask, info->si_signo);
40   }
41   ScopedSignalBlocker signal_blocker(&block_mask);
42 
43   // Save state to ucontext.
44   ThreadState* state = thread->state();
45   GuestContext ctx;
46   ctx.Save(&state->cpu);
47 
48   // Switch to alternate stack.
49   if (sa->sa_flags & SA_ONSTACK) {
50     thread->SwitchToSigAltStack();
51   }
52 
53   TRACE("delivering signal %d at %p", info->si_signo, ToHostAddr<void>(sa->guest_sa_sigaction));
54   // We get here only if guest set a custom signal action, default actions are handled by host.
55   CHECK_NE(sa->guest_sa_sigaction, Guest_SIG_DFL);
56   CHECK_NE(sa->guest_sa_sigaction, Guest_SIG_IGN);
57   CHECK_NE(sa->guest_sa_sigaction, Guest_SIG_ERR);
58   // Run guest signal handler. Assume this is
59   //   void (*sa_sigaction)(int, siginfo_t*, void*);
60   // If this is actually
61   //   void (*sa_handler)(int);
62   // then extra args will be just ignored.
63   GuestCall guest_call;
64   guest_call.AddArgInt32(info->si_signo);
65   guest_call.AddArgGuestAddr(ToGuestAddr(info));
66   guest_call.AddArgGuestAddr(ToGuestAddr(ctx.ptr()));
67   guest_call.RunVoid(sa->guest_sa_sigaction);
68   TRACE("signal %d delivered", info->si_signo);
69 
70   // Restore state from ucontext, it may be updated by the handler.
71   ctx.Restore(&state->cpu);
72 }
73 
74 }  // namespace berberis
75