Always take syscall_head/tail into account during the integrity check

Previously it wouldn't be taken into account if currently used by the
kernel.
This commit is contained in:
bjorn3
2025-09-26 23:26:06 +02:00
parent ede9a47f9c
commit 4c85131e36
3 changed files with 62 additions and 44 deletions
+42 -27
View File
@@ -71,6 +71,14 @@ pub enum HardBlockedReason {
const CONTEXT_NAME_CAPAC: usize = 32;
#[derive(Debug)]
pub enum SyscallFrame {
Free(RaiiFrame),
// The field is used by the consistency checker of the kernel debugger
Used { _frame: Frame },
Dummy,
}
/// A context, which is typically mapped to a userspace thread
#[derive(Debug)]
pub struct Context {
@@ -100,10 +108,10 @@ pub struct Context {
/// Head buffer to use when system call buffers are not page aligned
// TODO: Store in user memory?
pub syscall_head: Option<RaiiFrame>,
pub syscall_head: SyscallFrame,
/// Tail buffer to use when system call buffers are not page aligned
// TODO: Store in user memory?
pub syscall_tail: Option<RaiiFrame>,
pub syscall_tail: SyscallFrame,
/// Context should wake up at specified time
pub wake: Option<u128>,
/// The architecture specific context
@@ -168,8 +176,8 @@ impl Context {
cpu_time: 0,
sched_affinity: LogicalCpuSet::all(),
inside_syscall: false,
syscall_head: Some(RaiiFrame::allocate()?),
syscall_tail: Some(RaiiFrame::allocate()?),
syscall_head: SyscallFrame::Free(RaiiFrame::allocate()?),
syscall_tail: SyscallFrame::Free(RaiiFrame::allocate()?),
wake: None,
arch: arch::Context::new(),
kfx: AlignedBox::<[u8], { arch::KFX_ALIGN }>::try_zeroed_slice(crate::arch::kfx_size())?,
@@ -430,28 +438,36 @@ pub struct BorrowedHtBuf {
}
impl BorrowedHtBuf {
pub fn head(token: &mut CleanLockToken) -> Result<Self> {
Ok(Self {
inner: Some(
context::current()
.write(token.token())
.syscall_head
.take()
.ok_or(Error::new(EAGAIN))?,
),
head_and_not_tail: true,
})
let current = context::current();
let frame = &mut current.write(token.token()).syscall_head;
match mem::replace(frame, SyscallFrame::Dummy) {
SyscallFrame::Free(free_frame) => {
*frame = SyscallFrame::Used {
_frame: free_frame.get(),
};
Ok(Self {
inner: Some(free_frame),
head_and_not_tail: true,
})
}
SyscallFrame::Used { .. } | SyscallFrame::Dummy => Err(Error::new(EAGAIN)),
}
}
pub fn tail(token: &mut CleanLockToken) -> Result<Self> {
Ok(Self {
inner: Some(
context::current()
.write(token.token())
.syscall_tail
.take()
.ok_or(Error::new(EAGAIN))?,
),
head_and_not_tail: false,
})
let current = context::current();
let frame = &mut current.write(token.token()).syscall_tail;
match mem::replace(frame, SyscallFrame::Dummy) {
SyscallFrame::Free(free_frame) => {
*frame = SyscallFrame::Used {
_frame: free_frame.get(),
};
Ok(Self {
inner: Some(free_frame),
head_and_not_tail: false,
})
}
SyscallFrame::Used { .. } | SyscallFrame::Dummy => Err(Error::new(EAGAIN)),
}
}
pub fn buf(&self) -> &[u8; PAGE_SIZE] {
unsafe {
@@ -500,12 +516,11 @@ impl Drop for BorrowedHtBuf {
let mut token = unsafe { CleanLockToken::new() };
match context.write(token.token()) {
mut context => {
(if self.head_and_not_tail {
*(if self.head_and_not_tail {
&mut context.syscall_head
} else {
&mut context.syscall_tail
})
.get_or_insert(inner);
}) = SyscallFrame::Free(inner);
}
}
}
+17 -15
View File
@@ -1,5 +1,5 @@
use crate::{
context::{Context, ContextLock},
context::{context::SyscallFrame, Context, ContextLock},
memory::{get_page_info, the_zeroed_frame, Frame, RefCount},
paging::{RmmA, RmmArch, TableKind, PAGE_SIZE},
sync::CleanLockToken,
@@ -15,8 +15,6 @@ pub unsafe fn debugger(target_id: Option<*const ContextLock>, token: &mut CleanL
let mut tree = HashMap::new();
let mut spaces = HashSet::new();
let mut temporarily_taken_htbufs = 0;
tree.insert(the_zeroed_frame().0, (1, false));
let old_table = unsafe { RmmA::table(TableKind::User) };
@@ -30,15 +28,23 @@ pub unsafe fn debugger(target_id: Option<*const ContextLock>, token: &mut CleanL
let context = context_lock.0.read(context_token.token());
println!("{:p}: {}", Arc::as_ptr(&context_lock.0), context.name);
if let Some(ref head) = context.syscall_head {
tree.insert(head.get(), (1, false));
} else {
temporarily_taken_htbufs += 1;
match &context.syscall_head {
SyscallFrame::Free(head) => {
tree.insert(head.get(), (1, false));
}
SyscallFrame::Used { _frame: head } => {
tree.insert(*head, (1, false));
}
SyscallFrame::Dummy => {}
}
if let Some(ref tail) = context.syscall_tail {
tree.insert(tail.get(), (1, false));
} else {
temporarily_taken_htbufs += 1;
match &context.syscall_tail {
SyscallFrame::Free(tail) => {
tree.insert(tail.get(), (1, false));
}
SyscallFrame::Used { _frame: tail } => {
tree.insert(*tail, (1, false));
}
SyscallFrame::Dummy => {}
}
// Switch to context page table to ensure syscall debug and stack dump will work
@@ -156,10 +162,6 @@ pub unsafe fn debugger(target_id: Option<*const ContextLock>, token: &mut CleanL
);
}
}
println!(
"({} kernel-owned references were not counted)",
temporarily_taken_htbufs
);
println!("DEBUGGER END");
}
+3 -2
View File
@@ -6,6 +6,7 @@ use spin::RwLock;
use crate::{
context::{
context::SyscallFrame,
memory::{AddrSpace, Grant, PageSpan},
ContextRef,
},
@@ -37,8 +38,8 @@ pub fn exit_this_context(excp: Option<syscall::Exception>, token: &mut CleanLock
addrspace_opt = context
.set_addr_space(None)
.and_then(|a| Arc::try_unwrap(a).ok());
drop(context.syscall_head.take());
drop(context.syscall_tail.take());
drop(mem::replace(&mut context.syscall_head, SyscallFrame::Dummy));
drop(mem::replace(&mut context.syscall_tail, SyscallFrame::Dummy));
}
// Files must be closed while context is valid so that messages can be passed