102 lines
3.2 KiB
Rust
102 lines
3.2 KiB
Rust
// SPDX-License-Identifier: MPL-2.0
|
|
|
|
use super::{constants::*, sig_action::SigAction, sig_num::SigNum};
|
|
use crate::{
|
|
prelude::*,
|
|
process::signal::{sig_action::SigActionFlags, signals::Signal},
|
|
};
|
|
|
|
#[derive(Copy, Clone)]
|
|
pub struct SigDispositions {
|
|
// SigNum -> SigAction
|
|
map: [SigAction; COUNT_ALL_SIGS],
|
|
}
|
|
|
|
impl Default for SigDispositions {
|
|
fn default() -> Self {
|
|
Self::new()
|
|
}
|
|
}
|
|
|
|
impl SigDispositions {
|
|
pub fn new() -> Self {
|
|
Self {
|
|
map: [SigAction::default(); COUNT_ALL_SIGS],
|
|
}
|
|
}
|
|
|
|
pub fn get(&self, num: SigNum) -> SigAction {
|
|
let idx = Self::num_to_idx(num);
|
|
self.map[idx]
|
|
}
|
|
|
|
pub fn set(&mut self, num: SigNum, sa: SigAction) -> Result<SigAction> {
|
|
check_sigaction(&sa)?;
|
|
let idx = Self::num_to_idx(num);
|
|
Ok(core::mem::replace(&mut self.map[idx], sa))
|
|
}
|
|
|
|
pub fn set_default(&mut self, num: SigNum) {
|
|
let idx = Self::num_to_idx(num);
|
|
self.map[idx] = SigAction::Dfl;
|
|
}
|
|
|
|
/// man 7 signal:
|
|
/// When execve, the handled signals are reset to the default; the dispositions of
|
|
/// ignored signals are left unchanged.
|
|
/// This function should be used when execve.
|
|
pub fn inherit(&mut self) {
|
|
for sigaction in &mut self.map {
|
|
if let SigAction::User { .. } = sigaction {
|
|
*sigaction = SigAction::Dfl;
|
|
}
|
|
}
|
|
}
|
|
|
|
fn num_to_idx(num: SigNum) -> usize {
|
|
(num.as_u8() - MIN_STD_SIG_NUM) as usize
|
|
}
|
|
|
|
pub fn will_ignore(&self, signal: &dyn Signal) -> bool {
|
|
let signum = signal.num();
|
|
self.get(signum).will_ignore(signum)
|
|
}
|
|
}
|
|
|
|
fn check_sigaction(sig_action: &SigAction) -> Result<()> {
|
|
// Here we only check if the SA_RESTORER flag is set and restorer_addr is not 0.
|
|
// Note: Linux checks the SA_RESTORER flag when initializing the signal stack,
|
|
// whereas we have moved this check forward to prevent this action from being set.
|
|
// This may result in some differences from the behavior of Linux.
|
|
|
|
let SigAction::User {
|
|
flags,
|
|
restorer_addr,
|
|
..
|
|
} = sig_action
|
|
else {
|
|
return Ok(());
|
|
};
|
|
|
|
if flags.contains(SigActionFlags::SA_RESTORER) && *restorer_addr != 0 {
|
|
return Ok(());
|
|
}
|
|
|
|
cfg_if::cfg_if! {
|
|
if #[cfg(target_arch = "x86_64")] {
|
|
// On x86-64, `SA_RESTORER` is mandatory and cannot be omitted.
|
|
// Ref: <https://elixir.bootlin.com/linux/v6.13/source/arch/x86/kernel/signal_64.c#L172>
|
|
return_errno_with_message!(Errno::EINVAL, "x86-64 should always use SA_RESTORER");
|
|
} else if #[cfg(target_arch = "riscv64")] {
|
|
// On RISC-V, if `SA_RESTORER` is not specified, `__vdso_rt_sigreturn` will be used as a fallback.
|
|
Ok(())
|
|
} else {
|
|
// FIXME: The support for user-provided signal handlers
|
|
// without `SA_RESTORER` is arch-dependent.
|
|
// Other archs may need to handle scenarios where `SA_RESTORER` is omitted.
|
|
warn!("SA_RESTORER fallback mechanism not implemented for this architecture");
|
|
return_errno_with_message!(Errno::EINVAL, "this architecture currently requires SA_RESTORER");
|
|
}
|
|
}
|
|
}
|