Fix the SIGKILL fd leak bug.

This commit is contained in:
4lDO2
2024-03-07 20:01:44 +01:00
parent 8e19da338b
commit 4a3dc2dadd
9 changed files with 58 additions and 29 deletions
+20 -11
View File
@@ -1,4 +1,5 @@
use alloc::{borrow::Cow, sync::Arc, vec::Vec};
use syscall::{SIGKILL, SIGSTOP};
use core::{cmp::Ordering, mem, num::NonZeroUsize};
use spin::RwLock;
@@ -23,7 +24,7 @@ use crate::syscall::{
/// Unique identifier for a context (i.e. `pid`).
use ::core::sync::atomic::AtomicUsize;
use super::memory::{GrantFileRef, AddrSpaceWrapper};
use super::{memory::{GrantFileRef, AddrSpaceWrapper}, empty_cr3};
int_like!(ContextId, AtomicContextId, usize, AtomicUsize);
/// The status of a context - used for scheduling
@@ -396,13 +397,14 @@ impl Context {
}
pub fn set_addr_space(
&mut self,
addr_space: Arc<AddrSpaceWrapper>,
addr_space: Option<Arc<AddrSpaceWrapper>>,
) -> Option<Arc<AddrSpaceWrapper>> {
if let Some(ref old) = self.addr_space && Arc::ptr_eq(old, &addr_space) {
return Some(addr_space);
if let (Some(ref old), Some(ref new)) = (&self.addr_space, &addr_space) && Arc::ptr_eq(old, new) {
return addr_space;
};
if self.id == super::context_id() {
// TODO: Share more code with context::arch::switch_to.
let this_percpu = PercpuBlock::current();
if let Some(ref prev_addrsp) = self.addr_space {
@@ -410,19 +412,25 @@ impl Context {
prev_addrsp.acquire_read().used_by.atomic_clear(this_percpu.cpu_id);
}
*this_percpu.current_addrsp.borrow_mut() = Some(Arc::clone(&addr_space));
let _old_addrsp = core::mem::replace(&mut *this_percpu.current_addrsp.borrow_mut(), addr_space.clone());
let new_addrsp = addr_space.acquire_read();
new_addrsp.used_by.atomic_set(this_percpu.cpu_id);
if let Some(ref new) = addr_space {
let new_addrsp = new.acquire_read();
new_addrsp.used_by.atomic_set(this_percpu.cpu_id);
unsafe {
new_addrsp.table.utable.make_current();
unsafe {
new_addrsp.table.utable.make_current();
}
} else {
unsafe {
crate::paging::RmmA::set_table(rmm::TableKind::User, empty_cr3());
}
}
} else {
assert!(!self.running);
}
self.addr_space.replace(addr_space)
core::mem::replace(&mut self.addr_space, addr_space)
}
pub fn empty_actions() -> Arc<RwLock<Vec<(SigAction, usize)>>> {
Arc::new(RwLock::new(vec![(
@@ -470,7 +478,8 @@ impl Context {
impl SignalState {
pub fn deliverable(&self) -> u64 {
self.pending & !self.procmask
const CANT_BLOCK: u64 = (1 << (SIGKILL - 1)) | (1 << (SIGSTOP - 1));
self.pending & (CANT_BLOCK | !self.procmask)
}
}
+1 -1
View File
@@ -113,7 +113,7 @@ impl ContextList {
let context_lock = self.new_context()?;
{
let mut context = context_lock.write();
let _ = context.set_addr_space(AddrSpaceWrapper::new()?);
let _ = context.set_addr_space(Some(AddrSpaceWrapper::new()?));
let mut stack_top = unsafe { stack.as_mut_ptr().add(KSTACK_SIZE) };
+14 -2
View File
@@ -42,7 +42,7 @@ pub fn kmain_signal_handler() {
// TODO: Move everything but SIGKILL to userspace. SIGCONT and SIGSTOP do not necessarily need to
// be done from this current context.
pub fn signal_handler(eintr: bool) {
pub fn signal_handler() {
let (action, sig) = {
// FIXME: Can any low-level state become corrupt if a panic occurs here?
let context_lock = context::current().expect("context::signal_handler not inside of context");
@@ -53,7 +53,18 @@ pub fn signal_handler(eintr: bool) {
if context.sig.deliverable() == 0 {
return;
}
let selected = context.sig.deliverable().trailing_zeros() as usize + 1;
let bits = context.sig.deliverable();
// Always prioritize SIGKILL and SIGSTOP, so processes can't simply keep themselves alive
// by killing themselves.
let selected = if bits & (1 << (SIGKILL - 1)) != 0 {
SIGKILL
} else if bits & (1 << (SIGSTOP - 1)) != 0 {
SIGSTOP
} else {
bits.trailing_zeros() as usize + 1
};
context.sig.pending &= !(1 << (selected - 1));
let actions = context.actions.read();
@@ -111,6 +122,7 @@ pub fn signal_handler(eintr: bool) {
}
}
}
// FIXME: SIGSTOP shouldn't be overridable
SIGSTOP | SIGTSTP | SIGTTIN | SIGTTOU => {
// println!("Stop {}", sig);
+2 -2
View File
@@ -80,7 +80,7 @@ pub fn tick() {
if new_ticks >= 3 {
match switch() {
SwitchResult::Switched { signal: true } => {
crate::context::signal::signal_handler(false);
crate::context::signal::signal_handler();
},
_ => (),
}
@@ -94,8 +94,8 @@ pub unsafe extern "C" fn switch_finish_hook() {
// TODO: unreachable_unchecked()?
crate::arch::stop::emergency_reset();
}
crate::percpu::switch_arch_hook();
arch::CONTEXT_SWITCH_LOCK.store(false, Ordering::SeqCst);
crate::percpu::switch_arch_hook();
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]