starnix_uapi/
signals.rs

1// Copyright 2023 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use crate::errors::{Errno, errno, error};
6use crate::sigset_t;
7use linux_uapi as uapi;
8use static_assertions::assert_eq_size;
9use std::fmt;
10use std::ops::{BitAnd, BitOr, Not};
11use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
12
13pub const UNBLOCKABLE_SIGNALS: SigSet = SigSet(SIGKILL.mask() | SIGSTOP.mask());
14
15/// An unchecked signal represents a signal that has not been through verification, and may
16/// represent an invalid signal number.
17#[derive(Debug, Copy, Clone, Eq, PartialEq)]
18pub struct UncheckedSignal(u64);
19
20impl UncheckedSignal {
21    pub fn new(value: u64) -> UncheckedSignal {
22        UncheckedSignal(value)
23    }
24
25    pub fn is_zero(self) -> bool {
26        self.0 == 0
27    }
28}
29impl From<Signal> for UncheckedSignal {
30    fn from(signal: Signal) -> UncheckedSignal {
31        UncheckedSignal(signal.number as u64)
32    }
33}
34impl From<u32> for UncheckedSignal {
35    fn from(value: u32) -> UncheckedSignal {
36        UncheckedSignal(value as u64)
37    }
38}
39
40/// The `Signal` struct represents a valid signal.
41#[derive(Copy, Clone, PartialEq, Eq, Hash)]
42pub struct Signal {
43    number: u32,
44}
45
46impl Signal {
47    /// The signal number, guaranteed to be a value between 1..=NUM_SIGNALS.
48    pub fn number(&self) -> u32 {
49        self.number
50    }
51
52    /// Returns the bitmask for this signal number.
53    pub const fn mask(&self) -> u64 {
54        1 << (self.number - 1)
55    }
56
57    /// Returns true if the signal is a real-time signal.
58    pub fn is_real_time(&self) -> bool {
59        self.number >= super::SIGRTMIN
60    }
61
62    /// Returns true if this signal can't be blocked. This means either SIGKILL or SIGSTOP.
63    pub fn is_unblockable(&self) -> bool {
64        UNBLOCKABLE_SIGNALS.has_signal(*self)
65    }
66
67    /// Used exclusively for PTRACE_O_TRACESYSGOOD
68    pub fn set_ptrace_syscall_bit(&mut self) {
69        self.number |= 0x80
70    }
71
72    pub fn name(&self) -> &'static str {
73        if self.is_real_time() {
74            return "real time signal";
75        }
76        match self.number {
77            uapi::SIGHUP => "SIGHUP",
78            uapi::SIGINT => "SIGINT",
79            uapi::SIGQUIT => "SIGQUIT",
80            uapi::SIGILL => "SIGILL",
81            uapi::SIGTRAP => "SIGTRAP",
82            uapi::SIGABRT => "SIGABRT",
83            uapi::SIGBUS => "SIGBUS",
84            uapi::SIGFPE => "SIGFPE",
85            uapi::SIGKILL => "SIGKILL",
86            uapi::SIGUSR1 => "SIGUSR1",
87            uapi::SIGSEGV => "SIGSEGV",
88            uapi::SIGUSR2 => "SIGUSR2",
89            uapi::SIGPIPE => "SIGPIPE",
90            uapi::SIGALRM => "SIGALRM",
91            uapi::SIGTERM => "SIGTERM",
92            uapi::SIGSTKFLT => "SIGSTKFLT",
93            uapi::SIGCHLD => "SIGCHLD",
94            uapi::SIGCONT => "SIGCONT",
95            uapi::SIGSTOP => "SIGSTOP",
96            uapi::SIGTSTP => "SIGTSTP",
97            uapi::SIGTTIN => "SIGTTIN",
98            uapi::SIGTTOU => "SIGTTOU",
99            uapi::SIGURG => "SIGURG",
100            uapi::SIGXCPU => "SIGXCPU",
101            uapi::SIGXFSZ => "SIGXFSZ",
102            uapi::SIGVTALRM => "SIGVTALRM",
103            uapi::SIGPROF => "SIGPROF",
104            uapi::SIGWINCH => "SIGWINCH",
105            uapi::SIGIO => "SIGIO",
106            uapi::SIGPWR => "SIGPWR",
107            uapi::SIGSYS => "SIGSYS",
108            _ => "unknown signal",
109        }
110    }
111
112    /// The number of signals, also the highest valid signal number.
113    pub const NUM_SIGNALS: u32 = 64;
114}
115
116pub const SIGHUP: Signal = Signal { number: uapi::SIGHUP };
117pub const SIGINT: Signal = Signal { number: uapi::SIGINT };
118pub const SIGQUIT: Signal = Signal { number: uapi::SIGQUIT };
119pub const SIGILL: Signal = Signal { number: uapi::SIGILL };
120pub const SIGTRAP: Signal = Signal { number: uapi::SIGTRAP };
121pub const SIGABRT: Signal = Signal { number: uapi::SIGABRT };
122#[allow(dead_code)]
123pub const SIGIOT: Signal = Signal { number: uapi::SIGIOT };
124pub const SIGBUS: Signal = Signal { number: uapi::SIGBUS };
125pub const SIGFPE: Signal = Signal { number: uapi::SIGFPE };
126pub const SIGKILL: Signal = Signal { number: uapi::SIGKILL };
127pub const SIGUSR1: Signal = Signal { number: uapi::SIGUSR1 };
128pub const SIGSEGV: Signal = Signal { number: uapi::SIGSEGV };
129pub const SIGUSR2: Signal = Signal { number: uapi::SIGUSR2 };
130pub const SIGPIPE: Signal = Signal { number: uapi::SIGPIPE };
131pub const SIGALRM: Signal = Signal { number: uapi::SIGALRM };
132pub const SIGTERM: Signal = Signal { number: uapi::SIGTERM };
133pub const SIGSTKFLT: Signal = Signal { number: uapi::SIGSTKFLT };
134pub const SIGCHLD: Signal = Signal { number: uapi::SIGCHLD };
135pub const SIGCONT: Signal = Signal { number: uapi::SIGCONT };
136pub const SIGSTOP: Signal = Signal { number: uapi::SIGSTOP };
137pub const SIGTSTP: Signal = Signal { number: uapi::SIGTSTP };
138pub const SIGTTIN: Signal = Signal { number: uapi::SIGTTIN };
139pub const SIGTTOU: Signal = Signal { number: uapi::SIGTTOU };
140pub const SIGURG: Signal = Signal { number: uapi::SIGURG };
141pub const SIGXCPU: Signal = Signal { number: uapi::SIGXCPU };
142pub const SIGXFSZ: Signal = Signal { number: uapi::SIGXFSZ };
143pub const SIGVTALRM: Signal = Signal { number: uapi::SIGVTALRM };
144pub const SIGPROF: Signal = Signal { number: uapi::SIGPROF };
145pub const SIGWINCH: Signal = Signal { number: uapi::SIGWINCH };
146pub const SIGIO: Signal = Signal { number: uapi::SIGIO };
147pub const SIGPWR: Signal = Signal { number: uapi::SIGPWR };
148pub const SIGSYS: Signal = Signal { number: uapi::SIGSYS };
149#[allow(dead_code)]
150pub const SIGRTMIN: Signal = Signal { number: super::SIGRTMIN };
151
152impl TryFrom<UncheckedSignal> for Signal {
153    type Error = Errno;
154
155    fn try_from(value: UncheckedSignal) -> Result<Self, Self::Error> {
156        let value = u32::try_from(value.0).map_err(|_| errno!(EINVAL))?;
157        if (1..=Signal::NUM_SIGNALS).contains(&value) {
158            Ok(Signal { number: value })
159        } else {
160            error!(EINVAL)
161        }
162    }
163}
164
165impl fmt::Debug for Signal {
166    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
167        write!(f, "{self}")
168    }
169}
170
171impl fmt::Display for Signal {
172    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
173        if self.is_real_time() {
174            write!(f, "SIGRTMIN+{}({})", self.number - super::SIGRTMIN, self.number)
175        } else {
176            write!(f, "{}({})", self.name(), self.number)
177        }
178    }
179}
180
181/// POSIX defines sigset_t as either a numeric or structure type (so the number of signals can
182/// exceed the bits in a machine word). The programmer is supposed to modify this bitfield using
183/// sigaddset(), etc. rather than setting bits directly so client code can be agnostic to the
184/// definition.
185///
186///  * On x64, sigset_t is a typedef for "unsigned long".
187///  * On ARM64, sigset_t is a structure containing one "unsigned long" member.
188///
189/// To keep the Starnix code agnostic to the definition, this SigSet type provides a wrapper
190/// with a uniform interface for the things we need.
191///
192/// The layout of this object is designed to be identical to the layout of the current
193/// architecture's sigset_t type so UserRef<SigSet> can be used for system calls.
194#[repr(transparent)]
195#[derive(
196    Debug, Copy, Clone, Default, IntoBytes, Eq, KnownLayout, FromBytes, Immutable, PartialEq,
197)]
198pub struct SigSet(pub std::os::raw::c_ulong);
199assert_eq_size!(SigSet, sigset_t);
200
201impl SigSet {
202    /// Returns whether this signal set contains the given signal.
203    pub fn has_signal(&self, signal: Signal) -> bool {
204        (self.0 & (signal.mask() as std::os::raw::c_ulong)) != 0
205    }
206
207    /// Returns whether this signal set has any signals in common with another.
208    pub fn intersects(&self, other: &Self) -> bool {
209        (self.0 & other.0) != 0
210    }
211}
212
213impl From<sigset_t> for SigSet {
214    fn from(value: sigset_t) -> Self {
215        // `transmute()` is safe here because this is a POD value of the same size (see
216        // assert above).
217        #[allow(
218            clippy::undocumented_unsafe_blocks,
219            reason = "Force documented unsafe blocks in Starnix"
220        )]
221        SigSet(unsafe { std::mem::transmute(value) })
222    }
223}
224
225impl From<SigSet> for sigset_t {
226    fn from(val: SigSet) -> Self {
227        // `transmute()` is safe here because this is a POD value of the same size (see
228        // assert above).
229        #[allow(
230            clippy::undocumented_unsafe_blocks,
231            reason = "Force documented unsafe blocks in Starnix"
232        )]
233        unsafe {
234            std::mem::transmute(val.0)
235        }
236    }
237}
238
239impl BitAnd for SigSet {
240    type Output = Self;
241
242    // rhs is the "right-hand side" of the expression `a & b`
243    fn bitand(self, rhs: Self) -> Self::Output {
244        Self(self.0 & rhs.0)
245    }
246}
247
248impl BitOr for SigSet {
249    type Output = Self;
250
251    // rhs is the "right-hand side" of the expression `a | b`
252    fn bitor(self, rhs: Self) -> Self::Output {
253        Self(self.0 | rhs.0)
254    }
255}
256
257impl Not for SigSet {
258    type Output = Self;
259
260    fn not(self) -> Self::Output {
261        SigSet(!self.0)
262    }
263}
264
265impl From<Signal> for SigSet {
266    /// Constructs a sigset consisting of one signal value.
267    fn from(value: Signal) -> Self {
268        SigSet(value.mask() as std::os::raw::c_ulong)
269    }
270}
271
272pub fn sigaltstack_contains_pointer(stack: &uapi::sigaltstack, ptr: u64) -> bool {
273    let min = stack.ss_sp.addr as u64;
274    let max = (stack.ss_sp.addr as u64).saturating_add(stack.ss_size as u64);
275    ptr >= min && ptr <= max
276}