Add support for POSIX_SPAWN_SETSIGMASK and POSIX_SPAWN_SETSIGDEF
This commit is contained in:
parent
69c79d8252
commit
d15a75fafb
@ -256,6 +256,7 @@ fn do_new_process(
|
|||||||
argv,
|
argv,
|
||||||
&env_concat,
|
&env_concat,
|
||||||
&file_actions,
|
&file_actions,
|
||||||
|
None,
|
||||||
host_stdio_fds,
|
host_stdio_fds,
|
||||||
current,
|
current,
|
||||||
)?;
|
)?;
|
||||||
|
@ -51,6 +51,7 @@ pub fn do_clone(
|
|||||||
let rlimits = current.rlimits().clone();
|
let rlimits = current.rlimits().clone();
|
||||||
let fs = current.fs().clone();
|
let fs = current.fs().clone();
|
||||||
let name = current.name().clone();
|
let name = current.name().clone();
|
||||||
|
let sig_mask = current.sig_mask().read().unwrap().clone();
|
||||||
|
|
||||||
let mut builder = ThreadBuilder::new()
|
let mut builder = ThreadBuilder::new()
|
||||||
.process(current.process().clone())
|
.process(current.process().clone())
|
||||||
@ -59,12 +60,14 @@ pub fn do_clone(
|
|||||||
.fs(fs)
|
.fs(fs)
|
||||||
.files(files)
|
.files(files)
|
||||||
.name(name)
|
.name(name)
|
||||||
.rlimits(rlimits);
|
.rlimits(rlimits)
|
||||||
|
.sig_mask(sig_mask);
|
||||||
if let Some(ctid) = ctid {
|
if let Some(ctid) = ctid {
|
||||||
builder = builder.clear_ctid(ctid);
|
builder = builder.clear_ctid(ctid);
|
||||||
}
|
}
|
||||||
builder.build()?
|
builder.build()?
|
||||||
};
|
};
|
||||||
|
trace!("new thread sigmask = {:?}", new_thread_ref.sig_mask());
|
||||||
let new_tid = new_thread_ref.tid();
|
let new_tid = new_thread_ref.tid();
|
||||||
table::add_thread(new_thread_ref.clone());
|
table::add_thread(new_thread_ref.clone());
|
||||||
info!("Thread created: tid = {}", new_tid);
|
info!("Thread created: tid = {}", new_tid);
|
||||||
|
@ -5,6 +5,7 @@ use self::aux_vec::{AuxKey, AuxVec};
|
|||||||
use self::exec_loader::{load_exec_file_hdr_to_vec, load_file_hdr_to_vec};
|
use self::exec_loader::{load_exec_file_hdr_to_vec, load_file_hdr_to_vec};
|
||||||
use super::elf_file::{ElfFile, ElfHeader, ProgramHeaderExt};
|
use super::elf_file::{ElfFile, ElfHeader, ProgramHeaderExt};
|
||||||
use super::process::ProcessBuilder;
|
use super::process::ProcessBuilder;
|
||||||
|
use super::spawn_attribute::SpawnAttr;
|
||||||
use super::task::Task;
|
use super::task::Task;
|
||||||
use super::thread::ThreadName;
|
use super::thread::ThreadName;
|
||||||
use super::{table, task, ProcessRef, ThreadRef};
|
use super::{table, task, ProcessRef, ThreadRef};
|
||||||
@ -25,6 +26,7 @@ pub fn do_spawn(
|
|||||||
argv: &[CString],
|
argv: &[CString],
|
||||||
envp: &[CString],
|
envp: &[CString],
|
||||||
file_actions: &[FileAction],
|
file_actions: &[FileAction],
|
||||||
|
spawn_attributes: Option<SpawnAttr>,
|
||||||
current_ref: &ThreadRef,
|
current_ref: &ThreadRef,
|
||||||
) -> Result<pid_t> {
|
) -> Result<pid_t> {
|
||||||
let exec_now = true;
|
let exec_now = true;
|
||||||
@ -33,6 +35,7 @@ pub fn do_spawn(
|
|||||||
argv,
|
argv,
|
||||||
envp,
|
envp,
|
||||||
file_actions,
|
file_actions,
|
||||||
|
spawn_attributes,
|
||||||
None,
|
None,
|
||||||
current_ref,
|
current_ref,
|
||||||
exec_now,
|
exec_now,
|
||||||
@ -45,6 +48,7 @@ pub fn do_spawn_without_exec(
|
|||||||
argv: &[CString],
|
argv: &[CString],
|
||||||
envp: &[CString],
|
envp: &[CString],
|
||||||
file_actions: &[FileAction],
|
file_actions: &[FileAction],
|
||||||
|
spawn_attributes: Option<SpawnAttr>,
|
||||||
host_stdio_fds: &HostStdioFds,
|
host_stdio_fds: &HostStdioFds,
|
||||||
current_ref: &ThreadRef,
|
current_ref: &ThreadRef,
|
||||||
) -> Result<pid_t> {
|
) -> Result<pid_t> {
|
||||||
@ -54,6 +58,7 @@ pub fn do_spawn_without_exec(
|
|||||||
argv,
|
argv,
|
||||||
envp,
|
envp,
|
||||||
file_actions,
|
file_actions,
|
||||||
|
spawn_attributes,
|
||||||
Some(host_stdio_fds),
|
Some(host_stdio_fds),
|
||||||
current_ref,
|
current_ref,
|
||||||
exec_now,
|
exec_now,
|
||||||
@ -65,6 +70,7 @@ fn do_spawn_common(
|
|||||||
argv: &[CString],
|
argv: &[CString],
|
||||||
envp: &[CString],
|
envp: &[CString],
|
||||||
file_actions: &[FileAction],
|
file_actions: &[FileAction],
|
||||||
|
spawn_attributes: Option<SpawnAttr>,
|
||||||
host_stdio_fds: Option<&HostStdioFds>,
|
host_stdio_fds: Option<&HostStdioFds>,
|
||||||
current_ref: &ThreadRef,
|
current_ref: &ThreadRef,
|
||||||
exec_now: bool,
|
exec_now: bool,
|
||||||
@ -74,6 +80,7 @@ fn do_spawn_common(
|
|||||||
argv,
|
argv,
|
||||||
envp,
|
envp,
|
||||||
file_actions,
|
file_actions,
|
||||||
|
spawn_attributes,
|
||||||
host_stdio_fds,
|
host_stdio_fds,
|
||||||
current_ref,
|
current_ref,
|
||||||
)?;
|
)?;
|
||||||
@ -97,6 +104,7 @@ fn new_process(
|
|||||||
argv: &[CString],
|
argv: &[CString],
|
||||||
envp: &[CString],
|
envp: &[CString],
|
||||||
file_actions: &[FileAction],
|
file_actions: &[FileAction],
|
||||||
|
spawn_attributes: Option<SpawnAttr>,
|
||||||
host_stdio_fds: Option<&HostStdioFds>,
|
host_stdio_fds: Option<&HostStdioFds>,
|
||||||
current_ref: &ThreadRef,
|
current_ref: &ThreadRef,
|
||||||
) -> Result<ProcessRef> {
|
) -> Result<ProcessRef> {
|
||||||
@ -188,6 +196,28 @@ fn new_process(
|
|||||||
let fs_ref = Arc::new(RwLock::new(current_ref.fs().read().unwrap().clone()));
|
let fs_ref = Arc::new(RwLock::new(current_ref.fs().read().unwrap().clone()));
|
||||||
let sched_ref = Arc::new(SgxMutex::new(current_ref.sched().lock().unwrap().clone()));
|
let sched_ref = Arc::new(SgxMutex::new(current_ref.sched().lock().unwrap().clone()));
|
||||||
let rlimit_ref = Arc::new(SgxMutex::new(current_ref.rlimits().lock().unwrap().clone()));
|
let rlimit_ref = Arc::new(SgxMutex::new(current_ref.rlimits().lock().unwrap().clone()));
|
||||||
|
let sig_mask = if spawn_attributes.is_some() && spawn_attributes.unwrap().sig_mask.is_some()
|
||||||
|
{
|
||||||
|
spawn_attributes.unwrap().sig_mask.unwrap()
|
||||||
|
} else {
|
||||||
|
current_ref.sig_mask().read().unwrap().clone()
|
||||||
|
};
|
||||||
|
trace!("new process sigmask = {:?}", sig_mask);
|
||||||
|
|
||||||
|
let mut sig_dispositions = current_ref
|
||||||
|
.process()
|
||||||
|
.sig_dispositions()
|
||||||
|
.read()
|
||||||
|
.unwrap()
|
||||||
|
.clone();
|
||||||
|
sig_dispositions.inherit();
|
||||||
|
if spawn_attributes.is_some() && spawn_attributes.unwrap().sig_default.is_some() {
|
||||||
|
let sig_default_set = spawn_attributes.unwrap().sig_default.unwrap();
|
||||||
|
sig_default_set.iter().for_each(|b| {
|
||||||
|
sig_dispositions.set_default(b);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
trace!("new process sig_dispositions = {:?}", sig_dispositions);
|
||||||
|
|
||||||
// Make the default thread name to be the process's corresponding elf file name
|
// Make the default thread name to be the process's corresponding elf file name
|
||||||
let elf_name = elf_path.rsplit('/').collect::<Vec<&str>>()[0];
|
let elf_name = elf_path.rsplit('/').collect::<Vec<&str>>()[0];
|
||||||
@ -202,7 +232,9 @@ fn new_process(
|
|||||||
.rlimits(rlimit_ref)
|
.rlimits(rlimit_ref)
|
||||||
.fs(fs_ref)
|
.fs(fs_ref)
|
||||||
.files(files_ref)
|
.files(files_ref)
|
||||||
|
.sig_mask(sig_mask)
|
||||||
.name(thread_name)
|
.name(thread_name)
|
||||||
|
.sig_dispositions(sig_dispositions)
|
||||||
.build()?
|
.build()?
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -24,6 +24,7 @@ pub use self::do_exit::handle_force_exit;
|
|||||||
pub use self::do_futex::{futex_wait, futex_wake};
|
pub use self::do_futex::{futex_wait, futex_wake};
|
||||||
pub use self::do_spawn::do_spawn_without_exec;
|
pub use self::do_spawn::do_spawn_without_exec;
|
||||||
pub use self::process::{Process, ProcessFilter, ProcessStatus, IDLE};
|
pub use self::process::{Process, ProcessFilter, ProcessStatus, IDLE};
|
||||||
|
pub use self::spawn_attribute::posix_spawnattr_t;
|
||||||
pub use self::syscalls::*;
|
pub use self::syscalls::*;
|
||||||
pub use self::task::Task;
|
pub use self::task::Task;
|
||||||
pub use self::term_status::{ForcedExitStatus, TermStatus};
|
pub use self::term_status::{ForcedExitStatus, TermStatus};
|
||||||
@ -39,6 +40,7 @@ mod do_spawn;
|
|||||||
mod do_wait4;
|
mod do_wait4;
|
||||||
mod prctl;
|
mod prctl;
|
||||||
mod process;
|
mod process;
|
||||||
|
mod spawn_attribute;
|
||||||
mod syscalls;
|
mod syscalls;
|
||||||
mod term_status;
|
mod term_status;
|
||||||
mod thread;
|
mod thread;
|
||||||
|
@ -6,7 +6,7 @@ use super::super::{
|
|||||||
};
|
};
|
||||||
use super::{Process, ProcessInner};
|
use super::{Process, ProcessInner};
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use crate::signal::{SigDispositions, SigQueues};
|
use crate::signal::{SigDispositions, SigQueues, SigSet};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct ProcessBuilder {
|
pub struct ProcessBuilder {
|
||||||
@ -18,6 +18,7 @@ pub struct ProcessBuilder {
|
|||||||
exec_path: Option<String>,
|
exec_path: Option<String>,
|
||||||
parent: Option<ProcessRef>,
|
parent: Option<ProcessRef>,
|
||||||
no_parent: bool,
|
no_parent: bool,
|
||||||
|
sig_dispositions: Option<SigDispositions>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ProcessBuilder {
|
impl ProcessBuilder {
|
||||||
@ -30,6 +31,7 @@ impl ProcessBuilder {
|
|||||||
exec_path: None,
|
exec_path: None,
|
||||||
parent: None,
|
parent: None,
|
||||||
no_parent: false,
|
no_parent: false,
|
||||||
|
sig_dispositions: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -53,6 +55,11 @@ impl ProcessBuilder {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn sig_dispositions(mut self, sig_dispositions: SigDispositions) -> Self {
|
||||||
|
self.sig_dispositions = Some(sig_dispositions);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
pub fn task(mut self, task: Task) -> Self {
|
pub fn task(mut self, task: Task) -> Self {
|
||||||
self.thread_builder(|tb| tb.task(task))
|
self.thread_builder(|tb| tb.task(task))
|
||||||
}
|
}
|
||||||
@ -73,6 +80,10 @@ impl ProcessBuilder {
|
|||||||
self.thread_builder(|tb| tb.files(files))
|
self.thread_builder(|tb| tb.files(files))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn sig_mask(mut self, sig_mask: SigSet) -> Self {
|
||||||
|
self.thread_builder(|tb| tb.sig_mask(sig_mask))
|
||||||
|
}
|
||||||
|
|
||||||
pub fn rlimits(mut self, rlimits: ResourceLimitsRef) -> Self {
|
pub fn rlimits(mut self, rlimits: ResourceLimitsRef) -> Self {
|
||||||
self.thread_builder(|tb| tb.rlimits(rlimits))
|
self.thread_builder(|tb| tb.rlimits(rlimits))
|
||||||
}
|
}
|
||||||
@ -99,7 +110,7 @@ impl ProcessBuilder {
|
|||||||
let exec_path = self.exec_path.take().unwrap_or_default();
|
let exec_path = self.exec_path.take().unwrap_or_default();
|
||||||
let parent = self.parent.take().map(|parent| RwLock::new(parent));
|
let parent = self.parent.take().map(|parent| RwLock::new(parent));
|
||||||
let inner = SgxMutex::new(ProcessInner::new());
|
let inner = SgxMutex::new(ProcessInner::new());
|
||||||
let sig_dispositions = RwLock::new(SigDispositions::new());
|
let sig_dispositions = RwLock::new(self.sig_dispositions.unwrap_or_default());
|
||||||
let sig_queues = RwLock::new(SigQueues::new());
|
let sig_queues = RwLock::new(SigQueues::new());
|
||||||
let forced_exit_status = ForcedExitStatus::new();
|
let forced_exit_status = ForcedExitStatus::new();
|
||||||
Arc::new(Process {
|
Arc::new(Process {
|
||||||
|
87
src/libos/src/process/spawn_attribute.rs
Normal file
87
src/libos/src/process/spawn_attribute.rs
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
use super::*;
|
||||||
|
use crate::signal::{sigset_t, SigSet};
|
||||||
|
use crate::util::mem_util::from_user::check_ptr;
|
||||||
|
|
||||||
|
// Note: This is the Rust representation of `posix_spawnattr_t` defined in libc.
|
||||||
|
// The name of the elements follow the glibc style. The comments show the name in musl.
|
||||||
|
// Elements other than the listed ones are ignored because we don't care for now because
|
||||||
|
// Only POSIX_SPAWN_SETSIGDEF and POSIX_SPAWN_SETSIGMASK are supported now.
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct posix_spawnattr_t {
|
||||||
|
flags: SpawnAttributeFlags, // __flags
|
||||||
|
pgrp: i32, // __pgrp
|
||||||
|
sd: SpawnAttrSigSet, // __def
|
||||||
|
ss: SpawnAttrSigSet, // __mask
|
||||||
|
}
|
||||||
|
|
||||||
|
// Glibc and musl use 128 bytes to represent sig_set_t
|
||||||
|
type SpawnAttrSigSet = [sigset_t; 16];
|
||||||
|
|
||||||
|
bitflags! {
|
||||||
|
pub struct SpawnAttributeFlags: u16 {
|
||||||
|
const POSIX_SPAWN_RESETIDS = 1; // 0x1
|
||||||
|
const POSIX_SPAWN_SETPGROUP = 1 << 1; // 0x2
|
||||||
|
const POSIX_SPAWN_SETSIGDEF = 1 << 2; // 0x4
|
||||||
|
const POSIX_SPAWN_SETSIGMASK = 1 << 3; // 0x8
|
||||||
|
const POSIX_SPAWN_SETSCHEDPARAM = 1 << 4; // 0x10
|
||||||
|
const POSIX_SPAWN_SETSCHEDULER = 1 << 5; // 0x20
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SpawnAttributeFlags {
|
||||||
|
fn supported(&self) -> bool {
|
||||||
|
let unsupported_flags = SpawnAttributeFlags::all()
|
||||||
|
- SpawnAttributeFlags::POSIX_SPAWN_SETSIGDEF
|
||||||
|
- SpawnAttributeFlags::POSIX_SPAWN_SETSIGMASK;
|
||||||
|
if self.intersects(unsupported_flags) {
|
||||||
|
false
|
||||||
|
} else {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default, Debug, Copy, Clone)]
|
||||||
|
pub struct SpawnAttr {
|
||||||
|
pub sig_mask: Option<SigSet>,
|
||||||
|
pub sig_default: Option<SigSet>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn clone_spawn_atrributes_safely(
|
||||||
|
attr_ptr: *const posix_spawnattr_t,
|
||||||
|
) -> Result<Option<SpawnAttr>> {
|
||||||
|
if attr_ptr != std::ptr::null() {
|
||||||
|
check_ptr(attr_ptr)?;
|
||||||
|
} else {
|
||||||
|
return Ok(None);
|
||||||
|
}
|
||||||
|
|
||||||
|
let spawn_attr = unsafe { &*attr_ptr };
|
||||||
|
let mut safe_attr = SpawnAttr::default();
|
||||||
|
if spawn_attr.flags.is_empty() {
|
||||||
|
return Ok(None);
|
||||||
|
}
|
||||||
|
|
||||||
|
if !spawn_attr.flags.supported() {
|
||||||
|
warn!(
|
||||||
|
"Unsupported flags contained. Attribute flags: {:?}",
|
||||||
|
spawn_attr.flags
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if spawn_attr
|
||||||
|
.flags
|
||||||
|
.contains(SpawnAttributeFlags::POSIX_SPAWN_SETSIGDEF)
|
||||||
|
{
|
||||||
|
safe_attr.sig_default = Some(SigSet::from_c(spawn_attr.sd[0]));
|
||||||
|
}
|
||||||
|
if spawn_attr
|
||||||
|
.flags
|
||||||
|
.contains(SpawnAttributeFlags::POSIX_SPAWN_SETSIGMASK)
|
||||||
|
{
|
||||||
|
safe_attr.sig_mask = Some(SigSet::from_c(spawn_attr.ss[0]));
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(Some(safe_attr))
|
||||||
|
}
|
@ -5,6 +5,7 @@ use super::do_spawn::FileAction;
|
|||||||
use super::do_wait4::WaitOptions;
|
use super::do_wait4::WaitOptions;
|
||||||
use super::prctl::PrctlCmd;
|
use super::prctl::PrctlCmd;
|
||||||
use super::process::ProcessFilter;
|
use super::process::ProcessFilter;
|
||||||
|
use super::spawn_attribute::{clone_spawn_atrributes_safely, posix_spawnattr_t, SpawnAttr};
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use crate::time::{timespec_t, ClockID};
|
use crate::time::{timespec_t, ClockID};
|
||||||
use crate::util::mem_util::from_user::*;
|
use crate::util::mem_util::from_user::*;
|
||||||
@ -16,19 +17,22 @@ pub fn do_spawn_for_musl(
|
|||||||
argv: *const *const i8,
|
argv: *const *const i8,
|
||||||
envp: *const *const i8,
|
envp: *const *const i8,
|
||||||
fdop_list: *const FdOp,
|
fdop_list: *const FdOp,
|
||||||
|
attribute_list: *const posix_spawnattr_t,
|
||||||
) -> Result<isize> {
|
) -> Result<isize> {
|
||||||
check_mut_ptr(child_pid_ptr)?;
|
check_mut_ptr(child_pid_ptr)?;
|
||||||
let path = clone_cstring_safely(path)?.to_string_lossy().into_owned();
|
let path = clone_cstring_safely(path)?.to_string_lossy().into_owned();
|
||||||
let argv = clone_cstrings_safely(argv)?;
|
let argv = clone_cstrings_safely(argv)?;
|
||||||
let envp = clone_cstrings_safely(envp)?;
|
let envp = clone_cstrings_safely(envp)?;
|
||||||
let file_actions = clone_file_actions_safely(fdop_list)?;
|
let file_actions = clone_file_actions_safely(fdop_list)?;
|
||||||
|
let spawn_attrs = clone_spawn_atrributes_safely(attribute_list)?;
|
||||||
let current = current!();
|
let current = current!();
|
||||||
debug!(
|
debug!(
|
||||||
"spawn: path: {:?}, argv: {:?}, envp: {:?}, fdop: {:?}",
|
"spawn: path: {:?}, argv: {:?}, envp: {:?}, fdop: {:?}, spawn_attr: {:?}",
|
||||||
path, argv, envp, file_actions
|
path, argv, envp, file_actions, spawn_attrs
|
||||||
);
|
);
|
||||||
|
|
||||||
let child_pid = super::do_spawn::do_spawn(&path, &argv, &envp, &file_actions, ¤t)?;
|
let child_pid =
|
||||||
|
super::do_spawn::do_spawn(&path, &argv, &envp, &file_actions, spawn_attrs, ¤t)?;
|
||||||
|
|
||||||
unsafe { *child_pid_ptr = child_pid };
|
unsafe { *child_pid_ptr = child_pid };
|
||||||
Ok(0)
|
Ok(0)
|
||||||
@ -92,19 +96,22 @@ pub fn do_spawn_for_glibc(
|
|||||||
argv: *const *const i8,
|
argv: *const *const i8,
|
||||||
envp: *const *const i8,
|
envp: *const *const i8,
|
||||||
fa: *const SpawnFileActions,
|
fa: *const SpawnFileActions,
|
||||||
|
attribute_list: *const posix_spawnattr_t,
|
||||||
) -> Result<isize> {
|
) -> Result<isize> {
|
||||||
check_mut_ptr(child_pid_ptr)?;
|
check_mut_ptr(child_pid_ptr)?;
|
||||||
let path = clone_cstring_safely(path)?.to_string_lossy().into_owned();
|
let path = clone_cstring_safely(path)?.to_string_lossy().into_owned();
|
||||||
let argv = clone_cstrings_safely(argv)?;
|
let argv = clone_cstrings_safely(argv)?;
|
||||||
let envp = clone_cstrings_safely(envp)?;
|
let envp = clone_cstrings_safely(envp)?;
|
||||||
let file_actions = clone_file_actions_from_fa_safely(fa)?;
|
let file_actions = clone_file_actions_from_fa_safely(fa)?;
|
||||||
|
let spawn_attrs = clone_spawn_atrributes_safely(attribute_list)?;
|
||||||
let current = current!();
|
let current = current!();
|
||||||
debug!(
|
debug!(
|
||||||
"spawn: path: {:?}, argv: {:?}, envp: {:?}, actions: {:?}",
|
"spawn: path: {:?}, argv: {:?}, envp: {:?}, actions: {:?}, attributes: {:?}",
|
||||||
path, argv, envp, file_actions
|
path, argv, envp, file_actions, spawn_attrs
|
||||||
);
|
);
|
||||||
|
|
||||||
let child_pid = super::do_spawn::do_spawn(&path, &argv, &envp, &file_actions, ¤t)?;
|
let child_pid =
|
||||||
|
super::do_spawn::do_spawn(&path, &argv, &envp, &file_actions, spawn_attrs, ¤t)?;
|
||||||
|
|
||||||
unsafe { *child_pid_ptr = child_pid };
|
unsafe { *child_pid_ptr = child_pid };
|
||||||
Ok(0)
|
Ok(0)
|
||||||
|
@ -20,6 +20,7 @@ pub struct ThreadBuilder {
|
|||||||
files: Option<FileTableRef>,
|
files: Option<FileTableRef>,
|
||||||
sched: Option<SchedAgentRef>,
|
sched: Option<SchedAgentRef>,
|
||||||
rlimits: Option<ResourceLimitsRef>,
|
rlimits: Option<ResourceLimitsRef>,
|
||||||
|
sig_mask: Option<SigSet>,
|
||||||
clear_ctid: Option<NonNull<pid_t>>,
|
clear_ctid: Option<NonNull<pid_t>>,
|
||||||
name: Option<ThreadName>,
|
name: Option<ThreadName>,
|
||||||
}
|
}
|
||||||
@ -35,6 +36,7 @@ impl ThreadBuilder {
|
|||||||
files: None,
|
files: None,
|
||||||
sched: None,
|
sched: None,
|
||||||
rlimits: None,
|
rlimits: None,
|
||||||
|
sig_mask: None,
|
||||||
clear_ctid: None,
|
clear_ctid: None,
|
||||||
name: None,
|
name: None,
|
||||||
}
|
}
|
||||||
@ -70,6 +72,11 @@ impl ThreadBuilder {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn sig_mask(mut self, sig_mask: SigSet) -> Self {
|
||||||
|
self.sig_mask = Some(sig_mask);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
pub fn sched(mut self, sched: SchedAgentRef) -> Self {
|
pub fn sched(mut self, sched: SchedAgentRef) -> Self {
|
||||||
self.sched = Some(sched);
|
self.sched = Some(sched);
|
||||||
self
|
self
|
||||||
@ -108,8 +115,8 @@ impl ThreadBuilder {
|
|||||||
let sched = self.sched.unwrap_or_default();
|
let sched = self.sched.unwrap_or_default();
|
||||||
let rlimits = self.rlimits.unwrap_or_default();
|
let rlimits = self.rlimits.unwrap_or_default();
|
||||||
let name = RwLock::new(self.name.unwrap_or_default());
|
let name = RwLock::new(self.name.unwrap_or_default());
|
||||||
|
let sig_mask = RwLock::new(self.sig_mask.unwrap_or_default());
|
||||||
let sig_queues = RwLock::new(SigQueues::new());
|
let sig_queues = RwLock::new(SigQueues::new());
|
||||||
let sig_mask = RwLock::new(SigSet::new_empty());
|
|
||||||
let sig_tmp_mask = RwLock::new(SigSet::new_empty());
|
let sig_tmp_mask = RwLock::new(SigSet::new_empty());
|
||||||
let sig_stack = SgxMutex::new(None);
|
let sig_stack = SgxMutex::new(None);
|
||||||
let profiler = if cfg!(feature = "syscall_timing") {
|
let profiler = if cfg!(feature = "syscall_timing") {
|
||||||
|
@ -27,10 +27,32 @@ impl SigDispositions {
|
|||||||
self.map[idx] = sa;
|
self.map[idx] = sa;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_default(&mut self, num: SigNum) {
|
||||||
|
let idx = Self::num_to_idx(num);
|
||||||
|
self.map[idx] = SigAction::Dfl;
|
||||||
|
}
|
||||||
|
|
||||||
pub fn iter<'a>(&'a self) -> SigDispositionsIter<'a> {
|
pub fn iter<'a>(&'a self) -> SigDispositionsIter<'a> {
|
||||||
SigDispositionsIter::new(self)
|
SigDispositionsIter::new(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// inherit sigdispositions for child process, user defined sigaction should be set to default
|
||||||
|
pub fn inherit(&mut self) {
|
||||||
|
for mut sigaction in &mut self.map {
|
||||||
|
match sigaction {
|
||||||
|
SigAction::User {
|
||||||
|
handler_addr,
|
||||||
|
flags,
|
||||||
|
restorer_addr,
|
||||||
|
mask,
|
||||||
|
} => {
|
||||||
|
*sigaction = SigAction::Dfl;
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn num_to_idx(num: SigNum) -> usize {
|
fn num_to_idx(num: SigNum) -> usize {
|
||||||
(num.as_u8() - MIN_STD_SIG_NUM) as usize
|
(num.as_u8() - MIN_STD_SIG_NUM) as usize
|
||||||
}
|
}
|
||||||
@ -81,7 +103,7 @@ impl Default for SigDispositions {
|
|||||||
|
|
||||||
impl fmt::Debug for SigDispositions {
|
impl fmt::Debug for SigDispositions {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
write!(f, "SigDispositions ");
|
write!(f, "SigDispositions (only none-default is shown) ");
|
||||||
let non_default_dispositions = self.iter().filter(|(_, action)| **action != SigAction::Dfl);
|
let non_default_dispositions = self.iter().filter(|(_, action)| **action != SigAction::Dfl);
|
||||||
f.debug_map().entries(non_default_dispositions).finish()
|
f.debug_map().entries(non_default_dispositions).finish()
|
||||||
}
|
}
|
||||||
|
@ -42,7 +42,8 @@ use crate::net::{
|
|||||||
use crate::process::{
|
use crate::process::{
|
||||||
do_arch_prctl, do_clone, do_exit, do_exit_group, do_futex, do_getegid, do_geteuid, do_getgid,
|
do_arch_prctl, do_clone, do_exit, do_exit_group, do_futex, do_getegid, do_geteuid, do_getgid,
|
||||||
do_getpgid, do_getpid, do_getppid, do_gettid, do_getuid, do_prctl, do_set_tid_address,
|
do_getpgid, do_getpid, do_getppid, do_gettid, do_getuid, do_prctl, do_set_tid_address,
|
||||||
do_spawn_for_glibc, do_spawn_for_musl, do_wait4, pid_t, FdOp, SpawnFileActions, ThreadStatus,
|
do_spawn_for_glibc, do_spawn_for_musl, do_wait4, pid_t, posix_spawnattr_t, FdOp,
|
||||||
|
SpawnFileActions, ThreadStatus,
|
||||||
};
|
};
|
||||||
use crate::sched::{do_getcpu, do_sched_getaffinity, do_sched_setaffinity, do_sched_yield};
|
use crate::sched::{do_getcpu, do_sched_getaffinity, do_sched_setaffinity, do_sched_yield};
|
||||||
use crate::signal::{
|
use crate::signal::{
|
||||||
@ -412,8 +413,8 @@ macro_rules! process_syscall_table_with_callback {
|
|||||||
(Mlock2 = 325) => handle_unsupported(),
|
(Mlock2 = 325) => handle_unsupported(),
|
||||||
|
|
||||||
// Occlum-specific system calls
|
// Occlum-specific system calls
|
||||||
(SpawnGlibc = 359) => do_spawn_for_glibc(child_pid_ptr: *mut u32, path: *const i8, argv: *const *const i8, envp: *const *const i8, fa: *const SpawnFileActions),
|
(SpawnGlibc = 359) => do_spawn_for_glibc(child_pid_ptr: *mut u32, path: *const i8, argv: *const *const i8, envp: *const *const i8, fa: *const SpawnFileActions, attribute_list: *const posix_spawnattr_t),
|
||||||
(SpawnMusl = 360) => do_spawn_for_musl(child_pid_ptr: *mut u32, path: *const i8, argv: *const *const i8, envp: *const *const i8, fdop_list: *const FdOp),
|
(SpawnMusl = 360) => do_spawn_for_musl(child_pid_ptr: *mut u32, path: *const i8, argv: *const *const i8, envp: *const *const i8, fdop_list: *const FdOp, attribute_list: *const posix_spawnattr_t),
|
||||||
(HandleException = 361) => do_handle_exception(info: *mut sgx_exception_info_t, fpregs: *mut FpRegs, context: *mut CpuContext),
|
(HandleException = 361) => do_handle_exception(info: *mut sgx_exception_info_t, fpregs: *mut FpRegs, context: *mut CpuContext),
|
||||||
(HandleInterrupt = 362) => do_handle_interrupt(info: *mut sgx_interrupt_info_t, fpregs: *mut FpRegs, context: *mut CpuContext),
|
(HandleInterrupt = 362) => do_handle_interrupt(info: *mut sgx_interrupt_info_t, fpregs: *mut FpRegs, context: *mut CpuContext),
|
||||||
(MountRootFS = 363) => do_mount_rootfs(key_ptr: *const sgx_key_128bit_t, occlum_json_mac_ptr: *const sgx_aes_gcm_128bit_tag_t),
|
(MountRootFS = 363) => do_mount_rootfs(key_ptr: *const sgx_key_128bit_t, occlum_json_mac_ptr: *const sgx_aes_gcm_128bit_tag_t),
|
||||||
|
@ -13,12 +13,12 @@ PASS_LOG = $(BUILD_DIR)/test/.pass
|
|||||||
FAIL_LOG = $(BUILD_DIR)/test/.fail
|
FAIL_LOG = $(BUILD_DIR)/test/.fail
|
||||||
|
|
||||||
# Dependencies: need to be compiled but not to run by any Makefile target
|
# Dependencies: need to be compiled but not to run by any Makefile target
|
||||||
TEST_DEPS := client data_sink
|
TEST_DEPS := client data_sink naughty_child
|
||||||
# Tests: need to be compiled and run by test-% target
|
# Tests: need to be compiled and run by test-% target
|
||||||
TESTS ?= env empty hello_world malloc mmap file fs_perms getpid spawn sched pipe time \
|
TESTS ?= env empty hello_world malloc mmap file fs_perms getpid spawn sched pipe time \
|
||||||
truncate readdir mkdir open stat link symlink chmod chown tls pthread uname rlimit \
|
truncate readdir mkdir open stat link symlink chmod chown tls pthread uname rlimit \
|
||||||
server server_epoll unix_socket cout hostfs cpuid rdtsc device sleep exit_group \
|
server server_epoll unix_socket cout hostfs cpuid rdtsc device sleep exit_group \
|
||||||
ioctl fcntl eventfd emulate_syscall access signal sysinfo prctl rename procfs wait
|
ioctl fcntl eventfd emulate_syscall access signal sysinfo prctl rename procfs wait spawn_attribute
|
||||||
# Benchmarks: need to be compiled and run by bench-% target
|
# Benchmarks: need to be compiled and run by bench-% target
|
||||||
BENCHES := spawn_and_exit_latency pipe_throughput unix_socket_throughput
|
BENCHES := spawn_and_exit_latency pipe_throughput unix_socket_throughput
|
||||||
|
|
||||||
|
5
test/naughty_child/Makefile
Normal file
5
test/naughty_child/Makefile
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
include ../test_common.mk
|
||||||
|
|
||||||
|
EXTRA_C_FLAGS := -g
|
||||||
|
EXTRA_LINK_FLAGS :=
|
||||||
|
BIN_ARGS :=
|
127
test/naughty_child/main.c
Normal file
127
test/naughty_child/main.c
Normal file
@ -0,0 +1,127 @@
|
|||||||
|
// This test file may used by other test to test children behaviour spawned.
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <features.h>
|
||||||
|
#include "test.h"
|
||||||
|
|
||||||
|
void sigio_handler(int sig) {
|
||||||
|
printf("[child] SIGIO is caught in child!\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void sigabort_handler(int sig) {
|
||||||
|
printf("[child] sigabort is caught in child! This shouldn't happen!\n");
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parent process has set the sigmask of this child process to block SIGABORT by inheritage or posix_spawnattr_t
|
||||||
|
int test_spawn_attribute_sigmask() {
|
||||||
|
printf("[child] Run a child process with pid = %d and ppid = %d\n", getpid(), getppid());
|
||||||
|
|
||||||
|
#ifndef __GLIBC__
|
||||||
|
// musl can perform extra checks
|
||||||
|
struct __sigset_t current_block_sigmask;
|
||||||
|
struct __sigset_t test;
|
||||||
|
#else
|
||||||
|
sigset_t current_block_sigmask, test;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
sigprocmask(0, NULL, ¤t_block_sigmask);
|
||||||
|
sigemptyset(&test);
|
||||||
|
sigaddset(&test, SIGABRT);
|
||||||
|
|
||||||
|
#ifndef __GLIBC__
|
||||||
|
if (current_block_sigmask.__bits[0] != test.__bits[0]) {
|
||||||
|
THROW_ERROR("[child] signask in child process is wrong");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
signal(SIGIO, sigio_handler);
|
||||||
|
signal(SIGABRT, sigabort_handler);
|
||||||
|
raise(SIGIO);
|
||||||
|
raise(SIGABRT);
|
||||||
|
|
||||||
|
printf("[child] child test_spawn_attribute_sigmask - [Ok]\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parent process will set the sigaction of SIGALRM and SIGILL to SIG_IGN and SIGIO to user-defined handler. Then use posix_spawn attribute to set
|
||||||
|
// SIGALRM to SIG_DEF.
|
||||||
|
// Child process should inherit the ignore action of SIGILL and change SIGALRM and SIGIO sigaction to SIG_DEF.
|
||||||
|
int test_spawn_attribute_sigdef() {
|
||||||
|
struct sigaction action;
|
||||||
|
|
||||||
|
sigaction(SIGALRM, NULL, &action);
|
||||||
|
if (action.sa_handler != SIG_DFL) {
|
||||||
|
THROW_ERROR("[child] sig handler of SIGALRM is wrong");
|
||||||
|
}
|
||||||
|
|
||||||
|
sigaction(SIGIO, NULL, &action);
|
||||||
|
if (action.sa_handler != SIG_DFL) {
|
||||||
|
THROW_ERROR("[child] sig handler of SIGIO is wrong");
|
||||||
|
}
|
||||||
|
|
||||||
|
sigaction(SIGILL, NULL, &action);
|
||||||
|
if (action.sa_handler != SIG_IGN) {
|
||||||
|
THROW_ERROR("[child] sig handler of SIGILL is wrong");
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("[child] child test_spawn_attribute_sigdef - [Ok]\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Test suite
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
#define TEST_NAME_MAX 20
|
||||||
|
|
||||||
|
int start_test(const char *test_name) {
|
||||||
|
if (strcmp(test_name, "sigmask") == 0) {
|
||||||
|
return test_spawn_attribute_sigmask();
|
||||||
|
} else if (strcmp(test_name, "sigdef") == 0) {
|
||||||
|
return test_spawn_attribute_sigdef();
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "[child] test case not found\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void print_usage() {
|
||||||
|
fprintf(stderr, "Usage:\n nauty_child [-t testcase1] [-t testcase2] ...\n\n");
|
||||||
|
fprintf(stderr, " Now support testcase: <sigmask, sigdef>\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
if (argc <= 1) {
|
||||||
|
print_usage();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int opt;
|
||||||
|
char *testcase_name = calloc(1, TEST_NAME_MAX);
|
||||||
|
while ((opt = getopt(argc, argv, "t:")) != -1) {
|
||||||
|
switch (opt) {
|
||||||
|
case 't': {
|
||||||
|
int len = strlen(optarg);
|
||||||
|
if (len >= TEST_NAME_MAX) {
|
||||||
|
THROW_ERROR("[child] test case name too long");
|
||||||
|
}
|
||||||
|
memset(testcase_name, 0, TEST_NAME_MAX);
|
||||||
|
strncpy(testcase_name, optarg, len + 1);
|
||||||
|
printf("[child] start testcase: %s\n", testcase_name);
|
||||||
|
int ret = start_test(testcase_name);
|
||||||
|
if (ret != 0) {
|
||||||
|
THROW_ERROR("[child] test case failure");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
print_usage();
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
free(testcase_name);
|
||||||
|
return 0;
|
||||||
|
}
|
5
test/spawn_attribute/Makefile
Normal file
5
test/spawn_attribute/Makefile
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
include ../test_common.mk
|
||||||
|
|
||||||
|
EXTRA_C_FLAGS := -lpthread -g
|
||||||
|
EXTRA_LINK_FLAGS :=
|
||||||
|
BIN_ARGS :=
|
270
test/spawn_attribute/main.c
Normal file
270
test/spawn_attribute/main.c
Normal file
@ -0,0 +1,270 @@
|
|||||||
|
#include <spawn.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include "test.h"
|
||||||
|
|
||||||
|
void sigchld_handler(int sig) {
|
||||||
|
printf("SIGCHLD is caught in father process!\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void sigio_handler(int sig) {
|
||||||
|
printf("SIGIO is caught in father process!\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *thread_func(void *_arg) {
|
||||||
|
#ifndef __GLIBC__
|
||||||
|
// musl can perform extra checks
|
||||||
|
// child thread sigmask should be same with father thread
|
||||||
|
struct __sigset_t *father_thread_mask = (struct __sigset_t *)_arg;
|
||||||
|
struct __sigset_t current_mask;
|
||||||
|
sigprocmask(0, NULL, ¤t_mask);
|
||||||
|
assert(father_thread_mask->__bits[0] == current_mask.__bits[0]);
|
||||||
|
printf("[child thread] father: %ld, child: %ld\n", father_thread_mask->__bits[0],
|
||||||
|
current_mask.__bits[0]);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// SIGIO is IGNORED and shouldn't be handled
|
||||||
|
raise(SIGIO);
|
||||||
|
printf("[child thread] SIGIO is ignored\n");
|
||||||
|
raise(SIGABRT);
|
||||||
|
printf("[child thread] SIGABRT is sigmasked\n");
|
||||||
|
|
||||||
|
// change sigmask in child thread and monitor in father thread
|
||||||
|
#ifndef __GLIBC__
|
||||||
|
struct __sigset_t new_sigmask;
|
||||||
|
#else
|
||||||
|
sigset_t new_sigmask;
|
||||||
|
#endif
|
||||||
|
sigemptyset(&new_sigmask);
|
||||||
|
sigaddset(&new_sigmask, SIGALRM);
|
||||||
|
sigprocmask(SIG_BLOCK, &new_sigmask, NULL);
|
||||||
|
|
||||||
|
// change SIGIO sigaction in child thread and monitor in father thread
|
||||||
|
signal(SIGIO, sigio_handler);
|
||||||
|
printf("[child thread] SIGIO handler is changed\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Each thread of a process has its own sigmask but a process has the same sigaction for different thread。
|
||||||
|
// Father thread set SIGIO to SIG_IGN, and block SIGABRT. Child thread inherits the sigmask and sigaction and
|
||||||
|
// change both sigmask and sigaction. Father thread's sigmask is not changed but sigaction of SIGIO is changed.
|
||||||
|
int test_thread_inheritage() {
|
||||||
|
int ret;
|
||||||
|
printf("Run a parent process has pid = %d and ppid = %d\n", getpid(), getppid());
|
||||||
|
|
||||||
|
signal(SIGIO, SIG_IGN);
|
||||||
|
raise(SIGIO); // this should be ignored
|
||||||
|
printf("SIGIO is ignored.\n");
|
||||||
|
|
||||||
|
#ifndef __GLIBC__
|
||||||
|
struct __sigset_t sig_set;
|
||||||
|
#else
|
||||||
|
sigset_t sig_set;
|
||||||
|
#endif
|
||||||
|
sigemptyset (&sig_set);
|
||||||
|
sigaddset(&sig_set, SIGABRT);
|
||||||
|
sigprocmask(SIG_BLOCK, &sig_set, NULL);
|
||||||
|
|
||||||
|
// child thread will change the sigmask and change sigaction of SIGIO to signal handler
|
||||||
|
pthread_t tid;
|
||||||
|
ret = pthread_create(&tid, NULL, thread_func, (void *)&sig_set);
|
||||||
|
if (ret != 0) {
|
||||||
|
THROW_ERROR("create child error");
|
||||||
|
}
|
||||||
|
|
||||||
|
pthread_join(tid, NULL);
|
||||||
|
|
||||||
|
#ifndef __GLIBC__
|
||||||
|
// sigmask of father thread shouldn't be changed by child thread
|
||||||
|
struct __sigset_t current_block_sigmask_master;
|
||||||
|
sigprocmask(0, NULL, ¤t_block_sigmask_master);
|
||||||
|
assert(current_block_sigmask_master.__bits[0] == sig_set.__bits[0]);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// SIGIO sigaction should be changed by child thread
|
||||||
|
printf("SIGIO should be handled:\n");
|
||||||
|
raise(SIGIO); // this should be handled
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parent process sets the sigmask of this child process to block SIGABORT by inheritage or posix_spawnattr_t.
|
||||||
|
int test_spawn_attribute_setsigmask() {
|
||||||
|
int ret, child_pid, status;
|
||||||
|
printf("Run a parent process has pid = %d and ppid = %d\n", getpid(), getppid());
|
||||||
|
|
||||||
|
// construct child process args
|
||||||
|
int child_argc = 3; // ./nauty_child -t sigmask
|
||||||
|
char **child_argv = calloc(1, sizeof(char *) * (child_argc + 1));
|
||||||
|
child_argv[0] = strdup("naughty_child");
|
||||||
|
child_argv[1] = strdup("-t");
|
||||||
|
child_argv[2] = strdup("sigmask");
|
||||||
|
|
||||||
|
signal(SIGIO, sigio_handler);
|
||||||
|
sigset_t sig_set;
|
||||||
|
sigemptyset (&sig_set);
|
||||||
|
sigaddset(&sig_set, SIGABRT);
|
||||||
|
sigprocmask(SIG_BLOCK, &sig_set, NULL);
|
||||||
|
// child process should inherit sigmask to block SIGABRT
|
||||||
|
ret = posix_spawn(&child_pid, "/bin/naughty_child", NULL, NULL, child_argv, NULL);
|
||||||
|
if (ret != 0) {
|
||||||
|
THROW_ERROR("failed to spawn a child process\n");
|
||||||
|
}
|
||||||
|
printf("Spawn a new proces successfully (pid = %d)\n", child_pid);
|
||||||
|
|
||||||
|
ret = waitpid(child_pid, &status, 0);
|
||||||
|
if (ret < 0) {
|
||||||
|
THROW_ERROR("failed to wait4 the child process\n");
|
||||||
|
}
|
||||||
|
printf("child process %d exit status = %d\n", child_pid, status);
|
||||||
|
if (status != 0) {
|
||||||
|
THROW_ERROR("child process exit with error");
|
||||||
|
}
|
||||||
|
|
||||||
|
// make parent process block SIGIO
|
||||||
|
sigaddset(&sig_set, SIGIO);
|
||||||
|
sigprocmask(SIG_BLOCK, &sig_set, NULL);
|
||||||
|
|
||||||
|
posix_spawnattr_t attr;
|
||||||
|
posix_spawnattr_init(&attr);
|
||||||
|
|
||||||
|
posix_spawnattr_setflags(&attr, POSIX_SPAWN_SETSIGMASK);
|
||||||
|
sigdelset(&sig_set, SIGIO); // Child process don't block SIGIO
|
||||||
|
posix_spawnattr_setsigmask(&attr, &sig_set);
|
||||||
|
|
||||||
|
ret = posix_spawn(&child_pid, "/bin/naughty_child", NULL, &attr, child_argv, NULL);
|
||||||
|
if (ret != 0) {
|
||||||
|
THROW_ERROR("failed to spawn a child process");
|
||||||
|
}
|
||||||
|
printf("Spawn a new proces successfully (pid = %d)\n", child_pid);
|
||||||
|
|
||||||
|
ret = waitpid(child_pid, &status, 0);
|
||||||
|
if (ret < 0) {
|
||||||
|
THROW_ERROR("failed to wait4 the child process");
|
||||||
|
}
|
||||||
|
printf("child process %d exit status = %d\n", child_pid, status);
|
||||||
|
if (status != 0) {
|
||||||
|
THROW_ERROR("child process exit with error");
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parent process sets the sigaction of SIGALRM and SIGILL to SIG_IGN and SIGIO to user-defined handler. Then use posix_spawn attribute to set
|
||||||
|
// SIGALRM to SIG_DEF for child process.
|
||||||
|
// Child process should inherit the ignore action of SIGILL and change SIGALRM and SIGIO sigaction to SIG_DEF.
|
||||||
|
int test_spawn_attribute_setsigdef() {
|
||||||
|
int ret, child_pid, status;
|
||||||
|
printf("Run a parent process has pid = %d and ppid = %d\n", getpid(), getppid());
|
||||||
|
|
||||||
|
// construct child process args
|
||||||
|
int child_argc = 3; // ./nauty_child -t sigdef
|
||||||
|
char **child_argv = calloc(1, sizeof(char *) * (child_argc + 1));
|
||||||
|
child_argv[0] = strdup("naughty_child");
|
||||||
|
child_argv[1] = strdup("-t");
|
||||||
|
child_argv[2] = strdup("sigdef");
|
||||||
|
|
||||||
|
// parent process ignore SIGALRM and SIGILL and use user-defined signal handler for SIGIO
|
||||||
|
signal(SIGIO, sigio_handler);
|
||||||
|
signal(SIGILL, SIG_IGN);
|
||||||
|
signal(SIGALRM, SIG_IGN);
|
||||||
|
raise(SIGIO);
|
||||||
|
raise(SIGILL);
|
||||||
|
raise(SIGALRM);
|
||||||
|
printf("parent process shouldn't handle SIGALRM and SIGILL\n");
|
||||||
|
|
||||||
|
// use spawn attribute to set SIGALRM to default action
|
||||||
|
sigset_t child_default_sigset;
|
||||||
|
sigemptyset(&child_default_sigset);
|
||||||
|
sigaddset(&child_default_sigset, SIGALRM);
|
||||||
|
posix_spawnattr_t attr;
|
||||||
|
posix_spawnattr_init(&attr);
|
||||||
|
posix_spawnattr_setflags(&attr, POSIX_SPAWN_SETSIGDEF);
|
||||||
|
posix_spawnattr_setsigdefault(&attr, &child_default_sigset);
|
||||||
|
|
||||||
|
// child process should inherit sigaction to ignore SIGILL and set SIGIO and SIGALRM to SIG_DEF
|
||||||
|
ret = posix_spawn(&child_pid, "/bin/naughty_child", NULL, &attr, child_argv, NULL);
|
||||||
|
if (ret != 0) {
|
||||||
|
THROW_ERROR("failed to spawn a child process");
|
||||||
|
}
|
||||||
|
ret = waitpid(child_pid, &status, 0);
|
||||||
|
if (ret < 0) {
|
||||||
|
THROW_ERROR("failed to wait4 the child process");
|
||||||
|
}
|
||||||
|
printf("child process %d exit status = %d\n", child_pid, status);
|
||||||
|
if (status != 0) {
|
||||||
|
THROW_ERROR("child process exit with error");
|
||||||
|
}
|
||||||
|
|
||||||
|
raise(SIGIO);
|
||||||
|
raise(SIGILL);
|
||||||
|
raise(SIGALRM);
|
||||||
|
printf("parent process shouldn't handle SIGALRM and SIGILL\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create child process to pass naughty_child test by posix spawn attributes.
|
||||||
|
int test_multiple_spawn_attribute() {
|
||||||
|
int ret, child_pid, status;
|
||||||
|
printf("Run a parent process has pid = %d and ppid = %d\n", getpid(), getppid());
|
||||||
|
|
||||||
|
// construct child process args
|
||||||
|
int child_argc = 5; // ./naughty_child -t sigdef -t sigmask
|
||||||
|
char **child_argv = calloc(1, sizeof(char *) * (child_argc + 1));
|
||||||
|
child_argv[0] = strdup("naughty_child");
|
||||||
|
child_argv[1] = strdup("-t");
|
||||||
|
child_argv[2] =
|
||||||
|
strdup("sigdef"); // child process SIGALRM and SIGIO have default action and SIGILL is ignored
|
||||||
|
child_argv[3] = strdup("-t");
|
||||||
|
child_argv[4] = strdup("sigmask"); // child process block SIGABORT
|
||||||
|
|
||||||
|
posix_spawnattr_t attr;
|
||||||
|
posix_spawnattr_init(&attr);
|
||||||
|
posix_spawnattr_setflags(&attr, POSIX_SPAWN_SETSIGDEF | POSIX_SPAWN_SETSIGMASK);
|
||||||
|
|
||||||
|
// use spawn attribute to set SIGALRM and SIGIO to default action
|
||||||
|
sigset_t child_default_sigset;
|
||||||
|
sigemptyset(&child_default_sigset);
|
||||||
|
sigaddset(&child_default_sigset, SIGALRM);
|
||||||
|
sigaddset(&child_default_sigset, SIGIO);
|
||||||
|
posix_spawnattr_setsigdefault(&attr, &child_default_sigset);
|
||||||
|
signal(SIGILL, SIG_IGN); // child will inherit this
|
||||||
|
|
||||||
|
sigset_t child_sigmask;
|
||||||
|
sigemptyset(&child_sigmask);
|
||||||
|
sigaddset(&child_sigmask, SIGABRT);
|
||||||
|
posix_spawnattr_setsigmask(&attr, &child_sigmask);
|
||||||
|
|
||||||
|
// child process should inherit sigaction to ignore SIGABRT and set SIGIO to SIG_DEF
|
||||||
|
ret = posix_spawn(&child_pid, "/bin/naughty_child", NULL, &attr, child_argv, NULL);
|
||||||
|
if (ret != 0) {
|
||||||
|
THROW_ERROR("failed to spawn a child process");
|
||||||
|
}
|
||||||
|
ret = waitpid(child_pid, &status, 0);
|
||||||
|
if (ret < 0) {
|
||||||
|
THROW_ERROR("failed to wait4 the child process");
|
||||||
|
}
|
||||||
|
printf("child process %d exit status = %d\n", child_pid, status);
|
||||||
|
if (status != 0) {
|
||||||
|
THROW_ERROR("child process exit with error");
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Test suite
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
static test_case_t test_cases[] = {
|
||||||
|
TEST_CASE(test_thread_inheritage),
|
||||||
|
TEST_CASE(test_spawn_attribute_setsigmask),
|
||||||
|
TEST_CASE(test_spawn_attribute_setsigdef),
|
||||||
|
TEST_CASE(test_multiple_spawn_attribute),
|
||||||
|
};
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
return test_suite_run(test_cases, ARRAY_SIZE(test_cases));
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user