1 // Copyright 2019 Intel Corporation. All Rights Reserved.
2 //
3 // Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
4 //
5 // Copyright 2017 The Chromium OS Authors. All rights reserved.
6 //
7 // SPDX-License-Identifier: BSD-3-Clause
8 
9 //! Enums, traits and functions for working with
10 //! [`signal`](http://man7.org/linux/man-pages/man7/signal.7.html).
11 
12 use libc::{
13     c_int, c_void, pthread_kill, pthread_sigmask, pthread_t, sigaction, sigaddset, sigemptyset,
14     sigfillset, siginfo_t, sigismember, sigpending, sigset_t, sigtimedwait, timespec, EAGAIN,
15     EINTR, EINVAL, SIG_BLOCK, SIG_UNBLOCK,
16 };
17 
18 use crate::errno;
19 use std::fmt::{self, Display};
20 use std::io;
21 use std::mem;
22 use std::os::unix::thread::JoinHandleExt;
23 use std::ptr::{null, null_mut};
24 use std::result;
25 use std::thread::JoinHandle;
26 
27 /// The error cases enumeration for signal handling.
28 #[derive(Debug, PartialEq, Eq)]
29 pub enum Error {
30     /// Couldn't create a sigset.
31     CreateSigset(errno::Error),
32     /// The wrapped signal has already been blocked.
33     SignalAlreadyBlocked(c_int),
34     /// Failed to check if the requested signal is in the blocked set already.
35     CompareBlockedSignals(errno::Error),
36     /// The signal could not be blocked.
37     BlockSignal(errno::Error),
38     /// The signal mask could not be retrieved.
39     RetrieveSignalMask(c_int),
40     /// The signal could not be unblocked.
41     UnblockSignal(errno::Error),
42     /// Failed to wait for given signal.
43     ClearWaitPending(errno::Error),
44     /// Failed to get pending signals.
45     ClearGetPending(errno::Error),
46     /// Failed to check if given signal is in the set of pending signals.
47     ClearCheckPending(errno::Error),
48 }
49 
50 impl Display for Error {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result51     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
52         use self::Error::*;
53 
54         match self {
55             CreateSigset(e) => write!(f, "couldn't create a sigset: {}", e),
56             SignalAlreadyBlocked(num) => write!(f, "signal {} already blocked", num),
57             CompareBlockedSignals(e) => write!(
58                 f,
59                 "failed to check whether requested signal is in the blocked set: {}",
60                 e,
61             ),
62             BlockSignal(e) => write!(f, "signal could not be blocked: {}", e),
63             RetrieveSignalMask(errno) => write!(
64                 f,
65                 "failed to retrieve signal mask: {}",
66                 io::Error::from_raw_os_error(*errno),
67             ),
68             UnblockSignal(e) => write!(f, "signal could not be unblocked: {}", e),
69             ClearWaitPending(e) => write!(f, "failed to wait for given signal: {}", e),
70             ClearGetPending(e) => write!(f, "failed to get pending signals: {}", e),
71             ClearCheckPending(e) => write!(
72                 f,
73                 "failed to check whether given signal is in the pending set: {}",
74                 e,
75             ),
76         }
77     }
78 }
79 
80 /// A simplified [Result](https://doc.rust-lang.org/std/result/enum.Result.html) type
81 /// for operations that can return [`Error`](Enum.error.html).
82 pub type SignalResult<T> = result::Result<T, Error>;
83 
84 /// Public alias for a signal handler.
85 /// [`sigaction`](http://man7.org/linux/man-pages/man2/sigaction.2.html).
86 pub type SignalHandler =
87     extern "C" fn(num: c_int, info: *mut siginfo_t, _unused: *mut c_void) -> ();
88 
89 extern "C" {
__libc_current_sigrtmin() -> c_int90     fn __libc_current_sigrtmin() -> c_int;
__libc_current_sigrtmax() -> c_int91     fn __libc_current_sigrtmax() -> c_int;
92 }
93 
94 /// Return the minimum (inclusive) real-time signal number.
95 #[allow(non_snake_case)]
SIGRTMIN() -> c_int96 pub fn SIGRTMIN() -> c_int {
97     // SAFETY: We trust this libc function.
98     unsafe { __libc_current_sigrtmin() }
99 }
100 
101 /// Return the maximum (inclusive) real-time signal number.
102 #[allow(non_snake_case)]
SIGRTMAX() -> c_int103 pub fn SIGRTMAX() -> c_int {
104     // SAFETY: We trust this libc function.
105     unsafe { __libc_current_sigrtmax() }
106 }
107 
108 /// Verify that a signal number is valid.
109 ///
110 /// Supported signals range from `SIGHUP` to `SIGSYS` and from `SIGRTMIN` to `SIGRTMAX`.
111 /// We recommend using realtime signals `[SIGRTMIN(), SIGRTMAX()]` for VCPU threads.
112 ///
113 /// # Arguments
114 ///
115 /// * `num`: the signal number to be verified.
116 ///
117 /// # Examples
118 ///
119 /// ```
120 /// extern crate vmm_sys_util;
121 /// use vmm_sys_util::signal::validate_signal_num;
122 ///
123 /// let num = validate_signal_num(1).unwrap();
124 /// ```
validate_signal_num(num: c_int) -> errno::Result<()>125 pub fn validate_signal_num(num: c_int) -> errno::Result<()> {
126     if (libc::SIGHUP..=libc::SIGSYS).contains(&num) || (SIGRTMIN() <= num && num <= SIGRTMAX()) {
127         Ok(())
128     } else {
129         Err(errno::Error::new(EINVAL))
130     }
131 }
132 
133 /// Register the signal handler of `signum`.
134 ///
135 /// # Safety
136 ///
137 /// This is considered unsafe because the given handler will be called
138 /// asynchronously, interrupting whatever the thread was doing and therefore
139 /// must only do async-signal-safe operations.
140 ///
141 /// # Arguments
142 ///
143 /// * `num`: the signal number to be registered.
144 /// * `handler`: the signal handler function to register.
145 ///
146 /// # Examples
147 ///
148 /// ```
149 /// # extern crate libc;
150 /// extern crate vmm_sys_util;
151 /// # use libc::{c_int, c_void, siginfo_t, SA_SIGINFO};
152 /// use vmm_sys_util::signal::{register_signal_handler, SignalHandler};
153 ///
154 /// extern "C" fn handle_signal(_: c_int, _: *mut siginfo_t, _: *mut c_void) {}
155 /// register_signal_handler(0, handle_signal);
156 /// ```
157 
register_signal_handler(num: c_int, handler: SignalHandler) -> errno::Result<()>158 pub fn register_signal_handler(num: c_int, handler: SignalHandler) -> errno::Result<()> {
159     validate_signal_num(num)?;
160 
161     // signum specifies the signal and can be any valid signal except
162     // SIGKILL and SIGSTOP.
163     // [`sigaction`](http://man7.org/linux/man-pages/man2/sigaction.2.html).
164     if libc::SIGKILL == num || libc::SIGSTOP == num {
165         return Err(errno::Error::new(EINVAL));
166     }
167 
168     // SAFETY: Safe, because this is a POD struct.
169     let mut act: sigaction = unsafe { mem::zeroed() };
170     act.sa_sigaction = handler as *const () as usize;
171     act.sa_flags = libc::SA_SIGINFO;
172 
173     // Block all signals while the `handler` is running.
174     // Blocking other signals is needed to make sure the execution of
175     // the handler continues uninterrupted if another signal comes.
176     // SAFETY: The parameters are valid and we trust the sifillset function.
177     if unsafe { sigfillset(&mut act.sa_mask as *mut sigset_t) } < 0 {
178         return errno::errno_result();
179     }
180 
181     // SAFETY: Safe because the parameters are valid and we check the return value.
182     match unsafe { sigaction(num, &act, null_mut()) } {
183         0 => Ok(()),
184         _ => errno::errno_result(),
185     }
186 }
187 
188 /// Create a `sigset` with given signals.
189 ///
190 /// An array of signal numbers are added into the signal set by
191 /// [`sigaddset`](http://man7.org/linux/man-pages/man3/sigaddset.3p.html).
192 /// This is a helper function used when we want to manipulate signals.
193 ///
194 /// # Arguments
195 ///
196 /// * `signals`: signal numbers to be added to the new `sigset`.
197 ///
198 /// # Examples
199 ///
200 /// ```
201 /// # extern crate libc;
202 /// extern crate vmm_sys_util;
203 /// # use libc::sigismember;
204 /// use vmm_sys_util::signal::create_sigset;
205 ///
206 /// let sigset = create_sigset(&[1]).unwrap();
207 ///
208 /// unsafe {
209 ///     assert_eq!(sigismember(&sigset, 1), 1);
210 /// }
211 /// ```
create_sigset(signals: &[c_int]) -> errno::Result<sigset_t>212 pub fn create_sigset(signals: &[c_int]) -> errno::Result<sigset_t> {
213     // SAFETY: sigset will actually be initialized by sigemptyset below.
214     let mut sigset: sigset_t = unsafe { mem::zeroed() };
215 
216     // SAFETY: return value is checked.
217     let ret = unsafe { sigemptyset(&mut sigset) };
218     if ret < 0 {
219         return errno::errno_result();
220     }
221 
222     for signal in signals {
223         // SAFETY: return value is checked.
224         let ret = unsafe { sigaddset(&mut sigset, *signal) };
225         if ret < 0 {
226             return errno::errno_result();
227         }
228     }
229 
230     Ok(sigset)
231 }
232 
233 /// Retrieve the signal mask that is blocked of the current thread.
234 ///
235 /// Use [`pthread_sigmask`](http://man7.org/linux/man-pages/man3/pthread_sigmask.3.html)
236 /// to fetch the signal mask which is blocked for the caller, return the signal mask as
237 /// a vector of c_int.
238 ///
239 /// # Examples
240 ///
241 /// ```
242 /// extern crate vmm_sys_util;
243 /// use vmm_sys_util::signal::{block_signal, get_blocked_signals};
244 ///
245 /// block_signal(1).unwrap();
246 /// assert!(get_blocked_signals().unwrap().contains(&(1)));
247 /// ```
get_blocked_signals() -> SignalResult<Vec<c_int>>248 pub fn get_blocked_signals() -> SignalResult<Vec<c_int>> {
249     let mut mask = Vec::new();
250 
251     // SAFETY: return values are checked.
252     unsafe {
253         let mut old_sigset: sigset_t = mem::zeroed();
254         let ret = pthread_sigmask(SIG_BLOCK, null(), &mut old_sigset as *mut sigset_t);
255         if ret < 0 {
256             return Err(Error::RetrieveSignalMask(ret));
257         }
258 
259         for num in 0..=SIGRTMAX() {
260             if sigismember(&old_sigset, num) > 0 {
261                 mask.push(num);
262             }
263         }
264     }
265 
266     Ok(mask)
267 }
268 
269 /// Mask a given signal.
270 ///
271 /// Set the given signal `num` as blocked.
272 /// If signal is already blocked, the call will fail with
273 /// [`SignalAlreadyBlocked`](enum.Error.html#variant.SignalAlreadyBlocked).
274 ///
275 /// # Arguments
276 ///
277 /// * `num`: the signal to be masked.
278 ///
279 /// # Examples
280 ///
281 /// ```
282 /// extern crate vmm_sys_util;
283 /// use vmm_sys_util::signal::block_signal;
284 ///
285 /// block_signal(1).unwrap();
286 /// ```
287 // Allowing comparison chain because rewriting it with match makes the code less readable.
288 // Also, the risk of having non-exhaustive checks is low.
289 #[allow(clippy::comparison_chain)]
block_signal(num: c_int) -> SignalResult<()>290 pub fn block_signal(num: c_int) -> SignalResult<()> {
291     let sigset = create_sigset(&[num]).map_err(Error::CreateSigset)?;
292 
293     // SAFETY: return values are checked.
294     unsafe {
295         let mut old_sigset: sigset_t = mem::zeroed();
296         let ret = pthread_sigmask(SIG_BLOCK, &sigset, &mut old_sigset as *mut sigset_t);
297         if ret < 0 {
298             return Err(Error::BlockSignal(errno::Error::last()));
299         }
300         // Check if the given signal is already blocked.
301         let ret = sigismember(&old_sigset, num);
302         if ret < 0 {
303             return Err(Error::CompareBlockedSignals(errno::Error::last()));
304         } else if ret > 0 {
305             return Err(Error::SignalAlreadyBlocked(num));
306         }
307     }
308     Ok(())
309 }
310 
311 /// Unmask a given signal.
312 ///
313 /// # Arguments
314 ///
315 /// * `num`: the signal to be unmasked.
316 ///
317 /// # Examples
318 ///
319 /// ```
320 /// extern crate vmm_sys_util;
321 /// use vmm_sys_util::signal::{block_signal, get_blocked_signals, unblock_signal};
322 ///
323 /// block_signal(1).unwrap();
324 /// assert!(get_blocked_signals().unwrap().contains(&(1)));
325 /// unblock_signal(1).unwrap();
326 /// ```
unblock_signal(num: c_int) -> SignalResult<()>327 pub fn unblock_signal(num: c_int) -> SignalResult<()> {
328     let sigset = create_sigset(&[num]).map_err(Error::CreateSigset)?;
329 
330     // SAFETY: return value is checked.
331     let ret = unsafe { pthread_sigmask(SIG_UNBLOCK, &sigset, null_mut()) };
332     if ret < 0 {
333         return Err(Error::UnblockSignal(errno::Error::last()));
334     }
335     Ok(())
336 }
337 
338 /// Clear a pending signal.
339 ///
340 /// # Arguments
341 ///
342 /// * `num`: the signal to be cleared.
343 ///
344 /// # Examples
345 ///
346 /// ```
347 /// # extern crate libc;
348 /// extern crate vmm_sys_util;
349 /// # use libc::{pthread_kill, sigismember, sigpending, sigset_t};
350 /// # use std::mem;
351 /// # use std::thread;
352 /// # use std::time::Duration;
353 /// use vmm_sys_util::signal::{block_signal, clear_signal, Killable};
354 ///
355 /// block_signal(1).unwrap();
356 /// let killable = thread::spawn(move || {
357 ///     thread::sleep(Duration::from_millis(100));
358 ///     unsafe {
359 ///         let mut chkset: sigset_t = mem::zeroed();
360 ///         sigpending(&mut chkset);
361 ///         assert_eq!(sigismember(&chkset, 1), 1);
362 ///     }
363 /// });
364 /// unsafe {
365 ///     pthread_kill(killable.pthread_handle(), 1);
366 /// }
367 /// clear_signal(1).unwrap();
368 /// ```
clear_signal(num: c_int) -> SignalResult<()>369 pub fn clear_signal(num: c_int) -> SignalResult<()> {
370     let sigset = create_sigset(&[num]).map_err(Error::CreateSigset)?;
371 
372     while {
373         // SAFETY: This is safe as we are rigorously checking return values
374         // of libc calls.
375         unsafe {
376             let mut siginfo: siginfo_t = mem::zeroed();
377             let ts = timespec {
378                 tv_sec: 0,
379                 tv_nsec: 0,
380             };
381             // Attempt to consume one instance of pending signal. If signal
382             // is not pending, the call will fail with EAGAIN or EINTR.
383             let ret = sigtimedwait(&sigset, &mut siginfo, &ts);
384             if ret < 0 {
385                 let e = errno::Error::last();
386                 match e.errno() {
387                     EAGAIN | EINTR => {}
388                     _ => {
389                         return Err(Error::ClearWaitPending(errno::Error::last()));
390                     }
391                 }
392             }
393 
394             // This sigset will be actually filled with `sigpending` call.
395             let mut chkset: sigset_t = mem::zeroed();
396             // See if more instances of the signal are pending.
397             let ret = sigpending(&mut chkset);
398             if ret < 0 {
399                 return Err(Error::ClearGetPending(errno::Error::last()));
400             }
401 
402             let ret = sigismember(&chkset, num);
403             if ret < 0 {
404                 return Err(Error::ClearCheckPending(errno::Error::last()));
405             }
406 
407             // This is do-while loop condition.
408             ret != 0
409         }
410     } {}
411 
412     Ok(())
413 }
414 
415 /// Trait for threads that can be signalled via `pthread_kill`.
416 ///
417 /// Note that this is only useful for signals between `SIGRTMIN()` and
418 /// `SIGRTMAX()` because these are guaranteed to not be used by the C
419 /// runtime.
420 ///
421 /// # Safety
422 ///
423 /// This is marked unsafe because the implementation of this trait must
424 /// guarantee that the returned `pthread_t` is valid and has a lifetime at
425 /// least that of the trait object.
426 pub unsafe trait Killable {
427     /// Cast this killable thread as `pthread_t`.
pthread_handle(&self) -> pthread_t428     fn pthread_handle(&self) -> pthread_t;
429 
430     /// Send a signal to this killable thread.
431     ///
432     /// # Arguments
433     ///
434     /// * `num`: specify the signal
kill(&self, num: c_int) -> errno::Result<()>435     fn kill(&self, num: c_int) -> errno::Result<()> {
436         validate_signal_num(num)?;
437 
438         // SAFETY: Safe because we ensure we are using a valid pthread handle,
439         // a valid signal number, and check the return result.
440         let ret = unsafe { pthread_kill(self.pthread_handle(), num) };
441         if ret < 0 {
442             return errno::errno_result();
443         }
444         Ok(())
445     }
446 }
447 
448 // SAFETY: Safe because we fulfill our contract of returning a genuine pthread handle.
449 unsafe impl<T> Killable for JoinHandle<T> {
pthread_handle(&self) -> pthread_t450     fn pthread_handle(&self) -> pthread_t {
451         // JoinHandleExt::as_pthread_t gives c_ulong, convert it to the
452         // type that the libc crate expects
453         assert_eq!(mem::size_of::<pthread_t>(), mem::size_of::<usize>());
454         self.as_pthread_t() as usize as pthread_t
455     }
456 }
457 
458 #[cfg(test)]
459 mod tests {
460     #![allow(clippy::undocumented_unsafe_blocks)]
461     use super::*;
462     use std::thread;
463     use std::time::Duration;
464 
465     // Reserve for each vcpu signal.
466     static mut SIGNAL_HANDLER_CALLED: bool = false;
467 
handle_signal(_: c_int, _: *mut siginfo_t, _: *mut c_void)468     extern "C" fn handle_signal(_: c_int, _: *mut siginfo_t, _: *mut c_void) {
469         unsafe {
470             // In the tests, there only uses vcpu signal.
471             SIGNAL_HANDLER_CALLED = true;
472         }
473     }
474 
is_pending(signal: c_int) -> bool475     fn is_pending(signal: c_int) -> bool {
476         unsafe {
477             let mut chkset: sigset_t = mem::zeroed();
478             sigpending(&mut chkset);
479             sigismember(&chkset, signal) == 1
480         }
481     }
482 
483     #[test]
test_register_signal_handler()484     fn test_register_signal_handler() {
485         // testing bad value
486         assert!(register_signal_handler(libc::SIGKILL, handle_signal).is_err());
487         assert!(register_signal_handler(libc::SIGSTOP, handle_signal).is_err());
488         assert!(register_signal_handler(SIGRTMAX() + 1, handle_signal).is_err());
489         format!("{:?}", register_signal_handler(SIGRTMAX(), handle_signal));
490         assert!(register_signal_handler(SIGRTMIN(), handle_signal).is_ok());
491         assert!(register_signal_handler(libc::SIGSYS, handle_signal).is_ok());
492     }
493 
494     #[test]
495     #[allow(clippy::empty_loop)]
test_killing_thread()496     fn test_killing_thread() {
497         let killable = thread::spawn(|| thread::current().id());
498         let killable_id = killable.join().unwrap();
499         assert_ne!(killable_id, thread::current().id());
500 
501         // We install a signal handler for the specified signal; otherwise the whole process will
502         // be brought down when the signal is received, as part of the default behaviour. Signal
503         // handlers are global, so we install this before starting the thread.
504         register_signal_handler(SIGRTMIN(), handle_signal)
505             .expect("failed to register vcpu signal handler");
506 
507         let killable = thread::spawn(|| loop {});
508 
509         let res = killable.kill(SIGRTMAX() + 1);
510         assert!(res.is_err());
511         format!("{:?}", res);
512 
513         unsafe {
514             assert!(!SIGNAL_HANDLER_CALLED);
515         }
516 
517         assert!(killable.kill(SIGRTMIN()).is_ok());
518 
519         // We're waiting to detect that the signal handler has been called.
520         const MAX_WAIT_ITERS: u32 = 20;
521         let mut iter_count = 0;
522         loop {
523             thread::sleep(Duration::from_millis(100));
524 
525             if unsafe { SIGNAL_HANDLER_CALLED } {
526                 break;
527             }
528 
529             iter_count += 1;
530             // timeout if we wait too long
531             assert!(iter_count <= MAX_WAIT_ITERS);
532         }
533 
534         // Our signal handler doesn't do anything which influences the killable thread, so the
535         // previous signal is effectively ignored. If we were to join killable here, we would block
536         // forever as the loop keeps running. Since we don't join, the thread will become detached
537         // as the handle is dropped, and will be killed when the process/main thread exits.
538     }
539 
540     #[test]
test_block_unblock_signal()541     fn test_block_unblock_signal() {
542         let signal = SIGRTMIN();
543 
544         // Check if it is blocked.
545         unsafe {
546             let mut sigset: sigset_t = mem::zeroed();
547             pthread_sigmask(SIG_BLOCK, null(), &mut sigset as *mut sigset_t);
548             assert_eq!(sigismember(&sigset, signal), 0);
549         }
550 
551         block_signal(signal).unwrap();
552         assert!(get_blocked_signals().unwrap().contains(&(signal)));
553 
554         unblock_signal(signal).unwrap();
555         assert!(!get_blocked_signals().unwrap().contains(&(signal)));
556     }
557 
558     #[test]
test_clear_pending()559     fn test_clear_pending() {
560         let signal = SIGRTMIN() + 1;
561 
562         block_signal(signal).unwrap();
563 
564         // Block the signal, which means it won't be delivered until it is
565         // unblocked. Pending between the time when the signal which is set as blocked
566         // is generated and when is delivered.
567         let killable = thread::spawn(move || {
568             loop {
569                 // Wait for the signal being killed.
570                 thread::sleep(Duration::from_millis(100));
571                 if is_pending(signal) {
572                     clear_signal(signal).unwrap();
573                     assert!(!is_pending(signal));
574                     break;
575                 }
576             }
577         });
578 
579         // Send a signal to the thread.
580         assert!(killable.kill(SIGRTMIN() + 1).is_ok());
581         killable.join().unwrap();
582     }
583 }
584