diff --git a/crates/kernel/src/lib.rs b/crates/kernel/src/lib.rs index f0fc6a3..cbb8802 100644 --- a/crates/kernel/src/lib.rs +++ b/crates/kernel/src/lib.rs @@ -218,12 +218,13 @@ impl Kernel

{ } pub(crate) fn destroy_process(&mut self, pid: ProcessId) { - // Collect thread IDs before cleanup - let thread_ids: [Option; 4] = match self.processes.get(pid) { + use domain::process::MAX_THREADS_PER_PROCESS; + + let thread_ids: [Option; MAX_THREADS_PER_PROCESS] = match self.processes.get(pid) { Ok(p) => { - let mut ids = [None; 4]; + let mut ids = [None; MAX_THREADS_PER_PROCESS]; for (i, tid) in p.thread_ids().enumerate() { - if i < 4 { ids[i] = Some(tid); } + if i < MAX_THREADS_PER_PROCESS { ids[i] = Some(tid); } } ids } @@ -250,7 +251,7 @@ impl Kernel

{ self.process_memory[pid.raw() as usize] = None; } - pub(crate) fn cleanup_threads(&mut self, thread_ids: &[Option; 4]) { + pub(crate) fn cleanup_threads(&mut self, thread_ids: &[Option]) { use domain::scheduler::Scheduler; for slot in thread_ids { if let Some(tid) = slot { diff --git a/crates/kernel/src/syscall/ipc.rs b/crates/kernel/src/syscall/ipc.rs index 9da25a2..105a9b3 100644 --- a/crates/kernel/src/syscall/ipc.rs +++ b/crates/kernel/src/syscall/ipc.rs @@ -25,7 +25,10 @@ impl Kernel

{ all_perms, ) { Ok(slot) => SyscallOutcome::Complete(SyscallResult::Slot(slot)), - Err(e) => SyscallOutcome::Complete(SyscallResult::Error(e)), + Err(e) => { + let _ = self.endpoints.destroy(ep_id); + SyscallOutcome::Complete(SyscallResult::Error(e)) + } } } diff --git a/crates/kernel/src/syscall/lifecycle.rs b/crates/kernel/src/syscall/lifecycle.rs index ec1345f..fc44497 100644 --- a/crates/kernel/src/syscall/lifecycle.rs +++ b/crates/kernel/src/syscall/lifecycle.rs @@ -1,3 +1,4 @@ +use domain::process::MAX_THREADS_PER_PROCESS; use platform::Platform; use super::{SyscallOutcome, SyscallResult}; @@ -14,7 +15,7 @@ impl Kernel

{ use domain::thread::SavedContext; let priority = types::bounded::Priority::DEFAULT; - let time_slice = types::time::TimeSlice::DEFAULT; + let time_slice = types::time::TimeSlice::new(100); let context = SavedContext::with_entry_and_stack(entry, stack); let tid = match self.threads.spawn_with_context(pid, priority, time_slice, None, context) { @@ -38,8 +39,6 @@ impl Kernel

{ create_cap: types::bounded::CapSlot, _image: types::address::DataRef, ) -> SyscallOutcome { - use domain::scheduler::Scheduler; - if let Err(e) = self.check_cap(caller_pid, create_cap, types::permission::Permission::Execute) { return SyscallOutcome::Complete(SyscallResult::Error(e)); } @@ -55,18 +54,21 @@ impl Kernel

{ self.process_memory[new_pid.raw() as usize] = Some(domain::memory::process_memory::ProcessMemory::new(new_pid, 1024)); - let slot = match self.grant_cap( + match self.grant_cap( caller_pid, domain::resource::Resource::Process(new_pid), types::permission::PermissionSet::empty() .with(types::permission::Permission::Execute) .with(types::permission::Permission::Read), ) { - Ok(s) => s, - Err(e) => return SyscallOutcome::Complete(SyscallResult::Error(e)), - }; - - SyscallOutcome::Complete(SyscallResult::Slot(slot)) + Ok(slot) => SyscallOutcome::Complete(SyscallResult::Slot(slot)), + Err(e) => { + // Rollback: destroy orphaned process + let _ = self.processes.destroy(new_pid); + self.process_memory[new_pid.raw() as usize] = None; + SyscallOutcome::Complete(SyscallResult::Error(e)) + } + } } pub(crate) fn handle_spawn_thread_in( @@ -97,7 +99,7 @@ impl Kernel

{ }; let priority = types::bounded::Priority::DEFAULT; - let time_slice = types::time::TimeSlice::DEFAULT; + let time_slice = types::time::TimeSlice::new(100); let context = SavedContext::with_entry_and_stack(entry, stack); let tid = match self.threads.spawn_with_context(target_pid, priority, time_slice, None, context) { @@ -133,23 +135,7 @@ impl Kernel

{ Err(e) => return SyscallOutcome::Complete(SyscallResult::Error(e)), }; - let thread_ids: [Option; 4] = { - match self.processes.get(target_pid) { - Ok(p) => { - let mut ids = [None; 4]; - for (i, tid) in p.thread_ids().enumerate() { - if i < 4 { ids[i] = Some(tid); } - } - ids - } - Err(e) => return SyscallOutcome::Complete(SyscallResult::Error(e)), - } - }; - - self.cleanup_threads(&thread_ids); - - let _ = self.processes.destroy(target_pid); - self.process_memory[target_pid.raw() as usize] = None; + self.destroy_process(target_pid); SyscallOutcome::Complete(SyscallResult::Ok) } } diff --git a/crates/kernel/src/syscall/memory.rs b/crates/kernel/src/syscall/memory.rs index 0c6f677..02297a5 100644 --- a/crates/kernel/src/syscall/memory.rs +++ b/crates/kernel/src/syscall/memory.rs @@ -4,6 +4,8 @@ use types::address::{PhysicalAddress, VirtualAddress}; use super::{SyscallOutcome, SyscallResult}; use crate::Kernel; +const USER_VA_LIMIT: usize = 0x80000000; + impl Kernel

{ pub(crate) fn handle_request_pages( &mut self, @@ -12,7 +14,6 @@ impl Kernel

{ ) -> SyscallOutcome { let pages = count.value() as usize; - // Check limits first (separate borrow) match &mut self.process_memory[pid.raw() as usize] { Some(pm) => { if pm.grant(pages).is_err() { @@ -26,7 +27,6 @@ impl Kernel

{ )), } - // Allocate physical pages from pool let phys_addr = match self.page_pool.allocate(pages) { Some(a) => a, None => { @@ -39,24 +39,26 @@ impl Kernel

{ } }; - // Allocate user VA and record allocation (only after pool succeeds) let user_va = match &mut self.process_memory[pid.raw() as usize] { Some(pm) => { let va = pm.alloc_user_va(pages); pm.record_allocation(phys_addr, pages); va } - None => unreachable!(), + None => { + self.page_pool.free(phys_addr, pages); + return SyscallOutcome::Complete(SyscallResult::Error( + domain::error::KernelError::InvalidProcess(pid), + )); + } }; - // Map pages for i in 0..pages { let page_va = VirtualAddress::from_raw(user_va.raw() + i * 4096); let page_pa = PhysicalAddress::from_raw(phys_addr.raw() + i * 4096); self.platform.map_user_page(pid, page_va, page_pa, true, false); } - // Track region for ReleasePages let region = domain::memory::MemoryRegion::new( types::id::RegionId::from_raw(0), pid, @@ -77,6 +79,16 @@ impl Kernel

{ dst_va: VirtualAddress, executable: bool, ) -> SyscallOutcome { + // Prevent mapping kernel memory into userspace + if src_va.raw() >= USER_VA_LIMIT { + return SyscallOutcome::Complete(SyscallResult::Error( + domain::error::KernelError::PermissionDenied { + slot: process_cap, + needed: types::permission::Permission::Read, + }, + )); + } + let target_pid = match self.check_cap( caller_pid, process_cap,