xref: /aosp_15_r20/external/crosvm/base/src/sys/linux/signal.rs (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
1 // Copyright 2017 The ChromiumOS Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 use std::cmp::Ordering;
6 use std::convert::TryFrom;
7 use std::io;
8 use std::mem;
9 use std::os::unix::thread::JoinHandleExt;
10 use std::ptr::null;
11 use std::ptr::null_mut;
12 use std::result;
13 use std::thread::JoinHandle;
14 use std::time::Duration;
15 
16 use libc::c_int;
17 use libc::pthread_kill;
18 use libc::pthread_sigmask;
19 use libc::pthread_t;
20 use libc::sigaction;
21 use libc::sigaddset;
22 use libc::sigemptyset;
23 use libc::siginfo_t;
24 use libc::sigismember;
25 use libc::sigpending;
26 use libc::sigset_t;
27 use libc::sigtimedwait;
28 use libc::sigwait;
29 use libc::timespec;
30 use libc::EAGAIN;
31 use libc::EINTR;
32 use libc::EINVAL;
33 use libc::SA_RESTART;
34 use libc::SIG_BLOCK;
35 use libc::SIG_DFL;
36 use libc::SIG_UNBLOCK;
37 use remain::sorted;
38 use thiserror::Error;
39 
40 use super::errno_result;
41 use super::Error as ErrnoError;
42 use super::Pid;
43 use super::Result;
44 use crate::handle_eintr_errno;
45 use crate::handle_eintr_rc;
46 use crate::unix::duration_to_timespec;
47 
48 #[sorted]
49 #[derive(Error, Debug)]
50 pub enum Error {
51     /// The signal could not be blocked.
52     #[error("signal could not be blocked: {0}")]
53     BlockSignal(ErrnoError),
54     /// Failed to check if given signal is in the set of pending signals.
55     #[error("failed to check whether given signal is in the pending set: {0}")]
56     ClearCheckPending(ErrnoError),
57     /// Failed to get pending signals.
58     #[error("failed to get pending signals: {0}")]
59     ClearGetPending(ErrnoError),
60     /// Failed to wait for given signal.
61     #[error("failed to wait for given signal: {0}")]
62     ClearWaitPending(ErrnoError),
63     /// Failed to check if the requested signal is in the blocked set already.
64     #[error("failed to check whether requested signal is in the blocked set: {0}")]
65     CompareBlockedSignals(ErrnoError),
66     /// Couldn't create a sigset.
67     #[error("couldn't create a sigset: {0}")]
68     CreateSigset(ErrnoError),
69     /// Failed to get session id.
70     #[error("failed to get session id: {0}")]
71     GetSid(ErrnoError),
72     /// Failed to send signal to pid.
73     #[error("failed to send signal: {0}")]
74     Kill(ErrnoError),
75     /// The signal mask could not be retrieved.
76     #[error("failed to retrieve signal mask: {}", io::Error::from_raw_os_error(*.0))]
77     RetrieveSignalMask(i32),
78     /// Converted signum greater than SIGRTMAX.
79     #[error("got RT signal greater than max: {0:?}")]
80     RtSignumGreaterThanMax(Signal),
81     /// The wrapped signal has already been blocked.
82     #[error("signal {0} already blocked")]
83     SignalAlreadyBlocked(c_int),
84     /// Timeout reached.
85     #[error("timeout reached.")]
86     TimedOut,
87     /// The signal could not be unblocked.
88     #[error("signal could not be unblocked: {0}")]
89     UnblockSignal(ErrnoError),
90     /// Failed to convert signum to Signal.
91     #[error("unrecoginized signal number: {0}")]
92     UnrecognizedSignum(i32),
93     /// Failed to wait for signal.
94     #[error("failed to wait for signal: {0}")]
95     WaitForSignal(ErrnoError),
96     /// Failed to wait for pid.
97     #[error("failed to wait for process: {0}")]
98     WaitPid(ErrnoError),
99 }
100 
101 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
102 #[repr(i32)]
103 pub enum Signal {
104     Abort = libc::SIGABRT,
105     Alarm = libc::SIGALRM,
106     Bus = libc::SIGBUS,
107     Child = libc::SIGCHLD,
108     Continue = libc::SIGCONT,
109     ExceededFileSize = libc::SIGXFSZ,
110     FloatingPointException = libc::SIGFPE,
111     HangUp = libc::SIGHUP,
112     IllegalInstruction = libc::SIGILL,
113     Interrupt = libc::SIGINT,
114     Io = libc::SIGIO,
115     Kill = libc::SIGKILL,
116     Pipe = libc::SIGPIPE,
117     Power = libc::SIGPWR,
118     Profile = libc::SIGPROF,
119     Quit = libc::SIGQUIT,
120     SegmentationViolation = libc::SIGSEGV,
121     StackFault = libc::SIGSTKFLT,
122     Stop = libc::SIGSTOP,
123     Sys = libc::SIGSYS,
124     Trap = libc::SIGTRAP,
125     Terminate = libc::SIGTERM,
126     TtyIn = libc::SIGTTIN,
127     TtyOut = libc::SIGTTOU,
128     TtyStop = libc::SIGTSTP,
129     Urgent = libc::SIGURG,
130     User1 = libc::SIGUSR1,
131     User2 = libc::SIGUSR2,
132     VtAlarm = libc::SIGVTALRM,
133     Winch = libc::SIGWINCH,
134     Xcpu = libc::SIGXCPU,
135     // Rt signal numbers are be adjusted in the conversion to integer.
136     Rt0 = libc::SIGSYS + 1,
137     Rt1,
138     Rt2,
139     Rt3,
140     Rt4,
141     Rt5,
142     Rt6,
143     Rt7,
144     // Only 8 are guaranteed by POSIX, Linux has 32, but only 29 or 30 are usable.
145     Rt8,
146     Rt9,
147     Rt10,
148     Rt11,
149     Rt12,
150     Rt13,
151     Rt14,
152     Rt15,
153     Rt16,
154     Rt17,
155     Rt18,
156     Rt19,
157     Rt20,
158     Rt21,
159     Rt22,
160     Rt23,
161     Rt24,
162     Rt25,
163     Rt26,
164     Rt27,
165     Rt28,
166     Rt29,
167     Rt30,
168     Rt31,
169 }
170 
171 impl From<Signal> for c_int {
from(signal: Signal) -> c_int172     fn from(signal: Signal) -> c_int {
173         let num = signal as libc::c_int;
174         if num >= Signal::Rt0 as libc::c_int {
175             return num - (Signal::Rt0 as libc::c_int) + SIGRTMIN();
176         }
177         num
178     }
179 }
180 
181 impl TryFrom<c_int> for Signal {
182     type Error = Error;
183 
try_from(value: c_int) -> result::Result<Self, Self::Error>184     fn try_from(value: c_int) -> result::Result<Self, Self::Error> {
185         use Signal::*;
186 
187         Ok(match value {
188             libc::SIGABRT => Abort,
189             libc::SIGALRM => Alarm,
190             libc::SIGBUS => Bus,
191             libc::SIGCHLD => Child,
192             libc::SIGCONT => Continue,
193             libc::SIGXFSZ => ExceededFileSize,
194             libc::SIGFPE => FloatingPointException,
195             libc::SIGHUP => HangUp,
196             libc::SIGILL => IllegalInstruction,
197             libc::SIGINT => Interrupt,
198             libc::SIGIO => Io,
199             libc::SIGKILL => Kill,
200             libc::SIGPIPE => Pipe,
201             libc::SIGPWR => Power,
202             libc::SIGPROF => Profile,
203             libc::SIGQUIT => Quit,
204             libc::SIGSEGV => SegmentationViolation,
205             libc::SIGSTKFLT => StackFault,
206             libc::SIGSTOP => Stop,
207             libc::SIGSYS => Sys,
208             libc::SIGTRAP => Trap,
209             libc::SIGTERM => Terminate,
210             libc::SIGTTIN => TtyIn,
211             libc::SIGTTOU => TtyOut,
212             libc::SIGTSTP => TtyStop,
213             libc::SIGURG => Urgent,
214             libc::SIGUSR1 => User1,
215             libc::SIGUSR2 => User2,
216             libc::SIGVTALRM => VtAlarm,
217             libc::SIGWINCH => Winch,
218             libc::SIGXCPU => Xcpu,
219             _ => {
220                 if value < SIGRTMIN() {
221                     return Err(Error::UnrecognizedSignum(value));
222                 }
223                 let signal = match value - SIGRTMIN() {
224                     0 => Rt0,
225                     1 => Rt1,
226                     2 => Rt2,
227                     3 => Rt3,
228                     4 => Rt4,
229                     5 => Rt5,
230                     6 => Rt6,
231                     7 => Rt7,
232                     8 => Rt8,
233                     9 => Rt9,
234                     10 => Rt10,
235                     11 => Rt11,
236                     12 => Rt12,
237                     13 => Rt13,
238                     14 => Rt14,
239                     15 => Rt15,
240                     16 => Rt16,
241                     17 => Rt17,
242                     18 => Rt18,
243                     19 => Rt19,
244                     20 => Rt20,
245                     21 => Rt21,
246                     22 => Rt22,
247                     23 => Rt23,
248                     24 => Rt24,
249                     25 => Rt25,
250                     26 => Rt26,
251                     27 => Rt27,
252                     28 => Rt28,
253                     29 => Rt29,
254                     30 => Rt30,
255                     31 => Rt31,
256                     _ => {
257                         return Err(Error::UnrecognizedSignum(value));
258                     }
259                 };
260                 if value > SIGRTMAX() {
261                     return Err(Error::RtSignumGreaterThanMax(signal));
262                 }
263                 signal
264             }
265         })
266     }
267 }
268 
269 pub type SignalResult<T> = result::Result<T, Error>;
270 
271 #[link(name = "c")]
272 extern "C" {
__libc_current_sigrtmin() -> c_int273     fn __libc_current_sigrtmin() -> c_int;
__libc_current_sigrtmax() -> c_int274     fn __libc_current_sigrtmax() -> c_int;
275 }
276 
277 /// Returns the minimum (inclusive) real-time signal number.
278 #[allow(non_snake_case)]
SIGRTMIN() -> c_int279 pub fn SIGRTMIN() -> c_int {
280     // SAFETY: trivially safe
281     unsafe { __libc_current_sigrtmin() }
282 }
283 
284 /// Returns the maximum (inclusive) real-time signal number.
285 #[allow(non_snake_case)]
SIGRTMAX() -> c_int286 pub fn SIGRTMAX() -> c_int {
287     // SAFETY: trivially safe
288     unsafe { __libc_current_sigrtmax() }
289 }
290 
valid_rt_signal_num(num: c_int) -> bool291 fn valid_rt_signal_num(num: c_int) -> bool {
292     num >= SIGRTMIN() && num <= SIGRTMAX()
293 }
294 
295 /// Registers `handler` as the signal handler of signum `num`.
296 ///
297 /// # Safety
298 ///
299 /// This is considered unsafe because the given handler will be called asynchronously, interrupting
300 /// whatever the thread was doing and therefore must only do async-signal-safe operations.
register_signal_handler(num: c_int, handler: extern "C" fn(c_int)) -> Result<()>301 pub unsafe fn register_signal_handler(num: c_int, handler: extern "C" fn(c_int)) -> Result<()> {
302     let mut sigact: sigaction = mem::zeroed();
303     sigact.sa_flags = SA_RESTART;
304     sigact.sa_sigaction = handler as *const () as usize;
305 
306     let ret = sigaction(num, &sigact, null_mut());
307     if ret < 0 {
308         return errno_result();
309     }
310 
311     Ok(())
312 }
313 
314 /// Resets the signal handler of signum `num` back to the default.
clear_signal_handler(num: c_int) -> Result<()>315 pub fn clear_signal_handler(num: c_int) -> Result<()> {
316     // SAFETY:
317     // Safe because sigaction is owned and expected to be initialized ot zeros.
318     let mut sigact: sigaction = unsafe { mem::zeroed() };
319     sigact.sa_flags = SA_RESTART;
320     sigact.sa_sigaction = SIG_DFL;
321 
322     // SAFETY:
323     // Safe because sigact is owned, and this is restoring the default signal handler.
324     let ret = unsafe { sigaction(num, &sigact, null_mut()) };
325     if ret < 0 {
326         return errno_result();
327     }
328 
329     Ok(())
330 }
331 
332 /// Registers `handler` as the signal handler for the real-time signal with signum `num`.
333 ///
334 /// The value of `num` must be within [`SIGRTMIN`, `SIGRTMAX`] range.
335 ///
336 /// # Safety
337 ///
338 /// This is considered unsafe because the given handler will be called asynchronously, interrupting
339 /// whatever the thread was doing and therefore must only do async-signal-safe operations.
register_rt_signal_handler(num: c_int, handler: extern "C" fn(c_int)) -> Result<()>340 pub unsafe fn register_rt_signal_handler(num: c_int, handler: extern "C" fn(c_int)) -> Result<()> {
341     if !valid_rt_signal_num(num) {
342         return Err(ErrnoError::new(EINVAL));
343     }
344 
345     register_signal_handler(num, handler)
346 }
347 
348 /// Creates `sigset` from an array of signal numbers.
349 ///
350 /// This is a helper function used when we want to manipulate signals.
create_sigset(signals: &[c_int]) -> Result<sigset_t>351 pub fn create_sigset(signals: &[c_int]) -> Result<sigset_t> {
352     // SAFETY:
353     // sigset will actually be initialized by sigemptyset below.
354     let mut sigset: sigset_t = unsafe { mem::zeroed() };
355 
356     // SAFETY:
357     // Safe - return value is checked.
358     let ret = unsafe { sigemptyset(&mut sigset) };
359     if ret < 0 {
360         return errno_result();
361     }
362 
363     for signal in signals {
364         // SAFETY:
365         // Safe - return value is checked.
366         let ret = unsafe { sigaddset(&mut sigset, *signal) };
367         if ret < 0 {
368             return errno_result();
369         }
370     }
371 
372     Ok(sigset)
373 }
374 
375 /// Wait for signal before continuing. The signal number of the consumed signal is returned on
376 /// success. EAGAIN means the timeout was reached.
wait_for_signal(signals: &[c_int], timeout: Option<Duration>) -> Result<c_int>377 pub fn wait_for_signal(signals: &[c_int], timeout: Option<Duration>) -> Result<c_int> {
378     let sigset = create_sigset(signals)?;
379 
380     match timeout {
381         Some(timeout) => {
382             let ts = duration_to_timespec(timeout);
383             // SAFETY:
384             // Safe - return value is checked.
385             let ret = handle_eintr_errno!(unsafe { sigtimedwait(&sigset, null_mut(), &ts) });
386             if ret < 0 {
387                 errno_result()
388             } else {
389                 Ok(ret)
390             }
391         }
392         None => {
393             let mut ret: c_int = 0;
394             // SAFETY: Safe because args are valid and the return value is checked.
395             let err = handle_eintr_rc!(unsafe { sigwait(&sigset, &mut ret as *mut c_int) });
396             if err != 0 {
397                 Err(ErrnoError::new(err))
398             } else {
399                 Ok(ret)
400             }
401         }
402     }
403 }
404 
405 /// Retrieves the signal mask of the current thread as a vector of c_ints.
get_blocked_signals() -> SignalResult<Vec<c_int>>406 pub fn get_blocked_signals() -> SignalResult<Vec<c_int>> {
407     let mut mask = Vec::new();
408 
409     // SAFETY:
410     // Safe - return values are checked.
411     unsafe {
412         let mut old_sigset: sigset_t = mem::zeroed();
413         let ret = pthread_sigmask(SIG_BLOCK, null(), &mut old_sigset as *mut sigset_t);
414         if ret < 0 {
415             return Err(Error::RetrieveSignalMask(ret));
416         }
417 
418         for num in 0..=SIGRTMAX() {
419             if sigismember(&old_sigset, num) > 0 {
420                 mask.push(num);
421             }
422         }
423     }
424 
425     Ok(mask)
426 }
427 
428 /// Masks given signal.
429 ///
430 /// If signal is already blocked the call will fail with Error::SignalAlreadyBlocked
431 /// result.
block_signal(num: c_int) -> SignalResult<()>432 pub fn block_signal(num: c_int) -> SignalResult<()> {
433     let sigset = create_sigset(&[num]).map_err(Error::CreateSigset)?;
434 
435     // SAFETY:
436     // Safe - return values are checked.
437     unsafe {
438         let mut old_sigset: sigset_t = mem::zeroed();
439         let ret = pthread_sigmask(SIG_BLOCK, &sigset, &mut old_sigset as *mut sigset_t);
440         if ret < 0 {
441             return Err(Error::BlockSignal(ErrnoError::last()));
442         }
443         let ret = sigismember(&old_sigset, num);
444         match ret.cmp(&0) {
445             Ordering::Less => {
446                 return Err(Error::CompareBlockedSignals(ErrnoError::last()));
447             }
448             Ordering::Greater => {
449                 return Err(Error::SignalAlreadyBlocked(num));
450             }
451             _ => (),
452         };
453     }
454     Ok(())
455 }
456 
457 /// Unmasks given signal.
unblock_signal(num: c_int) -> SignalResult<()>458 pub fn unblock_signal(num: c_int) -> SignalResult<()> {
459     let sigset = create_sigset(&[num]).map_err(Error::CreateSigset)?;
460 
461     // SAFETY:
462     // Safe - return value is checked.
463     let ret = unsafe { pthread_sigmask(SIG_UNBLOCK, &sigset, null_mut()) };
464     if ret < 0 {
465         return Err(Error::UnblockSignal(ErrnoError::last()));
466     }
467     Ok(())
468 }
469 
470 /// Clears pending signal.
clear_signal(num: c_int) -> SignalResult<()>471 pub fn clear_signal(num: c_int) -> SignalResult<()> {
472     let sigset = create_sigset(&[num]).map_err(Error::CreateSigset)?;
473 
474     while {
475         // SAFETY:
476         // This is safe as we are rigorously checking return values
477         // of libc calls.
478         unsafe {
479             let mut siginfo: siginfo_t = mem::zeroed();
480             let ts = timespec {
481                 tv_sec: 0,
482                 tv_nsec: 0,
483             };
484             // Attempt to consume one instance of pending signal. If signal
485             // is not pending, the call will fail with EAGAIN or EINTR.
486             let ret = sigtimedwait(&sigset, &mut siginfo, &ts);
487             if ret < 0 {
488                 let e = ErrnoError::last();
489                 match e.errno() {
490                     EAGAIN | EINTR => {}
491                     _ => {
492                         return Err(Error::ClearWaitPending(ErrnoError::last()));
493                     }
494                 }
495             }
496 
497             // This sigset will be actually filled with `sigpending` call.
498             let mut chkset: sigset_t = mem::zeroed();
499             // See if more instances of the signal are pending.
500             let ret = sigpending(&mut chkset);
501             if ret < 0 {
502                 return Err(Error::ClearGetPending(ErrnoError::last()));
503             }
504 
505             let ret = sigismember(&chkset, num);
506             if ret < 0 {
507                 return Err(Error::ClearCheckPending(ErrnoError::last()));
508             }
509 
510             // This is do-while loop condition.
511             ret != 0
512         }
513     } {}
514 
515     Ok(())
516 }
517 
518 /// # Safety
519 /// This is marked unsafe because it allows signals to be sent to arbitrary PIDs. Sending some
520 /// signals may lead to undefined behavior. Also, the return codes of the child processes need to be
521 /// reaped to avoid leaking zombie processes.
kill(pid: Pid, signum: c_int) -> Result<()>522 pub unsafe fn kill(pid: Pid, signum: c_int) -> Result<()> {
523     let ret = libc::kill(pid, signum);
524 
525     if ret != 0 {
526         errno_result()
527     } else {
528         Ok(())
529     }
530 }
531 
532 /// Trait for threads that can be signalled via `pthread_kill`.
533 ///
534 /// Note that this is only useful for signals between SIGRTMIN and SIGRTMAX because these are
535 /// guaranteed to not be used by the C runtime.
536 ///
537 /// # Safety
538 /// This is marked unsafe because the implementation of this trait must guarantee that the returned
539 /// pthread_t is valid and has a lifetime at least that of the trait object.
540 pub unsafe trait Killable {
pthread_handle(&self) -> pthread_t541     fn pthread_handle(&self) -> pthread_t;
542 
543     /// Sends the signal `num` to this killable thread.
544     ///
545     /// The value of `num` must be within [`SIGRTMIN`, `SIGRTMAX`] range.
kill(&self, num: c_int) -> Result<()>546     fn kill(&self, num: c_int) -> Result<()> {
547         if !valid_rt_signal_num(num) {
548             return Err(ErrnoError::new(EINVAL));
549         }
550 
551         // SAFETY:
552         // Safe because we ensure we are using a valid pthread handle, a valid signal number, and
553         // check the return result.
554         let ret = unsafe { pthread_kill(self.pthread_handle(), num) };
555         if ret < 0 {
556             return errno_result();
557         }
558         Ok(())
559     }
560 }
561 
562 // SAFETY:
563 // Safe because we fulfill our contract of returning a genuine pthread handle.
564 unsafe impl<T> Killable for JoinHandle<T> {
pthread_handle(&self) -> pthread_t565     fn pthread_handle(&self) -> pthread_t {
566         self.as_pthread_t() as _
567     }
568 }
569 
570 // Represents a temporarily blocked signal. It will unblock the signal when dropped.
571 pub struct BlockedSignal {
572     signal_num: c_int,
573 }
574 
575 impl BlockedSignal {
576     // Returns a `BlockedSignal` if the specified signal can be blocked, otherwise None.
new(signal_num: c_int) -> Option<BlockedSignal>577     pub fn new(signal_num: c_int) -> Option<BlockedSignal> {
578         if block_signal(signal_num).is_ok() {
579             Some(BlockedSignal { signal_num })
580         } else {
581             None
582         }
583     }
584 }
585 
586 impl Drop for BlockedSignal {
drop(&mut self)587     fn drop(&mut self) {
588         unblock_signal(self.signal_num).expect("failed to restore signal mask");
589     }
590 }
591