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