WIP: implement kill syscall prototype

This commit is contained in:
4lDO2
2024-06-20 22:14:27 +02:00
parent 639ba74a7e
commit 55fe58adf6
7 changed files with 92 additions and 61 deletions
+32 -27
View File
@@ -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))
}
}
+2 -2
View File
@@ -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::{
+1 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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