WIP: implement kill syscall prototype
This commit is contained in:
+32
-27
@@ -1,5 +1,5 @@
|
||||
use alloc::{borrow::Cow, sync::Arc, vec::Vec};
|
||||
use syscall::{Sigcontrol, SIGKILL, SIGSTOP};
|
||||
use syscall::{SigProcControl, Sigcontrol, SIGKILL, SIGSTOP};
|
||||
use core::{cmp::Ordering, mem::{self, size_of}, num::NonZeroUsize, sync::atomic::AtomicU64};
|
||||
use spin::RwLock;
|
||||
|
||||
@@ -7,11 +7,7 @@ use crate::{
|
||||
arch::{interrupt::InterruptStack, paging::PAGE_SIZE}, common::aligned_box::AlignedBox, context::{self, arch, file::FileDescriptor, memory::AddrSpace}, cpu_set::{LogicalCpuId, LogicalCpuSet}, ipi::{ipi, IpiKind, IpiTarget}, memory::{allocate_p2frame, deallocate_p2frame, Enomem, Frame, RaiiFrame}, paging::{RmmA, RmmArch}, percpu::PercpuBlock, scheme::{CallerCtx, FileHandle, SchemeNamespace}, sync::WaitMap,
|
||||
};
|
||||
|
||||
use crate::syscall::{
|
||||
data::SigAction,
|
||||
error::{Error, Result, EAGAIN, ESRCH},
|
||||
flag::{SigActionFlags, SIG_DFL},
|
||||
};
|
||||
use crate::syscall::error::{Error, Result, EAGAIN, ESRCH};
|
||||
|
||||
/// Unique identifier for a context (i.e. `pid`).
|
||||
use ::core::sync::atomic::AtomicUsize;
|
||||
@@ -141,7 +137,7 @@ pub struct Context {
|
||||
pub ens: SchemeNamespace,
|
||||
|
||||
/// Signal handler
|
||||
pub sig: SignalState,
|
||||
pub sig: Option<SignalState>,
|
||||
|
||||
/// Process umask
|
||||
pub umask: usize,
|
||||
@@ -206,13 +202,16 @@ pub struct Context {
|
||||
#[derive(Debug)]
|
||||
pub struct SignalState {
|
||||
/// Offset to jump to when a signal is received.
|
||||
pub user_handler: Option<NonZeroUsize>,
|
||||
pub user_handler: NonZeroUsize,
|
||||
/// Offset to jump to when a program fault occurs.
|
||||
pub excp_handler: Option<NonZeroUsize>,
|
||||
/// Signal control page, required for signals to work.
|
||||
pub control: Option<RaiiFrame>,
|
||||
/// Offset within the control page of a naturally aligned, semiatomically accessed, u128.
|
||||
pub sigctl_off: u16,
|
||||
pub excp_handler: NonZeroUsize,
|
||||
|
||||
/// Signal control pages, shared memory
|
||||
pub thread_control: RaiiFrame,
|
||||
pub proc_control: RaiiFrame,
|
||||
/// Offset within the control pages of respective word-aligned structs.
|
||||
pub threadctl_off: u16,
|
||||
pub procctl_off: u16,
|
||||
|
||||
/// Set whenever the kernel is about to have the context jump to its signal trampoline, but the
|
||||
/// context is currently running.
|
||||
@@ -232,13 +231,7 @@ impl Context {
|
||||
euid: 0,
|
||||
egid: 0,
|
||||
ens: SchemeNamespace::from(0),
|
||||
sig: SignalState {
|
||||
user_handler: None,
|
||||
excp_handler: None,
|
||||
control: None,
|
||||
sigctl_off: 0,
|
||||
is_pending: false,
|
||||
},
|
||||
sig: None,
|
||||
umask: 0o022,
|
||||
status: Status::HardBlocked { reason: HardBlockedReason::NotYetStarted },
|
||||
status_reason: "",
|
||||
@@ -458,14 +451,26 @@ impl Context {
|
||||
};
|
||||
Some(unsafe { &mut *kstack.initial_top().sub(size_of::<InterruptStack>()).cast() })
|
||||
}
|
||||
pub fn sigcontrol(&self) -> Option<&Sigcontrol> {
|
||||
assert_eq!(usize::from(self.sig.sigctl_off) % mem::align_of::<usize>(), 0);
|
||||
assert!(usize::from(self.sig.sigctl_off).saturating_add(mem::size_of::<Sigcontrol>()) < PAGE_SIZE);
|
||||
pub fn sigcontrol(&mut self) -> Option<(&Sigcontrol, &SigProcControl, &mut SignalState)> {
|
||||
let sig = self.sig.as_mut()?;
|
||||
|
||||
Some(unsafe {
|
||||
&*(RmmA::phys_to_virt(self.sig.control.as_ref()?.get().start_address())
|
||||
.data() as *const Sigcontrol).byte_add(usize::from(self.sig.sigctl_off))
|
||||
})
|
||||
let check = |off| {
|
||||
assert_eq!(usize::from(off) % mem::align_of::<usize>(), 0);
|
||||
assert!(usize::from(off).saturating_add(mem::size_of::<Sigcontrol>()) < PAGE_SIZE);
|
||||
};
|
||||
check(sig.procctl_off);
|
||||
check(sig.threadctl_off);
|
||||
|
||||
let for_thread = unsafe {
|
||||
&*(RmmA::phys_to_virt(sig.thread_control.get().start_address())
|
||||
.data() as *const Sigcontrol).byte_add(usize::from(sig.threadctl_off))
|
||||
};
|
||||
let for_proc = unsafe {
|
||||
&*(RmmA::phys_to_virt(sig.proc_control.get().start_address())
|
||||
.data() as *const SigProcControl).byte_add(usize::from(sig.procctl_off))
|
||||
};
|
||||
|
||||
Some((for_thread, for_proc, sig))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,9 +3,9 @@ use core::mem::size_of;
|
||||
use syscall::{
|
||||
flag::{
|
||||
PTRACE_FLAG_IGNORE, PTRACE_STOP_SIGNAL, SIGCHLD, SIGCONT, SIGKILL, SIGSTOP, SIGTSTP,
|
||||
SIGTTIN, SIGTTOU, SIG_DFL, SIG_IGN,
|
||||
SIGTTIN, SIGTTOU, SIGTERM,
|
||||
},
|
||||
ptrace_event, SigActionFlags, IntRegisters, SIGTERM,
|
||||
ptrace_event, IntRegisters,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
|
||||
@@ -50,7 +50,7 @@ unsafe fn update_runnable(context: &mut Context, cpu_id: LogicalCpuId) -> Update
|
||||
|
||||
// Switch to context if it needs to run
|
||||
if context.status.is_runnable() {
|
||||
UpdateResult::CanSwitch { signal: mem::take(&mut context.sig.is_pending) }
|
||||
UpdateResult::CanSwitch { signal: context.sig.as_mut().map_or(false, |s| mem::take(&mut s.is_pending)) }
|
||||
} else {
|
||||
UpdateResult::Skip
|
||||
}
|
||||
|
||||
+28
-17
@@ -8,7 +8,7 @@ use crate::{
|
||||
scheme::{self, FileHandle, KernelScheme},
|
||||
syscall::{
|
||||
self,
|
||||
data::{GrantDesc, Map, PtraceEvent, SetSighandlerData, SigAction, Stat},
|
||||
data::{GrantDesc, Map, PtraceEvent, SetSighandlerData, Stat},
|
||||
error::*,
|
||||
flag::*,
|
||||
usercopy::{UserSliceRo, UserSliceWo},
|
||||
@@ -23,6 +23,7 @@ use alloc::{
|
||||
sync::{Arc, Weak},
|
||||
vec::Vec,
|
||||
};
|
||||
use ::syscall::{SigProcControl, Sigcontrol};
|
||||
use core::{
|
||||
mem,
|
||||
num::NonZeroUsize,
|
||||
@@ -1133,28 +1134,38 @@ impl<const FULL: bool> KernelScheme for ProcScheme<FULL> {
|
||||
return Err(Error::new(EPERM));
|
||||
}
|
||||
|
||||
let (control, sigctl_off) = if data.word_addr != 0 {
|
||||
let offset = u16::try_from(data.word_addr % PAGE_SIZE).unwrap();
|
||||
let state = if data.thread_control_addr != 0 && data.proc_control_addr != 0 {
|
||||
let offset = u16::try_from(data.thread_control_addr % PAGE_SIZE).unwrap();
|
||||
|
||||
if offset % 16 != 0 {
|
||||
return Err(Error::new(EINVAL));
|
||||
}
|
||||
let validate_off = |addr, sz| {
|
||||
let off = addr % PAGE_SIZE;
|
||||
if off % mem::align_of::<usize>() == 0 && off + sz <= PAGE_SIZE {
|
||||
Ok(off as u16)
|
||||
} else {
|
||||
Err(Error::new(EINVAL))
|
||||
}
|
||||
};
|
||||
|
||||
let frame = AddrSpace::current()?
|
||||
.borrow_frame_enforce_rw_allocated(Page::containing_address(VirtualAddress::new(data.word_addr)))?;
|
||||
let addrsp = AddrSpace::current()?;
|
||||
|
||||
(Some(frame), offset)
|
||||
|
||||
Some(SignalState {
|
||||
threadctl_off: validate_off(data.thread_control_addr, mem::size_of::<Sigcontrol>())?,
|
||||
procctl_off: validate_off(data.proc_control_addr, mem::size_of::<SigProcControl>())?,
|
||||
user_handler: NonZeroUsize::new(data.user_handler).ok_or(Error::new(EINVAL))?,
|
||||
excp_handler: NonZeroUsize::new(data.excp_handler).ok_or(Error::new(EINVAL))?,
|
||||
thread_control: addrsp
|
||||
.borrow_frame_enforce_rw_allocated(Page::containing_address(VirtualAddress::new(data.thread_control_addr)))?,
|
||||
proc_control: addrsp
|
||||
.borrow_frame_enforce_rw_allocated(Page::containing_address(VirtualAddress::new(data.proc_control_addr)))?,
|
||||
is_pending: false,
|
||||
})
|
||||
} else {
|
||||
(None, 0)
|
||||
None
|
||||
};
|
||||
|
||||
context::contexts().get(info.pid).ok_or(Error::new(ESRCH))?.write().sig = SignalState {
|
||||
user_handler: NonZeroUsize::new(data.user_handler),
|
||||
excp_handler: NonZeroUsize::new(data.excp_handler),
|
||||
control,
|
||||
sigctl_off,
|
||||
is_pending: false,
|
||||
};
|
||||
|
||||
context::contexts().get(info.pid).ok_or(Error::new(ESRCH))?.write().sig = state;
|
||||
|
||||
Ok(mem::size_of::<SetSighandlerData>())
|
||||
}
|
||||
|
||||
+1
-1
@@ -15,7 +15,7 @@ pub use self::{
|
||||
};
|
||||
|
||||
use self::{
|
||||
data::{Map, SigAction, TimeSpec},
|
||||
data::{Map, TimeSpec},
|
||||
error::{Error, Result, EINTR, EOVERFLOW, ENOSYS},
|
||||
flag::{EventFlags, MapFlags, WaitFlags},
|
||||
number::*,
|
||||
|
||||
+27
-12
@@ -1,5 +1,6 @@
|
||||
use alloc::{sync::Arc, vec::Vec};
|
||||
use core::{mem, num::NonZeroUsize};
|
||||
use syscall::{sig_bit, SIGKILL, SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU};
|
||||
use core::{mem, num::NonZeroUsize, sync::atomic::Ordering};
|
||||
|
||||
use rmm::Arch;
|
||||
use spin::RwLock;
|
||||
@@ -14,11 +15,10 @@ use crate::{
|
||||
paging::{Page, VirtualAddress, PAGE_SIZE},
|
||||
ptrace,
|
||||
syscall::{
|
||||
data::SigAction,
|
||||
error::*,
|
||||
flag::{
|
||||
wifcontinued, wifstopped, MapFlags, WaitFlags, PTRACE_STOP_EXIT, SIGCONT,
|
||||
SIG_BLOCK, SIG_SETMASK, SIG_UNBLOCK, WCONTINUED, WNOHANG, WUNTRACED,
|
||||
wifcontinued, wifstopped, MapFlags, WaitFlags, PTRACE_STOP_EXIT, SIGCONT, WCONTINUED,
|
||||
WNOHANG, WUNTRACED,
|
||||
},
|
||||
ptrace_event,
|
||||
},
|
||||
@@ -140,9 +140,11 @@ pub fn kill(pid: ContextId, sig: usize) -> Result<usize> {
|
||||
(context.ruid, context.euid, context.pgid)
|
||||
};
|
||||
|
||||
if sig >= 0x3F {
|
||||
if sig > 0x3F {
|
||||
return Err(Error::new(EINVAL));
|
||||
}
|
||||
let sig_group = sig / 32;
|
||||
|
||||
let mut found = 0;
|
||||
let mut sent = 0;
|
||||
|
||||
@@ -154,19 +156,32 @@ pub fn kill(pid: ContextId, sig: usize) -> Result<usize> {
|
||||
if euid != 0 && euid != context.ruid && ruid != context.ruid {
|
||||
return false;
|
||||
}
|
||||
// If sig = 0, test that process exists and can be
|
||||
// signalled, but don't send any signal.
|
||||
// If sig = 0, test that process exists and can be signalled, but don't send any
|
||||
// signal.
|
||||
if sig == 0 {
|
||||
return true;
|
||||
}
|
||||
|
||||
todo!();
|
||||
|
||||
// Convert stopped processes to blocked if sending SIGCONT
|
||||
if sig == SIGCONT {
|
||||
if let context::Status::Stopped(_sig) = context.status {
|
||||
context.status = context::Status::Blocked;
|
||||
if sig == SIGCONT && let context::Status::Stopped(_sig) = context.status {
|
||||
context.status = context::Status::Blocked;
|
||||
if let Some((ctl, _, _)) = context.sigcontrol() {
|
||||
ctl.word[0].fetch_and(!(sig_bit(SIGTTIN) | sig_bit(SIGTTOU) | sig_bit(SIGTSTP)), Ordering::Relaxed);
|
||||
}
|
||||
} else if sig == SIGSTOP || (matches!(sig, SIGTTIN | SIGTTOU | SIGTSTP) && context.sigcontrol().map_or(false, |(_, proc, _)| proc.signal_will_stop(sig))) {
|
||||
context.status = context::Status::Stopped(sig);
|
||||
if let Some((ctl, _, _)) = context.sigcontrol() {
|
||||
ctl.word[0].fetch_and(!sig_bit(SIGCONT), Ordering::Relaxed);
|
||||
}
|
||||
} else if sig == SIGKILL {
|
||||
context.being_sigkilled = true;
|
||||
} else if let Some((ctl, _, st)) = context.sigcontrol() {
|
||||
let was_new = ctl.word[sig_group].fetch_or(sig_bit(sig), Ordering::Relaxed);
|
||||
if (ctl.word[sig_group].load(Ordering::Relaxed) >> 32) & sig_bit(sig) != 0 {
|
||||
st.is_pending = true;
|
||||
}
|
||||
} else {
|
||||
context.being_sigkilled = true;
|
||||
}
|
||||
|
||||
true
|
||||
|
||||
+1
-1
Submodule syscall updated: a4e7729934...5b07568677
Reference in New Issue
Block a user