Unshare signal handler during execve
This commit is contained in:
parent
207bfe30e2
commit
caeec3cdc1
|
|
@ -626,15 +626,17 @@ fn clone_files(parent_file_table: &RwArc<FileTable>, clone_flags: CloneFlags) ->
|
|||
}
|
||||
|
||||
fn clone_sighand(
|
||||
parent_sig_dispositions: &Arc<Mutex<SigDispositions>>,
|
||||
parent_sig_dispositions: &Mutex<Arc<Mutex<SigDispositions>>>,
|
||||
clone_flags: CloneFlags,
|
||||
) -> Arc<Mutex<SigDispositions>> {
|
||||
// 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))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -132,6 +132,7 @@ pub fn kill_all(signal: Option<UserSignal>, ctx: &Context) -> Result<()> {
|
|||
|
||||
fn kill_process(process: &Process, signal: Option<UserSignal>, 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<UserSignal>, 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(())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -248,13 +248,14 @@ impl PosixThread {
|
|||
pub fn enqueue_signal(&self, signal: Box<dyn Signal>) {
|
||||
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<dyn Signal>,
|
||||
_sig_dispositions: MutexGuard<SigDispositions>,
|
||||
_sig_dispositions: &SigDispositions,
|
||||
) {
|
||||
self.sig_queues.enqueue(signal);
|
||||
self.wake_signalled_waker();
|
||||
|
|
|
|||
|
|
@ -118,7 +118,7 @@ pub struct Process {
|
|||
|
||||
// Signal
|
||||
/// Sig dispositions
|
||||
sig_dispositions: Arc<Mutex<SigDispositions>>,
|
||||
sig_dispositions: Mutex<Arc<Mutex<SigDispositions>>>,
|
||||
/// 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<Mutex<SigDispositions>> {
|
||||
pub fn sig_dispositions(&self) -> &Mutex<Arc<Mutex<SigDispositions>>> {
|
||||
&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.
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
Loading…
Reference in New Issue