diff --git a/kernel/src/cpu/paging.rs b/kernel/src/cpu/paging.rs index 3c35368..5ccb0bf 100644 --- a/kernel/src/cpu/paging.rs +++ b/kernel/src/cpu/paging.rs @@ -36,9 +36,10 @@ static PHYSICAL_FRAMES: Spinlock>> = Spinlock::new(OnceCell static HEAP_PHYS_MAPPING: Spinlock> = Spinlock::new(Vec::new()); const KERNEL_MAPPINGS_START: u64 = 0xfffffffd00000000; const KERNEL_MAPPINGS_END: u64 = 0xfffffffe00000000; +pub const USER_END: u64 = 0x800000000000 - 0x1000; // Avoid accidentally jumping to non-canonical address impl AddressSpace { - fn get_page(&mut self, virt: u64) -> Option<&mut PageEntry> { + pub fn get_page(&mut self, virt: u64) -> Option<&mut PageEntry> { let virt_page = virt as usize / 0x1000; let table_i = virt_page % 512; let directory_i = virt_page / 512 % 512; diff --git a/kernel/src/misc/elf.rs b/kernel/src/misc/elf.rs index ad939d7..f3c9cd0 100644 --- a/kernel/src/misc/elf.rs +++ b/kernel/src/misc/elf.rs @@ -4,12 +4,13 @@ use elf::{abi::PT_LOAD, endian::LittleEndian, ElfBytes}; use log::info; use crate::{ - cpu::cpu::{disable_user_memory_access, enable_user_memory_access}, + cpu::{ + cpu::{disable_user_memory_access, enable_user_memory_access}, + paging::USER_END, + }, sys::{lapic::get_current_lapic_id, task::CURRENT_TASKS}, }; -const USER_END: u64 = 0x800000000000 - 0x1000; // Avoid accidentally jumping to non-canonical address - extern "C" { fn jump_usermode(address: u64) -> !; } @@ -33,11 +34,9 @@ pub fn load_binary() { } let write = i.p_flags & 2 != 0; let exec = i.p_flags & 1 != 0; - assert!(i.p_vaddr + i.p_memsz < USER_END); - assert!(i.p_vaddr + i.p_memsz >= i.p_vaddr); + assert!(i.p_vaddr.checked_add(i.p_memsz).unwrap_or(USER_END + 1) <= USER_END); assert!(i.p_filesz <= i.p_memsz); - assert!(i.p_offset + i.p_filesz <= binary.len() as u64); - assert!(i.p_offset + i.p_filesz >= i.p_offset); + assert!(i.p_offset.checked_add(i.p_filesz).unwrap_or(binary.len() as u64 + 1) <= binary.len() as u64); assert!(!write || !exec); let start = i.p_vaddr / 0x1000 * 0x1000; let end = (i.p_vaddr + i.p_memsz + 0xfff) / 0x1000 * 0x1000; diff --git a/kernel/src/sys/syscall.rs b/kernel/src/sys/syscall.rs index 45a6b4b..c2904a4 100644 --- a/kernel/src/sys/syscall.rs +++ b/kernel/src/sys/syscall.rs @@ -1,21 +1,70 @@ -use log::debug; +use core::{error::Error, ptr::copy}; -use super::task::terminate_current_task; +use alloc::{boxed::Box, string::String, vec::Vec}; +use log::{debug, trace}; + +use crate::cpu::{ + cpu::{disable_user_memory_access, enable_user_memory_access}, + paging::USER_END, +}; + +use super::{ + lapic::get_current_lapic_id, + task::{terminate_current_task, CURRENT_TASKS}, +}; struct SyscallArgs { - _arg1: usize, - _arg2: usize, + arg1: usize, + arg2: usize, _arg3: usize, _arg4: usize, _arg5: usize, } -const SYSCALL_TABLE: [fn(SyscallArgs) -> usize; 1] = [syscall_get_kernel_version]; +const SYSCALL_TABLE: [fn(SyscallArgs) -> Result>; 3] = [syscall_get_kernel_version, syscall_exit, syscall_debug_print]; -fn syscall_get_kernel_version(_args: SyscallArgs) -> usize { - 0 +fn copy_from_user(start: u64, size: usize) -> Result, Box> { + if size > 16 * 1024 * 1024 { + return Err("Too large copy requested".into()); + } + let end = start.checked_add(size as u64).ok_or("Invalid copy requested")?; + if end > USER_END { + return Err("Invalid copy requested".into()); + } + let process; + { + let tasks = CURRENT_TASKS.lock(); + process = tasks[get_current_lapic_id()].as_ref().unwrap().process.clone(); + } + let mut process = process.lock(); + for i in start / 0x1000..(end + 0xfff) / 0x1000 { + let page = process.address_space.get_page(i * 0x1000); + if page.is_none() || page.unwrap().present() == 0 { + return Err("Invalid copy requested".into()); + } + } + let mut buffer = Vec::with_capacity(size); + buffer.resize(size, 0); + enable_user_memory_access(); + unsafe { + copy(start as *const u8, buffer.as_mut_ptr(), size); + } + disable_user_memory_access(); + Ok(buffer) +} +fn syscall_get_kernel_version(_args: SyscallArgs) -> Result> { + Ok(0) +} +fn syscall_exit(_args: SyscallArgs) -> Result> { + // TODO: Also terminate other threads + terminate_current_task(); +} +fn syscall_debug_print(args: SyscallArgs) -> Result> { + let data = copy_from_user(args.arg1 as u64, args.arg2)?; + let string = String::from_utf8(data)?; + trace!("{}", string); + Ok(0) } - #[no_mangle] extern "C" fn syscall_handler(syscall: u64, arg1: u64, arg2: u64, arg3: u64, arg4: u64, arg5: u64) -> u64 { if syscall as usize >= SYSCALL_TABLE.len() { @@ -23,12 +72,16 @@ extern "C" fn syscall_handler(syscall: u64, arg1: u64, arg2: u64, arg3: u64, arg terminate_current_task(); } let args = SyscallArgs { - _arg1: arg1 as usize, - _arg2: arg2 as usize, + arg1: arg1 as usize, + arg2: arg2 as usize, _arg3: arg3 as usize, _arg4: arg4 as usize, _arg5: arg5 as usize, }; let result = SYSCALL_TABLE[syscall as usize](args); - result as u64 + if result.is_err() { + debug!("Error during syscall: {}", result.err().unwrap()); + terminate_current_task(); + } + result.unwrap() as u64 } diff --git a/kernel/src/sys/task.rs b/kernel/src/sys/task.rs index 5b778cf..d29b329 100644 --- a/kernel/src/sys/task.rs +++ b/kernel/src/sys/task.rs @@ -146,7 +146,9 @@ fn create_idle_task() { } } pub fn terminate_current_task() -> ! { - CURRENT_TASKS.lock()[get_current_lapic_id()].as_mut().unwrap().task_state = TaskState::Terminated; + { + CURRENT_TASKS.lock()[get_current_lapic_id()].as_mut().unwrap().task_state = TaskState::Terminated; + } yield_task(); panic!("Failed to terminate task"); }