diff --git a/services/libs/jinux-rights/src/lib.rs b/services/libs/jinux-rights/src/lib.rs index 75222815d..8b59cd257 100644 --- a/services/libs/jinux-rights/src/lib.rs +++ b/services/libs/jinux-rights/src/lib.rs @@ -50,6 +50,7 @@ typeflags::typeflags! { pub type Full = TRightSet; pub type ReadOp = TRights![Read]; pub type WriteOp = TRights![Write]; +pub type FullOp = TRights![Read, Write, Dup]; /// Wrapper for TRights, used to bypass an error message from the Rust compiler, /// the relevant issue is: https://github.com/rust-lang/rfcs/issues/2758 diff --git a/services/libs/jinux-std/src/process/exit.rs b/services/libs/jinux-std/src/process/exit.rs index 2bd217f71..20da64981 100644 --- a/services/libs/jinux-std/src/process/exit.rs +++ b/services/libs/jinux-std/src/process/exit.rs @@ -48,7 +48,7 @@ pub fn do_exit_group(term_status: TermStatus) { if let Some(parent) = current.parent() { // Notify parent - let signal = Box::new(KernelSignal::new(SIGCHLD)); + let signal = KernelSignal::new(SIGCHLD); parent.enqueue_signal(signal); parent.children_pauser().resume_all(); } diff --git a/services/libs/jinux-std/src/process/kill.rs b/services/libs/jinux-std/src/process/kill.rs new file mode 100644 index 000000000..4bd565895 --- /dev/null +++ b/services/libs/jinux-std/src/process/kill.rs @@ -0,0 +1,168 @@ +use super::posix_thread::PosixThreadExt; +use super::signal::signals::user::UserSignal; +use super::signal::signals::Signal; +use super::{credentials, process_table, Pgid, Pid, Process, Sid, Uid}; +use crate::prelude::*; +use crate::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.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!(); + let processes = process_table::get_all_processes(); + for process in processes { + 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 + } +} diff --git a/services/libs/jinux-std/src/process/mod.rs b/services/libs/jinux-std/src/process/mod.rs index 5aa8884a8..ef96eb101 100644 --- a/services/libs/jinux-std/src/process/mod.rs +++ b/services/libs/jinux-std/src/process/mod.rs @@ -1,5 +1,7 @@ mod clone; +mod credentials; mod exit; +mod kill; pub mod posix_thread; #[allow(clippy::module_inception)] mod process; @@ -14,7 +16,9 @@ mod term_status; mod wait; pub use clone::{clone_child, CloneArgs, CloneFlags}; +pub use credentials::{credentials, credentials_mut, Credentials, Gid, Uid}; pub use exit::do_exit_group; +pub use kill::{kill, kill_all, kill_group, tgkill}; pub use process::ProcessBuilder; pub use process::{ current, ExitCode, JobControl, Pgid, Pid, Process, ProcessGroup, Session, Sid, Terminal, diff --git a/services/libs/jinux-std/src/process/process/builder.rs b/services/libs/jinux-std/src/process/process/builder.rs index dd49dcc39..7d4683566 100644 --- a/services/libs/jinux-std/src/process/process/builder.rs +++ b/services/libs/jinux-std/src/process/process/builder.rs @@ -5,6 +5,7 @@ use crate::process::posix_thread::{PosixThreadBuilder, PosixThreadExt}; use crate::process::process_vm::ProcessVm; use crate::process::rlimit::ResourceLimits; use crate::process::signal::sig_disposition::SigDispositions; +use crate::process::Credentials; use crate::thread::Thread; use super::{Pid, Process}; @@ -26,6 +27,7 @@ pub struct ProcessBuilder<'a> { umask: Option>>, resource_limits: Option, sig_dispositions: Option>>, + credentials: Option, } impl<'a> ProcessBuilder<'a> { @@ -43,6 +45,7 @@ impl<'a> ProcessBuilder<'a> { umask: None, resource_limits: None, sig_dispositions: None, + credentials: None, } } @@ -91,17 +94,24 @@ impl<'a> ProcessBuilder<'a> { self } + pub fn credentials(&mut self, credentials: Credentials) -> &mut Self { + self.credentials = Some(credentials); + self + } + fn check_build(&self) -> Result<()> { if self.main_thread_builder.is_some() { debug_assert!(self.parent.upgrade().is_some()); debug_assert!(self.argv.is_none()); debug_assert!(self.envp.is_none()); + debug_assert!(self.credentials.is_none()); } if self.main_thread_builder.is_none() { debug_assert!(self.parent.upgrade().is_none()); debug_assert!(self.argv.is_some()); debug_assert!(self.envp.is_some()); + debug_assert!(self.credentials.is_some()); } Ok(()) @@ -122,6 +132,7 @@ impl<'a> ProcessBuilder<'a> { umask, resource_limits, sig_dispositions, + credentials, } = self; let process_vm = process_vm.or_else(|| Some(ProcessVm::alloc())).unwrap(); @@ -168,6 +179,7 @@ impl<'a> ProcessBuilder<'a> { } else { Thread::new_posix_thread_from_executable( pid, + credentials.unwrap(), process.vm(), &process.fs().read(), executable_path, diff --git a/services/libs/jinux-std/src/process/process/mod.rs b/services/libs/jinux-std/src/process/process/mod.rs index ee12e3483..b0574666b 100644 --- a/services/libs/jinux-std/src/process/process/mod.rs +++ b/services/libs/jinux-std/src/process/process/mod.rs @@ -5,20 +5,17 @@ use super::rlimit::ResourceLimits; use super::signal::constants::SIGCHLD; use super::signal::sig_disposition::SigDispositions; use super::signal::sig_mask::SigMask; -use super::signal::sig_queues::SigQueues; use super::signal::signals::Signal; -use super::signal::{Pauser, SigEvents, SigEventsFilter}; +use super::signal::Pauser; use super::status::ProcessStatus; -use super::{process_table, TermStatus}; +use super::{process_table, Credentials, TermStatus}; use crate::device::tty::open_ntty_as_controlling_terminal; -use crate::events::Observer; use crate::fs::file_table::FileTable; use crate::fs::fs_resolver::FsResolver; use crate::fs::utils::FileCreationMask; use crate::prelude::*; use crate::thread::{allocate_tid, Thread}; use crate::vm::vmar::Vmar; -use jinux_rights::Full; mod builder; mod job_control; @@ -27,6 +24,7 @@ mod session; mod terminal; pub use builder::ProcessBuilder; +use jinux_rights::Full; pub use job_control::JobControl; pub use process_group::ProcessGroup; pub use session::Session; @@ -73,10 +71,8 @@ pub struct Process { resource_limits: Mutex, // Signal - /// sig dispositions + /// Sig dispositions sig_dispositions: Arc>, - /// Process-level signal queues - sig_queues: Mutex, } impl Process { @@ -94,11 +90,10 @@ impl Process { resource_limits: ResourceLimits, ) -> Self { let children_pauser = { - let mut sigset = SigMask::new_full(); // SIGCHID does not interrupt pauser. Child process will // resume paused parent when doing exit. - sigset.remove_signal(SIGCHLD); - Pauser::new_with_sigset(sigset) + let sigmask = SigMask::from(SIGCHLD); + Pauser::new_with_mask(sigmask) }; Self { @@ -115,7 +110,6 @@ impl Process { fs, umask, sig_dispositions, - sig_queues: Mutex::new(SigQueues::new()), resource_limits: Mutex::new(resource_limits), } } @@ -144,8 +138,11 @@ impl Process { let process_builder = { let pid = allocate_tid(); let parent = Weak::new(); + + let credentials = Credentials::new_root(); + let mut builder = ProcessBuilder::new(pid, executable_path, parent); - builder.argv(argv).envp(envp); + builder.argv(argv).envp(envp).credentials(credentials); builder }; @@ -206,11 +203,23 @@ impl Process { &self.resource_limits } + fn main_thread(&self) -> Option> { + self.threads + .lock() + .iter() + .find(|thread| thread.tid() == self.pid) + .cloned() + } + // *********** Parent and child *********** pub fn parent(&self) -> Option> { self.parent.lock().upgrade() } + pub fn is_init_process(&self) -> bool { + self.parent().is_none() + } + pub(super) fn children(&self) -> &Mutex>> { &self.children } @@ -501,30 +510,35 @@ impl Process { &self.sig_dispositions } - pub fn has_pending_signal(&self) -> bool { - !self.sig_queues.lock().is_empty() - } - - pub fn enqueue_signal(&self, signal: Box) { - if !self.is_zombie() { - self.sig_queues.lock().enqueue(signal); + /// Enqueues a process-directed signal. This method should only be used for enqueue kernel + /// signal and fault signal. + /// + /// The signal may be delivered to any one of the threads that does not currently have the + /// signal blocked. If more than one of the threads has the signal unblocked, then this method + /// chooses an arbitrary thread to which to deliver the signal. + /// + /// TODO: restrict these method with access control tool. + pub fn enqueue_signal(&self, signal: impl Signal + Clone + 'static) { + if self.is_zombie() { + return; } - } - pub fn dequeue_signal(&self, mask: &SigMask) -> Option> { - self.sig_queues.lock().dequeue(mask) - } + // TODO: check that the signal is not user signal - pub fn register_sigqueue_observer( - &self, - observer: Weak>, - filter: SigEventsFilter, - ) { - self.sig_queues.lock().register_observer(observer, filter); - } + // Enqueue signal to the first thread that does not block the signal + let threads = self.threads.lock(); + for thread in threads.iter() { + let posix_thread = thread.as_posix_thread().unwrap(); + if !posix_thread.has_signal_blocked(&signal) { + posix_thread.enqueue_signal(Box::new(signal)); + return; + } + } - pub fn unregiser_sigqueue_observer(&self, observer: &Weak>) { - self.sig_queues.lock().unregister_observer(observer); + // If all threads block the signal, enqueue signal to the first thread + let thread = threads.iter().next().unwrap(); + let posix_thread = thread.as_posix_thread().unwrap(); + posix_thread.enqueue_signal(Box::new(signal)); } // ******************* Status ******************** diff --git a/services/libs/jinux-std/src/process/process/process_group.rs b/services/libs/jinux-std/src/process/process/process_group.rs index 3cc819050..9090cbd62 100644 --- a/services/libs/jinux-std/src/process/process/process_group.rs +++ b/services/libs/jinux-std/src/process/process/process_group.rs @@ -66,9 +66,13 @@ impl ProcessGroup { } /// Broadcasts signal to all processes in the group. + /// + /// This method should only be used to broadcast fault signal and kernel signal. + /// + /// TODO: do more check to forbid user signal pub fn broadcast_signal(&self, signal: impl Signal + Clone + 'static) { for process in self.inner.lock().processes.values() { - process.enqueue_signal(Box::new(signal.clone())); + process.enqueue_signal(signal.clone()); } } diff --git a/services/libs/jinux-std/src/process/signal/c_types.rs b/services/libs/jinux-std/src/process/signal/c_types.rs index b8a93e498..60ce41b7d 100644 --- a/services/libs/jinux-std/src/process/signal/c_types.rs +++ b/services/libs/jinux-std/src/process/signal/c_types.rs @@ -4,9 +4,12 @@ use core::mem; use jinux_frame::cpu::GeneralRegs; use jinux_util::{read_union_fields, union_read_ptr::UnionReadPtr}; -use crate::{prelude::*, process::Pid}; +use crate::{ + prelude::*, + process::{Pid, Uid}, +}; -use super::{sig_num::SigNum, signals::user::Uid}; +use super::sig_num::SigNum; pub type sigset_t = u64; // FIXME: this type should be put at suitable place diff --git a/services/libs/jinux-std/src/process/signal/events.rs b/services/libs/jinux-std/src/process/signal/events.rs index 0a0f5ad5d..37b472609 100644 --- a/services/libs/jinux-std/src/process/signal/events.rs +++ b/services/libs/jinux-std/src/process/signal/events.rs @@ -26,6 +26,6 @@ impl SigEventsFilter { impl EventsFilter for SigEventsFilter { fn filter(&self, event: &SigEvents) -> bool { - self.0.contains(event.0) + !self.0.contains(event.0) } } diff --git a/services/libs/jinux-std/src/process/signal/mod.rs b/services/libs/jinux-std/src/process/signal/mod.rs index c9b966bc6..e74326a44 100644 --- a/services/libs/jinux-std/src/process/signal/mod.rs +++ b/services/libs/jinux-std/src/process/signal/mod.rs @@ -37,67 +37,68 @@ use crate::{ pub fn handle_pending_signal(context: &mut UserContext) -> Result<()> { let current = current!(); let current_thread = current_thread!(); - let posix_thread = current_thread.as_posix_thread().unwrap(); - let pid = current.pid(); - let sig_mask = *posix_thread.sig_mask().lock(); + // We first deal with signal in current thread, then signal in current process. - let signal = if let Some(signal) = posix_thread.dequeue_signal(&sig_mask) { - Some(signal) - } else { - current.dequeue_signal(&sig_mask) + let signal = { + let posix_thread = current_thread.as_posix_thread().unwrap(); + let sig_mask = *posix_thread.sig_mask().lock(); + if let Some(signal) = posix_thread.dequeue_signal(&sig_mask) { + signal + } else { + return Ok(()); + } }; - if let Some(signal) = signal { - let sig_num = signal.num(); - trace!("sig_num = {:?}, sig_name = {}", sig_num, sig_num.sig_name()); - let sig_action = current.sig_dispositions().lock().get(sig_num); - trace!("sig action: {:x?}", sig_action); - match sig_action { - SigAction::Ign => { - trace!("Ignore signal {:?}", sig_num); - } - SigAction::User { - handler_addr, - flags, - restorer_addr, - mask, - } => handle_user_signal( - sig_num, - handler_addr, - flags, - restorer_addr, - mask, - context, - signal.to_info(), - )?, - SigAction::Dfl => { - let sig_default_action = SigDefaultAction::from_signum(sig_num); - trace!("sig_default_action: {:?}", sig_default_action); - match sig_default_action { - SigDefaultAction::Core | SigDefaultAction::Term => { - warn!( - "{:?}: terminating on signal {}", - current.executable_path(), - sig_num.sig_name() - ); - do_exit_group(TermStatus::Killed(sig_num)); - // We should exit current here, since we cannot restore a valid status from trap now. - Task::current().exit(); + + let sig_num = signal.num(); + trace!("sig_num = {:?}, sig_name = {}", sig_num, sig_num.sig_name()); + let sig_action = current.sig_dispositions().lock().get(sig_num); + trace!("sig action: {:x?}", sig_action); + match sig_action { + SigAction::Ign => { + trace!("Ignore signal {:?}", sig_num); + } + SigAction::User { + handler_addr, + flags, + restorer_addr, + mask, + } => handle_user_signal( + sig_num, + handler_addr, + flags, + restorer_addr, + mask, + context, + signal.to_info(), + )?, + SigAction::Dfl => { + let sig_default_action = SigDefaultAction::from_signum(sig_num); + trace!("sig_default_action: {:?}", sig_default_action); + match sig_default_action { + SigDefaultAction::Core | SigDefaultAction::Term => { + warn!( + "{:?}: terminating on signal {}", + current.executable_path(), + sig_num.sig_name() + ); + do_exit_group(TermStatus::Killed(sig_num)); + // We should exit current here, since we cannot restore a valid status from trap now. + Task::current().exit(); + } + SigDefaultAction::Ign => {} + SigDefaultAction::Stop => { + let mut status = current_thread.status().lock(); + if status.is_running() { + status.set_stopped(); } - SigDefaultAction::Ign => {} - SigDefaultAction::Stop => { - let mut status = current_thread.status().lock(); - if status.is_running() { - status.set_stopped(); - } - drop(status); - } - SigDefaultAction::Cont => { - let mut status = current_thread.status().lock(); - if status.is_stopped() { - status.set_running(); - } - drop(status); + drop(status); + } + SigDefaultAction::Cont => { + let mut status = current_thread.status().lock(); + if status.is_stopped() { + status.set_running(); } + drop(status); } } } @@ -120,6 +121,7 @@ pub fn handle_user_signal( debug!("restorer_addr = 0x{:x}", restorer_addr); // FIXME: How to respect flags? if flags.contains_unsupported_flag() { + println!("flags = {:?}", flags); panic!("Unsupported Signal flags"); } if !flags.contains(SigActionFlags::SA_NODEFER) { diff --git a/services/libs/jinux-std/src/process/signal/pauser.rs b/services/libs/jinux-std/src/process/signal/pauser.rs index 57432f1bf..a242f8930 100644 --- a/services/libs/jinux-std/src/process/signal/pauser.rs +++ b/services/libs/jinux-std/src/process/signal/pauser.rs @@ -55,23 +55,24 @@ use super::{SigEvents, SigEventsFilter}; /// ``` pub struct Pauser { wait_queue: WaitQueue, - sigset: SigMask, + sig_mask: SigMask, is_interrupted: AtomicBool, } impl Pauser { - /// Create a new `Pauser`. The `Pauser` can be interrupted by all signals. + /// Create a new `Pauser`. The `Pauser` can be interrupted by all signals except that + /// are blocked by current thread. pub fn new() -> Arc { - Self::new_with_sigset(SigMask::new_full()) + Self::new_with_mask(SigMask::new_empty()) } - /// Create a new `Pauser`, the `Pauser` can only be interrupted by signals - /// in `sigset`. - pub fn new_with_sigset(sigset: SigMask) -> Arc { + /// Create a new `Pauser`, the `Pauser` will ignore signals that are in `sig_mask` and + /// blocked by current thread. + pub fn new_with_mask(sig_mask: SigMask) -> Arc { let wait_queue = WaitQueue::new(); Arc::new(Self { wait_queue, - sigset, + sig_mask, is_interrupted: AtomicBool::new(false), }) } @@ -106,20 +107,25 @@ impl Pauser { { self.is_interrupted.store(false, Ordering::Release); - // Register observers on sigqueues - + // Register observer on sigqueue let observer = Arc::downgrade(self) as Weak>; - let filter = SigEventsFilter::new(self.sigset); - - let current = current!(); - current.register_sigqueue_observer(observer.clone(), filter); + let filter = { + let sig_mask = { + let current_thread = current_thread!(); + let poxis_thread = current_thread.as_posix_thread().unwrap(); + let mut current_sigmask = *poxis_thread.sig_mask().lock(); + current_sigmask.block(self.sig_mask.as_u64()); + current_sigmask + }; + SigEventsFilter::new(sig_mask) + }; let current_thread = current_thread!(); let posix_thread = current_thread.as_posix_thread().unwrap(); posix_thread.register_sigqueue_observer(observer.clone(), filter); // Some signal may come before we register observer, so we do another check here. - if posix_thread.has_pending_signal() || current.has_pending_signal() { + if posix_thread.has_pending_signal() { self.is_interrupted.store(true, Ordering::Release); } @@ -148,7 +154,6 @@ impl Pauser { self.wait_queue.wait_until(cond) }; - current.unregiser_sigqueue_observer(&observer); posix_thread.unregiser_sigqueue_observer(&observer); match res { diff --git a/services/libs/jinux-std/src/process/signal/signals/kernel.rs b/services/libs/jinux-std/src/process/signal/signals/kernel.rs index bb01f1426..cdd17f754 100644 --- a/services/libs/jinux-std/src/process/signal/signals/kernel.rs +++ b/services/libs/jinux-std/src/process/signal/signals/kernel.rs @@ -1,6 +1,7 @@ -use crate::process::signal::{c_types::siginfo_t, constants::SI_KERNEL, sig_num::SigNum}; - use super::Signal; +use crate::process::signal::c_types::siginfo_t; +use crate::process::signal::constants::SI_KERNEL; +use crate::process::signal::sig_num::SigNum; #[derive(Debug, Clone, Copy, PartialEq)] pub struct KernelSignal { diff --git a/services/libs/jinux-std/src/process/signal/signals/mod.rs b/services/libs/jinux-std/src/process/signal/signals/mod.rs index 0d297c512..15f77042a 100644 --- a/services/libs/jinux-std/src/process/signal/signals/mod.rs +++ b/services/libs/jinux-std/src/process/signal/signals/mod.rs @@ -2,11 +2,12 @@ pub mod fault; pub mod kernel; pub mod user; +use super::c_types::siginfo_t; +use super::sig_num::SigNum; +use core::any::Any; use core::fmt::Debug; -use super::{c_types::siginfo_t, sig_num::SigNum}; - -pub trait Signal: Send + Sync + Debug { +pub trait Signal: Send + Sync + Debug + Any { /// Returns the number of the signal. fn num(&self) -> SigNum; /// Returns the siginfo_t that gives more details about a signal. diff --git a/services/libs/jinux-std/src/process/signal/signals/user.rs b/services/libs/jinux-std/src/process/signal/signals/user.rs index c784d938d..40d56e149 100644 --- a/services/libs/jinux-std/src/process/signal/signals/user.rs +++ b/services/libs/jinux-std/src/process/signal/signals/user.rs @@ -1,15 +1,8 @@ -use crate::process::{ - signal::{ - c_types::siginfo_t, - constants::{SI_QUEUE, SI_TKILL, SI_USER}, - sig_num::SigNum, - }, - Pid, -}; - use super::Signal; - -pub type Uid = usize; +use crate::process::signal::c_types::siginfo_t; +use crate::process::signal::constants::{SI_QUEUE, SI_TKILL, SI_USER}; +use crate::process::signal::sig_num::SigNum; +use crate::process::{Pid, Uid}; #[derive(Debug, Clone, Copy)] pub struct UserSignal { @@ -40,10 +33,6 @@ impl UserSignal { self.pid } - pub fn uid(&self) -> Uid { - self.uid - } - pub fn kind(&self) -> UserSignalKind { self.kind } diff --git a/services/libs/jinux-std/src/syscall/kill.rs b/services/libs/jinux-std/src/syscall/kill.rs index e0c82be0b..6f8e04ef5 100644 --- a/services/libs/jinux-std/src/syscall/kill.rs +++ b/services/libs/jinux-std/src/syscall/kill.rs @@ -1,18 +1,21 @@ -use crate::{log_syscall_entry, prelude::*}; - -use crate::process::process_table; +use super::{SyscallReturn, SYS_KILL}; +use crate::log_syscall_entry; +use crate::prelude::*; +use crate::process::kill; +use crate::process::kill_all; +use crate::process::kill_group; +use crate::process::signal::sig_num::SigNum; use crate::process::signal::signals::user::{UserSignal, UserSignalKind}; -use crate::{ - process::{signal::sig_num::SigNum, ProcessFilter}, - syscall::SYS_KILL, -}; - -use super::SyscallReturn; +use crate::process::{credentials, ProcessFilter}; pub fn sys_kill(process_filter: u64, sig_num: u64) -> Result { log_syscall_entry!(SYS_KILL); let process_filter = ProcessFilter::from_id(process_filter as _); - let sig_num = SigNum::try_from(sig_num as u8).unwrap(); + let sig_num = if sig_num == 0 { + None + } else { + Some(SigNum::try_from(sig_num as u8)?) + }; debug!( "process_filter = {:?}, sig_num = {:?}", process_filter, sig_num @@ -21,32 +24,19 @@ pub fn sys_kill(process_filter: u64, sig_num: u64) -> Result { Ok(SyscallReturn::Return(0)) } -pub fn do_sys_kill(filter: ProcessFilter, sig_num: SigNum) -> Result<()> { +pub fn do_sys_kill(filter: ProcessFilter, sig_num: Option) -> Result<()> { let current = current!(); - let pid = current.pid(); - // FIXME: use the correct uid - let uid = 0; - let signal = UserSignal::new(sig_num, UserSignalKind::Kill, pid, uid); + + let signal = sig_num.map(|sig_num| { + let pid = current.pid(); + let uid = credentials().ruid(); + UserSignal::new(sig_num, UserSignalKind::Kill, pid, uid) + }); + match filter { - ProcessFilter::Any => { - for process in process_table::get_all_processes() { - process.enqueue_signal(Box::new(signal)); - } - } - ProcessFilter::WithPid(pid) => { - if let Some(process) = process_table::get_process(&pid) { - process.enqueue_signal(Box::new(signal)); - } else { - return_errno_with_message!(Errno::ESRCH, "No such process in process table"); - } - } - ProcessFilter::WithPgid(pgid) => { - if let Some(process_group) = process_table::get_process_group(&pgid) { - process_group.broadcast_signal(signal); - } else { - return_errno_with_message!(Errno::ESRCH, "No such process group in process table"); - } - } + ProcessFilter::Any => kill_all(signal)?, + ProcessFilter::WithPid(pid) => kill(pid, signal)?, + ProcessFilter::WithPgid(pgid) => kill_group(pgid, signal)?, } Ok(()) } diff --git a/services/libs/jinux-std/src/syscall/tgkill.rs b/services/libs/jinux-std/src/syscall/tgkill.rs index 014fa0d64..1941370c4 100644 --- a/services/libs/jinux-std/src/syscall/tgkill.rs +++ b/services/libs/jinux-std/src/syscall/tgkill.rs @@ -1,44 +1,29 @@ -use crate::process::posix_thread::PosixThreadExt; -use crate::thread::{thread_table, Tid}; -use crate::{log_syscall_entry, prelude::*}; - +use super::SyscallReturn; +use crate::log_syscall_entry; +use crate::prelude::*; use crate::process::signal::sig_num::SigNum; use crate::process::signal::signals::user::{UserSignal, UserSignalKind}; -use crate::process::Pid; +use crate::process::tgkill; +use crate::process::{credentials, Pid}; use crate::syscall::SYS_TGKILL; - -use super::SyscallReturn; +use crate::thread::Tid; /// tgkill send a signal to a thread with pid as its thread id, and tgid as its thread group id. -/// Since jinuxx only supports one-thread process now, tgkill will send signal to process with pid as its process id, -/// and tgid as its process group id. pub fn sys_tgkill(tgid: Pid, tid: Tid, sig_num: u8) -> Result { log_syscall_entry!(SYS_TGKILL); - let sig_num = SigNum::from_u8(sig_num); - info!("tgid = {}, pid = {}, sig_num = {:?}", tgid, tid, sig_num); - let target_thread = - thread_table::get_thread(tid).ok_or(Error::with_message(Errno::EINVAL, "Invalid pid"))?; - let posix_thread = target_thread.as_posix_thread().unwrap(); - let pid = posix_thread.process().pid(); - if pid != tgid { - return_errno_with_message!( - Errno::EINVAL, - "the combination of tgid and pid is not valid" - ); - } - if target_thread.status().lock().is_exited() { - return Ok(SyscallReturn::Return(0)); - } - let signal = { - let src_pid = current!().pid(); - let src_uid = 0; - Box::new(UserSignal::new( - sig_num, - UserSignalKind::Tkill, - src_pid, - src_uid, - )) + let sig_num = if sig_num == 0 { + None + } else { + Some(SigNum::try_from(sig_num)?) }; - posix_thread.enqueue_signal(signal); + + debug!("tgid = {}, pid = {}, sig_num = {:?}", tgid, tid, sig_num); + + let signal = sig_num.map(|sig_num| { + let pid = current!().pid(); + let uid = credentials().ruid(); + UserSignal::new(sig_num, UserSignalKind::Tkill, pid, uid) + }); + tgkill(tid, tgid, signal)?; Ok(SyscallReturn::Return(0)) } diff --git a/services/libs/jinux-std/src/thread/exception.rs b/services/libs/jinux-std/src/thread/exception.rs index db94d0975..4bdd22fad 100644 --- a/services/libs/jinux-std/src/thread/exception.rs +++ b/services/libs/jinux-std/src/thread/exception.rs @@ -1,7 +1,8 @@ -use jinux_frame::{cpu::*, vm::VmIo}; - +use crate::prelude::*; +use crate::process::signal::signals::fault::FaultSignal; use crate::vm::page_fault_handler::PageFaultHandler; -use crate::{prelude::*, process::signal::signals::fault::FaultSignal}; +use jinux_frame::cpu::*; +use jinux_frame::vm::VmIo; /// We can't handle most exceptions, just send self a fault signal before return to user space. pub fn handle_exception(context: &UserContext) { @@ -56,7 +57,7 @@ fn handle_page_fault(trap_info: &CpuExceptionInfo) { /// generate a fault signal for current process. fn generate_fault_signal(trap_info: &CpuExceptionInfo) { let current = current!(); - let signal = Box::new(FaultSignal::new(trap_info)); + let signal = FaultSignal::new(trap_info); current.enqueue_signal(signal); } diff --git a/services/libs/jinux-std/src/vm/vmar/mod.rs b/services/libs/jinux-std/src/vm/vmar/mod.rs index dfb02cd81..4c19882a0 100644 --- a/services/libs/jinux-std/src/vm/vmar/mod.rs +++ b/services/libs/jinux-std/src/vm/vmar/mod.rs @@ -420,8 +420,16 @@ impl Vmar_ { } pub fn write(&self, offset: usize, buf: &[u8]) -> Result<()> { - let write_start = self.base + offset; - let write_end = buf.len() + write_start; + let write_start = self + .base + .checked_add(offset) + .ok_or_else(|| Error::with_message(Errno::EFAULT, "Arithmetic Overflow"))?; + + let write_end = buf + .len() + .checked_add(write_start) + .ok_or_else(|| Error::with_message(Errno::EFAULT, "Arithmetic Overflow"))?; + // if the write range is in child vmar for (child_vmar_base, child_vmar) in &self.inner.lock().child_vmar_s { let child_vmar_end = *child_vmar_base + child_vmar.size;