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 "guest_signal_action.h"
18 
19 #include <cerrno>
20 #include <csignal>
21 #include <cstring>
22 
23 #include "berberis/base/bit_util.h"
24 #include "berberis/base/checks.h"
25 #include "berberis/base/host_signal.h"
26 #include "berberis/base/scoped_errno.h"
27 #include "berberis/guest_os_primitives/guest_signal.h"
28 #include "berberis/runtime_primitives/host_function_wrapper_impl.h"  // UnwrapHostFunction
29 
30 // glibc doesn't define SA_RESTORER globally.
31 #ifndef SA_RESTORER
32 #define SA_RESTORER 0x04000000
33 #endif
34 
35 namespace berberis {
36 
37 namespace {
38 
DoSigaction(int sig,const HostStructSigaction * sa,HostStructSigaction * old_sa,int * error)39 bool DoSigaction(int sig, const HostStructSigaction* sa, HostStructSigaction* old_sa, int* error) {
40   ScopedErrno scoped_errno;
41   if (HostSigaction(sig, sa, old_sa) == 0) {
42     return true;
43   }
44   *error = errno;
45   return false;
46 }
47 
ConvertHostSigactionToGuest(const HostStructSigaction * host_sa,Guest_sigaction * guest_sa)48 void ConvertHostSigactionToGuest(const HostStructSigaction* host_sa, Guest_sigaction* guest_sa) {
49   guest_sa->guest_sa_sigaction = WrapHostSigactionForGuest(*host_sa);
50 
51   // We don't support SA_RESTORER flag for non-canonical handlers.  See: b/36458045
52   if (bool(host_sa->sa_flags & SA_RESTORER)) {
53     // Recognize canonical (kernel-provided) x86 handlers.
54     // ATTENTION: kernel tolerates the case when SA_RESTORER is set but sa_restorer is null!
55     if (host_sa->sa_restorer) {
56       const char* handler = bit_cast<const char*>(host_sa->sa_restorer);
57 #if defined(__i386__)
58       if ((memcmp(handler, "\x58\xb8\x77\x00\x00\x00\xcd\x80", 8) != 0) &&  // x86 sigreturn
59           (memcmp(handler, "\xb8\xad\x00\x00\x00\xcd\x80", 7) != 0)) {      // x86 rt_sigreturn
60         LOG_ALWAYS_FATAL("Unknown x86 sa_restorer in host sigaction!");
61       }
62 #elif defined(__x86_64__)
63       if (memcmp(handler, "\x48\xc7\xc0\x0f\x00\x00\x00\x0f\x05", 9) != 0) {  // x86_64 sigreturn
64         LOG_ALWAYS_FATAL("Unknown x86_64 sa_restorer in host sigaction!");
65       }
66 #elif defined(__riscv)
67       LOG_ALWAYS_FATAL("Unimplemented for riscv64");
68 #elif defined(__aarch64__)
69       LOG_ALWAYS_FATAL("Unimplemented for arm64");
70 #else
71 #error "Unknown host arch"
72 #endif
73     }
74   }
75 
76   guest_sa->sa_flags = host_sa->sa_flags & ~SA_RESTORER;
77   ResetSigactionRestorer(guest_sa);
78   ConvertToSmallSigset(host_sa->sa_mask, &guest_sa->sa_mask);
79 }
80 
ConvertGuestSigactionToHost(const Guest_sigaction * guest_sa,GuestSignalAction::host_sa_sigaction_t claimed_host_sa_sigaction,HostStructSigaction * host_sa)81 bool ConvertGuestSigactionToHost(const Guest_sigaction* guest_sa,
82                                  GuestSignalAction::host_sa_sigaction_t claimed_host_sa_sigaction,
83                                  HostStructSigaction* host_sa) {
84   bool claim = false;
85   if (guest_sa->sa_flags & SA_SIGINFO) {
86     if (guest_sa->guest_sa_sigaction == 0) {
87       // It can happen that we are requested to set SIG_DFL (= 0) _sigaction_ (not _handler_)!
88       // Don't claim and just keep host responsible for this!
89       host_sa->sa_sigaction = nullptr;
90     } else if (void* func = UnwrapHostFunction(guest_sa->guest_sa_sigaction)) {
91       host_sa->sa_sigaction = reinterpret_cast<GuestSignalAction::host_sa_sigaction_t>(func);
92     } else {
93       host_sa->sa_sigaction = claimed_host_sa_sigaction;
94       claim = true;
95     }
96   } else if (guest_sa->guest_sa_sigaction == Guest_SIG_DFL) {
97     host_sa->sa_handler = SIG_DFL;
98   } else if (guest_sa->guest_sa_sigaction == Guest_SIG_IGN) {
99     host_sa->sa_handler = SIG_IGN;
100   } else if (guest_sa->guest_sa_sigaction == Guest_SIG_ERR) {
101     host_sa->sa_handler = SIG_ERR;
102   } else {
103     void* func = UnwrapHostFunction(guest_sa->guest_sa_sigaction);
104     if (func) {
105       host_sa->sa_handler = reinterpret_cast<void (*)(int)>(func);
106     } else {
107       host_sa->sa_sigaction = claimed_host_sa_sigaction;
108       claim = true;
109     }
110   }
111 
112   // We don't support SA_RESTORER flag for non-canonical handlers.  See: b/36458045
113   if (bool(guest_sa->sa_flags & SA_RESTORER)) {
114     CheckSigactionRestorer(guest_sa);
115   }
116 
117   host_sa->sa_flags = guest_sa->sa_flags & ~SA_RESTORER;
118   host_sa->sa_restorer = nullptr;
119   if (claim) {
120     host_sa->sa_flags |= SA_SIGINFO;
121   }
122 
123   // ATTENTION: it might seem tempting to run claimed_host_sa_sigaction with all signals blocked.
124   // But, guest signal handler should run with current thread signal mask + guest action signal
125   // mask, and might expect certain signals to interrupt. If pending signals are disabled, then
126   // claimed_host_sa_sigaction executes guest signal handler within, so at that point signal mask
127   // should be correct. Unfortunately, if claimed_host_sa_sigaction gets invoked with all signals
128   // blocked, there seems to be no way to restore the correct signal mask before running guest
129   // signal handler.
130   ConvertToBigSigset(guest_sa->sa_mask, &host_sa->sa_mask);
131 
132   return claim;
133 }
134 
135 }  // namespace
136 
Change(int sig,const Guest_sigaction * new_sa,host_sa_sigaction_t claimed_host_sa_sigaction,Guest_sigaction * old_sa,int * error)137 bool GuestSignalAction::Change(int sig,
138                                const Guest_sigaction* new_sa,
139                                host_sa_sigaction_t claimed_host_sa_sigaction,
140                                Guest_sigaction* old_sa,
141                                int* error) {
142   HostStructSigaction host_sa{};
143 
144   Guest_sigaction saved_new_sa{};
145   HostStructSigaction* new_host_sa = nullptr;
146   bool claim = false;
147   if (new_sa) {
148     // ATTENTION: new_sa and old_sa might point to the same object!
149     // Make a copy of new_sa so we can write to old_sa before all reads of new_sa!
150     saved_new_sa = *new_sa;
151     new_sa = &saved_new_sa;
152 
153     new_host_sa = &host_sa;
154     claim = ConvertGuestSigactionToHost(new_sa, claimed_host_sa_sigaction, new_host_sa);
155   }
156 
157   // Even if we only set new action for already claimed signal, we still need to call host
158   // sigaction to update kernel action mask and flags!
159   HostStructSigaction* old_host_sa = &host_sa;
160   if (!DoSigaction(sig, new_host_sa, old_host_sa, error)) {
161     return false;
162   }
163 
164   if (old_sa) {
165     if (IsClaimed()) {
166       *old_sa = GetClaimedGuestAction();
167     } else {
168       ConvertHostSigactionToGuest(old_host_sa, old_sa);
169     }
170   }
171 
172   if (new_sa) {
173     if (claim) {
174       Claim(new_sa);
175     } else {
176       Unclaim();
177     }
178   }
179 
180   return true;
181 }
182 
183 }  // namespace berberis
184