diff --git a/kernel/src/process/clone.rs b/kernel/src/process/clone.rs index a37811353..da76e5796 100644 --- a/kernel/src/process/clone.rs +++ b/kernel/src/process/clone.rs @@ -626,15 +626,17 @@ fn clone_files(parent_file_table: &RwArc, clone_flags: CloneFlags) -> } fn clone_sighand( - parent_sig_dispositions: &Arc>, + parent_sig_dispositions: &Mutex>>, clone_flags: CloneFlags, ) -> Arc> { // If CLONE_SIGHAND is set, the child and parent shares the same signal handlers. // Otherwise, the child has a copy of the parent's signal handlers. if clone_flags.contains(CloneFlags::CLONE_SIGHAND) { - parent_sig_dispositions.clone() + parent_sig_dispositions.lock().clone() } else { - Arc::new(Mutex::new(*parent_sig_dispositions.lock())) + let sig_dispositions = parent_sig_dispositions.lock(); + let sig_dispositions = sig_dispositions.lock(); + Arc::new(Mutex::new(*sig_dispositions)) } } diff --git a/kernel/src/process/execve.rs b/kernel/src/process/execve.rs index a4c86afc7..4498e0bb6 100644 --- a/kernel/src/process/execve.rs +++ b/kernel/src/process/execve.rs @@ -161,8 +161,8 @@ fn do_execve_no_return( *posix_thread.thread_name().lock() = ThreadName::new_from_executable_path(&executable_path); process.set_executable_path(executable_path); - // Reset signal dispositions to their default actions. - process.sig_dispositions().lock().inherit(); + // Unshare and reset signal dispositions to their default actions. + unshare_and_reset_sigdispositions(process); // Reset the alternate signal stack to its default state. *thread_local.sig_stack().borrow_mut() = SigStack::default(); // Restore the process exit signal to SIGCHLD. @@ -303,3 +303,12 @@ fn unshare_and_close_files(ctx: &Context) { .write() .close_files_on_exec(); } + +fn unshare_and_reset_sigdispositions(process: &Process) { + let mut sig_dispositions = process.sig_dispositions().lock(); + + let mut new = *sig_dispositions.lock(); + new.inherit(); + + *sig_dispositions = Arc::new(Mutex::new(new)); +} diff --git a/kernel/src/process/kill.rs b/kernel/src/process/kill.rs index f4c07a07b..6a2f49ba2 100644 --- a/kernel/src/process/kill.rs +++ b/kernel/src/process/kill.rs @@ -132,6 +132,7 @@ pub fn kill_all(signal: Option, ctx: &Context) -> Result<()> { fn kill_process(process: &Process, signal: Option, ctx: &Context) -> Result<()> { let sig_dispositions = process.sig_dispositions().lock(); + let sig_dispositions = sig_dispositions.lock(); let tasks = process.tasks().lock(); let signum = signal.map(|signal| signal.num()); @@ -196,7 +197,7 @@ fn kill_process(process: &Process, signal: Option, ctx: &Context) -> return Ok(()); } - thread_to_enqueue.enqueue_signal_locked(Box::new(signal), sig_dispositions); + thread_to_enqueue.enqueue_signal_locked(Box::new(signal), &sig_dispositions); Ok(()) } diff --git a/kernel/src/process/posix_thread/mod.rs b/kernel/src/process/posix_thread/mod.rs index 1eca8289f..2c170b197 100644 --- a/kernel/src/process/posix_thread/mod.rs +++ b/kernel/src/process/posix_thread/mod.rs @@ -248,13 +248,14 @@ impl PosixThread { pub fn enqueue_signal(&self, signal: Box) { let process = self.process(); let sig_dispositions = process.sig_dispositions().lock(); + let sig_dispositions = sig_dispositions.lock(); let signum = signal.num(); if sig_dispositions.get(signum).will_ignore(signum) { return; } - self.enqueue_signal_locked(signal, sig_dispositions); + self.enqueue_signal_locked(signal, &sig_dispositions); } /// Enqueues a thread-directed signal with locked dispositions. @@ -271,7 +272,7 @@ impl PosixThread { pub(in crate::process) fn enqueue_signal_locked( &self, signal: Box, - _sig_dispositions: MutexGuard, + _sig_dispositions: &SigDispositions, ) { self.sig_queues.enqueue(signal); self.wake_signalled_waker(); diff --git a/kernel/src/process/process/mod.rs b/kernel/src/process/process/mod.rs index 549100ab7..73af6b44c 100644 --- a/kernel/src/process/process/mod.rs +++ b/kernel/src/process/process/mod.rs @@ -118,7 +118,7 @@ pub struct Process { // Signal /// Sig dispositions - sig_dispositions: Arc>, + sig_dispositions: Mutex>>, /// The signal that the process should receive when parent process exits. parent_death_signal: AtomicSigNum, @@ -232,7 +232,7 @@ impl Process { reaped_children_stats: Mutex::new(ReapedChildrenStats::default()), is_child_subreaper: AtomicBool::new(false), has_child_subreaper: AtomicBool::new(false), - sig_dispositions, + sig_dispositions: Mutex::new(sig_dispositions), parent_death_signal: AtomicSigNum::new_empty(), exit_signal: AtomicSigNum::new_empty(), resource_limits, @@ -628,7 +628,7 @@ impl Process { // ****************** Signal ****************** - pub fn sig_dispositions(&self) -> &Arc> { + pub fn sig_dispositions(&self) -> &Mutex>> { &self.sig_dispositions } @@ -647,6 +647,7 @@ impl Process { } let sig_dispositions = self.sig_dispositions.lock(); + let sig_dispositions = sig_dispositions.lock(); // Drop the signal if it's ignored. See explanation at `enqueue_signal_locked`. let signum = signal.num(); @@ -660,7 +661,7 @@ impl Process { for thread in threads.as_slice() { let posix_thread = thread.as_posix_thread().unwrap(); if !posix_thread.has_signal_blocked(signal.num()) { - posix_thread.enqueue_signal_locked(Box::new(signal), sig_dispositions); + posix_thread.enqueue_signal_locked(Box::new(signal), &sig_dispositions); return; } } @@ -668,7 +669,7 @@ impl Process { // If all threads block the signal, enqueue the signal to the main thread. let thread = threads.main(); let posix_thread = thread.as_posix_thread().unwrap(); - posix_thread.enqueue_signal_locked(Box::new(signal), sig_dispositions); + posix_thread.enqueue_signal_locked(Box::new(signal), &sig_dispositions); } /// Clears the parent death signal. diff --git a/kernel/src/process/signal/mod.rs b/kernel/src/process/signal/mod.rs index be780a858..328e510f8 100644 --- a/kernel/src/process/signal/mod.rs +++ b/kernel/src/process/signal/mod.rs @@ -75,9 +75,22 @@ pub fn handle_pending_signal( let sig_num = signal.num(); trace!("sig_num = {:?}, sig_name = {}", sig_num, sig_num.sig_name()); - let mut sig_dispositions = current.sig_dispositions().lock(); + let sig_action = { + let sig_dispositions = current.sig_dispositions().lock(); + let mut sig_dispositions = sig_dispositions.lock(); + let sig_action = sig_dispositions.get(sig_num); - let sig_action = sig_dispositions.get(sig_num); + if let SigAction::User { flags, .. } = &sig_action + && flags.contains(SigActionFlags::SA_RESETHAND) + { + // In Linux, SA_RESETHAND corresponds to SA_ONESHOT, + // which means the user handler will be executed only once and then reset to the default. + // Refer to https://elixir.bootlin.com/linux/v6.0.9/source/kernel/signal.c#L2761. + sig_dispositions.set_default(sig_num); + } + + sig_action + }; trace!("sig action: {:x?}", sig_action); match sig_action { @@ -105,14 +118,6 @@ pub fn handle_pending_signal( .set_instruction_pointer(user_ctx.instruction_pointer() - SYSCALL_INSTR_LEN); } - if flags.contains(SigActionFlags::SA_RESETHAND) { - // In Linux, SA_RESETHAND corresponds to SA_ONESHOT, - // which means the user handler will be executed only once and then reset to the default. - // Refer to https://elixir.bootlin.com/linux/v6.0.9/source/kernel/signal.c#L2761. - sig_dispositions.set_default(sig_num); - } - - drop(sig_dispositions); if let Err(e) = handle_user_signal( ctx, sig_num, @@ -130,8 +135,6 @@ pub fn handle_pending_signal( } } SigAction::Dfl => { - drop(sig_dispositions); - let sig_default_action = SigDefaultAction::from_signum(sig_num); trace!("sig_default_action: {:?}", sig_default_action); match sig_default_action { diff --git a/kernel/src/syscall/rt_sigaction.rs b/kernel/src/syscall/rt_sigaction.rs index 270ad7a15..1cf135c3c 100644 --- a/kernel/src/syscall/rt_sigaction.rs +++ b/kernel/src/syscall/rt_sigaction.rs @@ -35,7 +35,8 @@ pub fn sys_rt_sigaction( return_errno_with_message!(Errno::EINVAL, "sigset size is not equal to 8"); } - let mut sig_dispositions = ctx.process.sig_dispositions().lock(); + let sig_dispositions = ctx.process.sig_dispositions().lock(); + let mut sig_dispositions = sig_dispositions.lock(); let old_action = if sig_action_addr != 0 { if sig_num == SIGKILL || sig_num == SIGSTOP {