Enable sig_action test from gVisor test

This commit is contained in:
jiangjianfeng
2025-03-14 06:53:00 +00:00
committed by Tate, Hongliang Tian
parent 7e96810e1a
commit d366043876
3 changed files with 75 additions and 13 deletions

View File

@ -2,7 +2,12 @@
use bitflags::bitflags; use bitflags::bitflags;
use super::{c_types::sigaction_t, constants::*, sig_mask::SigMask, sig_num::SigNum}; use super::{
c_types::sigaction_t,
constants::*,
sig_mask::{SigMask, SigSet},
sig_num::SigNum,
};
use crate::prelude::*; use crate::prelude::*;
#[derive(Debug, Copy, Clone, PartialEq, Eq, Default)] #[derive(Debug, Copy, Clone, PartialEq, Eq, Default)]
@ -19,16 +24,20 @@ pub enum SigAction {
}, },
} }
impl TryFrom<sigaction_t> for SigAction { impl From<sigaction_t> for SigAction {
type Error = Error; fn from(input: sigaction_t) -> Self {
match input.handler_ptr {
fn try_from(input: sigaction_t) -> Result<Self> {
let action = match input.handler_ptr {
SIG_DFL => SigAction::Dfl, SIG_DFL => SigAction::Dfl,
SIG_IGN => SigAction::Ign, SIG_IGN => SigAction::Ign,
_ => { _ => {
let flags = SigActionFlags::from_bits_truncate(input.flags); let flags = SigActionFlags::from_bits_truncate(input.flags);
let mask = input.mask.into(); let mask = {
let mut sigset = SigSet::from(input.mask);
// SIGSTOP and SIGKILL cannot be masked
sigset -= SIGSTOP;
sigset -= SIGKILL;
sigset
};
SigAction::User { SigAction::User {
handler_addr: input.handler_ptr, handler_addr: input.handler_ptr,
flags, flags,
@ -36,8 +45,7 @@ impl TryFrom<sigaction_t> for SigAction {
mask, mask,
} }
} }
}; }
Ok(action)
} }
} }
@ -105,7 +113,7 @@ impl SigActionFlags {
} }
/// The default action to signals /// The default action to signals
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum SigDefaultAction { pub enum SigDefaultAction {
Term, // Default action is to terminate the process. Term, // Default action is to terminate the process.
Ign, // Default action is to ignore the signal. Ign, // Default action is to ignore the signal.

View File

@ -3,7 +3,16 @@
use super::SyscallReturn; use super::SyscallReturn;
use crate::{ use crate::{
prelude::*, prelude::*,
process::signal::{c_types::sigaction_t, sig_action::SigAction, sig_num::SigNum}, process::{
posix_thread::AsPosixThread,
signal::{
c_types::sigaction_t,
constants::{SIGKILL, SIGSTOP},
sig_action::{SigAction, SigDefaultAction},
sig_mask::SigSet,
sig_num::SigNum,
},
},
}; };
pub fn sys_rt_sigaction( pub fn sys_rt_sigaction(
@ -29,10 +38,18 @@ pub fn sys_rt_sigaction(
let mut sig_dispositions = ctx.process.sig_dispositions().lock(); let mut sig_dispositions = ctx.process.sig_dispositions().lock();
let old_action = if sig_action_addr != 0 { let old_action = if sig_action_addr != 0 {
if sig_num == SIGKILL || sig_num == SIGSTOP {
return_errno_with_message!(
Errno::EINVAL,
"cannot set a new signal action for SIGKILL and SIGSTOP"
);
}
let sig_action_c = ctx.user_space().read_val::<sigaction_t>(sig_action_addr)?; let sig_action_c = ctx.user_space().read_val::<sigaction_t>(sig_action_addr)?;
let sig_action = SigAction::try_from(sig_action_c).unwrap(); let sig_action = SigAction::from(sig_action_c);
trace!("sig action = {:?}", sig_action); trace!("sig action = {:?}", sig_action);
sig_dispositions.set(sig_num, sig_action) discard_signals_if_ignored(ctx, sig_num, &sig_action);
sig_dispositions.set(sig_num, sig_action)?
} else { } else {
sig_dispositions.get(sig_num) sig_dispositions.get(sig_num)
}; };
@ -45,3 +62,39 @@ pub fn sys_rt_sigaction(
Ok(SyscallReturn::Return(0)) Ok(SyscallReturn::Return(0))
} }
/// Discard signals if the new action is to ignore the signal.
///
/// Ref: <https://elixir.bootlin.com/linux/v6.13/source/kernel/signal.c#L4323>
//
// POSIX 3.3.1.3:
// Setting a signal action to SIG_IGN for a signal that is
// pending shall cause the pending signal to be discarded,
// whether or not it is blocked.
//
// Setting a signal action to SIG_DFL for a signal that is
// pending and whose default action is to ignore the signal
// (for example, SIGCHLD), shall cause the pending signal to
// be discarded, whether or not it is blocked
fn discard_signals_if_ignored(ctx: &Context, signum: SigNum, sig_action: &SigAction) {
match sig_action {
SigAction::Dfl => {
let default_action = SigDefaultAction::from_signum(signum);
if default_action != SigDefaultAction::Ign {
return;
}
}
SigAction::Ign => {}
SigAction::User { .. } => return,
}
let mask = SigSet::new_full() - signum;
for task in ctx.process.tasks().lock().as_slice() {
let Some(posix_thread) = task.as_posix_thread() else {
continue;
};
posix_thread.dequeue_signal(&mask);
}
}

View File

@ -42,6 +42,7 @@ TESTS ?= \
sched_yield_test \ sched_yield_test \
semaphore_test \ semaphore_test \
sendfile_test \ sendfile_test \
sigaction_test \
sigaltstack_test \ sigaltstack_test \
stat_test \ stat_test \
stat_times_test \ stat_times_test \