// SPDX-License-Identifier: MPL-2.0 use super::{ credentials, posix_thread::PosixThreadExt, process_table, signal::signals::{user::UserSignal, Signal}, Pgid, Pid, Process, Sid, Uid, }; use crate::{ prelude::*, thread::{thread_table, Tid}, }; /// Sends a signal to a process, using the current process as the sender. /// /// The credentials of the current process will be checked to determine /// if it is authorized to send the signal to this particular target process. /// /// If `signal` is `None`, this method will only check permission without sending /// any signal. pub fn kill(pid: Pid, signal: Option) -> Result<()> { let process = process_table::get_process(&pid) .ok_or_else(|| Error::with_message(Errno::ESRCH, "the target process does not exist"))?; kill_process(&process, signal) } /// Sends a signal to all processes in a group, using the current process /// as the sender. /// /// The credentials of the current process will be checked to determine /// if it is authorized to send the signal to the target group. /// /// If `signal` is `None`, this method will only check permission without sending /// any signal. pub fn kill_group(pgid: Pgid, signal: Option) -> Result<()> { let process_group = process_table::get_process_group(&pgid) .ok_or_else(|| Error::with_message(Errno::ESRCH, "target group does not exist"))?; let inner = process_group.inner.lock(); for process in inner.processes.values() { kill_process(process, signal)?; } Ok(()) } /// Sends a signal to a target thread, using the current process /// as the sender. /// /// If `signal` is `None`, this method will only check permission without sending /// any signal. pub fn tgkill(tid: Tid, tgid: Pid, signal: Option) -> Result<()> { let thread = thread_table::get_thread(tid) .ok_or_else(|| Error::with_message(Errno::ESRCH, "target thread does not exist"))?; if thread.status().is_exited() { return Ok(()); } let posix_thread = thread.as_posix_thread().unwrap(); // Check tgid let pid = posix_thread.process().pid(); if pid != tgid { return_errno_with_message!( Errno::EINVAL, "the combination of tgid and pid is not valid" ); } // Check permission let signum = signal.map(|signal| signal.num()); let sender = current_thread_sender_ids(); posix_thread.check_signal_perm(signum.as_ref(), &sender)?; if let Some(signal) = signal { posix_thread.enqueue_signal(Box::new(signal)); } Ok(()) } /// Sends a signal to all processes except current process and init process, using /// the current process as the sender. /// /// The credentials of the current process will be checked to determine /// if it is authorized to send the signal to the target group. pub fn kill_all(signal: Option) -> Result<()> { let current = current!(); for process in process_table::process_table().iter() { if Arc::ptr_eq(¤t, process) || process.is_init_process() { continue; } kill_process(process, signal)?; } Ok(()) } fn kill_process(process: &Process, signal: Option) -> Result<()> { let threads = process.threads().lock(); let posix_threads = threads .iter() .map(|thread| thread.as_posix_thread().unwrap()); // First check permission let signum = signal.map(|signal| signal.num()); let sender_ids = current_thread_sender_ids(); let mut permitted_threads = { posix_threads.clone().filter(|posix_thread| { posix_thread .check_signal_perm(signum.as_ref(), &sender_ids) .is_ok() }) }; if permitted_threads.clone().count() == 0 { return_errno_with_message!(Errno::EPERM, "cannot send signal to the target process"); } let Some(signal) = signal else { return Ok(()) }; // Send signal to any thread that does not blocks the signal. for thread in permitted_threads.clone() { if !thread.has_signal_blocked(&signal) { thread.enqueue_signal(Box::new(signal)); return Ok(()); } } // If all threads block the signal, send signal to the first thread. let first_thread = permitted_threads.next().unwrap(); first_thread.enqueue_signal(Box::new(signal)); Ok(()) } fn current_thread_sender_ids() -> SignalSenderIds { let credentials = credentials(); let ruid = credentials.ruid(); let euid = credentials.euid(); let sid = current!().session().unwrap().sid(); SignalSenderIds::new(ruid, euid, sid) } /// The ids of the signal sender process. /// /// This struct now includes effective user id, real user id and session id. pub(super) struct SignalSenderIds { ruid: Uid, euid: Uid, sid: Sid, } impl SignalSenderIds { fn new(ruid: Uid, euid: Uid, sid: Sid) -> Self { Self { ruid, euid, sid } } pub(super) fn ruid(&self) -> Uid { self.ruid } pub(super) fn euid(&self) -> Uid { self.euid } pub(super) fn sid(&self) -> Sid { self.sid } }