asterinas/kernel/src/process/signal/sig_disposition.rs

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");
}
}
}