From d9a3ba81e50f4e55e6e2adeb5b70039b5bd839de Mon Sep 17 00:00:00 2001 From: Chinmay Shringi Date: Mon, 25 Nov 2024 16:31:33 -0500 Subject: [PATCH 01/66] Changes from vmmap alice rawposix --- src/RawPOSIX/Cargo.toml | 2 + src/RawPOSIX/src/interface/types.rs | 4 - src/RawPOSIX/src/safeposix/cage.rs | 11 +- src/RawPOSIX/src/safeposix/dispatcher.rs | 52 -- src/RawPOSIX/src/safeposix/mod.rs | 2 + .../src/safeposix/syscalls/sys_calls.rs | 135 ---- src/RawPOSIX/src/safeposix/vmmap.rs | 630 ++++++++++++++++++ src/RawPOSIX/src/safeposix/vmmap_constants.rs | 32 + src/RawPOSIX/src/tests/sys_tests.rs | 49 -- 9 files changed, 669 insertions(+), 248 deletions(-) create mode 100644 src/RawPOSIX/src/safeposix/vmmap.rs create mode 100644 src/RawPOSIX/src/safeposix/vmmap_constants.rs diff --git a/src/RawPOSIX/Cargo.toml b/src/RawPOSIX/Cargo.toml index 5682de9c9..2c0d6544c 100644 --- a/src/RawPOSIX/Cargo.toml +++ b/src/RawPOSIX/Cargo.toml @@ -24,6 +24,8 @@ ringbuf = "0.2.6" dashmap = { version = "5.1", features=["serde"] } parking_lot = "0.12" bit-set = "0.5" +nodit = "0.9.2" # Used for VMMAP +quick_cache = "0.6.9" [dependencies.lazy_static] version = "1.0" diff --git a/src/RawPOSIX/src/interface/types.rs b/src/RawPOSIX/src/interface/types.rs index e5b545f21..40efd4d93 100644 --- a/src/RawPOSIX/src/interface/types.rs +++ b/src/RawPOSIX/src/interface/types.rs @@ -379,10 +379,6 @@ pub fn get_ioctlptrunion<'a>(generic_argument: u64) -> Result<&'a mut u8, i32> { )); } -pub fn get_i32_ref<'a>(generic_argument: u64) -> Result<&'a mut i32, i32> { - unsafe { Ok(&mut *((generic_argument) as *mut i32)) } -} - pub fn get_pipearray<'a>(generic_argument: u64) -> Result<&'a mut PipeArray, i32> { let pointer = generic_argument as *mut PipeArray; if !pointer.is_null() { diff --git a/src/RawPOSIX/src/safeposix/cage.rs b/src/RawPOSIX/src/safeposix/cage.rs index 6f7a3eac8..375f32bd1 100644 --- a/src/RawPOSIX/src/safeposix/cage.rs +++ b/src/RawPOSIX/src/safeposix/cage.rs @@ -11,15 +11,11 @@ use super::filesystem::normpath; pub use super::syscalls::fs_constants::*; pub use super::syscalls::net_constants::*; pub use super::syscalls::sys_constants::*; +pub use super::vmmap::*; +pub use super::vmmap_constants::*; pub use crate::interface::CAGE_TABLE; -#[derive(Debug, Clone, Copy)] -pub struct Zombie { - pub cageid: u64, - pub exit_code: i32 -} - #[derive(Debug)] pub struct Cage { pub cageid: u64, @@ -40,8 +36,7 @@ pub struct Cage { pub pendingsigset: interface::RustHashMap, pub main_threadid: interface::RustAtomicU64, pub interval_timer: interface::IntervalTimer, - pub zombies: interface::RustLock>, - pub child_num: interface::RustAtomicU64 + pub vmmap: Vmmap, } impl Cage { diff --git a/src/RawPOSIX/src/safeposix/dispatcher.rs b/src/RawPOSIX/src/safeposix/dispatcher.rs index 5b47f23a1..814a24090 100644 --- a/src/RawPOSIX/src/safeposix/dispatcher.rs +++ b/src/RawPOSIX/src/safeposix/dispatcher.rs @@ -114,8 +114,6 @@ const SYNC_FILE_RANGE: i32 = 164; const WRITEV_SYSCALL: i32 = 170; const CLONE_SYSCALL: i32 = 171; -const WAIT_SYSCALL: i32 = 172; -const WAITPID_SYSCALL: i32 = 173; const NANOSLEEP_TIME64_SYSCALL : i32 = 181; @@ -356,16 +354,6 @@ pub fn lind_syscall_api( .exit_syscall(status) } - SELECT_SYSCALL => { - let nfds = arg1 as i32; - let readfds = interface::get_fdset(arg2).unwrap(); - let writefds = interface::get_fdset(arg3).unwrap(); - let errorfds = interface::get_fdset(arg4).unwrap(); - let rposix_timeout = interface::duration_fromtimeval(arg5).unwrap(); - interface::cagetable_getref(cageid) - .select_syscall(nfds, readfds, writefds, errorfds, rposix_timeout) - } - RENAME_SYSCALL => { let old_ptr = (start_address + arg1) as *const u8; let new_ptr = (start_address + arg2) as *const u8; @@ -819,26 +807,6 @@ pub fn lind_syscall_api( .epoll_create_syscall(size) } - EPOLL_CTL_SYSCALL=> { - let virtual_epfd = arg1 as i32; - let op = arg2 as i32; - let virtual_fd = arg3 as i32; - let epollevent = interface::get_epollevent(arg4).unwrap(); - - interface::cagetable_getref(cageid) - .epoll_ctl_syscall(virtual_epfd, op, virtual_fd, epollevent) - } - - EPOLL_WAIT_SYSCALL => { - let virtual_epfd = arg1 as i32; - let maxevents = arg3 as i32; - let events = interface::get_epollevent_slice(arg2, maxevents).unwrap(); - let timeout = arg4 as i32; - interface::cagetable_getref(cageid) - .epoll_wait_syscall(virtual_epfd, events, maxevents, timeout) - } - - SETSOCKOPT_SYSCALL => { let virtual_fd = arg1 as i32; let level = arg2 as i32; @@ -1037,22 +1005,6 @@ pub fn lind_syscall_api( .nanosleep_time64_syscall(clockid, flags, req, rem) } - WAIT_SYSCALL => { - let mut status = interface::get_i32_ref(start_address + arg1).unwrap(); - - interface::cagetable_getref(cageid) - .wait_syscall(&mut status) - } - - WAITPID_SYSCALL => { - let pid = arg1 as i32; - let mut status = interface::get_i32_ref(start_address + arg2).unwrap(); - let options = arg3 as i32; - - interface::cagetable_getref(cageid) - .waitpid_syscall(pid, &mut status, options) - } - _ => -1, // Return -1 for unknown syscalls }; ret @@ -1145,8 +1097,6 @@ pub fn lindrustinit(verbosity: isize) { pendingsigset: interface::RustHashMap::new(), main_threadid: interface::RustAtomicU64::new(0), interval_timer: interface::IntervalTimer::new(0), - zombies: interface::RustLock::new(vec![]), - child_num: interface::RustAtomicU64::new(0), }; interface::cagetable_insert(0, utilcage); @@ -1186,8 +1136,6 @@ pub fn lindrustinit(verbosity: isize) { pendingsigset: interface::RustHashMap::new(), main_threadid: interface::RustAtomicU64::new(0), interval_timer: interface::IntervalTimer::new(1), - zombies: interface::RustLock::new(vec![]), - child_num: interface::RustAtomicU64::new(0), }; interface::cagetable_insert(1, initcage); fdtables::init_empty_cage(1); diff --git a/src/RawPOSIX/src/safeposix/mod.rs b/src/RawPOSIX/src/safeposix/mod.rs index 9957c3976..6f4bc0e36 100644 --- a/src/RawPOSIX/src/safeposix/mod.rs +++ b/src/RawPOSIX/src/safeposix/mod.rs @@ -3,3 +3,5 @@ pub mod dispatcher; pub mod filesystem; pub mod shm; pub mod syscalls; +pub mod vmmap; +pub mod vmmap_constants; diff --git a/src/RawPOSIX/src/safeposix/syscalls/sys_calls.rs b/src/RawPOSIX/src/safeposix/syscalls/sys_calls.rs index f2659924a..85a7b151f 100644 --- a/src/RawPOSIX/src/safeposix/syscalls/sys_calls.rs +++ b/src/RawPOSIX/src/safeposix/syscalls/sys_calls.rs @@ -169,13 +169,8 @@ impl Cage { pendingsigset: interface::RustHashMap::new(), main_threadid: interface::RustAtomicU64::new(0), interval_timer: interface::IntervalTimer::new(child_cageid), - zombies: interface::RustLock::new(vec![]), - child_num: interface::RustAtomicU64::new(0), }; - // increment child counter for parent - self.child_num.fetch_add(1, interface::RustAtomicOrdering::SeqCst); - let shmtable = &SHM_METADATA.shmtable; //update fields for shared mappings in cage for rev_mapping in cageobj.rev_shm.lock().iter() { @@ -207,11 +202,6 @@ impl Cage { self.unmap_shm_mappings(); - let zombies = self.zombies.read(); - let cloned_zombies = zombies.clone(); - let child_num = self.child_num.load(interface::RustAtomicOrdering::Relaxed); - drop(zombies); - // we grab the parent cages main threads sigset and store it at 0 // this way the child can initialize the sigset properly when it establishes its own mainthreadid let newsigset = interface::RustHashMap::new(); @@ -251,9 +241,6 @@ impl Cage { pendingsigset: interface::RustHashMap::new(), main_threadid: interface::RustAtomicU64::new(0), interval_timer: self.interval_timer.clone_with_new_cageid(child_cageid), - // when a process exec-ed, its child relationship should be perserved - zombies: interface::RustLock::new(cloned_zombies), - child_num: interface::RustAtomicU64::new(child_num), }; //wasteful clone of fdtable, but mutability constraints exist @@ -271,23 +258,6 @@ impl Cage { //may not be removable in case of lindrustfinalize, we don't unwrap the remove result interface::cagetable_remove(self.cageid); - // if the cage has parent - if self.parent != self.cageid { - let parent_cage = interface::cagetable_getref_opt(self.parent); - // if parent hasn't exited yet - if let Some(parent) = parent_cage { - // decrement parent's child counter - parent.child_num.fetch_sub(1, interface::RustAtomicOrdering::SeqCst); - - // push the exit status to parent's zombie list - let mut zombie_vec = parent.zombies.write(); - zombie_vec.push(Zombie { cageid: self.cageid, exit_code: status }); - } else { - // if parent already exited - // BUG: we currently do not handle the situation where a parent has exited already - } - } - // Trigger SIGCHLD if !interface::RUSTPOSIX_TESTSUITE.load(interface::RustAtomicOrdering::Relaxed) { // dont trigger SIGCHLD for test suite @@ -301,111 +271,6 @@ impl Cage { status } - //------------------------------------WAITPID SYSCALL------------------------------------ - /* - * waitpid() will return the cageid of waited cage, or 0 when WNOHANG is set and there is no cage already exited - * waitpid_syscall utilizes the zombie list stored in cage struct. When a cage exited, a zombie entry will be inserted - * into the end of its parent's zombie list. Then when parent wants to wait for any of child, it could just check its - * zombie list and retrieve the first entry from it (first in, first out). - */ - pub fn waitpid_syscall(&self, cageid: i32, status: &mut i32, options: i32) -> i32 { - let mut zombies = self.zombies.write(); - let child_num = self.child_num.load(interface::RustAtomicOrdering::Relaxed); - - // if there is no pending zombies to wait, and there is no active child, return ECHILD - if zombies.len() == 0 && child_num == 0 { - return syscall_error(Errno::ECHILD, "waitpid", "no existing unwaited-for child processes"); - } - - let mut zombie_opt: Option = None; - - // cageid <= 0 means wait for ANY child - // cageid < 0 actually refers to wait for any child process whose process group ID equals -pid - // but we do not have the concept of process group in lind, so let's just treat it as cageid == 0 - if cageid <= 0 { - loop { - if zombies.len() == 0 && (options & libc::WNOHANG > 0) { - // if there is no pending zombies and WNOHANG is set - // return immediately - return 0; - } else if zombies.len() == 0 { - // if there is no pending zombies and WNOHANG is not set - // then we need to wait for children to exit - // drop the zombies list before sleep to avoid deadlock - drop(zombies); - // TODO: replace busy waiting with more efficient mechanism - interface::lind_yield(); - // after sleep, get the write access of zombies list back - zombies = self.zombies.write(); - continue; - } else { - // there are zombies avaliable - // let's retrieve the first zombie - zombie_opt = Some(zombies.remove(0)); - break; - } - } - } - // if cageid is specified, then we need to look up the zombie list for the id - else { - // first let's check if the cageid is in the zombie list - if let Some(index) = zombies.iter().position(|zombie| zombie.cageid == cageid as u64) { - // find the cage in zombie list, remove it from the list and break - zombie_opt = Some(zombies.remove(index)); - } else { - // if the cageid is not in the zombie list, then we know either - // 1. the child is still running, or - // 2. the cage has exited, but it is not the child of this cage, or - // 3. the cage does not exist - // we need to make sure the child is still running, and it is the child of this cage - let child = interface::cagetable_getref_opt(cageid as u64); - if let Some(child_cage) = child { - // make sure the child's parent is correct - if child_cage.parent != self.cageid { - return syscall_error(Errno::ECHILD, "waitpid", "waited cage is not the child of the cage"); - } - } else { - // cage does not exist - return syscall_error(Errno::ECHILD, "waitpid", "cage does not exist"); - } - - // now we have verified that the cage exists and is the child of the cage - loop { - // the cage is not in the zombie list - // we need to wait for the cage to actually exit - - // drop the zombies list before sleep to avoid deadlock - drop(zombies); - // TODO: replace busy waiting with more efficient mechanism - interface::lind_yield(); - // after sleep, get the write access of zombies list back - zombies = self.zombies.write(); - - // let's check if the zombie list contains the cage - if let Some(index) = zombies.iter().position(|zombie| zombie.cageid == cageid as u64) { - // find the cage in zombie list, remove it from the list and break - zombie_opt = Some(zombies.remove(index)); - break; - } - - continue; - } - } - } - - // reach here means we already found the desired exited child - let zombie = zombie_opt.unwrap(); - // update the status - *status = zombie.exit_code; - - // return child's cageid - zombie.cageid as i32 - } - - pub fn wait_syscall(&self, status: &mut i32) -> i32 { - self.waitpid_syscall(0, status, 0) - } - pub fn getpid_syscall(&self) -> i32 { self.cageid as i32 //not sure if this is quite what we want but it's easy enough to change later } diff --git a/src/RawPOSIX/src/safeposix/vmmap.rs b/src/RawPOSIX/src/safeposix/vmmap.rs new file mode 100644 index 000000000..08ae0d1d3 --- /dev/null +++ b/src/RawPOSIX/src/safeposix/vmmap.rs @@ -0,0 +1,630 @@ +use super::vmmap_constants::*; +use std::io; +use nodit::NoditMap; +use nodit::{interval::ie, Interval}; + +/// Used to identify whether the vmmap entry is backed anonymously, +/// by an fd, or by a shared memory segment + +#[allow(dead_code)] +#[derive(Clone, Copy, PartialEq, Eq, Debug)] +pub enum MemoryBackingType { + None, // just a dummy value for places where it needs to be passed, but you dont have the value + Anonymous, + SharedMemory(u64), // stores shmid + FileDescriptor(u64), // stores file descriptor addr +} + + +/// An entry in the virtual memory map that contains fields such as page number, number of pages, +/// permissions, file offset, file size, shared memory ID, and backing fields to distinguish memory types. +#[derive(Clone, PartialEq, Eq, Debug)] +pub struct VmmapEntry { + pub page_num: u32, /* base virtual addr >> NACL_PAGESHIFT */ + pub npages: u32, /* number of pages */ + pub prot: i32, /* mprotect attribute */ + pub maxprot: i32, + pub flags: i32, /* mapping flags */ + pub removed: bool, /* flag set in fn Update(); */ + pub file_offset: i64, /* offset into desc */ + pub file_size: i64, /* backing store size */ + pub cage_id: u64, + pub backing: MemoryBackingType, +} + + +// Implement methods for VmmapEntry +// Constructor to create a new VmmapEntry +#[allow(dead_code)] +impl VmmapEntry { + pub fn new( + page_num: u32, + npages: u32, + prot: i32, + maxprot: i32, + flags: i32, + removed: bool, + file_offset: i64, + file_size: i64, + cage_id: u64, //This is the cage id to refer to for file backings + backing: MemoryBackingType, + ) -> Self { + return VmmapEntry { + page_num, + npages, + prot, + maxprot, + flags, + removed, + file_offset, + file_size, + cage_id, + backing, + }; + } + + // get maximum protection for file based mappings + // this is effectively whatever mode the file was opened with + // we need this because we shouldnt be able to change filed backed mappings + // to have protections exceeding that of the file + fn get_max_prot(&self, cage_id: u64, virtual_fd: u64 -> i32 { + + let wrappedvfd = fdtables::translate_virtual_fd(cage_id, virtual_fd as u64); + if wrappedvfd.is_err() { + return syscall_error(Errno::EBADF, "fstat", "Bad File Descriptor"); + } + let vfd = wrappedvfd.unwrap(); + + // Declare statbuf by ourselves + let mut libc_statbuf: stat = unsafe { std::mem::zeroed() }; + let libcret = unsafe { + libc::fstat(vfd.underfd as i32, &mut libc_statbuf) + }; + + libc_statbuf.mode as i32 + } +} + +// VmmapOps trait provides an interface that can be shared by different virtual memory management implementations, +// allowing different Vmmap versions to share the same interface. +#[allow(dead_code)] +pub trait VmmapOps { + + // Method to update a memory map entry + fn update( + &mut self, + page_num: u32, + npages: u32, + prot: i32, + maxprot: i32, + flags: i32, + backing: MemoryBackingType, + remove: bool, + file_offset: i64, + file_size: i64, + cage_id: u64, + ) -> Result<(), io::Error>; + + // Method to add a new entry to the memory map + fn add_entry(&mut self, vmmap_entry_ref: VmmapEntry); + + // Method to add an entry with override + fn add_entry_with_overwrite( + &mut self, + page_num: u32, + npages: u32, + prot: i32, + maxprot: i32, + flags: i32, + backing: MemoryBackingType, + file_offset: i64, + file_size: i64, + cage_id: u64, + ) -> Result<(), io::Error>; + + // Method to change protection of a memory region + fn change_prot(&mut self, page_num: u32, npages: u32, new_prot: i32); + + // Method to remove an entry from the memory map + fn remove_entry(&mut self, page_num: u32, npages: u32) -> Result<(), io::Error>; + + // Method to check if a mapping exists + fn check_existing_mapping(&self, page_num: u32, npages: u32, prot: i32) -> bool; + + // Method to check address mapping + fn check_addr_mapping(&mut self, page_num: u32, npages: u32, prot: i32) -> Option; + + // Method to find a page in the memory map + fn find_page(&self, page_num: u32) -> Option<&VmmapEntry>; + + // Method to find a mutable page in the memory map + fn find_page_mut(&mut self, page_num: u32) -> Option<&mut VmmapEntry>; + + // Method to iterate over pages + fn find_page_iter( + &self, + page_num: u32, + ) -> impl DoubleEndedIterator, &VmmapEntry)>; + + // Method to iterate over mutable pages + fn find_page_iter_mut( + &mut self, + page_num: u32, + ) -> impl DoubleEndedIterator, &mut VmmapEntry)>; + + + // Method to get the first entry in the memory map + fn first_entry(&self) -> Option<(&Interval, &VmmapEntry)>; + + // Method to get the last entry in the memory map + fn last_entry(&self) -> Option<(&Interval, &VmmapEntry)>; + + // Method to iterate over entries in both directions + fn double_ended_iter(&self) -> impl DoubleEndedIterator, &VmmapEntry)>; + + // Method to iterate over mutable entries in both directions + fn double_ended_iter_mut( + &mut self, + ) -> impl DoubleEndedIterator, &mut VmmapEntry)>; + + // Method to find space in the memory map + fn find_space(&self, npages: u32) -> Option>; + + // Method to find space above a hint + fn find_space_above_hint(&self, npages: u32, hint: u32) -> Option>; + + // Method to find map space + fn find_map_space(&self, num_pages: u32, pages_per_map: u32) -> Option>; + + // Method to find map space with a hint + fn find_map_space_with_hint( + &self, + num_pages: u32, + pages_per_map: u32, + hint: u32, + ) -> Option>; +} + +#[derive(Clone, PartialEq, Eq, Debug)] +pub struct Vmmap { + pub entries: NoditMap, VmmapEntry>, // Keyed by `page_num` + pub cached_entry: Option, // TODO: is this still needed? + // Use Option for safety +} + +#[allow(dead_code)] +impl Vmmap { + pub fn new() -> Self { + Vmmap { + entries: NoditMap::new(), + cached_entry: None, + } + } + + // Method to round page number up to the nearest multiple of pages_per_map + fn round_page_num_up_to_map_multiple(&self, npages: u32, pages_per_map: u32) -> u32 { + (npages + pages_per_map - 1) & !(pages_per_map - 1) + } + + // Method to truncate page number down to the nearest multiple of pages_per_map + fn trunc_page_num_down_to_map_multiple(&self, npages: u32, pages_per_map: u32) -> u32 { + npages & !(pages_per_map - 1) + } + + fn visit() {} + + fn debug() {} +} + +impl VmmapOps for Vmmap { + fn add_entry(&mut self, vmmap_entry_ref: VmmapEntry) { + let _ = self.entries.insert_strict( + // pages x to y, y included + ie( + vmmap_entry_ref.page_num, + vmmap_entry_ref.page_num + vmmap_entry_ref.npages, + ), + vmmap_entry_ref, + ); + } + + // Method to add an entry with override, using update method + fn add_entry_with_overwrite( + &mut self, + page_num: u32, + npages: u32, + prot: i32, + maxprot: i32, + flags: i32, + backing: MemoryBackingType, + file_offset: i64, + file_size: i64, + cage_id: u64, + ) -> Result<(), io::Error> { + self.update( + page_num, + npages, + prot, + maxprot, + flags, + backing, + false, + file_offset, + file_size, + cage_id, + ) + } + + /// This function will not return any errors pertaining to the page number not mapping + /// to any existing pages, as the remove operation is done on a best efforts basis: + /// 1. First an insert overwrite operation with the below page range is performed, causing + /// a new interval to be created over the provided page range, appropriately partitioning + /// boundary pages. + /// 2. This new interval is then deleted, leaving the underlying range unmapped + fn remove_entry(&mut self, page_num: u32, npages: u32) -> Result<(), io::Error> { + self.update( + page_num, + npages, + 0, + 0, + 0, + MemoryBackingType::None, + true, + 0, + 0, + 0, + ) + } + + // Method to update a memory map entry, handling insertion and removal + fn update( + &mut self, + page_num: u32, + npages: u32, + prot: i32, + maxprot: i32, + flags: i32, + backing: MemoryBackingType, + remove: bool, + file_offset: i64, + file_size: i64, + cage_id: u64, + ) -> Result<(), io::Error> { + if npages == 0 { + return Err(io::Error::new( + io::ErrorKind::InvalidInput, + "Number of pages cannot be zero", + )); + } + + let new_region_end_page = page_num + npages; + let new_region_start_page = page_num; // just for ease of understanding + + // Insert the new entry if not marked for removal + let new_entry = VmmapEntry { + page_num, + npages, + prot, + maxprot, + flags, + backing, + file_offset, + file_size, + removed: false, + cage_id, + }; + let _ = self + .entries + .insert_overwrite(ie(new_region_start_page, new_region_end_page), new_entry); + + if remove { + // strange way to do this, but this is the best using the library we have at hand + // while also maintaining the shrunk down entries + // using remove first, then insert will cause us to lose existing entries + let _ = self + .entries + .remove_overlapping(ie(new_region_start_page, new_region_end_page)); + } + + Ok(()) + } + + // Method to change protection of a memory region + fn change_prot(&mut self, page_num: u32, npages: u32, new_prot: i32) { + let new_region_end_page = page_num + npages; + let new_region_start_page = page_num; + + let mut to_insert = Vec::new(); + + for (overlap_interval, entry) in self + .entries + .overlapping_mut(ie(new_region_start_page, new_region_end_page)) + { + let mut ent_start = overlap_interval.start(); + let ent_end = overlap_interval.end(); + + if ent_start < new_region_start_page && ent_end > new_region_start_page { + to_insert.push(ie(new_region_start_page, ent_end)); + ent_start = new_region_start_page; // need to update incase next condition is true + } + if ent_start < new_region_end_page && ent_end > new_region_end_page { + to_insert.push(ie(ent_start, new_region_end_page)); + } else { + entry.prot = new_prot; + } + } + + for interval in to_insert { + let mut interval_val = self.entries.get_at_point(interval.start()).unwrap().clone(); + interval_val.prot = new_prot; + let _ = self.entries.insert_overwrite(interval, interval_val); + } + } + + // Method to check if a mapping exists + fn check_existing_mapping(&self, page_num: u32, npages: u32, prot: i32) -> bool { + let region_end_page = page_num + npages; + let region_interval = ie(page_num, region_end_page); + + // If no overlap, return false + if !self.entries.overlaps(region_interval) { + return false; + } + + let mut current_page = page_num; + + // Iterate over overlapping intervals + for (_interval, entry) in self.entries.overlapping(region_interval) { + let ent_end_page = entry.page_num + entry.npages; + let flags = entry.maxprot; + + // Case 1: Fully inside the existing entry + if entry.page_num <= current_page && region_end_page <= ent_end_page { + return (prot & !flags) == 0; + } + + // Case 2: Overlaps with the current entry + if entry.page_num <= current_page && current_page < ent_end_page { + if (prot & !flags) != 0 { + return false; + } + current_page = ent_end_page; // Move to the next region + } + + // Case 3: If there's a gap (no backing store), return false + if current_page < entry.page_num { + return false; + } + } + + false + } + + // Method to check address mapping, using cached entry if possible + fn check_addr_mapping(&mut self, page_num: u32, npages: u32, prot: i32) -> Option { + let region_end_page = page_num + npages; + + // First, check if the cached entry can be used + if let Some(ref cached_entry) = self.cached_entry { + let ent_end_page = cached_entry.page_num + cached_entry.npages; + let mut flags = cached_entry.prot; + + // If the protection is not PROT_NONE, enforce PROT_READ + if flags & (PROT_EXEC | PROT_READ | PROT_WRITE) != PROT_NONE { + flags |= PROT_READ; + } + + if cached_entry.page_num <= page_num && region_end_page <= ent_end_page { + if prot & !flags == 0 { + return Some(ent_end_page); // Mapping found inside the cached entry + } + } + } + + // If no cached entry, check the overlapping regions in memory map + let mut current_page = page_num; + for (_, entry) in self.entries.overlapping(ie(page_num, region_end_page)) { + let ent_end_page = entry.page_num + entry.npages; + let mut flags = entry.prot; + + // If the protection is not PROT_NONE, enforce PROT_READ + if flags & (PROT_EXEC | PROT_READ | PROT_WRITE) != PROT_NONE { + flags |= PROT_READ; + } + + if entry.page_num <= current_page && region_end_page <= ent_end_page { + // Mapping is fully inside the current entry + self.cached_entry = Some(entry.clone()); // Cache the entry + if prot & !flags == 0 { + return Some(ent_end_page); + } + } else if entry.page_num <= current_page && current_page < ent_end_page { + // Mapping overlaps with this entry + if prot & !flags != 0 { + return None; + } + current_page = ent_end_page; // Move to next region + } else if current_page < entry.page_num { + // There's a gap between entries, return failure + return None; + } + } + + // If no valid mapping is found, return None + None + } + + //Method to find a page in the memory map + fn find_page(&self, page_num: u32) -> Option<&VmmapEntry> { + self.entries.get_at_point(page_num) + } + // Method to find a mutable page in the memory map + fn find_page_mut(&mut self, page_num: u32) -> Option<&mut VmmapEntry> { + self.entries.get_at_point_mut(page_num) + } + + // Method to get the last entry in the memory map + fn last_entry(&self) -> Option<(&Interval, &VmmapEntry)> { + self.entries.last_key_value() + } + + // Method to get the first entry in the memory map + fn first_entry(&self) -> Option<(&Interval, &VmmapEntry)> { + self.entries.first_key_value() + } + + // Method to iterate over entries in both directions + fn double_ended_iter(&self) -> impl DoubleEndedIterator, &VmmapEntry)> { + self.entries.iter() + } + + // Method to iterate over mutable entries in both directions + fn double_ended_iter_mut( + &mut self, + ) -> impl DoubleEndedIterator, &mut VmmapEntry)> { + self.entries.iter_mut() + } + + // Method to iterate over pages, starting from a given page number + fn find_page_iter( + &self, + page_num: u32, + ) -> impl DoubleEndedIterator, &VmmapEntry)> { + if let Some(last_entry) = self.last_entry() { + self.entries.overlapping(ie(page_num, last_entry.0.end())) + } else { + // Return an empty iterator if no last_entry + self.entries.overlapping(ie(page_num, page_num)) + } + } + + // Method to iterate over mutable pages, starting from a given page number + fn find_page_iter_mut( + &mut self, + page_num: u32, + ) -> impl DoubleEndedIterator, &mut VmmapEntry)> { + if let Some(last_entry) = self.last_entry() { + self.entries + .overlapping_mut(ie(page_num, last_entry.0.end())) + } else { + // Return an empty iterator if no last_entry + self.entries.overlapping_mut(ie(page_num, page_num)) + } + } + + // Method to find space in the memory map + fn find_space(&self, npages: u32) -> Option> { + let start = self.first_entry(); + let end = self.last_entry(); + + if start == None || end == None { + return None; + } else { + let start_unwrapped = start.unwrap().0.start(); + let end_unwrapped = end.unwrap().0.end(); + + let desired_space = npages + 1; // TODO: check if this is correct + + for gap in self + .entries + .gaps_trimmed(ie(start_unwrapped, end_unwrapped)) + { + if gap.end() - gap.start() >= desired_space { + return Some(gap); + } + } + } + + None + } + + // Method to find space above a hint + fn find_space_above_hint(&self, npages: u32, hint: u32) -> Option> { + let start = hint; + let end = self.last_entry(); + + if end == None { + return None; + } else { + let end_unwrapped = end.unwrap().0.end(); + + let desired_space = npages + 1; // TODO: check if this is correct + + for gap in self.entries.gaps_trimmed(ie(start, end_unwrapped)) { + if gap.end() - gap.start() >= desired_space { + return Some(gap); + } + } + } + + None + } + + // Method to find map space, rounding page numbers up to the nearest multiple of pages_per_map + fn find_map_space(&self, num_pages: u32, pages_per_map: u32) -> Option> { + let start = self.first_entry(); + let end = self.last_entry(); + + if start == None || end == None { + return None; + } else { + let start_unwrapped = start.unwrap().0.start(); + let end_unwrapped = end.unwrap().0.end(); + + let rounded_num_pages = + self.round_page_num_up_to_map_multiple(num_pages, pages_per_map); + + for gap in self + .entries + .gaps_trimmed(ie(start_unwrapped, end_unwrapped)) + { + let aligned_start_page = + self.trunc_page_num_down_to_map_multiple(gap.start(), pages_per_map); + let aligned_end_page = + self.round_page_num_up_to_map_multiple(gap.end(), pages_per_map); + + let gap_size = aligned_end_page - aligned_start_page; + if gap_size >= rounded_num_pages { + return Some(ie(aligned_end_page - rounded_num_pages, aligned_end_page)); + } + } + } + + None + } + + // Method to find map space with a hint, rounding page numbers up to the nearest multiple of pages_per_map + fn find_map_space_with_hint( + &self, + num_pages: u32, + pages_per_map: u32, + hint: u32, + ) -> Option> { + let start = hint; + let end = self.last_entry(); + + if end == None { + return None; + } else { + let end_unwrapped = end.unwrap().0.end(); + + let rounded_num_pages = + self.round_page_num_up_to_map_multiple(num_pages, pages_per_map); + + for gap in self.entries.gaps_trimmed(ie(start, end_unwrapped)) { + let aligned_start_page = + self.trunc_page_num_down_to_map_multiple(gap.start(), pages_per_map); + let aligned_end_page = + self.round_page_num_up_to_map_multiple(gap.end(), pages_per_map); + + let gap_size = aligned_end_page - aligned_start_page; + if gap_size >= rounded_num_pages { + return Some(ie(aligned_end_page - rounded_num_pages, aligned_end_page)); + } + } + } + + None + } +} + diff --git a/src/RawPOSIX/src/safeposix/vmmap_constants.rs b/src/RawPOSIX/src/safeposix/vmmap_constants.rs new file mode 100644 index 000000000..373dba649 --- /dev/null +++ b/src/RawPOSIX/src/safeposix/vmmap_constants.rs @@ -0,0 +1,32 @@ +pub const PROT_READ: i32 = 0x1; /* Page can be read. */ +pub const PROT_WRITE: i32 = 0x2; /* Page can be written. */ +pub const PROT_EXEC: i32 = 0x4; /* Page can be executed. */ +pub const PROT_NONE: i32 = 0x0; /* Page can not be accessed. */ + +pub const PROT_MASK: u32 = 0x7; + +pub const MAP_SHARED: u32 = 0x01; /* Share changes. */ +pub const MAP_PRIVATE: u32 = 0x02; /* Changes are private. */ + +/* this must be a multiple of the system page size */ +pub const PAGESHIFT: u32 = 12; +pub const PAGESIZE: u32 = 1 << PAGESHIFT; + +pub const MAP_PAGESHIFT: u32 = 16; +pub const MAP_PAGESIZE: u32 = 1 << MAP_PAGESHIFT; + +pub const MAP_SHARING_MASK: u32 = 0x03; + +pub const MAP_FIXED: u32 = 0x10; /* Interpret addr exactly. */ +pub const MAP_ANON: u32 = 0x20; /* Don't use a file. */ +pub const MAP_ANONYMOUS: u32 = MAP_ANON; /* Linux alias. */ + +pub const MAP_FAILED: *mut std::ffi::c_void = (-1isize) as *mut std::ffi::c_void; + +pub const MREMAP_MAYMOVE: u32 = 0x01; +pub const MREMAP_FIXED: u32 = 0x02; + +pub const O_ACCMODE: i32 = 0003; +pub const O_RDONLY: i32 = 00; +pub const O_WRONLY: i32 = 01; +pub const O_RDWR: i32 = 02; diff --git a/src/RawPOSIX/src/tests/sys_tests.rs b/src/RawPOSIX/src/tests/sys_tests.rs index 5d3bbb1d9..f72b4f1c5 100644 --- a/src/RawPOSIX/src/tests/sys_tests.rs +++ b/src/RawPOSIX/src/tests/sys_tests.rs @@ -135,53 +135,4 @@ pub mod sys_tests { lindrustfinalize(); } - - #[test] - pub fn ut_lind_waitpid() { - // acquiring a lock on TESTMUTEX prevents other tests from running concurrently, - // and also performs clean env setup - let _thelock = setup::lock_and_init(); - let cage = interface::cagetable_getref(1); - - // first let's fork some children - cage.fork_syscall(2); - cage.fork_syscall(3); - cage.fork_syscall(4); - cage.fork_syscall(5); - - let child_cage2 = interface::cagetable_getref(2); - let child_cage3 = interface::cagetable_getref(3); - let child_cage4 = interface::cagetable_getref(4); - - // cage2 exit before parent wait - child_cage2.exit_syscall(123); - - let mut status = 0; - let pid = cage.waitpid_syscall(2, &mut status, 0); - assert_eq!(pid, 2); - assert_eq!(status, 123); - - // test for WNOHANG option - let pid = cage.waitpid_syscall(0, &mut status, libc::WNOHANG); - assert_eq!(pid, 0); - - // test for waitpid when the cage exits in the middle of waiting - let thread1 = interface::helper_thread(move || { - interface::sleep(interface::RustDuration::from_millis(100)); - child_cage4.exit_syscall(4); - child_cage3.exit_syscall(3); - }); - - let pid = cage.waitpid_syscall(0, &mut status, 0); - assert_eq!(pid, 4); - assert_eq!(status, 4); - - let pid = cage.waitpid_syscall(0, &mut status, 0); - assert_eq!(pid, 3); - assert_eq!(status, 3); - - let _ = thread1.join().unwrap(); - - lindrustfinalize(); - } } From 5b13d4c2232b2b16b87fa984e3c1657322ccb750 Mon Sep 17 00:00:00 2001 From: Chinmay Shringi Date: Mon, 25 Nov 2024 16:41:14 -0500 Subject: [PATCH 02/66] fix: revert removed lines --- src/RawPOSIX/src/interface/types.rs | 4 + src/RawPOSIX/src/safeposix/cage.rs | 8 ++ src/RawPOSIX/src/safeposix/dispatcher.rs | 51 +++++++ .../src/safeposix/syscalls/sys_calls.rs | 132 +++++++++++++++++- src/RawPOSIX/src/tests/sys_tests.rs | 49 +++++++ 5 files changed, 243 insertions(+), 1 deletion(-) diff --git a/src/RawPOSIX/src/interface/types.rs b/src/RawPOSIX/src/interface/types.rs index 40efd4d93..e5b545f21 100644 --- a/src/RawPOSIX/src/interface/types.rs +++ b/src/RawPOSIX/src/interface/types.rs @@ -379,6 +379,10 @@ pub fn get_ioctlptrunion<'a>(generic_argument: u64) -> Result<&'a mut u8, i32> { )); } +pub fn get_i32_ref<'a>(generic_argument: u64) -> Result<&'a mut i32, i32> { + unsafe { Ok(&mut *((generic_argument) as *mut i32)) } +} + pub fn get_pipearray<'a>(generic_argument: u64) -> Result<&'a mut PipeArray, i32> { let pointer = generic_argument as *mut PipeArray; if !pointer.is_null() { diff --git a/src/RawPOSIX/src/safeposix/cage.rs b/src/RawPOSIX/src/safeposix/cage.rs index 375f32bd1..2e6d6ad43 100644 --- a/src/RawPOSIX/src/safeposix/cage.rs +++ b/src/RawPOSIX/src/safeposix/cage.rs @@ -16,6 +16,12 @@ pub use super::vmmap_constants::*; pub use crate::interface::CAGE_TABLE; +#[derive(Debug, Clone, Copy)] +pub struct Zombie { + pub cageid: u64, + pub exit_code: i32 +} + #[derive(Debug)] pub struct Cage { pub cageid: u64, @@ -36,6 +42,8 @@ pub struct Cage { pub pendingsigset: interface::RustHashMap, pub main_threadid: interface::RustAtomicU64, pub interval_timer: interface::IntervalTimer, + pub zombies: interface::RustLock>, + pub child_num: interface::RustAtomicU64 pub vmmap: Vmmap, } diff --git a/src/RawPOSIX/src/safeposix/dispatcher.rs b/src/RawPOSIX/src/safeposix/dispatcher.rs index 814a24090..06ad67690 100644 --- a/src/RawPOSIX/src/safeposix/dispatcher.rs +++ b/src/RawPOSIX/src/safeposix/dispatcher.rs @@ -114,6 +114,8 @@ const SYNC_FILE_RANGE: i32 = 164; const WRITEV_SYSCALL: i32 = 170; const CLONE_SYSCALL: i32 = 171; +const WAIT_SYSCALL: i32 = 172; +const WAITPID_SYSCALL: i32 = 173; const NANOSLEEP_TIME64_SYSCALL : i32 = 181; @@ -354,6 +356,16 @@ pub fn lind_syscall_api( .exit_syscall(status) } + SELECT_SYSCALL => { + let nfds = arg1 as i32; + let readfds = interface::get_fdset(arg2).unwrap(); + let writefds = interface::get_fdset(arg3).unwrap(); + let errorfds = interface::get_fdset(arg4).unwrap(); + let rposix_timeout = interface::duration_fromtimeval(arg5).unwrap(); + interface::cagetable_getref(cageid) + .select_syscall(nfds, readfds, writefds, errorfds, rposix_timeout) + } + RENAME_SYSCALL => { let old_ptr = (start_address + arg1) as *const u8; let new_ptr = (start_address + arg2) as *const u8; @@ -807,6 +819,25 @@ pub fn lind_syscall_api( .epoll_create_syscall(size) } + EPOLL_CTL_SYSCALL=> { + let virtual_epfd = arg1 as i32; + let op = arg2 as i32; + let virtual_fd = arg3 as i32; + let epollevent = interface::get_epollevent(arg4).unwrap(); + + interface::cagetable_getref(cageid) + .epoll_ctl_syscall(virtual_epfd, op, virtual_fd, epollevent) + } + + EPOLL_WAIT_SYSCALL => { + let virtual_epfd = arg1 as i32; + let maxevents = arg3 as i32; + let events = interface::get_epollevent_slice(arg2, maxevents).unwrap(); + let timeout = arg4 as i32; + interface::cagetable_getref(cageid) + .epoll_wait_syscall(virtual_epfd, events, maxevents, timeout) + } + SETSOCKOPT_SYSCALL => { let virtual_fd = arg1 as i32; let level = arg2 as i32; @@ -1005,6 +1036,22 @@ pub fn lind_syscall_api( .nanosleep_time64_syscall(clockid, flags, req, rem) } + WAIT_SYSCALL => { + let mut status = interface::get_i32_ref(start_address + arg1).unwrap(); + + interface::cagetable_getref(cageid) + .wait_syscall(&mut status) + } + + WAITPID_SYSCALL => { + let pid = arg1 as i32; + let mut status = interface::get_i32_ref(start_address + arg2).unwrap(); + let options = arg3 as i32; + + interface::cagetable_getref(cageid) + .waitpid_syscall(pid, &mut status, options) + } + _ => -1, // Return -1 for unknown syscalls }; ret @@ -1097,6 +1144,8 @@ pub fn lindrustinit(verbosity: isize) { pendingsigset: interface::RustHashMap::new(), main_threadid: interface::RustAtomicU64::new(0), interval_timer: interface::IntervalTimer::new(0), + zombies: interface::RustLock::new(vec![]), + child_num: interface::RustAtomicU64::new(0), }; interface::cagetable_insert(0, utilcage); @@ -1136,6 +1185,8 @@ pub fn lindrustinit(verbosity: isize) { pendingsigset: interface::RustHashMap::new(), main_threadid: interface::RustAtomicU64::new(0), interval_timer: interface::IntervalTimer::new(1), + zombies: interface::RustLock::new(vec![]), + child_num: interface::RustAtomicU64::new(0), }; interface::cagetable_insert(1, initcage); fdtables::init_empty_cage(1); diff --git a/src/RawPOSIX/src/safeposix/syscalls/sys_calls.rs b/src/RawPOSIX/src/safeposix/syscalls/sys_calls.rs index 85a7b151f..06567f16b 100644 --- a/src/RawPOSIX/src/safeposix/syscalls/sys_calls.rs +++ b/src/RawPOSIX/src/safeposix/syscalls/sys_calls.rs @@ -169,6 +169,8 @@ impl Cage { pendingsigset: interface::RustHashMap::new(), main_threadid: interface::RustAtomicU64::new(0), interval_timer: interface::IntervalTimer::new(child_cageid), + zombies: interface::RustLock::new(vec![]), + child_num: interface::RustAtomicU64::new(0), }; let shmtable = &SHM_METADATA.shmtable; @@ -202,6 +204,11 @@ impl Cage { self.unmap_shm_mappings(); + let zombies = self.zombies.read(); + let cloned_zombies = zombies.clone(); + let child_num = self.child_num.load(interface::RustAtomicOrdering::Relaxed); + drop(zombies); + // we grab the parent cages main threads sigset and store it at 0 // this way the child can initialize the sigset properly when it establishes its own mainthreadid let newsigset = interface::RustHashMap::new(); @@ -241,6 +248,9 @@ impl Cage { pendingsigset: interface::RustHashMap::new(), main_threadid: interface::RustAtomicU64::new(0), interval_timer: self.interval_timer.clone_with_new_cageid(child_cageid), + // when a process exec-ed, its child relationship should be perserved + zombies: interface::RustLock::new(cloned_zombies), + child_num: interface::RustAtomicU64::new(child_num), }; //wasteful clone of fdtable, but mutability constraints exist @@ -257,7 +267,22 @@ impl Cage { //may not be removable in case of lindrustfinalize, we don't unwrap the remove result interface::cagetable_remove(self.cageid); - + // if the cage has parent + if self.parent != self.cageid { + let parent_cage = interface::cagetable_getref_opt(self.parent); + // if parent hasn't exited yet + if let Some(parent) = parent_cage { + // decrement parent's child counter + parent.child_num.fetch_sub(1, interface::RustAtomicOrdering::SeqCst); + + // push the exit status to parent's zombie list + let mut zombie_vec = parent.zombies.write(); + zombie_vec.push(Zombie { cageid: self.cageid, exit_code: status }); + } else { + // if parent already exited + // BUG: we currently do not handle the situation where a parent has exited already + } + } // Trigger SIGCHLD if !interface::RUSTPOSIX_TESTSUITE.load(interface::RustAtomicOrdering::Relaxed) { // dont trigger SIGCHLD for test suite @@ -271,6 +296,111 @@ impl Cage { status } + //------------------------------------WAITPID SYSCALL------------------------------------ + /* + * waitpid() will return the cageid of waited cage, or 0 when WNOHANG is set and there is no cage already exited + * waitpid_syscall utilizes the zombie list stored in cage struct. When a cage exited, a zombie entry will be inserted + * into the end of its parent's zombie list. Then when parent wants to wait for any of child, it could just check its + * zombie list and retrieve the first entry from it (first in, first out). + */ + pub fn waitpid_syscall(&self, cageid: i32, status: &mut i32, options: i32) -> i32 { + let mut zombies = self.zombies.write(); + let child_num = self.child_num.load(interface::RustAtomicOrdering::Relaxed); + + // if there is no pending zombies to wait, and there is no active child, return ECHILD + if zombies.len() == 0 && child_num == 0 { + return syscall_error(Errno::ECHILD, "waitpid", "no existing unwaited-for child processes"); + } + + let mut zombie_opt: Option = None; + + // cageid <= 0 means wait for ANY child + // cageid < 0 actually refers to wait for any child process whose process group ID equals -pid + // but we do not have the concept of process group in lind, so let's just treat it as cageid == 0 + if cageid <= 0 { + loop { + if zombies.len() == 0 && (options & libc::WNOHANG > 0) { + // if there is no pending zombies and WNOHANG is set + // return immediately + return 0; + } else if zombies.len() == 0 { + // if there is no pending zombies and WNOHANG is not set + // then we need to wait for children to exit + // drop the zombies list before sleep to avoid deadlock + drop(zombies); + // TODO: replace busy waiting with more efficient mechanism + interface::lind_yield(); + // after sleep, get the write access of zombies list back + zombies = self.zombies.write(); + continue; + } else { + // there are zombies avaliable + // let's retrieve the first zombie + zombie_opt = Some(zombies.remove(0)); + break; + } + } + } + // if cageid is specified, then we need to look up the zombie list for the id + else { + // first let's check if the cageid is in the zombie list + if let Some(index) = zombies.iter().position(|zombie| zombie.cageid == cageid as u64) { + // find the cage in zombie list, remove it from the list and break + zombie_opt = Some(zombies.remove(index)); + } else { + // if the cageid is not in the zombie list, then we know either + // 1. the child is still running, or + // 2. the cage has exited, but it is not the child of this cage, or + // 3. the cage does not exist + // we need to make sure the child is still running, and it is the child of this cage + let child = interface::cagetable_getref_opt(cageid as u64); + if let Some(child_cage) = child { + // make sure the child's parent is correct + if child_cage.parent != self.cageid { + return syscall_error(Errno::ECHILD, "waitpid", "waited cage is not the child of the cage"); + } + } else { + // cage does not exist + return syscall_error(Errno::ECHILD, "waitpid", "cage does not exist"); + } + + // now we have verified that the cage exists and is the child of the cage + loop { + // the cage is not in the zombie list + // we need to wait for the cage to actually exit + + // drop the zombies list before sleep to avoid deadlock + drop(zombies); + // TODO: replace busy waiting with more efficient mechanism + interface::lind_yield(); + // after sleep, get the write access of zombies list back + zombies = self.zombies.write(); + + // let's check if the zombie list contains the cage + if let Some(index) = zombies.iter().position(|zombie| zombie.cageid == cageid as u64) { + // find the cage in zombie list, remove it from the list and break + zombie_opt = Some(zombies.remove(index)); + break; + } + + continue; + } + } + } + + // reach here means we already found the desired exited child + let zombie = zombie_opt.unwrap(); + // update the status + *status = zombie.exit_code; + + // return child's cageid + zombie.cageid as i32 + } + + pub fn wait_syscall(&self, status: &mut i32) -> i32 { + self.waitpid_syscall(0, status, 0) + } + pub fn getpid_syscall(&self) -> i32 { self.cageid as i32 //not sure if this is quite what we want but it's easy enough to change later } diff --git a/src/RawPOSIX/src/tests/sys_tests.rs b/src/RawPOSIX/src/tests/sys_tests.rs index f72b4f1c5..bb2ba00e2 100644 --- a/src/RawPOSIX/src/tests/sys_tests.rs +++ b/src/RawPOSIX/src/tests/sys_tests.rs @@ -135,4 +135,53 @@ pub mod sys_tests { lindrustfinalize(); } + + #[test] + pub fn ut_lind_waitpid() { + // acquiring a lock on TESTMUTEX prevents other tests from running concurrently, + // and also performs clean env setup + let _thelock = setup::lock_and_init(); + let cage = interface::cagetable_getref(1); + + // first let's fork some children + cage.fork_syscall(2); + cage.fork_syscall(3); + cage.fork_syscall(4); + cage.fork_syscall(5); + + let child_cage2 = interface::cagetable_getref(2); + let child_cage3 = interface::cagetable_getref(3); + let child_cage4 = interface::cagetable_getref(4); + + // cage2 exit before parent wait + child_cage2.exit_syscall(123); + + let mut status = 0; + let pid = cage.waitpid_syscall(2, &mut status, 0); + assert_eq!(pid, 2); + assert_eq!(status, 123); + + // test for WNOHANG option + let pid = cage.waitpid_syscall(0, &mut status, libc::WNOHANG); + assert_eq!(pid, 0); + + // test for waitpid when the cage exits in the middle of waiting + let thread1 = interface::helper_thread(move || { + interface::sleep(interface::RustDuration::from_millis(100)); + child_cage4.exit_syscall(4); + child_cage3.exit_syscall(3); + }); + + let pid = cage.waitpid_syscall(0, &mut status, 0); + assert_eq!(pid, 4); + assert_eq!(status, 4); + + let pid = cage.waitpid_syscall(0, &mut status, 0); + assert_eq!(pid, 3); + assert_eq!(status, 3); + + let _ = thread1.join().unwrap(); + + lindrustfinalize(); + } } From 70fa146634dca36882b10bf44d3206d03e5353a6 Mon Sep 17 00:00:00 2001 From: Chinmay Shringi Date: Mon, 25 Nov 2024 16:48:41 -0500 Subject: [PATCH 03/66] fix: formatting --- src/RawPOSIX/src/safeposix/dispatcher.rs | 3 ++- src/RawPOSIX/src/safeposix/syscalls/sys_calls.rs | 7 ++++++- src/RawPOSIX/src/tests/sys_tests.rs | 3 ++- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/RawPOSIX/src/safeposix/dispatcher.rs b/src/RawPOSIX/src/safeposix/dispatcher.rs index 06ad67690..9d0673ab9 100644 --- a/src/RawPOSIX/src/safeposix/dispatcher.rs +++ b/src/RawPOSIX/src/safeposix/dispatcher.rs @@ -838,6 +838,7 @@ pub fn lind_syscall_api( .epoll_wait_syscall(virtual_epfd, events, maxevents, timeout) } + SETSOCKOPT_SYSCALL => { let virtual_fd = arg1 as i32; let level = arg2 as i32; @@ -1047,7 +1048,7 @@ pub fn lind_syscall_api( let pid = arg1 as i32; let mut status = interface::get_i32_ref(start_address + arg2).unwrap(); let options = arg3 as i32; - + interface::cagetable_getref(cageid) .waitpid_syscall(pid, &mut status, options) } diff --git a/src/RawPOSIX/src/safeposix/syscalls/sys_calls.rs b/src/RawPOSIX/src/safeposix/syscalls/sys_calls.rs index 06567f16b..f2659924a 100644 --- a/src/RawPOSIX/src/safeposix/syscalls/sys_calls.rs +++ b/src/RawPOSIX/src/safeposix/syscalls/sys_calls.rs @@ -173,6 +173,9 @@ impl Cage { child_num: interface::RustAtomicU64::new(0), }; + // increment child counter for parent + self.child_num.fetch_add(1, interface::RustAtomicOrdering::SeqCst); + let shmtable = &SHM_METADATA.shmtable; //update fields for shared mappings in cage for rev_mapping in cageobj.rev_shm.lock().iter() { @@ -267,6 +270,7 @@ impl Cage { //may not be removable in case of lindrustfinalize, we don't unwrap the remove result interface::cagetable_remove(self.cageid); + // if the cage has parent if self.parent != self.cageid { let parent_cage = interface::cagetable_getref_opt(self.parent); @@ -283,6 +287,7 @@ impl Cage { // BUG: we currently do not handle the situation where a parent has exited already } } + // Trigger SIGCHLD if !interface::RUSTPOSIX_TESTSUITE.load(interface::RustAtomicOrdering::Relaxed) { // dont trigger SIGCHLD for test suite @@ -296,7 +301,7 @@ impl Cage { status } - //------------------------------------WAITPID SYSCALL------------------------------------ + //------------------------------------WAITPID SYSCALL------------------------------------ /* * waitpid() will return the cageid of waited cage, or 0 when WNOHANG is set and there is no cage already exited * waitpid_syscall utilizes the zombie list stored in cage struct. When a cage exited, a zombie entry will be inserted diff --git a/src/RawPOSIX/src/tests/sys_tests.rs b/src/RawPOSIX/src/tests/sys_tests.rs index bb2ba00e2..2064bc8fe 100644 --- a/src/RawPOSIX/src/tests/sys_tests.rs +++ b/src/RawPOSIX/src/tests/sys_tests.rs @@ -136,6 +136,7 @@ pub mod sys_tests { lindrustfinalize(); } + #[test] pub fn ut_lind_waitpid() { // acquiring a lock on TESTMUTEX prevents other tests from running concurrently, @@ -152,7 +153,7 @@ pub mod sys_tests { let child_cage2 = interface::cagetable_getref(2); let child_cage3 = interface::cagetable_getref(3); let child_cage4 = interface::cagetable_getref(4); - + // cage2 exit before parent wait child_cage2.exit_syscall(123); From 5a3ebbbd406eba24157b61eede5f63d972b1a7c7 Mon Sep 17 00:00:00 2001 From: Chinmay Shringi Date: Mon, 25 Nov 2024 16:49:17 -0500 Subject: [PATCH 04/66] fix: rm new line --- src/RawPOSIX/src/tests/sys_tests.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/RawPOSIX/src/tests/sys_tests.rs b/src/RawPOSIX/src/tests/sys_tests.rs index 2064bc8fe..5d3bbb1d9 100644 --- a/src/RawPOSIX/src/tests/sys_tests.rs +++ b/src/RawPOSIX/src/tests/sys_tests.rs @@ -136,7 +136,6 @@ pub mod sys_tests { lindrustfinalize(); } - #[test] pub fn ut_lind_waitpid() { // acquiring a lock on TESTMUTEX prevents other tests from running concurrently, From ef9e7ad5581ffdba3fe60e5cd9a910b91eed3062 Mon Sep 17 00:00:00 2001 From: Chinmay Shringi Date: Mon, 25 Nov 2024 17:42:35 -0500 Subject: [PATCH 05/66] feat: new constants folder --- src/RawPOSIX/src/constants/fs_constants.rs | 202 +++++++++ src/RawPOSIX/src/constants/mod.rs | 7 + src/RawPOSIX/src/constants/net_constants.rs | 371 +++++++++++++++++ src/RawPOSIX/src/constants/sys_constants.rs | 97 +++++ src/RawPOSIX/src/interface/misc.rs | 2 +- src/RawPOSIX/src/lib.rs | 1 + src/RawPOSIX/src/safeposix/cage.rs | 16 +- src/RawPOSIX/src/safeposix/dispatcher.rs | 5 +- src/RawPOSIX/src/safeposix/mod.rs | 2 +- src/RawPOSIX/src/safeposix/shm.rs | 10 +- .../src/safeposix/syscalls/fs_calls.rs | 23 +- .../src/safeposix/syscalls/fs_constants.rs | 196 --------- src/RawPOSIX/src/safeposix/syscalls/mod.rs | 6 - .../src/safeposix/syscalls/net_calls.rs | 4 +- .../src/safeposix/syscalls/net_constants.rs | 392 ------------------ .../src/safeposix/syscalls/sys_calls.rs | 31 +- .../src/safeposix/syscalls/sys_constants.rs | 77 ---- src/RawPOSIX/src/safeposix/vmmap.rs | 8 +- src/RawPOSIX/src/safeposix/vmmap_constants.rs | 32 -- src/RawPOSIX/src/tests/sys_tests.rs | 1 + 20 files changed, 747 insertions(+), 736 deletions(-) create mode 100644 src/RawPOSIX/src/constants/fs_constants.rs create mode 100644 src/RawPOSIX/src/constants/mod.rs create mode 100644 src/RawPOSIX/src/constants/net_constants.rs create mode 100644 src/RawPOSIX/src/constants/sys_constants.rs delete mode 100644 src/RawPOSIX/src/safeposix/syscalls/fs_constants.rs delete mode 100644 src/RawPOSIX/src/safeposix/syscalls/net_constants.rs delete mode 100644 src/RawPOSIX/src/safeposix/syscalls/sys_constants.rs delete mode 100644 src/RawPOSIX/src/safeposix/vmmap_constants.rs diff --git a/src/RawPOSIX/src/constants/fs_constants.rs b/src/RawPOSIX/src/constants/fs_constants.rs new file mode 100644 index 000000000..79a1cf04e --- /dev/null +++ b/src/RawPOSIX/src/constants/fs_constants.rs @@ -0,0 +1,202 @@ +//! File System Constants Module +//! These constants define file system-related flags and parameters +//! +//! Primary Source References: +//! - Linux kernel v6.5: include/uapi/asm-generic/fcntl.h +//! - Linux kernel v6.5: include/uapi/linux/stat.h +//! - POSIX.1-2017 (IEEE Std 1003.1-2017) + +#![allow(dead_code)] +#![allow(unused_variables)] + +use crate::interface; + +// ===== File Descriptor Constants ===== +pub const DT_UNKNOWN: u8 = 0; + +pub const STARTINGFD: i32 = 0; // Starting file descriptor number +pub const MAXFD: i32 = 1024; // Maximum number of file descriptors +pub const STARTINGPIPE: i32 = 0; // Starting pipe descriptor number +pub const MAXPIPE: i32 = 1024; // Maximum number of pipes + +// ===== Inode Constants ===== +pub const ROOTDIRECTORYINODE: usize = 1; // Root directory inode number +pub const STREAMINODE: usize = 2; // Stream inode number + +// ===== Pipe Constants ===== +pub const PIPE_CAPACITY: usize = 65536; // Maximum pipe buffer size + +// ===== File Access Permission Flags ===== +pub const F_OK: u32 = 0; // Test for existence +pub const X_OK: u32 = 1; // Test for execute permission +pub const W_OK: u32 = 2; // Test for write permission +pub const R_OK: u32 = 4; // Test for read permission + +// ===== File Access Modes ===== +// Source: include/uapi/asm-generic/fcntl.h +pub const O_RDONLY: i32 = 0o0; // Open read-only +pub const O_WRONLY: i32 = 0o1; // Open write-only +pub const O_RDWR: i32 = 0o2; // Open read-write +pub const O_RDWRFLAGS: i32 = 0o3; // Mask for access modes + +// ===== File Creation and Status Flags ===== +pub const O_CREAT: i32 = 0o100; // Create file if it doesn't exist +pub const O_EXCL: i32 = 0o200; // Error if O_CREAT and file exists +pub const O_NOCTTY: i32 = 0o400; // Don't assign controlling terminal +pub const O_TRUNC: i32 = 0o1000; // Truncate file to zero length +pub const O_APPEND: i32 = 0o2000; // Append mode - writes always at end +pub const O_NONBLOCK: i32 = 0o4000; // Non-blocking mode +// O_NDELAY=O_NONBLOCK +pub const O_SYNC: i32 = 0o10000; // Synchronous writes +// O_FSYNC=O_SYNC +pub const O_ASYNC: i32 = 0o20000; // Signal-driven I/O +pub const O_CLOEXEC: i32 = 0o2000000; // Close on exec + +pub const DEFAULTTIME: u64 = 1323630836; // Default timestamp value + +// ===== File Permissions ===== +// Source: include/uapi/linux/stat.h +pub const S_IRWXA: u32 = 0o777; // All permissions for all users +pub const S_IRWXU: u32 = 0o700; // User read, write, execute +pub const S_IRUSR: u32 = 0o400; // User read +pub const S_IWUSR: u32 = 0o200; // User write +pub const S_IXUSR: u32 = 0o100; // User execute +pub const S_IRWXG: u32 = 0o070; // Group read, write, execute +pub const S_IRGRP: u32 = 0o040; // Group read +pub const S_IWGRP: u32 = 0o020; // Group write +pub const S_IXGRP: u32 = 0o010; // Group execute +pub const S_IRWXO: u32 = 0o007; // Others read, write, execute +pub const S_IROTH: u32 = 0o004; // Others read +pub const S_IWOTH: u32 = 0o002; // Others write +pub const S_IXOTH: u32 = 0o001; // Others execute + +//Commands for FCNTL +pub const F_DUPFD: i32 = 0; +pub const F_GETFD: i32 = 1; +pub const F_SETFD: i32 = 2; +pub const F_GETFL: i32 = 3; +pub const F_SETFL: i32 = 4; +pub const F_GETLK: i32 = 5; +pub const F_GETLK64: i32 = 5; +pub const F_SETLK: i32 = 6; +pub const F_SETLK64: i32 = 6; +pub const F_SETLKW: i32 = 7; +pub const F_SETLKW64: i32 = 7; +pub const F_SETOWN: i32 = 8; +pub const F_GETOWN: i32 = 9; +pub const F_SETSIG: i32 = 10; +pub const F_GETSIG: i32 = 11; +pub const F_SETLEASE: i32 = 1024; +pub const F_GETLEASE: i32 = 1025; +pub const F_NOTIFY: i32 = 1026; + +//Commands for IOCTL +pub const FIONBIO: u32 = 21537; +pub const FIOASYNC: u32 = 21586; + +//File types for open/stat etc. +pub const S_IFBLK: i32 = 0o60000; +pub const S_IFCHR: i32 = 0o20000; +pub const S_IFDIR: i32 = 0o40000; +pub const S_IFIFO: i32 = 0o10000; +pub const S_IFLNK: i32 = 0o120000; +pub const S_IFREG: i32 = 0o100000; +pub const S_IFSOCK: i32 = 0o140000; +pub const S_FILETYPEFLAGS: i32 = 0o170000; + +//for flock syscall +pub const LOCK_SH: i32 = 1; +pub const LOCK_EX: i32 = 2; +pub const LOCK_UN: i32 = 8; +pub const LOCK_NB: i32 = 4; +//for mmap/munmap syscall +pub const MAP_SHARED: i32 = 1; +pub const MAP_PRIVATE: i32 = 2; +pub const MAP_FIXED: i32 = 16; +pub const MAP_ANONYMOUS: i32 = 32; +pub const MAP_HUGE_SHIFT: i32 = 26; +pub const MAP_HUGETLB: i32 = 262144; + +pub const PROT_NONE: i32 = 0; +pub const PROT_READ: i32 = 1; +pub const PROT_WRITE: i32 = 2; +pub const PROT_EXEC: i32 = 4; + +pub const SEEK_SET: i32 = 0; // Seek from beginning of file +pub const SEEK_CUR: i32 = 1; // Seek from current position +pub const SEEK_END: i32 = 2; // Seek from end of file + +pub const IPC_PRIVATE: i32 = 0o0; +pub const IPC_CREAT: i32 = 0o1000; +pub const IPC_EXCL: i32 = 0o2000; + +pub const IPC_RMID: i32 = 0; +pub const IPC_SET: i32 = 1; +pub const IPC_STAT: i32 = 2; + +pub const SHM_DEST: i32 = 0o1000; // Destroy segment when last process detaches +pub const SHM_LOCKED: i32 = 0o2000; // Lock segment in memory +pub const SHM_HUGETLB: i32 = 0o4000; // Use huge TLB pages + +pub const SHM_R: i32 = 0o400; // Read permission +pub const SHM_W: i32 = 0o200; // Write permission +pub const SHM_RDONLY: i32 = 0o10000; // Read-only access +pub const SHM_RND: i32 = 0o20000; // Round attach address to SHMLBA +pub const SHM_REMAP: i32 = 0o40000; // Take-over region on attach +pub const SHM_EXEC: i32 = 0o100000; // Execute permission + +pub const SHMMIN: u32 = 1; // Minimum shared memory segment size +pub const SHMMNI: u32 = 4096; // Maximum number of segments system wide +pub const SHMMAX: u32 = 4278190079; // Maximum shared memory segment size +pub const SHMALL: u32 = 4278190079; // Maximum total shared memory system wide +pub const SHMSEG: u32 = SHMMNI; // Maximum segments per process + +pub const SEM_VALUE_MAX: u32 = 2147483647; // Maximum value for a semaphore + +// ===== Memory Protection Flags ===== +// Source: include/uapi/asm-generic/mman-common.h +pub const PROT_NONE: i32 = 0x0; // Page cannot be accessed +pub const PROT_READ: i32 = 0x1; // Page can be read +pub const PROT_WRITE: i32 = 0x2; // Page can be written +pub const PROT_EXEC: i32 = 0x4; // Page can be executed + +// Mask for all protection bits +// Note: Some architectures may support additional bits +pub const PROT_MASK: u32 = 0x7; + +// ===== Memory Mapping Flags ===== +// Source: include/uapi/asm-generic/mman.h +pub const MAP_SHARED: u32 = 0x01; // Share changes with other processes +pub const MAP_PRIVATE: u32 = 0x02; // Changes are private to this process +pub const MAP_SHARING_MASK: u32 = 0x03; // Mask to isolate sharing bits + +pub const MAP_FIXED: u32 = 0x10; // Interpret address exactly +pub const MAP_ANON: u32 = 0x20; // Don't use a file descriptor +pub const MAP_ANONYMOUS: u32 = MAP_ANON; // Linux alias for MAP_ANON + +// ===== Page Size Constants ===== +// Note: These values are architecture-dependent +// Current values are for x86_64 Linux +pub const PAGESHIFT: u32 = 12; // 4KB pages (1 << 12 = 4096) +pub const PAGESIZE: u32 = 1 << PAGESHIFT; + +// Lind-specific page size constants +pub const MAP_PAGESHIFT: u32 = 16; // Custom value for Lind +pub const MAP_PAGESIZE: u32 = 1 << MAP_PAGESHIFT; + +// ===== Memory Mapping Error Value ===== +// Source: include/uapi/asm-generic/mman-common.h +pub const MAP_FAILED: *mut std::ffi::c_void = (-1isize) as *mut std::ffi::c_void; + +// ===== Memory Remapping Flags ===== +// Source: include/uapi/asm-generic/mman-common.h +pub const MREMAP_MAYMOVE: u32 = 0x01; // Can relocate mapping +pub const MREMAP_FIXED: u32 = 0x02; // New address is specified exactly + +// ===== File Access Modes ===== +// Source: include/uapi/asm-generic/fcntl.h +// NOTE: These should probably be moved to fs_constants.rs +pub const O_ACCMODE: i32 = 0o003; // Mask for file access modes +pub const O_RDONLY: i32 = 0o0; // Open read-only +pub const O_WRONLY: i32 = 0o1; // Open write-only +pub const O_RDWR: i32 = 0o2; // Open read-write diff --git a/src/RawPOSIX/src/constants/mod.rs b/src/RawPOSIX/src/constants/mod.rs new file mode 100644 index 000000000..265316cff --- /dev/null +++ b/src/RawPOSIX/src/constants/mod.rs @@ -0,0 +1,7 @@ +pub mod fs_constants; +pub mod net_constants; +pub mod sys_constants; + +pub use fs_constants::*; +pub use net_constants::*; +pub use sys_constants::*; diff --git a/src/RawPOSIX/src/constants/net_constants.rs b/src/RawPOSIX/src/constants/net_constants.rs new file mode 100644 index 000000000..4290f9048 --- /dev/null +++ b/src/RawPOSIX/src/constants/net_constants.rs @@ -0,0 +1,371 @@ +//! Network Constants Module +//! These constants define network-related flags and parameters +//! +//! Primary Source References: +//! - Linux kernel v6.5: include/uapi/linux/socket.h +//! - Linux kernel v6.5: include/uapi/linux/in.h +//! - Linux kernel v6.5: include/uapi/linux/tcp.h +//! - Linux kernel v6.5: include/uapi/linux/poll.h +//! - Linux kernel v6.5: include/uapi/linux/eventpoll.h +//! - POSIX.1-2017 (IEEE Std 1003.1-2017) + +#![allow(dead_code)] +#![allow(non_upper_case_globals)] + +use crate::interface; + +// ===== Lind-specific Configuration ===== +pub const DEFAULT_HOSTNAME: &str = "Lind"; +pub const BLOCK_TIME: interface::RustDuration = interface::RustDuration::from_micros(100); +pub const UDSOCK_CAPACITY: usize = 212992; // Unix domain socket buffer size + +// ===== Socket Types ===== +// Source: include/linux/net.h +pub const SOCK_STREAM: i32 = 1; // Stream (connection) socket +pub const SOCK_DGRAM: i32 = 2; // Datagram (connectionless) socket +pub const SOCK_RAW: i32 = 3; // Raw protocol interface +pub const SOCK_RDM: i32 = 4; // Reliably-delivered message +pub const SOCK_SEQPACKET: i32 = 5; // Sequential packet socket +pub const SOCK_CLOEXEC: i32 = 0o02000000; // Set close-on-exec +pub const SOCK_NONBLOCK: i32 = 0o00004000; // Set non-blocking mode + +// ===== Address Families ===== +// Source: include/linux/socket.h +pub const AF_UNSPEC: i32 = 0; // Unspecified +pub const AF_UNIX: i32 = 1; // Unix domain sockets +pub const AF_LOCAL: i32 = 1; // POSIX name for AF_UNIX +pub const AF_INET: i32 = 2; // Internet IP Protocol +pub const AF_AX25: i32 = 3; // Amateur Radio AX.25 +pub const AF_IPX: i32 = 4; // Novell IPX +pub const AF_APPLETALK: i32 = 5; // AppleTalk DDP +pub const AF_NETROM: i32 = 6; // Amateur Radio NET/ROM +pub const AF_BRIDGE: i32 = 7; // Multiprotocol bridge +pub const AF_ATMPVC: i32 = 8; // ATM PVCs +pub const AF_X25: i32 = 9; // Reserved for X.25 project +pub const AF_INET6: i32 = 10; // IP version 6 +pub const AF_ROSE: i32 = 11; // Amateur Radio X.25 PLP +pub const AF_DECnet: i32 = 12; // Reserved for DECnet project +pub const AF_NETBEUI: i32 = 13; // Reserved for 802.2LLC project +pub const AF_SECURITY: i32 = 14; // Security callback pseudo AF +pub const AF_KEY: i32 = 15; // PF_KEY key management API +pub const AF_NETLINK: i32 = 16; // Netlink +pub const AF_ROUTE: i32 = AF_NETLINK; // Alias to emulate 4.4BSD +pub const AF_PACKET: i32 = 17; // Packet family +pub const AF_ASH: i32 = 18; // Ash +pub const AF_ECONET: i32 = 19; // Acorn Econet +pub const AF_ATMSVC: i32 = 20; // ATM SVCs +pub const AF_RDS: i32 = 21; // RDS sockets +pub const AF_SNA: i32 = 22; // Linux SNA Project +pub const AF_IRDA: i32 = 23; // IRDA sockets +pub const AF_PPPOX: i32 = 24; // PPPoX sockets +pub const AF_WANPIPE: i32 = 25; // Wanpipe API Sockets +pub const AF_LLC: i32 = 26; // Linux LLC +pub const AF_IB: i32 = 27; // Native InfiniBand address +pub const AF_MPLS: i32 = 28; // MPLS +pub const AF_CAN: i32 = 29; // Controller Area Network +pub const AF_TIPC: i32 = 30; // TIPC sockets +pub const AF_BLUETOOTH: i32 = 31; // Bluetooth sockets +pub const AF_IUCV: i32 = 32; // IUCV sockets +pub const AF_RXRPC: i32 = 33; // RxRPC sockets +pub const AF_ISDN: i32 = 34; // mISDN sockets +pub const AF_PHONET: i32 = 35; // Phonet sockets +pub const AF_IEEE802154: i32 = 36; // IEEE802154 sockets +pub const AF_CAIF: i32 = 37; // CAIF sockets +pub const AF_ALG: i32 = 38; // Algorithm sockets +pub const AF_NFC: i32 = 39; // NFC sockets +pub const AF_VSOCK: i32 = 40; // vSockets +pub const AF_KCM: i32 = 41; // Kernel Connection Multiplexor +pub const AF_QIPCRTR: i32 = 42; // Qualcomm IPC Router +pub const AF_SMC: i32 = 43; // SMC sockets +pub const AF_XDP: i32 = 44; // XDP sockets +pub const AF_MCTP: i32 = 45; // Management Component Transport Protocol +pub const AF_MAX: i32 = 46; // Maximum address family value + +// ===== Protocol Families ===== +// Source: include/linux/socket.h +// Note: PF_* constants are aliases for AF_* for backward compatibility +pub const PF_UNSPEC: i32 = AF_UNSPEC; +pub const PF_UNIX: i32 = AF_UNIX; +pub const PF_LOCAL: i32 = AF_LOCAL; +pub const PF_INET: i32 = AF_INET; +pub const PF_AX25: i32 = AF_AX25; +pub const PF_IPX: i32 = AF_IPX; +pub const PF_APPLETALK: i32 = AF_APPLETALK; +pub const PF_NETROM: i32 = AF_NETROM; +pub const PF_BRIDGE: i32 = AF_BRIDGE; +pub const PF_ATMPVC: i32 = AF_ATMPVC; +pub const PF_X25: i32 = AF_X25; +pub const PF_INET6: i32 = AF_INET6; +pub const PF_ROSE: i32 = AF_ROSE; +pub const PF_DECnet: i32 = AF_DECnet; +pub const PF_NETBEUI: i32 = AF_NETBEUI; +pub const PF_SECURITY: i32 = AF_SECURITY; +pub const PF_KEY: i32 = AF_KEY; +pub const PF_NETLINK: i32 = AF_NETLINK; +pub const PF_ROUTE: i32 = AF_ROUTE; +pub const PF_PACKET: i32 = AF_PACKET; +pub const PF_ASH: i32 = AF_ASH; +pub const PF_ECONET: i32 = AF_ECONET; +pub const PF_ATMSVC: i32 = AF_ATMSVC; +pub const PF_RDS: i32 = AF_RDS; +pub const PF_SNA: i32 = AF_SNA; +pub const PF_IRDA: i32 = AF_IRDA; +pub const PF_PPPOX: i32 = AF_PPPOX; +pub const PF_WANPIPE: i32 = AF_WANPIPE; +pub const PF_LLC: i32 = AF_LLC; +pub const PF_IB: i32 = AF_IB; +pub const PF_MPLS: i32 = AF_MPLS; +pub const PF_CAN: i32 = AF_CAN; +pub const PF_TIPC: i32 = AF_TIPC; +pub const PF_BLUETOOTH: i32 = AF_BLUETOOTH; +pub const PF_IUCV: i32 = AF_IUCV; +pub const PF_RXRPC: i32 = AF_RXRPC; +pub const PF_ISDN: i32 = AF_ISDN; +pub const PF_PHONET: i32 = AF_PHONET; +pub const PF_IEEE802154: i32 = AF_IEEE802154; +pub const PF_CAIF: i32 = AF_CAIF; +pub const PF_ALG: i32 = AF_ALG; +pub const PF_NFC: i32 = AF_NFC; +pub const PF_VSOCK: i32 = AF_VSOCK; +pub const PF_KCM: i32 = AF_KCM; +pub const PF_QIPCRTR: i32 = AF_QIPCRTR; +pub const PF_SMC: i32 = AF_SMC; +pub const PF_XDP: i32 = AF_XDP; +pub const PF_MCTP: i32 = AF_MCTP; +pub const PF_MAX: i32 = AF_MAX; + +// ===== IP Protocol Numbers ===== +// Source: include/uapi/linux/in.h +pub const IPPROTO_IP: i32 = 0; // Dummy protocol for TCP +pub const IPPROTO_ICMP: i32 = 1; // Internet Control Message Protocol +pub const IPPROTO_IGMP: i32 = 2; // Internet Group Management Protocol +pub const IPPROTO_GGP: i32 = 3; // Gateway-Gateway Protocol (deprecated) +pub const IPPROTO_IPV4: i32 = 4; // IPv4 encapsulation +pub const IPPROTO_IPIP: i32 = IPPROTO_IPV4; // IP in IP encapsulation +pub const IPPROTO_TCP: i32 = 6; // Transmission Control Protocol +pub const IPPROTO_ST: i32 = 7; // Stream Protocol +pub const IPPROTO_EGP: i32 = 8; // Exterior Gateway Protocol +pub const IPPROTO_PIGP: i32 = 9; // Private Interior Gateway Protocol +pub const IPPROTO_RCCMON: i32 = 10; // BBN RCC Monitoring +pub const IPPROTO_NVPII: i32 = 11; // Network Voice Protocol +pub const IPPROTO_PUP: i32 = 12; // PARC Universal Packet Protocol +pub const IPPROTO_ARGUS: i32 = 13; // ARGUS +pub const IPPROTO_EMCON: i32 = 14; // EMCON +pub const IPPROTO_XNET: i32 = 15; // Cross Net Debugger +pub const IPPROTO_CHAOS: i32 = 16; // Chaos +pub const IPPROTO_UDP: i32 = 17; // User Datagram Protocol +pub const IPPROTO_MUX: i32 = 18; // Multiplexing Protocol +pub const IPPROTO_MEAS: i32 = 19; // DCN Measurement Subsystems +pub const IPPROTO_HMP: i32 = 20; // Host Monitoring Protocol +pub const IPPROTO_PRM: i32 = 21; // Packet Radio Measurement Protocol +pub const IPPROTO_IDP: i32 = 22; // Xerox NS IDP +pub const IPPROTO_TRUNK1: i32 = 23; // Trunk-1 +pub const IPPROTO_TRUNK2: i32 = 24; // Trunk-2 +pub const IPPROTO_LEAF1: i32 = 25; // Leaf-1 +pub const IPPROTO_LEAF2: i32 = 26; // Leaf-2 +pub const IPPROTO_RDP: i32 = 27; // Reliable Datagram Protocol +pub const IPPROTO_IRTP: i32 = 28; // Internet Reliable Transaction Protocol +pub const IPPROTO_TP: i32 = 29; // ISO Transport Protocol Class 4 +pub const IPPROTO_BLT: i32 = 30; // Bulk Data Transfer Protocol +pub const IPPROTO_NSP: i32 = 31; // Network Services Protocol +pub const IPPROTO_INP: i32 = 32; // Merit Internodal Protocol +pub const IPPROTO_SEP: i32 = 33; // Sequential Exchange Protocol +pub const IPPROTO_3PC: i32 = 34; // Third Party Connect Protocol +pub const IPPROTO_IDPR: i32 = 35; // Inter-Domain Policy Routing Protocol +pub const IPPROTO_XTP: i32 = 36; // Xpress Transport Protocol +pub const IPPROTO_DDP: i32 = 37; // Datagram Delivery Protocol +pub const IPPROTO_CMTP: i32 = 38; // Control Message Transport Protocol +pub const IPPROTO_TPXX: i32 = 39; // TP++ Transport Protocol +pub const IPPROTO_IL: i32 = 40; // IL Transport Protocol +pub const IPPROTO_IPV6: i32 = 41; // IPv6 header +pub const IPPROTO_SDRP: i32 = 42; // Source Demand Routing Protocol +pub const IPPROTO_ROUTING: i32 = 43; // IPv6 routing header +pub const IPPROTO_FRAGMENT: i32 = 44; // IPv6 fragmentation header +pub const IPPROTO_IDRP: i32 = 45; // Inter-Domain Routing Protocol +pub const IPPROTO_RSVP: i32 = 46; // Resource Reservation Protocol +pub const IPPROTO_GRE: i32 = 47; // Generic Routing Encapsulation +pub const IPPROTO_MHRP: i32 = 48; // Mobile Host Routing Protocol +pub const IPPROTO_BHA: i32 = 49; // BHA +pub const IPPROTO_ESP: i32 = 50; // IPv6 Encapsulating Security Payload +pub const IPPROTO_AH: i32 = 51; // IPv6 Authentication Header +pub const IPPROTO_INLSP: i32 = 52; // Integrated Net Layer Security Protocol +pub const IPPROTO_SWIPE: i32 = 53; // IP with Encryption +pub const IPPROTO_NHRP: i32 = 54; // Next Hop Resolution Protocol + // 55-57: Unassigned +pub const IPPROTO_ICMPV6: i32 = 58; // ICMPv6 +pub const IPPROTO_NONE: i32 = 59; // IPv6 no next header +pub const IPPROTO_DSTOPTS: i32 = 60; // IPv6 destination options +pub const IPPROTO_AHIP: i32 = 61; // Any host internal protocol +pub const IPPROTO_CFTP: i32 = 62; // CFTP +pub const IPPROTO_HELLO: i32 = 63; // "hello" routing protocol +pub const IPPROTO_SATEXPAK: i32 = 64; // SATNET/Backroom EXPAK +pub const IPPROTO_KRYPTOLAN: i32 = 65; // Kryptolan +pub const IPPROTO_RVD: i32 = 66; // Remote Virtual Disk +pub const IPPROTO_IPPC: i32 = 67; // Pluribus Packet Core +pub const IPPROTO_ADFS: i32 = 68; // Any distributed file system +pub const IPPROTO_SATMON: i32 = 69; // SATNET Monitoring +pub const IPPROTO_VISA: i32 = 70; // VISA Protocol +pub const IPPROTO_IPCV: i32 = 71; // Internet Packet Core Utility +pub const IPPROTO_CPNX: i32 = 72; // Computer Protocol Network Executive +pub const IPPROTO_CPHB: i32 = 73; // Computer Protocol Heart Beat +pub const IPPROTO_WSN: i32 = 74; // Wang Span Network +pub const IPPROTO_PVP: i32 = 75; // Packet Video Protocol +pub const IPPROTO_BRSATMON: i32 = 76; // BackRoom SATNET Monitoring +pub const IPPROTO_ND: i32 = 77; // Sun net disk protocol (temporary) +pub const IPPROTO_WBMON: i32 = 78; // WIDEBAND Monitoring +pub const IPPROTO_WBEXPAK: i32 = 79; // WIDEBAND EXPAK +pub const IPPROTO_EON: i32 = 80; // ISO CNLP +pub const IPPROTO_VMTP: i32 = 81; // Versatile Message Transaction Protocol +pub const IPPROTO_SVMTP: i32 = 82; // Secure VMTP +pub const IPPROTO_VINES: i32 = 83; // VINES +pub const IPPROTO_TTP: i32 = 84; // TTP +pub const IPPROTO_IGP: i32 = 85; // NSFNET-IGP +pub const IPPROTO_DGP: i32 = 86; // Dissimilar Gateway Protocol +pub const IPPROTO_TCF: i32 = 87; // TCF +pub const IPPROTO_IGRP: i32 = 88; // Interior Gateway Routing Protocol +pub const IPPROTO_OSPFIGP: i32 = 89; // OSPF IGP +pub const IPPROTO_SRPC: i32 = 90; // Sprite RPC Protocol +pub const IPPROTO_LARP: i32 = 91; // Locus Address Resolution Protocol +pub const IPPROTO_MTP: i32 = 92; // Multicast Transport Protocol +pub const IPPROTO_AX25: i32 = 93; // AX.25 Frames +pub const IPPROTO_IPEIP: i32 = 94; // IP encapsulated in IP +pub const IPPROTO_MICP: i32 = 95; // Mobile Internetworking Control Protocol +pub const IPPROTO_SCCSP: i32 = 96; // Semaphore Communications Security Protocol +pub const IPPROTO_ETHERIP: i32 = 97; // Ethernet-within-IP Encapsulation +pub const IPPROTO_ENCAP: i32 = 98; // Encapsulation Header +pub const IPPROTO_APES: i32 = 99; // Any private encryption scheme +pub const IPPROTO_GMTP: i32 = 100; // GMTP +pub const IPPROTO_PIM: i32 = 103; // Protocol Independent Multicast +pub const IPPROTO_IPCOMP: i32 = 108; // IP Payload Compression Protocol +pub const IPPROTO_PGM: i32 = 113; // PGM Reliable Transport Protocol +pub const IPPROTO_SCTP: i32 = 132; // Stream Control Transmission Protocol +pub const IPPROTO_DIVERT: i32 = 254; // Divert pseudo-protocol +pub const IPPROTO_RAW: i32 = 255; // Raw IP packets +pub const IPPROTO_MAX: i32 = 256; +pub const IPPROTO_DONE: i32 = 257; // All processing for this packet is done + +// ===== Message Flags ===== +// Source: include/linux/socket.h +pub const MSG_OOB: i32 = 1; // Process out-of-band data +pub const MSG_PEEK: i32 = 2; // Peek at incoming message +pub const MSG_DONTROUTE: i32 = 4; // Don't use local routing +pub const MSG_TRYHARD: i32 = 4; // Synonym for MSG_DONTROUTE for DECnet +pub const MSG_CTRUNC: i32 = 8; // Control data lost before delivery +pub const MSG_PROBE: i32 = 0x10; // Do not send, probe path for MTU +pub const MSG_TRUNC: i32 = 0x20; // Message was truncated +pub const MSG_DONTWAIT: i32 = 0x40; // Non-blocking I/O +pub const MSG_EOR: i32 = 0x80; // End of record +pub const MSG_WAITALL: i32 = 0x100; // Wait for a full request +pub const MSG_FIN: i32 = 0x200; // Sender will send no more +pub const MSG_SYN: i32 = 0x400; // Initiate a connection +pub const MSG_CONFIRM: i32 = 0x800; // Confirm path validity +pub const MSG_RST: i32 = 0x1000; // Reset the connection +pub const MSG_ERRQUEUE: i32 = 0x2000; // Fetch message from error queue +pub const MSG_NOSIGNAL: i32 = 0x4000; // Do not generate SIGPIPE +pub const MSG_MORE: i32 = 0x8000; // Sender will send more +pub const MSG_WAITFORONE: i32 = 0x10000; // Wait for at least one packet +pub const MSG_SENDPAGE_NOPOLICY: i32 = 0x10000; // sendpage() internal: no policy +pub const MSG_SENDPAGE_NOTLAST: i32 = 0x20000; // sendpage() internal: not last page +pub const MSG_BATCH: i32 = 0x40000; // sendmmsg(): more messages coming +pub const MSG_EOF: i32 = MSG_FIN; // Alias for MSG_FIN +pub const MSG_NO_SHARED_FRAGS: i32 = 0x80000; // sendpage() internal: no shared frags +pub const MSG_SENDPAGE_DECRYPTED: i32 = 0x100000; // sendpage() internal: page needs encryption + +// ===== Shutdown Constants ===== +// Source: include/linux/socket.h +pub const SHUT_RD: i32 = 0; // Disable further receives +pub const SHUT_WR: i32 = 1; // Disable further sends +pub const SHUT_RDWR: i32 = 2; // Disable further sends/receives + +// ===== Socket Options ===== +// Source: include/uapi/asm-generic/socket.h +pub const SOL_SOCKET: i32 = 1; // Socket-level options +pub const SO_DEBUG: i32 = 1; // Debug info recording +pub const SO_REUSEADDR: i32 = 2; // Allow reuse of local addresses +pub const SO_TYPE: i32 = 3; // Get socket type +pub const SO_ERROR: i32 = 4; // Get and clear error status +pub const SO_DONTROUTE: i32 = 5; // Use interface addresses +pub const SO_BROADCAST: i32 = 6; // Permit sending of broadcast msgs +pub const SO_SNDBUF: i32 = 7; // Send buffer size +pub const SO_RCVBUF: i32 = 8; // Receive buffer size +pub const SO_SNDBUFFORCE: i32 = 32; // Send buffer size (privileged) +pub const SO_RCVBUFFORCE: i32 = 33; // Receive buffer size (privileged) +pub const SO_KEEPALIVE: i32 = 9; // Keep connections alive +pub const SO_OOBINLINE: i32 = 10; // Leave received OOB data in line +pub const SO_NO_CHECK: i32 = 11; // Disable checksums +pub const SO_PRIORITY: i32 = 12; // Set the protocol-defined priority +pub const SO_LINGER: i32 = 13; // Linger on close if data present +pub const SO_BSDCOMPAT: i32 = 14; // Enable BSD bug-to-bug compatibility +pub const SO_REUSEPORT: i32 = 15; // Allow reuse of address/port pairs +pub const SO_PASSCRED: i32 = 16; // Receive SCM_CREDENTIALS messages +pub const SO_PEERCRED: i32 = 17; // Get socket's peer credentials +pub const SO_RCVLOWAT: i32 = 18; // Receive low-water mark +pub const SO_SNDLOWAT: i32 = 19; // Send low-water mark +pub const SO_RCVTIMEO_OLD: i32 = 20; // Receive timeout (old) +pub const SO_SNDTIMEO_OLD: i32 = 21; // Send timeout (old) +pub const SO_PEERNAME: i32 = 28; // Name of connected peer +pub const SO_ACCEPTCONN: i32 = 30; // Socket has had listen() + +// ===== TCP Options ===== +// Source: include/uapi/linux/tcp.h +pub const SOL_TCP: i32 = IPPROTO_TCP; // TCP protocol level +pub const SOL_UDP: i32 = IPPROTO_UDP; // UDP protocol level + +pub const TCP_NODELAY: i32 = 0x01; // Don't delay send to coalesce packets +pub const TCP_MAXSEG: i32 = 0x02; // Set maximum segment size +pub const TCP_NOPUSH: i32 = 0x04; // Don't push last block of write +pub const TCP_NOOPT: i32 = 0x08; // Don't use TCP options +pub const TCP_KEEPALIVE: i32 = 0x10; // Idle time for keepalive +pub const TCP_CONNECTIONTIMEOUT: i32 = 0x20; // Connection timeout +pub const PERSIST_TIMEOUT: i32 = 0x40; // Persist timeout +pub const TCP_RXT_CONNDROPTIME: i32 = 0x80; // Retransmission timeout before drop +pub const TCP_RXT_FINDROP: i32 = 0x100; // Drop after 3 FIN retransmissions + +// ===== Socket Object ID Range ===== +// Lind-specific constants +pub const MINSOCKOBJID: i32 = 0; +pub const MAXSOCKOBJID: i32 = 1024; + +// ===== Poll Constants ===== +// Source: include/uapi/asm-generic/poll.h +pub const POLLIN: i16 = 0o1; // Ready for reading +pub const POLLPRI: i16 = 0o2; // Priority data ready +pub const POLLOUT: i16 = 0o4; // Ready for writing +pub const POLLERR: i16 = 0o10; // Error condition +pub const POLLHUP: i16 = 0o20; // Hung up +pub const POLLNVAL: i16 = 0o40; // Invalid polling request + +// ===== Epoll Constants ===== +// Source: include/uapi/linux/eventpoll.h +pub const EPOLLIN: i32 = 0x001; // Ready for reading +pub const EPOLLPRI: i32 = 0x002; // Priority data ready +pub const EPOLLOUT: i32 = 0x004; // Ready for writing +pub const EPOLLRDNORM: i32 = 0x040; // Normal data ready for reading +pub const EPOLLRDBAND: i32 = 0x080; // Priority band data ready for reading +pub const EPOLLWRNORM: i32 = 0x100; // Normal data ready for writing +pub const EPOLLWRBAND: i32 = 0x200; // Priority band data ready for writing +pub const EPOLLMSG: i32 = 0x400; // Message ready +pub const EPOLLERR: i32 = 0x008; // Error condition +pub const EPOLLHUP: i32 = 0x010; // Hang up +pub const EPOLLRDHUP: i32 = 0x2000; // Peer closed the connection +pub const EPOLLWAKEUP: i32 = 1 << 29; // Prevent system suspend +pub const EPOLLONESHOT: i32 = 1 << 30; // One-shot edge trigger +pub const EPOLLET: i32 = 1 << 31; // Edge-triggered + +pub const EPOLL_CTL_ADD: i32 = 1; // Add a file descriptor +pub const EPOLL_CTL_DEL: i32 = 2; // Remove a file descriptor +pub const EPOLL_CTL_MOD: i32 = 3; // Change event registration + +pub const FD_SET_MAX_FD: i32 = 1024; // Maximum file descriptor for fd_set + +// ===== Connection States ===== +// Lind-specific enum for internal use +#[derive(Debug, PartialEq, Eq, Clone)] +pub enum ConnState { + NOTCONNECTED, + CONNECTED, + CONNRDONLY, + CONNWRONLY, + LISTEN, + INPROGRESS, +} diff --git a/src/RawPOSIX/src/constants/sys_constants.rs b/src/RawPOSIX/src/constants/sys_constants.rs new file mode 100644 index 000000000..34492abf4 --- /dev/null +++ b/src/RawPOSIX/src/constants/sys_constants.rs @@ -0,0 +1,97 @@ +//! System Constants Module +//! +//! Primary Source References: +//! - Linux kernel v6.5: include/uapi/asm-generic/signal.h +//! - Linux kernel v6.5: include/uapi/asm-generic/resource.h +//! - POSIX.1-2017 (IEEE Std 1003.1-2017) +//! - Linux man-pages project: signal(7) + +#![allow(dead_code)] +#![allow(unused_variables)] + +use crate::interface; + +// ===== User and Group ID Constants ===== +// Lind-specific default values +pub const DEFAULT_UID: u32 = 1000; // Default user ID +pub const DEFAULT_GID: u32 = 1000; // Default group ID + +// ===== Resource Limits ===== +// Source: include/uapi/asm-generic/resource.h +pub const SIGNAL_MAX: i32 = 64; // Maximum number of signals + +// File descriptor limits +pub const NOFILE_CUR: u64 = 1024; // Soft limit for number of open files +pub const NOFILE_MAX: u64 = 4 * 1024; // Hard limit for number of open files + +// Stack size limits +pub const STACK_CUR: u64 = 8192 * 1024; // Soft limit for stack size (8MB) +pub const STACK_MAX: u64 = 1 << 32; // Hard limit for stack size (4GB) + +// Resource identifiers +pub const RLIMIT_STACK: u64 = 0; // Limit type for stack size +pub const RLIMIT_NOFILE: u64 = 1; // Limit type for number of files + +// ===== Process Exit Status ===== +// Source: and POSIX standard +pub const EXIT_SUCCESS: i32 = 0; // Successful termination +pub const EXIT_FAILURE: i32 = 1; // Unsuccessful termination + +// ===== Signal Constants ===== +// Source: include/uapi/asm-generic/signal.h +// Reference: https://man7.org/linux/man-pages/man7/signal.7.html +// Note: Signal numbers can vary by architecture. These are for x86/ARM. + +// Terminal control signals +pub const SIGHUP: i32 = 1; // Hangup +pub const SIGINT: i32 = 2; // Interrupt (Ctrl+C) +pub const SIGQUIT: i32 = 3; // Quit (Ctrl+\) +pub const SIGTERM: i32 = 15; // Termination request + +// Error signals +pub const SIGILL: i32 = 4; // Illegal instruction +pub const SIGTRAP: i32 = 5; // Trace/breakpoint trap +pub const SIGABRT: i32 = 6; // Abort program +pub const SIGIOT: i32 = 6; // Alias for SIGABRT +pub const SIGBUS: i32 = 7; // Bus error (bad memory access) +pub const SIGFPE: i32 = 8; // Floating point exception +pub const SIGSEGV: i32 = 11; // Segmentation violation +pub const SIGSYS: i32 = 31; // Bad system call +pub const SIGUNUSED: i32 = 31; // Alias for SIGSYS + +// User-defined signals +pub const SIGUSR1: i32 = 10; // User-defined signal 1 +pub const SIGUSR2: i32 = 12; // User-defined signal 2 + +// Process control signals +pub const SIGCHLD: i32 = 17; // Child stopped or terminated +pub const SIGCONT: i32 = 18; // Continue if stopped +pub const SIGSTOP: i32 = 19; // Stop process +pub const SIGTSTP: i32 = 20; // Stop typed at terminal +pub const SIGTTIN: i32 = 21; // Terminal input for background process +pub const SIGTTOU: i32 = 22; // Terminal output for background process + +// Resource limit signals +pub const SIGXCPU: i32 = 24; // CPU time limit exceeded +pub const SIGXFSZ: i32 = 25; // File size limit exceeded + +// Alarm signals +pub const SIGALRM: i32 = 14; // Timer signal from alarm(2) +pub const SIGVTALRM: i32 = 26; // Virtual timer expired +pub const SIGPROF: i32 = 27; // Profiling timer expired + +// I/O signals +pub const SIGPIPE: i32 = 13; // Broken pipe +pub const SIGURG: i32 = 23; // Urgent condition on socket +pub const SIGWINCH: i32 = 28; // Window resize signal +pub const SIGIO: i32 = 29; // I/O now possible +pub const SIGPOLL: i32 = 29; // Pollable event (same as SIGIO) +pub const SIGPWR: i32 = 30; // Power failure + +// Signal actions +pub const SIG_BLOCK: i32 = 0; // Block signals in signal mask +pub const SIG_UNBLOCK: i32 = 1; // Unblock signals in signal mask +pub const SIG_SETMASK: i32 = 2; // Set the signal mask + +// Timer types +pub const ITIMER_REAL: i32 = 0; // Real-time timer diff --git a/src/RawPOSIX/src/interface/misc.rs b/src/RawPOSIX/src/interface/misc.rs index 2476b23f1..0f9fcd5c7 100644 --- a/src/RawPOSIX/src/interface/misc.rs +++ b/src/RawPOSIX/src/interface/misc.rs @@ -34,7 +34,7 @@ pub use serde_cbor::{ use crate::interface; use crate::interface::errnos::VERBOSE; use crate::interface::types::SigsetType; -use crate::safeposix::syscalls::fs_constants::SEM_VALUE_MAX; +use crate::constants::SEM_VALUE_MAX; use std::sync::LazyLock; use std::time::Duration; diff --git a/src/RawPOSIX/src/lib.rs b/src/RawPOSIX/src/lib.rs index d7f3d819b..29e66e4a8 100644 --- a/src/RawPOSIX/src/lib.rs +++ b/src/RawPOSIX/src/lib.rs @@ -11,3 +11,4 @@ pub mod interface; pub mod safeposix; pub mod tests; pub mod fdtables; +pub mod constants; diff --git a/src/RawPOSIX/src/safeposix/cage.rs b/src/RawPOSIX/src/safeposix/cage.rs index 2e6d6ad43..372b39a11 100644 --- a/src/RawPOSIX/src/safeposix/cage.rs +++ b/src/RawPOSIX/src/safeposix/cage.rs @@ -1,6 +1,14 @@ #![allow(dead_code)] use crate::interface; -//going to get the datatypes and errnos from the cage file from now on +use crate::constants::{ + SIGNAL_MAX, + S_IRWXU, S_IRWXG, S_IRWXO, + PROT_READ, PROT_WRITE, + O_RDONLY, O_WRONLY, O_RDWR, O_CREAT, O_TRUNC, + MAP_SHARED, MAP_PRIVATE, +}; + +// Going to get the datatypes and errnos from the cage file from now on pub use crate::interface::errnos::{syscall_error, Errno}; pub use crate::interface::types::{ @@ -8,12 +16,8 @@ pub use crate::interface::types::{ }; use super::filesystem::normpath; -pub use super::syscalls::fs_constants::*; -pub use super::syscalls::net_constants::*; -pub use super::syscalls::sys_constants::*; -pub use super::vmmap::*; -pub use super::vmmap_constants::*; +pub use super::vmmap::*; pub use crate::interface::CAGE_TABLE; #[derive(Debug, Clone, Copy)] diff --git a/src/RawPOSIX/src/safeposix/dispatcher.rs b/src/RawPOSIX/src/safeposix/dispatcher.rs index 9d0673ab9..427411bbf 100644 --- a/src/RawPOSIX/src/safeposix/dispatcher.rs +++ b/src/RawPOSIX/src/safeposix/dispatcher.rs @@ -135,6 +135,7 @@ use crate::interface::types; use crate::interface::{SigactionStruct, StatData}; use crate::{fdtables, interface}; use crate::interface::errnos::*; +use crate::constants::{O_RDONLY, O_WRONLY}; macro_rules! get_onearg { ($arg: expr) => { @@ -1155,8 +1156,8 @@ pub fn lindrustinit(verbosity: isize) { // STDIN let dev_null = CString::new("/home/lind/lind_project/src/safeposix-rust/tmp/dev/null").unwrap(); unsafe { - libc::open(dev_null.as_ptr(), libc::O_RDONLY); - libc::open(dev_null.as_ptr(), libc::O_WRONLY); + libc::open(dev_null.as_ptr(), O_RDONLY); + libc::open(dev_null.as_ptr(), O_WRONLY); libc::dup(1); } diff --git a/src/RawPOSIX/src/safeposix/mod.rs b/src/RawPOSIX/src/safeposix/mod.rs index 6f4bc0e36..2f4c3760d 100644 --- a/src/RawPOSIX/src/safeposix/mod.rs +++ b/src/RawPOSIX/src/safeposix/mod.rs @@ -4,4 +4,4 @@ pub mod filesystem; pub mod shm; pub mod syscalls; pub mod vmmap; -pub mod vmmap_constants; +// pub mod vmmap_constants; diff --git a/src/RawPOSIX/src/safeposix/shm.rs b/src/RawPOSIX/src/safeposix/shm.rs index a450af6ec..5df5c7421 100644 --- a/src/RawPOSIX/src/safeposix/shm.rs +++ b/src/RawPOSIX/src/safeposix/shm.rs @@ -1,8 +1,12 @@ // Filesystem metadata struct #![allow(dead_code)] -use super::syscalls::fs_constants::*; -use super::syscalls::sys_constants::*; +use crate::constants::{ + PROT_NONE, PROT_READ, PROT_WRITE, + MAP_SHARED, MAP_PRIVATE, MAP_FIXED, MAP_ANONYMOUS, + SHM_RDONLY, SHM_DEST, +}; + use crate::interface; use libc::*; @@ -118,7 +122,7 @@ impl ShmSegment { } } interface::RustHashEntry::Vacant(_) => { - panic!("Cage not avilable in segment attached cages"); + panic!("Cage not available in segment attached cages"); } }; } diff --git a/src/RawPOSIX/src/safeposix/syscalls/fs_calls.rs b/src/RawPOSIX/src/safeposix/syscalls/fs_calls.rs index 18b6f3aab..675e51f24 100644 --- a/src/RawPOSIX/src/safeposix/syscalls/fs_calls.rs +++ b/src/RawPOSIX/src/safeposix/syscalls/fs_calls.rs @@ -1,10 +1,23 @@ #![allow(dead_code)] use std::fs; -use super::fs_constants; -// File system related system calls -use super::fs_constants::*; -use super::sys_constants; +// Removed these since we'll import from constants directly +// use super::fs_constants; +// use super::fs_constants::*; +// use super::sys_constants; + +// Add constants imports +use crate::constants::{ + S_IRWXU, S_IRWXG, S_IRWXO, + PROT_READ, PROT_WRITE, + O_RDONLY, O_WRONLY, O_RDWR, O_CREAT, O_TRUNC, O_CLOEXEC, + MAP_SHARED, MAP_PRIVATE, + SEEK_SET, SEEK_CUR, SEEK_END, + SHMMIN, SHMMAX, SHM_RDONLY, SHM_DEST, + DEFAULT_UID, DEFAULT_GID, + SEM_VALUE_MAX, +}; + use crate::interface; use crate::interface::get_errno; use crate::interface::handle_errno; @@ -1178,7 +1191,7 @@ impl Cage { let metadata = &SHM_METADATA; let prot: i32; if let Some(mut segment) = metadata.shmtable.get_mut(&shmid) { - if 0 != (shmflg & fs_constants::SHM_RDONLY) { + if 0 != (shmflg & SHM_RDONLY) { prot = PROT_READ; } else { prot = PROT_READ | PROT_WRITE; diff --git a/src/RawPOSIX/src/safeposix/syscalls/fs_constants.rs b/src/RawPOSIX/src/safeposix/syscalls/fs_constants.rs deleted file mode 100644 index a5c1fb61b..000000000 --- a/src/RawPOSIX/src/safeposix/syscalls/fs_constants.rs +++ /dev/null @@ -1,196 +0,0 @@ -// File system related constants -#![allow(dead_code)] -#![allow(unused_variables)] - -use crate::interface; - -// Define constants using static or const -// Imported into fs_calls file -// pub const DT_UNKNOWN: u8 = 0; - -// pub const STARTINGFD: i32 = 0; -// pub const MAXFD: i32 = 1024; -// pub const STARTINGPIPE: i32 = 0; -// pub const MAXPIPE: i32 = 1024; - -// pub const ROOTDIRECTORYINODE: usize = 1; -// pub const STREAMINODE: usize = 2; - -// pub const PIPE_CAPACITY: usize = 65536; - -// pub const F_OK: u32 = 0; -// pub const X_OK: u32 = 1; -// pub const W_OK: u32 = 2; -// pub const R_OK: u32 = 4; - -// pub const O_RDONLY: i32 = 0o0; -// pub const O_WRONLY: i32 = 0o1; -// pub const O_RDWR: i32 = 0o2; -// pub const O_RDWRFLAGS: i32 = 0o3; - -// pub const O_CREAT: i32 = 0o100; -// pub const O_EXCL: i32 = 0o200; -// pub const O_NOCTTY: i32 = 0o400; -// pub const O_TRUNC: i32 = 0o1000; -// pub const O_APPEND: i32 = 0o2000; -// pub const O_NONBLOCK: i32 = 0o4000; -// // O_NDELAY=O_NONBLOCK -// pub const O_SYNC: i32 = 0o10000; -// // O_FSYNC=O_SYNC -// pub const O_ASYNC: i32 = 0o20000; -// pub const O_CLOEXEC: i32 = 0o2000000; - -// pub const DEFAULTTIME: u64 = 1323630836; - -//Standard flag combinations -pub const S_IRWXA: u32 = 0o777; -pub const S_IRWXU: u32 = 0o700; -pub const S_IRUSR: u32 = 0o400; -pub const S_IWUSR: u32 = 0o200; -pub const S_IXUSR: u32 = 0o100; -pub const S_IRWXG: u32 = 0o070; -pub const S_IRGRP: u32 = 0o040; -pub const S_IWGRP: u32 = 0o020; -pub const S_IXGRP: u32 = 0o010; -pub const S_IRWXO: u32 = 0o007; -pub const S_IROTH: u32 = 0o004; -pub const S_IWOTH: u32 = 0o002; -pub const S_IXOTH: u32 = 0o001; - -// //Commands for FCNTL -// pub const F_DUPFD: i32 = 0; -// pub const F_GETFD: i32 = 1; -// pub const F_SETFD: i32 = 2; -// pub const F_GETFL: i32 = 3; -// pub const F_SETFL: i32 = 4; -// pub const F_GETLK: i32 = 5; -// pub const F_GETLK64: i32 = 5; -// pub const F_SETLK: i32 = 6; -// pub const F_SETLK64: i32 = 6; -// pub const F_SETLKW: i32 = 7; -// pub const F_SETLKW64: i32 = 7; -// pub const F_SETOWN: i32 = 8; -// pub const F_GETOWN: i32 = 9; -// pub const F_SETSIG: i32 = 10; -// pub const F_GETSIG: i32 = 11; -// pub const F_SETLEASE: i32 = 1024; -// pub const F_GETLEASE: i32 = 1025; -// pub const F_NOTIFY: i32 = 1026; - -// //Commands for IOCTL -// pub const FIONBIO: u32 = 21537; -// pub const FIOASYNC: u32 = 21586; - -// //File types for open/stat etc. -// pub const S_IFBLK: i32 = 0o60000; -// pub const S_IFCHR: i32 = 0o20000; -// pub const S_IFDIR: i32 = 0o40000; -// pub const S_IFIFO: i32 = 0o10000; -// pub const S_IFLNK: i32 = 0o120000; -// pub const S_IFREG: i32 = 0o100000; -// pub const S_IFSOCK: i32 = 0o140000; -// pub const S_FILETYPEFLAGS: i32 = 0o170000; - -// //for flock syscall -// pub const LOCK_SH: i32 = 1; -// pub const LOCK_EX: i32 = 2; -// pub const LOCK_UN: i32 = 8; -// pub const LOCK_NB: i32 = 4; -// //for mmap/munmap syscall -// pub const MAP_SHARED: i32 = 1; -// pub const MAP_PRIVATE: i32 = 2; -// pub const MAP_FIXED: i32 = 16; -// pub const MAP_ANONYMOUS: i32 = 32; -// pub const MAP_HUGE_SHIFT: i32 = 26; -// pub const MAP_HUGETLB: i32 = 262144; - -// pub const PROT_NONE: i32 = 0; -// pub const PROT_READ: i32 = 1; -// pub const PROT_WRITE: i32 = 2; -// pub const PROT_EXEC: i32 = 4; - -// pub const SEEK_SET: i32 = 0; -// pub const SEEK_CUR: i32 = 1; -// pub const SEEK_END: i32 = 2; - -// pub const IPC_PRIVATE: i32 = 0o0; -// pub const IPC_CREAT: i32 = 0o1000; -// pub const IPC_EXCL: i32 = 0o2000; - -// pub const IPC_RMID: i32 = 0; -// pub const IPC_SET: i32 = 1; -// pub const IPC_STAT: i32 = 2; - -pub const SHM_DEST: i32 = 0o1000; -pub const SHM_LOCKED: i32 = 0o2000; -pub const SHM_HUGETLB: i32 = 0o4000; - -pub const SHM_R: i32 = 0o400; -pub const SHM_W: i32 = 0o200; -pub const SHM_RDONLY: i32 = 0o10000; -pub const SHM_RND: i32 = 0o20000; -pub const SHM_REMAP: i32 = 0o40000; -pub const SHM_EXEC: i32 = 0o100000; - -pub const SHMMIN: u32 = 1; -pub const SHMMNI: u32 = 4096; -pub const SHMMAX: u32 = 4278190079; // (ULONG_MAX - (1UL << 24)) -pub const SHMALL: u32 = 4278190079; // (ULONG_MAX - (1UL << 24)); -pub const SHMSEG: u32 = SHMMNI; - -pub const SEM_VALUE_MAX: u32 = 2147483647; - -// //device info for char files -// #[derive(interface::SerdeSerialize, interface::SerdeDeserialize, PartialEq, Eq, Debug)] -// pub struct DevNo { -// pub major: u32, -// pub minor: u32, -// } -// pub const NULLDEVNO: DevNo = DevNo { major: 1, minor: 3 }; -// pub const ZERODEVNO: DevNo = DevNo { major: 1, minor: 5 }; -// pub const RANDOMDEVNO: DevNo = DevNo { major: 1, minor: 8 }; -// pub const URANDOMDEVNO: DevNo = DevNo { major: 1, minor: 9 }; - -// pub const FILEDATAPREFIX: &str = "linddata."; - -// pub fn is_reg(mode: u32) -> bool { -// (mode as i32 & S_FILETYPEFLAGS) == S_IFREG -// } - -// pub fn is_chr(mode: u32) -> bool { -// (mode as i32 & S_FILETYPEFLAGS) == S_IFCHR -// } - -// pub fn is_dir(mode: u32) -> bool { -// (mode as i32 & S_FILETYPEFLAGS) == S_IFDIR -// } - -// pub fn is_wronly(flags: i32) -> bool { -// (flags & O_RDWRFLAGS) == O_WRONLY -// } -// pub fn is_rdonly(flags: i32) -> bool { -// (flags & O_RDWRFLAGS) == O_RDONLY -// } - -// //the same as the glibc makedev -// pub fn makedev(dev: &DevNo) -> u64 { -// ((dev.major as u64 & 0x00000fff) << 8) -// | ((dev.major as u64 & 0xfffff000) << 32) -// | ((dev.minor as u64 & 0x000000ff) << 0) -// | ((dev.minor as u64 & 0xffffff00) << 12) -// } - -// //the same as the glibc major and minor functions -// pub fn major(devnum: u64) -> u32 { -// (((devnum & 0x00000000000fff00) >> 8) | ((devnum & 0xfffff00000000000) >> 32)) as u32 -// } -// pub fn minor(devnum: u64) -> u32 { -// (((devnum & 0x00000000000000ff) >> 0) | ((devnum & 0x00000ffffff00000) >> 12)) as u32 -// } - -// pub fn devtuple(devnum: u64) -> DevNo { -// DevNo { -// major: major(devnum), -// minor: minor(devnum), -// } -// } diff --git a/src/RawPOSIX/src/safeposix/syscalls/mod.rs b/src/RawPOSIX/src/safeposix/syscalls/mod.rs index 51b60b43b..efb27fb26 100644 --- a/src/RawPOSIX/src/safeposix/syscalls/mod.rs +++ b/src/RawPOSIX/src/safeposix/syscalls/mod.rs @@ -1,12 +1,6 @@ pub mod fs_calls; -pub mod fs_constants; pub mod net_calls; -pub mod net_constants; pub mod sys_calls; -pub mod sys_constants; pub use fs_calls::*; -pub use fs_constants::*; pub use net_calls::*; -pub use net_constants::*; pub use sys_calls::*; -pub use sys_constants::*; diff --git a/src/RawPOSIX/src/safeposix/syscalls/net_calls.rs b/src/RawPOSIX/src/safeposix/syscalls/net_calls.rs index 471b85b99..39ce957ce 100644 --- a/src/RawPOSIX/src/safeposix/syscalls/net_calls.rs +++ b/src/RawPOSIX/src/safeposix/syscalls/net_calls.rs @@ -1,9 +1,9 @@ #![allow(dead_code)] -use super::net_constants; +use crate::constants::net_constants; use crate::{interface::FdSet, safeposix::cage::*}; use crate::interface::*; use crate::interface; -use super::sys_constants; +use crate::constants::sys_constants; use crate::fdtables::{self, FDTableEntry}; diff --git a/src/RawPOSIX/src/safeposix/syscalls/net_constants.rs b/src/RawPOSIX/src/safeposix/syscalls/net_constants.rs deleted file mode 100644 index c600aeeba..000000000 --- a/src/RawPOSIX/src/safeposix/syscalls/net_constants.rs +++ /dev/null @@ -1,392 +0,0 @@ -// Network related constants -#![allow(dead_code)] -#![allow(non_upper_case_globals)] - -use crate::interface; - -//used for gethostname syscall -pub const DEFAULT_HOSTNAME: &str = "Lind"; -pub const BLOCK_TIME: interface::RustDuration = interface::RustDuration::from_micros(100); - -pub const UDSOCK_CAPACITY: usize = 212992; - -// Define constants using static or const -// Imported into net_calls file - -pub const SOCK_STREAM: i32 = 1; //stream socket -pub const SOCK_DGRAM: i32 = 2; //datagram socket -pub const SOCK_RAW: i32 = 3; //raw protocol interface -pub const SOCK_RDM: i32 = 4; //reliably delivered message -pub const SOCK_SEQPACKET: i32 = 5; //sequenced packet stream -pub const SOCK_CLOEXEC: i32 = 0o02000000; // Atomically set close-on-exec -pub const SOCK_NONBLOCK: i32 = 0o00004000; // Mark as non-blocking - -/* Supported address families. */ -pub const AF_UNSPEC: i32 = 0; -pub const AF_UNIX: i32 = 1; /* Unix domain sockets */ -pub const AF_LOCAL: i32 = 1; /* POSIX name for AF_UNIX */ -pub const AF_INET: i32 = 2; /* Internet IP Protocol */ -pub const AF_AX25: i32 = 3; /* Amateur Radio AX.25 */ -pub const AF_IPX: i32 = 4; /* Novell IPX */ -pub const AF_APPLETALK: i32 = 5; /* AppleTalk DDP */ -pub const AF_NETROM: i32 = 6; /* Amateur Radio NET/ROM */ -pub const AF_BRIDGE: i32 = 7; /* Multiprotocol bridge */ -pub const AF_ATMPVC: i32 = 8; /* ATM PVCs */ -pub const AF_X25: i32 = 9; /* Reserved for X.25 project */ -pub const AF_INET6: i32 = 10; /* IP version 6 */ -pub const AF_ROSE: i32 = 11; /* Amateur Radio X.25 PLP */ -pub const AF_DECnet: i32 = 12; /* Reserved for DECnet project */ -pub const AF_NETBEUI: i32 = 13; /* Reserved for 802.2LLC project*/ -pub const AF_SECURITY: i32 = 14; /* Security callback pseudo AF */ -pub const AF_KEY: i32 = 15; /* PF_KEY key management API */ -pub const AF_NETLINK: i32 = 16; -pub const AF_ROUTE: i32 = AF_NETLINK; /* Alias to emulate 4.4BSD */ -pub const AF_PACKET: i32 = 17; /* Packet family */ -pub const AF_ASH: i32 = 18; /* Ash */ -pub const AF_ECONET: i32 = 19; /* Acorn Econet */ -pub const AF_ATMSVC: i32 = 20; /* ATM SVCs */ -pub const AF_RDS: i32 = 21; /* RDS sockets */ -pub const AF_SNA: i32 = 22; /* Linux SNA Project (nutters!) */ -pub const AF_IRDA: i32 = 23; /* IRDA sockets */ -pub const AF_PPPOX: i32 = 24; /* PPPoX sockets */ -pub const AF_WANPIPE: i32 = 25; /* Wanpipe API Sockets */ -pub const AF_LLC: i32 = 26; /* Linux LLC */ -pub const AF_IB: i32 = 27; /* Native InfiniBand address */ -pub const AF_MPLS: i32 = 28; /* MPLS */ -pub const AF_CAN: i32 = 29; /* Controller Area Network */ -pub const AF_TIPC: i32 = 30; /* TIPC sockets */ -pub const AF_BLUETOOTH: i32 = 31; /* Bluetooth sockets */ -pub const AF_IUCV: i32 = 32; /* IUCV sockets */ -pub const AF_RXRPC: i32 = 33; /* RxRPC sockets */ -pub const AF_ISDN: i32 = 34; /* mISDN sockets */ -pub const AF_PHONET: i32 = 35; /* Phonet sockets */ -pub const AF_IEEE802154: i32 = 36; /* IEEE802154 sockets */ -pub const AF_CAIF: i32 = 37; /* CAIF sockets */ -pub const AF_ALG: i32 = 38; /* Algorithm sockets */ -pub const AF_NFC: i32 = 39; /* NFC sockets */ -pub const AF_VSOCK: i32 = 40; /* vSockets */ -pub const AF_KCM: i32 = 41; /* Kernel Connection Multiplexor*/ -pub const AF_QIPCRTR: i32 = 42; /* Qualcomm IPC Router */ -pub const AF_SMC: i32 = 43; /* smc sockets: reserve number for - * PF_SMC protocol family that - * reuses AF_INET address family - */ -pub const AF_XDP: i32 = 44; /* XDP sockets */ -pub const AF_MCTP: i32 = 45; /* Management component - * transport protocol - */ - -pub const AF_MAX: i32 = 46; /* For now.. */ - -/* Protocol families, same as address families. */ -pub const PF_UNSPEC: i32 = AF_UNSPEC; -pub const PF_UNIX: i32 = AF_UNIX; -pub const PF_LOCAL: i32 = AF_LOCAL; -pub const PF_INET: i32 = AF_INET; -pub const PF_AX25: i32 = AF_AX25; -pub const PF_IPX: i32 = AF_IPX; -pub const PF_APPLETALK: i32 = AF_APPLETALK; -pub const PF_NETROM: i32 = AF_NETROM; -pub const PF_BRIDGE: i32 = AF_BRIDGE; -pub const PF_ATMPVC: i32 = AF_ATMPVC; -pub const PF_X25: i32 = AF_X25; -pub const PF_INET6: i32 = AF_INET6; -pub const PF_ROSE: i32 = AF_ROSE; -pub const PF_DECnet: i32 = AF_DECnet; -pub const PF_NETBEUI: i32 = AF_NETBEUI; -pub const PF_SECURITY: i32 = AF_SECURITY; -pub const PF_KEY: i32 = AF_KEY; -pub const PF_NETLINK: i32 = AF_NETLINK; -pub const PF_ROUTE: i32 = AF_ROUTE; -pub const PF_PACKET: i32 = AF_PACKET; -pub const PF_ASH: i32 = AF_ASH; -pub const PF_ECONET: i32 = AF_ECONET; -pub const PF_ATMSVC: i32 = AF_ATMSVC; -pub const PF_RDS: i32 = AF_RDS; -pub const PF_SNA: i32 = AF_SNA; -pub const PF_IRDA: i32 = AF_IRDA; -pub const PF_PPPOX: i32 = AF_PPPOX; -pub const PF_WANPIPE: i32 = AF_WANPIPE; -pub const PF_LLC: i32 = AF_LLC; -pub const PF_IB: i32 = AF_IB; -pub const PF_MPLS: i32 = AF_MPLS; -pub const PF_CAN: i32 = AF_CAN; -pub const PF_TIPC: i32 = AF_TIPC; -pub const PF_BLUETOOTH: i32 = AF_BLUETOOTH; -pub const PF_IUCV: i32 = AF_IUCV; -pub const PF_RXRPC: i32 = AF_RXRPC; -pub const PF_ISDN: i32 = AF_ISDN; -pub const PF_PHONET: i32 = AF_PHONET; -pub const PF_IEEE802154: i32 = AF_IEEE802154; -pub const PF_CAIF: i32 = AF_CAIF; -pub const PF_ALG: i32 = AF_ALG; -pub const PF_NFC: i32 = AF_NFC; -pub const PF_VSOCK: i32 = AF_VSOCK; -pub const PF_KCM: i32 = AF_KCM; -pub const PF_QIPCRTR: i32 = AF_QIPCRTR; -pub const PF_SMC: i32 = AF_SMC; -pub const PF_XDP: i32 = AF_XDP; -pub const PF_MCTP: i32 = AF_MCTP; -pub const PF_MAX: i32 = AF_MAX; - -// protocols... - -pub const IPPROTO_IP: i32 = 0; // dummy for IP -pub const IPPROTO_ICMP: i32 = 1; // control message protocol -pub const IPPROTO_IGMP: i32 = 2; // group mgmt protocol -pub const IPPROTO_GGP: i32 = 3; // gateway^2 (deprecated) -pub const IPPROTO_IPV4: i32 = 4; // IPv4 encapsulation -pub const IPPROTO_IPIP: i32 = IPPROTO_IPV4; // for compatibility -pub const IPPROTO_TCP: i32 = 6; // tcp -pub const IPPROTO_ST: i32 = 7; // Stream protocol II -pub const IPPROTO_EGP: i32 = 8; // exterior gateway protocol -pub const IPPROTO_PIGP: i32 = 9; // private interior gateway -pub const IPPROTO_RCCMON: i32 = 10; // BBN RCC Monitoring -pub const IPPROTO_NVPII: i32 = 11; // network voice protocol -pub const IPPROTO_PUP: i32 = 12; // pup -pub const IPPROTO_ARGUS: i32 = 13; // Argus -pub const IPPROTO_EMCON: i32 = 14; // EMCON -pub const IPPROTO_XNET: i32 = 15; // Cross Net Debugger -pub const IPPROTO_CHAOS: i32 = 16; // Chaos -pub const IPPROTO_UDP: i32 = 17; // user datagram protocol -pub const IPPROTO_MUX: i32 = 18; // Multiplexing -pub const IPPROTO_MEAS: i32 = 19; // DCN Measurement Subsystems -pub const IPPROTO_HMP: i32 = 20; // Host Monitoring -pub const IPPROTO_PRM: i32 = 21; // Packet Radio Measurement -pub const IPPROTO_IDP: i32 = 22; // xns idp -pub const IPPROTO_TRUNK1: i32 = 23; // Trunk-1 -pub const IPPROTO_TRUNK2: i32 = 24; // Trunk-2 -pub const IPPROTO_LEAF1: i32 = 25; // Leaf-1 -pub const IPPROTO_LEAF2: i32 = 26; // Leaf-2 -pub const IPPROTO_RDP: i32 = 27; // Reliable Data -pub const IPPROTO_IRTP: i32 = 28; // Reliable Transaction -pub const IPPROTO_TP: i32 = 29; // tp-4 w/ class negotiation -pub const IPPROTO_BLT: i32 = 30; // Bulk Data Transfer -pub const IPPROTO_NSP: i32 = 31; // Network Services -pub const IPPROTO_INP: i32 = 32; // Merit Internodal -pub const IPPROTO_SEP: i32 = 33; // Sequential Exchange -pub const IPPROTO_3PC: i32 = 34; // Third Party Connect -pub const IPPROTO_IDPR: i32 = 35; // InterDomain Policy Routing -pub const IPPROTO_XTP: i32 = 36; // XTP -pub const IPPROTO_DDP: i32 = 37; // Datagram Delivery -pub const IPPROTO_CMTP: i32 = 38; // Control Message Transport -pub const IPPROTO_TPXX: i32 = 39; // TP++ Transport -pub const IPPROTO_IL: i32 = 40; // IL transport protocol -pub const IPPROTO_IPV6: i32 = 41; // IP6 header -pub const IPPROTO_SDRP: i32 = 42; // Source Demand Routing -pub const IPPROTO_ROUTING: i32 = 43; // IP6 routing header -pub const IPPROTO_FRAGMENT: i32 = 44; // IP6 fragmentation header -pub const IPPROTO_IDRP: i32 = 45; // InterDomain Routing -pub const IPPROTO_RSVP: i32 = 46; // resource reservation -pub const IPPROTO_GRE: i32 = 47; // General Routing Encap. -pub const IPPROTO_MHRP: i32 = 48; // Mobile Host Routing -pub const IPPROTO_BHA: i32 = 49; // BHA -pub const IPPROTO_ESP: i32 = 50; // IP6 Encap Sec. Payload -pub const IPPROTO_AH: i32 = 51; // IP6 Auth Header -pub const IPPROTO_INLSP: i32 = 52; // Integ. Net Layer Security -pub const IPPROTO_SWIPE: i32 = 53; // IP with encryption -pub const IPPROTO_NHRP: i32 = 54; // Next Hop Resolution - // 55-57: Unassigned -pub const IPPROTO_ICMPV6: i32 = 58; // ICMP6 -pub const IPPROTO_NONE: i32 = 59; // IP6 no next header -pub const IPPROTO_DSTOPTS: i32 = 60; // IP6 destination option -pub const IPPROTO_AHIP: i32 = 61; // any host internal protocol -pub const IPPROTO_CFTP: i32 = 62; // CFTP -pub const IPPROTO_HELLO: i32 = 63; // "hello" routing protocol -pub const IPPROTO_SATEXPAK: i32 = 64; // SATNET/Backroom EXPAK -pub const IPPROTO_KRYPTOLAN: i32 = 65; // Kryptolan -pub const IPPROTO_RVD: i32 = 66; // Remote Virtual Disk -pub const IPPROTO_IPPC: i32 = 67; // Pluribus Packet Core -pub const IPPROTO_ADFS: i32 = 68; // Any distributed FS -pub const IPPROTO_SATMON: i32 = 69; // Satnet Monitoring -pub const IPPROTO_VISA: i32 = 70; // VISA Protocol -pub const IPPROTO_IPCV: i32 = 71; // Packet Core Utility -pub const IPPROTO_CPNX: i32 = 72; // Comp. Prot. Net. Executive -pub const IPPROTO_CPHB: i32 = 73; // Comp. Prot. HeartBeat -pub const IPPROTO_WSN: i32 = 74; // Wang Span Network -pub const IPPROTO_PVP: i32 = 75; // Packet Video Protocol -pub const IPPROTO_BRSATMON: i32 = 76; // BackRoom SATNET Monitoring -pub const IPPROTO_ND: i32 = 77; // Sun net disk proto (temp.) -pub const IPPROTO_WBMON: i32 = 78; // WIDEBAND Monitoring -pub const IPPROTO_WBEXPAK: i32 = 79; // WIDEBAND EXPAK -pub const IPPROTO_EON: i32 = 80; // ISO cnlp -pub const IPPROTO_VMTP: i32 = 81; // VMTP -pub const IPPROTO_SVMTP: i32 = 82; // Secure VMTP -pub const IPPROTO_VINES: i32 = 83; // Banyon VINES -pub const IPPROTO_TTP: i32 = 84; // TTP -pub const IPPROTO_IGP: i32 = 85; // NSFNET-IGP -pub const IPPROTO_DGP: i32 = 86; // dissimilar gateway prot. -pub const IPPROTO_TCF: i32 = 87; // TCF -pub const IPPROTO_IGRP: i32 = 88; // Cisco/GXS IGRP -pub const IPPROTO_OSPFIGP: i32 = 89; // OSPFIGP -pub const IPPROTO_SRPC: i32 = 90; // Strite RPC protocol -pub const IPPROTO_LARP: i32 = 91; // Locus Address Resoloution -pub const IPPROTO_MTP: i32 = 92; // Multicast Transport -pub const IPPROTO_AX25: i32 = 93; // AX.25 Frames -pub const IPPROTO_IPEIP: i32 = 94; // IP encapsulated in IP -pub const IPPROTO_MICP: i32 = 95; // Mobile Int.ing control -pub const IPPROTO_SCCSP: i32 = 96; // Semaphore Comm. security -pub const IPPROTO_ETHERIP: i32 = 97; // Ethernet IP encapsulation -pub const IPPROTO_ENCAP: i32 = 98; // encapsulation header -pub const IPPROTO_APES: i32 = 99; // any private encr. scheme -pub const IPPROTO_GMTP: i32 = 100; // GMTP -pub const IPPROTO_PIM: i32 = 103; // Protocol Independent Mcast -pub const IPPROTO_IPCOMP: i32 = 108; // payload compression (IPComp) -pub const IPPROTO_PGM: i32 = 113; // PGM -pub const IPPROTO_SCTP: i32 = 132; // SCTP -pub const IPPROTO_DIVERT: i32 = 254; // divert pseudo-protocol -pub const IPPROTO_RAW: i32 = 255; // raw IP packet -pub const IPPROTO_MAX: i32 = 256; -// last return value of *_input(), meaning "all job for this pkt is done". -pub const IPPROTO_DONE: i32 = 257; - -pub const MSG_OOB: i32 = 1; -pub const MSG_PEEK: i32 = 2; -pub const MSG_DONTROUTE: i32 = 4; -pub const MSG_TRYHARD: i32 = 4; /* Synonym for MSG_DONTROUTE for DECnet */ -pub const MSG_CTRUNC: i32 = 8; -pub const MSG_PROBE: i32 = 0x10; /* Do not send. Only probe path f.e. for MTU */ -pub const MSG_TRUNC: i32 = 0x20; -pub const MSG_DONTWAIT: i32 = 0x40; /* Nonblocking io */ -pub const MSG_EOR: i32 = 0x80; /* End of record */ -pub const MSG_WAITALL: i32 = 0x100; /* Wait for a full request */ -pub const MSG_FIN: i32 = 0x200; -pub const MSG_SYN: i32 = 0x400; -pub const MSG_CONFIRM: i32 = 0x800; /* Confirm path validity */ -pub const MSG_RST: i32 = 0x1000; -pub const MSG_ERRQUEUE: i32 = 0x2000; /* Fetch message from error queue */ -pub const MSG_NOSIGNAL: i32 = 0x4000; /* Do not generate SIGPIPE */ -pub const MSG_MORE: i32 = 0x8000; /* Sender will send more */ -pub const MSG_WAITFORONE: i32 = 0x10000; /* recvmmsg(): block until 1+ packets avail */ -pub const MSG_SENDPAGE_NOPOLICY: i32 = 0x10000; /* sendpage() internal : do no apply policy */ -pub const MSG_SENDPAGE_NOTLAST: i32 = 0x20000; /* sendpage() internal : not the last page */ -pub const MSG_BATCH: i32 = 0x40000; /* sendmmsg(): more messages coming */ -pub const MSG_EOF: i32 = MSG_FIN; -pub const MSG_NO_SHARED_FRAGS: i32 = 0x80000; /* sendpage() internal : page frags are not shared */ -pub const MSG_SENDPAGE_DECRYPTED: i32 = 0x100000; /* sendpage() internal : page may carry - * plain text and require encryption - */ - -//shutdown -pub const SHUT_RD: i32 = 0; -pub const SHUT_WR: i32 = 1; -pub const SHUT_RDWR: i32 = 2; - -////////////////////// setsockopt / getsockopt... -pub const SOL_SOCKET: i32 = 1; - -pub const SO_DEBUG: i32 = 1; -pub const SO_REUSEADDR: i32 = 2; -pub const SO_TYPE: i32 = 3; -pub const SO_ERROR: i32 = 4; -pub const SO_DONTROUTE: i32 = 5; -pub const SO_BROADCAST: i32 = 6; -pub const SO_SNDBUF: i32 = 7; -pub const SO_RCVBUF: i32 = 8; -pub const SO_SNDBUFFORCE: i32 = 32; -pub const SO_RCVBUFFORCE: i32 = 33; -pub const SO_KEEPALIVE: i32 = 9; -pub const SO_OOBINLINE: i32 = 10; -pub const SO_NO_CHECK: i32 = 11; -pub const SO_PRIORITY: i32 = 12; -pub const SO_LINGER: i32 = 13; -pub const SO_BSDCOMPAT: i32 = 14; -pub const SO_REUSEPORT: i32 = 15; -pub const SO_PASSCRED: i32 = 16; -pub const SO_PEERCRED: i32 = 17; -pub const SO_RCVLOWAT: i32 = 18; -pub const SO_SNDLOWAT: i32 = 19; -pub const SO_RCVTIMEO_OLD: i32 = 20; -pub const SO_SNDTIMEO_OLD: i32 = 21; -pub const SO_PEERNAME: i32 = 28; -pub const SO_ACCEPTCONN: i32 = 30; - -// pub const SO_SECURITY_AUTHENTICATION: i32 = 22; -// pub const SO_SECURITY_ENCRYPTION_TRANSPORT: i32 = 23; -// pub const SO_SECURITY_ENCRYPTION_NETWORK: i32 = 24; - -// pub const SO_BINDTODEVICE: i32 = 25; - -// /* Socket filtering */ -// pub const SO_ATTACH_FILTER: i32 = 26; -// pub const SO_DETACH_FILTER: i32 = 27; - -// pub const SO_TIMESTAMP: i32 = 29; -// pub const SCM_TIMESTAMP: i32 = SO_TIMESTAMP; - -// pub const SO_PEERSEC: i32 = 31; -// pub const SO_PASSSEC: i32 = 34; -// pub const SO_TIMESTAMPNS: i32 = 35; -// pub const SCM_TIMESTAMPNS: i32 = SO_TIMESTAMPNS; - -// pub const SO_MARK: i32 = 36; - -// pub const SO_TIMESTAMPING: i32 = 37; -// pub const SCM_TIMESTAMPING: i32 = SO_TIMESTAMPING; - -// pub const SO_PROTOCOL: i32 = 38; -// pub const SO_DOMAIN: i32 = 39; - -// pub const SO_RXQ_OVFL: i32 = 40; - -// Use this to specify options on a socket. Use the protocol with setsockopt -// to specify something for all sockets with a protocol -pub const SOL_TCP: i32 = IPPROTO_TCP; -pub const SOL_UDP: i32 = IPPROTO_UDP; - -pub const TCP_NODELAY: i32 = 0x01; // don't delay send to coalesce packets -pub const TCP_MAXSEG: i32 = 0x02; // set maximum segment size -pub const TCP_NOPUSH: i32 = 0x04; // don't push last block of write -pub const TCP_NOOPT: i32 = 0x08; // don't use TCP options -pub const TCP_KEEPALIVE: i32 = 0x10; // idle time used when SO_KEEPALIVE is enabled -pub const TCP_CONNECTIONTIMEOUT: i32 = 0x20; // connection timeout -pub const PERSIST_TIMEOUT: i32 = 0x40; // time after which a connection in persist timeout - // will terminate. - // see draft-ananth-tcpm-persist-02.txt -pub const TCP_RXT_CONNDROPTIME: i32 = 0x80; // time after which tcp retransmissions will be - // stopped and the connection will be dropped -pub const TCP_RXT_FINDROP: i32 = 0x100; // When set, a connection is dropped after 3 FINs - -pub const MINSOCKOBJID: i32 = 0; -pub const MAXSOCKOBJID: i32 = 1024; - -//POLL CONSTANTS -pub const POLLIN: i16 = 0o1; // There is data to read. -pub const POLLPRI: i16 = 0o2; //There is urgent data to read. -pub const POLLOUT: i16 = 0o4; // Writing now will not block. -pub const POLLERR: i16 = 0o10; // Error condition. -pub const POLLHUP: i16 = 0o20; // Hung up. -pub const POLLNVAL: i16 = 0o40; // Invalid polling request. - -//EPOLL CONSTANTS -pub const EPOLLIN: i32 = 0x001; -pub const EPOLLPRI: i32 = 0x002; -pub const EPOLLOUT: i32 = 0x004; -pub const EPOLLRDNORM: i32 = 0x040; -pub const EPOLLRDBAND: i32 = 0x080; -pub const EPOLLWRNORM: i32 = 0x100; -pub const EPOLLWRBAND: i32 = 0x200; -pub const EPOLLMSG: i32 = 0x400; -pub const EPOLLERR: i32 = 0x008; -pub const EPOLLHUP: i32 = 0x010; -pub const EPOLLRDHUP: i32 = 0x2000; -pub const EPOLLWAKEUP: i32 = 1 << 29; -pub const EPOLLONESHOT: i32 = 1 << 30; -pub const EPOLLET: i32 = 1 << 31; - -pub const EPOLL_CTL_ADD: i32 = 1; -pub const EPOLL_CTL_DEL: i32 = 2; -pub const EPOLL_CTL_MOD: i32 = 3; - -pub const FD_SET_MAX_FD: i32 = 1024; - -//for internal use -#[derive(Debug, PartialEq, Eq, Clone)] -pub enum ConnState { - NOTCONNECTED, - CONNECTED, - CONNRDONLY, - CONNWRONLY, - LISTEN, - INPROGRESS, -} diff --git a/src/RawPOSIX/src/safeposix/syscalls/sys_calls.rs b/src/RawPOSIX/src/safeposix/syscalls/sys_calls.rs index f2659924a..c45e02adc 100644 --- a/src/RawPOSIX/src/safeposix/syscalls/sys_calls.rs +++ b/src/RawPOSIX/src/safeposix/syscalls/sys_calls.rs @@ -1,10 +1,19 @@ #![allow(dead_code)] // System related system calls -use super::fs_constants::*; -use super::net_constants::*; -use super::sys_constants; -use super::sys_constants::*; +use crate::constants::{ + DEFAULT_UID, DEFAULT_GID, + SIG_BLOCK, SIG_UNBLOCK, SIG_SETMASK, + SIGNAL_MAX, + ITIMER_REAL, + RLIMIT_NOFILE, RLIMIT_STACK, + NOFILE_CUR, NOFILE_MAX, + STACK_CUR, STACK_MAX, + SHMMIN, SHMMAX, + SHM_RDONLY, SHM_DEST, + SEM_VALUE_MAX, +}; + use crate::interface; use crate::safeposix::cage; use crate::safeposix::cage::*; @@ -518,7 +527,7 @@ impl Cage { if let Some(some_set) = set { let curr_sigset = sigset.load(interface::RustAtomicOrdering::Relaxed); res = match how { - cage::SIG_BLOCK => { + SIG_BLOCK => { // Block signals in set sigset.store( curr_sigset | *some_set, @@ -526,7 +535,7 @@ impl Cage { ); 0 } - cage::SIG_UNBLOCK => { + SIG_UNBLOCK => { // Unblock signals in set let newset = curr_sigset & !*some_set; let pendingsignals = curr_sigset & some_set; @@ -534,7 +543,7 @@ impl Cage { self.send_pending_signals(pendingsignals, pthreadid); 0 } - cage::SIG_SETMASK => { + SIG_SETMASK => { // Set sigset to set sigset.store(*some_set, interface::RustAtomicOrdering::Relaxed); 0 @@ -552,7 +561,7 @@ impl Cage { old_value: Option<&mut interface::ITimerVal>, ) -> i32 { match which { - sys_constants::ITIMER_REAL => { + ITIMER_REAL => { if let Some(some_old_value) = old_value { let (curr_duration, next_duration) = self.interval_timer.get_itimer(); some_old_value.it_value.tv_sec = curr_duration.as_secs() as i64; @@ -582,11 +591,11 @@ impl Cage { pub fn getrlimit(&self, res_type: u64, rlimit: &mut interface::Rlimit) -> i32 { match res_type { - sys_constants::RLIMIT_NOFILE => { + RLIMIT_NOFILE => { rlimit.rlim_cur = NOFILE_CUR; rlimit.rlim_max = NOFILE_MAX; } - sys_constants::RLIMIT_STACK => { + RLIMIT_STACK => { rlimit.rlim_cur = STACK_CUR; rlimit.rlim_max = STACK_MAX; } @@ -597,7 +606,7 @@ impl Cage { pub fn setrlimit(&self, res_type: u64, _limit_value: u64) -> i32 { match res_type { - sys_constants::RLIMIT_NOFILE => { + RLIMIT_NOFILE => { if NOFILE_CUR > NOFILE_MAX { -1 } else { diff --git a/src/RawPOSIX/src/safeposix/syscalls/sys_constants.rs b/src/RawPOSIX/src/safeposix/syscalls/sys_constants.rs deleted file mode 100644 index 89feb7158..000000000 --- a/src/RawPOSIX/src/safeposix/syscalls/sys_constants.rs +++ /dev/null @@ -1,77 +0,0 @@ -// System related constants -#![allow(dead_code)] -#![allow(unused_variables)] - -use crate::interface; - -// Define constants using static or const -// Imported into fs_calls file - -//GID AND UID DEFAULT VALUES - -pub const DEFAULT_UID: u32 = 1000; -pub const DEFAULT_GID: u32 = 1000; - -// RESOURCE LIMITS - -pub const SIGNAL_MAX: i32 = 64; - -pub const NOFILE_CUR: u64 = 1024; -pub const NOFILE_MAX: u64 = 4 * 1024; - -pub const STACK_CUR: u64 = 8192 * 1024; -pub const STACK_MAX: u64 = 1 << 32; - -pub const RLIMIT_STACK: u64 = 0; -pub const RLIMIT_NOFILE: u64 = 1; - -// Constants for exit_syscall status - -pub const EXIT_SUCCESS: i32 = 0; -pub const EXIT_FAILURE: i32 = 1; - -// Signal Table (x86/ARM) -// Based on https://man7.org/linux/man-pages/man7/signal.7.html -pub const SIGHUP: i32 = 1; -pub const SIGINT: i32 = 2; -pub const SIGQUIT: i32 = 3; -pub const SIGILL: i32 = 4; -pub const SIGTRAP: i32 = 5; -pub const SIGABRT: i32 = 6; -pub const SIGIOT: i32 = 6; -pub const SIGBUS: i32 = 7; -// pub const SIGEMT: i32 -pub const SIGFPE: i32 = 8; -pub const SIGKILL: i32 = 9; -pub const SIGUSR1: i32 = 10; -pub const SIGSEGV: i32 = 11; -pub const SIGUSR2: i32 = 12; -pub const SIGPIPE: i32 = 13; -pub const SIGALRM: i32 = 14; -pub const SIGTERM: i32 = 15; -pub const SIGSTKFLT: i32 = 16; -pub const SIGCHLD: i32 = 17; -// pub const SIGCLD: i32 -pub const SIGCONT: i32 = 18; -pub const SIGSTOP: i32 = 19; -pub const SIGTSTP: i32 = 20; -pub const SIGTTIN: i32 = 21; -pub const SIGTTOU: i32 = 22; -pub const SIGURG: i32 = 23; -pub const SIGXCPU: i32 = 24; -pub const SIGXFSZ: i32 = 25; -pub const SIGVTALRM: i32 = 26; -pub const SIGPROF: i32 = 27; -pub const SIGWINCH: i32 = 28; -pub const SIGIO: i32 = 29; -pub const SIGPOLL: i32 = 29; -pub const SIGPWR: i32 = 30; -// pub const SIGINFO: i32 -// pub const SIGLOST: i32 -pub const SIGSYS: i32 = 31; -pub const SIGUNUSED: i32 = 31; - -pub const SIG_BLOCK: i32 = 0; -pub const SIG_UNBLOCK: i32 = 1; -pub const SIG_SETMASK: i32 = 2; -pub const ITIMER_REAL: i32 = 0; diff --git a/src/RawPOSIX/src/safeposix/vmmap.rs b/src/RawPOSIX/src/safeposix/vmmap.rs index 08ae0d1d3..7e2efacee 100644 --- a/src/RawPOSIX/src/safeposix/vmmap.rs +++ b/src/RawPOSIX/src/safeposix/vmmap.rs @@ -1,4 +1,8 @@ -use super::vmmap_constants::*; +use crate::constants::{ + PROT_NONE, PROT_READ, PROT_WRITE, PROT_EXEC, + MAP_SHARED, MAP_PRIVATE, MAP_FIXED, MAP_ANONYMOUS, + MAP_FAILED +}; use std::io; use nodit::NoditMap; use nodit::{interval::ie, Interval}; @@ -67,7 +71,7 @@ impl VmmapEntry { // this is effectively whatever mode the file was opened with // we need this because we shouldnt be able to change filed backed mappings // to have protections exceeding that of the file - fn get_max_prot(&self, cage_id: u64, virtual_fd: u64 -> i32 { + fn get_max_prot(&self, cage_id: u64, virtual_fd: u64) -> i32 { let wrappedvfd = fdtables::translate_virtual_fd(cage_id, virtual_fd as u64); if wrappedvfd.is_err() { diff --git a/src/RawPOSIX/src/safeposix/vmmap_constants.rs b/src/RawPOSIX/src/safeposix/vmmap_constants.rs deleted file mode 100644 index 373dba649..000000000 --- a/src/RawPOSIX/src/safeposix/vmmap_constants.rs +++ /dev/null @@ -1,32 +0,0 @@ -pub const PROT_READ: i32 = 0x1; /* Page can be read. */ -pub const PROT_WRITE: i32 = 0x2; /* Page can be written. */ -pub const PROT_EXEC: i32 = 0x4; /* Page can be executed. */ -pub const PROT_NONE: i32 = 0x0; /* Page can not be accessed. */ - -pub const PROT_MASK: u32 = 0x7; - -pub const MAP_SHARED: u32 = 0x01; /* Share changes. */ -pub const MAP_PRIVATE: u32 = 0x02; /* Changes are private. */ - -/* this must be a multiple of the system page size */ -pub const PAGESHIFT: u32 = 12; -pub const PAGESIZE: u32 = 1 << PAGESHIFT; - -pub const MAP_PAGESHIFT: u32 = 16; -pub const MAP_PAGESIZE: u32 = 1 << MAP_PAGESHIFT; - -pub const MAP_SHARING_MASK: u32 = 0x03; - -pub const MAP_FIXED: u32 = 0x10; /* Interpret addr exactly. */ -pub const MAP_ANON: u32 = 0x20; /* Don't use a file. */ -pub const MAP_ANONYMOUS: u32 = MAP_ANON; /* Linux alias. */ - -pub const MAP_FAILED: *mut std::ffi::c_void = (-1isize) as *mut std::ffi::c_void; - -pub const MREMAP_MAYMOVE: u32 = 0x01; -pub const MREMAP_FIXED: u32 = 0x02; - -pub const O_ACCMODE: i32 = 0003; -pub const O_RDONLY: i32 = 00; -pub const O_WRONLY: i32 = 01; -pub const O_RDWR: i32 = 02; diff --git a/src/RawPOSIX/src/tests/sys_tests.rs b/src/RawPOSIX/src/tests/sys_tests.rs index 5d3bbb1d9..22260b38c 100644 --- a/src/RawPOSIX/src/tests/sys_tests.rs +++ b/src/RawPOSIX/src/tests/sys_tests.rs @@ -6,6 +6,7 @@ pub mod sys_tests { use super::super::*; use crate::interface; + use crate::constants::DEFAULT_UID; // use crate::safeposix::cage::{FileDescriptor::*, *}; use crate::safeposix::{cage::*, dispatcher::*, filesystem}; From 38d8a322f18261ac3d99c8af22b3fbcbe957ffdf Mon Sep 17 00:00:00 2001 From: Chinmay Shringi Date: Wed, 4 Dec 2024 12:31:10 -0500 Subject: [PATCH 06/66] feat: update from raw-posix --- src/RawPOSIX/src/interface/mem.rs | 228 ++++++ src/RawPOSIX/src/interface/mod.rs | 2 + src/RawPOSIX/src/safeposix/dispatcher.rs | 58 +- .../src/safeposix/syscalls/fs_calls.rs | 33 +- .../src/safeposix/syscalls/sys_calls.rs | 4 + src/RawPOSIX/src/safeposix/vmmap.rs | 52 +- src/RawPOSIX/src/tests/vmmap_test.rs | 699 ++++++++++++++++++ 7 files changed, 1051 insertions(+), 25 deletions(-) create mode 100644 src/RawPOSIX/src/interface/mem.rs create mode 100644 src/RawPOSIX/src/tests/vmmap_test.rs diff --git a/src/RawPOSIX/src/interface/mem.rs b/src/RawPOSIX/src/interface/mem.rs new file mode 100644 index 000000000..df0fc40f8 --- /dev/null +++ b/src/RawPOSIX/src/interface/mem.rs @@ -0,0 +1,228 @@ +use libc::{MAP_ANONYMOUS, MAP_FIXED, MAP_PRIVATE, PROT_EXEC}; + +use crate::safeposix::cage::{MemoryBackingType, Vmmap, VmmapOps, MAP_SHARED, PAGESHIFT, PAGESIZE, PROT_NONE, PROT_READ, PROT_WRITE}; + +use crate::interface::{cagetable_getref, syscall_error, Errno}; + +// heap is placed at the very top of the memory +pub const HEAP_ENTRY_INDEX: u32 = 0; + +pub fn round_up_page(length: u64) -> u64 { + if length % PAGESIZE as u64 == 0 { + length + } else { + ((length / PAGESIZE as u64) + 1) * PAGESIZE as u64 + } +} + +pub fn fork_vmmap(parent_vmmap: &Vmmap, child_vmmap: &Vmmap) { + let parent_base = parent_vmmap.base_address.unwrap(); + let child_base = child_vmmap.base_address.unwrap(); + + // iterate through each vmmap entry + for (_interval, entry) in parent_vmmap.entries.iter() { + // if the entry has PROT_NONE, that means the entry is currently not used + if entry.prot == PROT_NONE { continue; } + // translate page number to user address + let addr_st = (entry.page_num << PAGESHIFT) as i32; + let addr_len = (entry.npages << PAGESHIFT) as usize; + + // translate user address to system address + let parent_st = parent_vmmap.user_to_sys(addr_st); + let child_st = child_vmmap.user_to_sys(addr_st); + if entry.flags & (MAP_SHARED as i32) > 0 { + // for shared memory, we are using mremap to fork shared memory + // See "man 2 mremap" for description of what MREMAP_MAYMOVE does with old_size=0 + // when old_address points to a shared mapping + let result = unsafe { libc::mremap(parent_st as *mut libc::c_void, 0, addr_len, libc::MREMAP_MAYMOVE | libc::MREMAP_FIXED, child_st as *mut libc::c_void) }; + } else { + unsafe { + // temporarily enable write on child's memory region to write parent data + libc::mprotect(child_st as *mut libc::c_void, addr_len, PROT_READ | PROT_WRITE); + + // write parent data + // TODO: replace copy_nonoverlapping with writev for potential performance boost + std::ptr::copy_nonoverlapping(parent_st as *const u8, child_st as *mut u8, addr_len); + + // revert child's memory region prot + libc::mprotect(child_st as *mut libc::c_void, addr_len, entry.prot) + }; + } + } +} + +pub fn munmap_handler(cageid: u64, addr: *mut u8, len: usize) -> i32 { + let cage = cagetable_getref(cageid); + + // check if the provided address is multiple of pages + let rounded_addr = round_up_page(addr as u64) as usize; + if rounded_addr != addr as usize { + return syscall_error(Errno::EINVAL, "mmap", "address it not aligned"); + } + + let vmmap = cage.vmmap.read(); + let sysaddr = vmmap.user_to_sys(rounded_addr as i32); + drop(vmmap); + + let rounded_length = round_up_page(len as u64) as usize; + + // we are replacing munmap with mmap because we do not want to really deallocate the memory region + // we just want to set the prot of the memory region back to PROT_NONE + let result = cage.mmap_syscall(sysaddr as *mut u8, rounded_length, PROT_NONE, (MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED) as i32, -1, 0); + if result != sysaddr { + panic!("MAP_FIXED not fixed"); + } + + let mut vmmap = cage.vmmap.write(); + + vmmap.remove_entry(rounded_addr as u32 >> PAGESHIFT, len as u32 >> PAGESHIFT); + + 0 +} + +pub fn mmap_handler(cageid: u64, addr: *mut u8, len: usize, mut prot: i32, mut flags: i32, mut fildes: i32, off: i64) -> i32 { + let cage = cagetable_getref(cageid); + + // only these four flags are allowed + let allowed_flags = (MAP_FIXED as i32 | MAP_SHARED as i32 | MAP_PRIVATE as i32 | MAP_ANONYMOUS as i32); + if flags & !allowed_flags > 0 { + // truncate flag to remove flags that are not allowed + flags &= allowed_flags; + } + + if prot & PROT_EXEC > 0 { + return syscall_error(Errno::EINVAL, "mmap", "PROT_EXEC is not allowed"); + } + + // check if the provided address is multiple of pages + let rounded_addr = round_up_page(addr as u64); + if rounded_addr != addr as u64 { + return syscall_error(Errno::EINVAL, "mmap", "address it not aligned"); + } + + // offset should be non-negative and multiple of pages + if off < 0 { + return syscall_error(Errno::EINVAL, "mmap", "offset cannot be negative"); + } + let rounded_off = round_up_page(off as u64); + if rounded_off != off as u64 { + return syscall_error(Errno::EINVAL, "mmap", "offset it not aligned"); + } + + // round up length to be multiple of pages + let rounded_length = round_up_page(len as u64); + + let mut useraddr = addr as i32; + // if MAP_FIXED is not set, then we need to find an address for the user + if flags & MAP_FIXED as i32 == 0 { + let mut vmmap = cage.vmmap.write(); + let result; + + // pick an address of appropriate size, anywhere + if addr as usize == 0 { + result = vmmap.find_map_space(rounded_length as u32 >> PAGESHIFT, 1); + } else { + // use address user provided as hint to find address + result = vmmap.find_map_space_with_hint(rounded_length as u32 >> PAGESHIFT, 1, addr as u32); + } + + // did not find desired memory region + if result.is_none() { + return syscall_error(Errno::ENOMEM, "mmap", "no memory"); + } + + let space = result.unwrap(); + useraddr = (space.start() << PAGESHIFT) as i32; + } + + // TODO: validate useraddr (like checking whether within the program break) + + flags |= MAP_FIXED as i32; + + // either MAP_PRIVATE or MAP_SHARED should be set, but not both + if (flags & MAP_PRIVATE as i32 == 0) == (flags & MAP_SHARED as i32 == 0) { + return syscall_error(Errno::EINVAL, "mmap", "invalid flags"); + } + + let vmmap = cage.vmmap.read(); + + let sysaddr = vmmap.user_to_sys(useraddr); + + drop(vmmap); + + if rounded_length > 0 { + if flags & MAP_ANONYMOUS as i32 > 0 { + fildes = -1; + } + + let result = cage.mmap_syscall(sysaddr as *mut u8, rounded_length as usize, prot, flags, fildes, off); + + let vmmap = cage.vmmap.read(); + let result = vmmap.sys_to_user(result); + drop(vmmap); + + if result >= 0 { + if result != useraddr { + panic!("MAP_FIXED not fixed"); + } + + let mut vmmap = cage.vmmap.write(); + let backing = { + MemoryBackingType::Anonymous + // TODO: should return backing type accordingly + // if flags & MAP_ANONYMOUS > 0 { + // MemoryBackingType::Anonymous + // } else if flags & MAP_SHARED > 0 { + + // } + }; + vmmap.add_entry_with_overwrite((useraddr >> PAGESHIFT) as u32, (rounded_length >> PAGESHIFT) as u32, prot, 0, flags, backing, off, 0, cageid); + } + } + + useraddr +} + +pub fn sbrk_handler(cageid: u64, brk: u32) -> i32 { + let cage = cagetable_getref(cageid); + + let mut vmmap = cage.vmmap.write(); + let heap = vmmap.find_page(HEAP_ENTRY_INDEX).unwrap().clone(); + + if brk == 0 { + return (PAGESIZE * heap.npages) as i32; + } + + let brk_page = ((brk + 65536 - 1) / 65536) * 16; + + let heap_size = heap.npages; + vmmap.add_entry_with_overwrite(0, heap_size + brk_page, heap.prot, heap.maxprot, heap.flags, heap.backing, heap.file_offset, heap.file_size, heap.cage_id); + + let usr_heap_base = (heap_size * PAGESIZE) as i32; + let sys_heap_base = vmmap.user_to_sys(usr_heap_base)as *mut u8; + + drop(vmmap); + + // TODO: Currently we are not calling mmap to change prot here + // since this is handled within wasmtime. This will be changed + // later + // let ret = cage.mmap_syscall( + // sys_heap_base, + // (brk_page * PAGESIZE) as usize, + // heap.prot, + // heap.flags | MAP_FIXED, + // -1, + // 0 + // ); + // + // unsafe { + // let val = *sys_heap_base.add(65); + // println!("val: {}", val); + // } + // + // if ret < 0 { + // panic!("sbrk mmap failed"); + // } + + (PAGESIZE * heap.npages) as i32 +} diff --git a/src/RawPOSIX/src/interface/mod.rs b/src/RawPOSIX/src/interface/mod.rs index e8c7353b0..5a5399c6f 100644 --- a/src/RawPOSIX/src/interface/mod.rs +++ b/src/RawPOSIX/src/interface/mod.rs @@ -3,6 +3,7 @@ pub mod errnos; mod file; mod misc; mod timer; +mod mem; pub mod types; pub use comm::*; pub use errnos::*; @@ -10,3 +11,4 @@ pub use file::*; pub use misc::*; pub use timer::*; pub use types::*; +pub use mem::*; diff --git a/src/RawPOSIX/src/safeposix/dispatcher.rs b/src/RawPOSIX/src/safeposix/dispatcher.rs index 427411bbf..751fb616d 100644 --- a/src/RawPOSIX/src/safeposix/dispatcher.rs +++ b/src/RawPOSIX/src/safeposix/dispatcher.rs @@ -116,6 +116,8 @@ const WRITEV_SYSCALL: i32 = 170; const CLONE_SYSCALL: i32 = 171; const WAIT_SYSCALL: i32 = 172; const WAITPID_SYSCALL: i32 = 173; +const BRK_SYSCALL: i32 = 175; +const SBRK_SYSCALL: i32 = 176; const NANOSLEEP_TIME64_SYSCALL : i32 = 181; @@ -219,23 +221,21 @@ pub fn lind_syscall_api( } MUNMAP_SYSCALL => { - let addr = (start_address + arg1) as *mut u8; + let addr = arg1 as *mut u8; let len = arg2 as usize; - - interface::cagetable_getref(cageid) - .munmap_syscall(addr, len) + + interface::munmap_handler(cageid, addr, len) } MMAP_SYSCALL => { - let addr = (start_address + arg1) as *mut u8; + let addr = arg1 as *mut u8; let len = arg2 as usize; - let prot = arg3 as i32; - let flags = arg4 as i32; - let fildes = arg5 as i32; + let mut prot = arg3 as i32; + let mut flags = arg4 as i32; + let mut fildes = arg5 as i32; let off = arg6 as i64; - - interface::cagetable_getref(cageid) - .mmap_syscall(addr, len, prot, flags, fildes, off) + + interface::mmap_handler(cageid, addr, len, prot, flags, fildes, off) } PREAD_SYSCALL => { @@ -1054,11 +1054,45 @@ pub fn lind_syscall_api( .waitpid_syscall(pid, &mut status, options) } + + SBRK_SYSCALL => { + let brk = arg1 as u32; + + interface::sbrk_handler(cageid, brk) + } + _ => -1, // Return -1 for unknown syscalls }; ret } +// initilize the vmmap, invoked by wasmtime +pub fn lind_cage_vmmap_init(cageid: u64) { + let cage = interface::cagetable_getref(cageid); + let mut vmmap = cage.vmmap.write(); + vmmap.add_entry(VmmapEntry::new(0, 0x30, PROT_WRITE | PROT_READ, 0 /* not sure about this field */, (MAP_PRIVATE | MAP_ANONYMOUS) as i32, false, 0, 0, cageid, MemoryBackingType::Anonymous)); + // BUG: currently need to insert an entry at the end to indicate the end of memory space. This should be fixed soon so that + // no dummy entries are required to be inserted + vmmap.add_entry(VmmapEntry::new(1 << 18, 1, PROT_NONE, 0 /* not sure about this field */, (MAP_PRIVATE | MAP_ANONYMOUS) as i32, false, 0, 0, cageid, MemoryBackingType::Anonymous)); +} + +// set the wasm linear memory base address to vmmap +pub fn set_base_address(cageid: u64, base_address: i64) { + let cage = interface::cagetable_getref(cageid); + let mut vmmap = cage.vmmap.write(); + vmmap.set_base_address(base_address); +} + +// clone the cage memory. Invoked by wasmtime after cage is forked +pub fn fork_vmmap_helper(parent_cageid: u64, child_cageid: u64) { + let parent_cage = interface::cagetable_getref(parent_cageid); + let child_cage = interface::cagetable_getref(child_cageid); + let parent_vmmap = parent_cage.vmmap.read(); + let child_vmmap = child_cage.vmmap.read(); + + interface::fork_vmmap(&parent_vmmap, &child_vmmap); +} + #[no_mangle] pub fn lindcancelinit(cageid: u64) { let cage = interface::cagetable_getref(cageid); @@ -1146,6 +1180,7 @@ pub fn lindrustinit(verbosity: isize) { pendingsigset: interface::RustHashMap::new(), main_threadid: interface::RustAtomicU64::new(0), interval_timer: interface::IntervalTimer::new(0), + vmmap: interface::RustLock::new(Vmmap::new()) // Initialize empty virtual memory map for new process zombies: interface::RustLock::new(vec![]), child_num: interface::RustAtomicU64::new(0), }; @@ -1187,6 +1222,7 @@ pub fn lindrustinit(verbosity: isize) { pendingsigset: interface::RustHashMap::new(), main_threadid: interface::RustAtomicU64::new(0), interval_timer: interface::IntervalTimer::new(1), + vmmap: interface::RustLock::new(Vmmap::new()) // Initialize empty virtual memory map for new process zombies: interface::RustLock::new(vec![]), child_num: interface::RustAtomicU64::new(0), }; diff --git a/src/RawPOSIX/src/safeposix/syscalls/fs_calls.rs b/src/RawPOSIX/src/safeposix/syscalls/fs_calls.rs index 675e51f24..ddf905a8c 100644 --- a/src/RawPOSIX/src/safeposix/syscalls/fs_calls.rs +++ b/src/RawPOSIX/src/safeposix/syscalls/fs_calls.rs @@ -40,7 +40,14 @@ use std::ptr; use std::mem; use crate::fdtables; - +use crate::safeposix::cage::Cage; +use libc::{ + PROT_READ, PROT_WRITE, // Memory protection flags + O_RDONLY, O_WRONLY, O_RDWR, O_CREAT, O_TRUNC, // File open flags + MAP_SHARED, MAP_PRIVATE, // Memory mapping flags + SEEK_SET, SEEK_CUR, SEEK_END, // Seek constants + S_IRWXU, S_IRWXG, S_IRWXO, // Permission flags (user, group, others) +}; static LIND_ROOT: &str = "/home/lind/lind_project/src/safeposix-rust/tmp"; const FDKIND_KERNEL: u32 = 0; @@ -782,19 +789,24 @@ impl Cage { prot: i32, flags: i32, virtual_fd: i32, - off: i64, - ) -> i32 { + off: i64 + ) -> i64 { if virtual_fd != -1 { match fdtables::translate_virtual_fd(self.cageid, virtual_fd as u64) { Ok(kernel_fd) => { let ret = unsafe { - ((libc::mmap(addr as *mut c_void, len, prot, flags, kernel_fd.underfd as i32, off) as i64) - & 0xffffffff) as i32 + (libc::mmap(addr as *mut c_void, len, prot, flags, kernel_fd.underfd as i32, off) as i64) }; - return ret; + + // Check if mmap failed and return the appropriate error if so + if ret == -1 { + return syscall_error(Errno::EINVAL, "mmap", "mmap failed with invalid flags") as i64; + } + + ret }, Err(_e) => { - return syscall_error(Errno::EBADF, "mmap", "Bad File Descriptor"); + return syscall_error(Errno::EBADF, "mmap", "Bad File Descriptor") as i64; } } } else { @@ -804,9 +816,10 @@ impl Cage { }; // Check if mmap failed and return the appropriate error if so if ret == -1 { - return syscall_error(Errno::EINVAL, "mmap", "mmap failed with invalid flags"); + return syscall_error(Errno::EINVAL, "mmap", "mmap failed with invalid flags") as i64; } - return (ret & 0xffffffff) as i32; + + ret } } @@ -1194,7 +1207,7 @@ impl Cage { if 0 != (shmflg & SHM_RDONLY) { prot = PROT_READ; } else { - prot = PROT_READ | PROT_WRITE; + prot = libc::PROT_READ | libc::PROT_WRITE; } let mut rev_shm = self.rev_shm.lock(); rev_shm.push((shmaddr as u32, shmid)); diff --git a/src/RawPOSIX/src/safeposix/syscalls/sys_calls.rs b/src/RawPOSIX/src/safeposix/syscalls/sys_calls.rs index c45e02adc..19e53185c 100644 --- a/src/RawPOSIX/src/safeposix/syscalls/sys_calls.rs +++ b/src/RawPOSIX/src/safeposix/syscalls/sys_calls.rs @@ -149,6 +149,8 @@ impl Cage { for pair in semtable.iter() { new_semtable.insert((*pair.key()).clone(), pair.value().clone()); } + let parent_vmmap = self.vmmap.read(); + let new_vmmap = parent_vmmap.clone(); let cageobj = Cage { cageid: child_cageid, @@ -178,6 +180,7 @@ impl Cage { pendingsigset: interface::RustHashMap::new(), main_threadid: interface::RustAtomicU64::new(0), interval_timer: interface::IntervalTimer::new(child_cageid), + vmmap: interface::RustLock::new(Vmmap::new()) // Initialize empty virtual memory map for new process zombies: interface::RustLock::new(vec![]), child_num: interface::RustAtomicU64::new(0), }; @@ -260,6 +263,7 @@ impl Cage { pendingsigset: interface::RustHashMap::new(), main_threadid: interface::RustAtomicU64::new(0), interval_timer: self.interval_timer.clone_with_new_cageid(child_cageid), + vmmap: interface::RustLock::new(Vmmap::new()) // Fresh clean vmmap // when a process exec-ed, its child relationship should be perserved zombies: interface::RustLock::new(cloned_zombies), child_num: interface::RustAtomicU64::new(child_num), diff --git a/src/RawPOSIX/src/safeposix/vmmap.rs b/src/RawPOSIX/src/safeposix/vmmap.rs index 7e2efacee..368c2880a 100644 --- a/src/RawPOSIX/src/safeposix/vmmap.rs +++ b/src/RawPOSIX/src/safeposix/vmmap.rs @@ -80,12 +80,12 @@ impl VmmapEntry { let vfd = wrappedvfd.unwrap(); // Declare statbuf by ourselves - let mut libc_statbuf: stat = unsafe { std::mem::zeroed() }; + let mut libc_statbuf: libc::stat = unsafe { std::mem::zeroed() }; let libcret = unsafe { libc::fstat(vfd.underfd as i32, &mut libc_statbuf) }; - libc_statbuf.mode as i32 + libc_statbuf.st_mode as i32 } } @@ -127,12 +127,17 @@ pub trait VmmapOps { ) -> Result<(), io::Error>; // Method to change protection of a memory region + // Modifies protection for existing pages in the region + // Should be able to handle splitting of existing pages when necessary + // Should maintain mapping consistency while changing protections fn change_prot(&mut self, page_num: u32, npages: u32, new_prot: i32); // Method to remove an entry from the memory map fn remove_entry(&mut self, page_num: u32, npages: u32) -> Result<(), io::Error>; - // Method to check if a mapping exists + // Method to check if requested pages exist with proper permissions + // NaCl code enforces PROT_READ when any protection exists + // Returns end page number if mapping is found and has proper permissions fn check_existing_mapping(&self, page_num: u32, npages: u32, prot: i32) -> bool; // Method to check address mapping @@ -172,12 +177,16 @@ pub trait VmmapOps { ) -> impl DoubleEndedIterator, &mut VmmapEntry)>; // Method to find space in the memory map + // Searches for a contiguous region of at least 'n' free pages + // Returns the interval of the free space fn find_space(&self, npages: u32) -> Option>; // Method to find space above a hint fn find_space_above_hint(&self, npages: u32, hint: u32) -> Option>; - // Method to find map space + // Method to find space for memory mappings with alignment requirements + // Rounds page numbers up to the nearest multiple of pages_per_map + // Returns the interval of the free space fn find_map_space(&self, num_pages: u32, pages_per_map: u32) -> Option>; // Method to find map space with a hint @@ -194,6 +203,8 @@ pub struct Vmmap { pub entries: NoditMap, VmmapEntry>, // Keyed by `page_num` pub cached_entry: Option, // TODO: is this still needed? // Use Option for safety + pub base_address: Option, // wasm base address. None means uninitialized yet + } #[allow(dead_code)] @@ -202,6 +213,7 @@ impl Vmmap { Vmmap { entries: NoditMap::new(), cached_entry: None, + base_address: None } } @@ -215,8 +227,37 @@ impl Vmmap { npages & !(pages_per_map - 1) } + pub fn set_base_address(&mut self, base_address: i64) { + self.base_address = Some(base_address); + } + + pub fn user_to_sys(&self, address: i32) -> i64 { + address as i64 + self.base_address.unwrap() + } + + pub fn sys_to_user(&self, address: i64) -> i32 { + (address as i64 - self.base_address.unwrap()) as i32 + } + + // Visits each entry in the vmmap, applying a visitor function to each entry + // + // The visitor function should be used to: + // - Validate memory map consistency + // - Gather statistics about memory usage + // - Perform operations across all entries + // - Support debugging and auditing features fn visit() {} + + // Prints detailed debug information about the vmmap's current state + // + // Should output information including: + // - Page ranges and sizes for each mapping + // - Protection flags (current and maximum) + // - Mapping flags + // - Backing store information (Anonymous, File, or Shared Memory) + // - File information (offset and size) when applicable + // - Any gaps in the address space fn debug() {} } @@ -334,6 +375,9 @@ impl VmmapOps for Vmmap { } // Method to change protection of a memory region + // Modifies protection for existing pages in the region + // Should be able to handle splitting of existing pages when necessary + // Should maintain mapping consistency while changing protections fn change_prot(&mut self, page_num: u32, npages: u32, new_prot: i32) { let new_region_end_page = page_num + npages; let new_region_start_page = page_num; diff --git a/src/RawPOSIX/src/tests/vmmap_test.rs b/src/RawPOSIX/src/tests/vmmap_test.rs new file mode 100644 index 000000000..b62da42b8 --- /dev/null +++ b/src/RawPOSIX/src/tests/vmmap_test.rs @@ -0,0 +1,699 @@ +#[cfg(test)] +pub mod vmmap_tests { + use super::super::*; + use crate::interface; + use crate::safeposix::{cage::*, dispatcher::*, filesystem}; + use crate::safeposix::syscalls::*; + use crate::interface; + + // Constants for testing + // Base address for test memory regions (4KB aligned) + const TEST_MEM_START: usize = 0x1000; + // Size of test memory regions (4KB) + const TEST_MEM_SIZE: usize = 0x1000; + // Memory protection flags + const PROT_READ: u32 = 1; // Read permission + const PROT_WRITE: u32 = 2; // Write permission + const PROT_EXEC: u32 = 4; // Execute permission + const EXIT_SUCCESS: i32 = 0; + + + /* + Test memory persistence after cage exit + + Layout: + Initial: + Cage A: [----Memory Region----] + [Written: "test_data"] + + After Exit: + Cage A: (cleaned up) + New Cage: [----Memory Region----] + [Should be clean] + */ + #[test] + pub fn ut_lind_vmmap_memory_persistence() { + //acquiring a lock on TESTMUTEX prevents other tests from running concurrently, + // and also performs clean env setup + let _thelock = setup::lock_and_init(); + // Create initial cage + let cage = interface::cagetable_getref(1); + + // Allocate memory region with read/write permissions + let mut vmmap = cage.vmmap.write(); + assert_eq!( + vmmap.map_memory(TEST_MEM_START, TEST_MEM_SIZE, PROT_READ | PROT_WRITE), + Ok(()), + "Failed to map memory" + ); + + // Get the mapped region + let region = vmmap.get_region(TEST_MEM_START) + .expect("Memory region not found"); + + // Verify initial mapping + assert_eq!(region.permissions, PROT_READ | PROT_WRITE); + assert!(region.contains_range(TEST_MEM_START, TEST_MEM_SIZE)); + + // Exit the cage + assert_eq!(cage.exit_syscall(EXIT_SUCCESS), EXIT_SUCCESS); + + // Verify cleanup + assert!(interface::cagetable_lookup(1).is_none(), + "Cage still exists after exit"); + + // Create new cage and try to map same region + let new_cage = interface::cagetable_getref(2); + let mut new_vmmap = new_cage.vmmap.write(); + + // Try to map the same memory region + assert_eq!( + new_vmmap.map_memory(TEST_MEM_START, TEST_MEM_SIZE, PROT_READ | PROT_WRITE), + Ok(()), + "Failed to map previously used memory region" + ); + + // Verify new mapping is clean + let new_region = new_vmmap.get_region(TEST_MEM_START) + .expect("New memory region not found"); + + assert_eq!(new_region.permissions, PROT_READ | PROT_WRITE); + assert!(new_region.contains_range(TEST_MEM_START, TEST_MEM_SIZE)); + + // Cleanup new cage + assert_eq!(new_cage.exit_syscall(EXIT_SUCCESS), EXIT_SUCCESS); + + lindrustfinalize(); + } + + /* + Test basic memory cleanup after exit + + Initial: + Cage A: [----Memory Region----] + + After Exit: + Cage A: (cleaned up) + */ + #[test] + fn ut_lind_test_basic_exit_cleanup() { + let _thelock = setup::lock_and_init(); + + // Setup cage with memory allocation + let cage_a = create_test_cage(); + + // Allocate memory and verify + setup_memory_region(&cage_a, TEST_MEM_START, TEST_MEM_SIZE, PROT_READ | PROT_WRITE); + verify_memory_access(&cage_a, TEST_MEM_START, TEST_MEM_SIZE, PROT_READ | PROT_WRITE); + + // Exit cage + assert_eq!(cage_a.exit_syscall(EXIT_SUCCESS), EXIT_SUCCESS); + + // Verify cleanup + verify_memory_cleanup(cage_a.cageid); + lindrustfinalize(); + } + + /* + Test nested memory regions across multiple cages + + Layout: + Cage A: [----------------] + Cage B: [--------] + Cage C: [----] + */ + #[test] + fn ut_lind_test_nested_overlaps() { + let _thelock = setup::lock_and_init(); + + // Create cages + let cage_a = create_test_cage(); + let cage_b = create_test_cage(); + let cage_c = create_test_cage(); + + // Setup nested memory regions + setup_memory_region(&cage_a, TEST_MEM_START, TEST_MEM_SIZE * 4, PROT_READ | PROT_WRITE); + setup_memory_region(&cage_b, TEST_MEM_START + TEST_MEM_SIZE, TEST_MEM_SIZE * 2, PROT_READ | PROT_WRITE); + setup_memory_region(&cage_c, TEST_MEM_START + TEST_MEM_SIZE * 2, TEST_MEM_SIZE, PROT_READ | PROT_WRITE); + + // Verify initial setup + verify_memory_access(&cage_a, TEST_MEM_START, TEST_MEM_SIZE * 4, PROT_READ | PROT_WRITE); + verify_memory_access(&cage_b, TEST_MEM_START + TEST_MEM_SIZE, TEST_MEM_SIZE * 2, PROT_READ | PROT_WRITE); + verify_memory_access(&cage_c, TEST_MEM_START + TEST_MEM_SIZE * 2, TEST_MEM_SIZE, PROT_READ | PROT_WRITE); + + // Test exits in sequence + assert_eq!(cage_c.exit_syscall(EXIT_SUCCESS), EXIT_SUCCESS); + verify_memory_cleanup(cage_c.cageid); + + // Verify B and A still accessible + verify_memory_access(&cage_b, TEST_MEM_START + TEST_MEM_SIZE, TEST_MEM_SIZE * 2, PROT_READ | PROT_WRITE); + verify_memory_access(&cage_a, TEST_MEM_START, TEST_MEM_SIZE * 4, PROT_READ | PROT_WRITE); + + assert_eq!(cage_b.exit_syscall(EXIT_SUCCESS), EXIT_SUCCESS); + verify_memory_cleanup(cage_b.cageid); + + // Verify A still accessible + verify_memory_access(&cage_a, TEST_MEM_START, TEST_MEM_SIZE * 4, PROT_READ | PROT_WRITE); + + assert_eq!(cage_a.exit_syscall(EXIT_SUCCESS), EXIT_SUCCESS); + verify_memory_cleanup(cage_a.cageid); + lindrustfinalize(); + } + + /* + Test interleaved memory regions + + Layout: + Cage A: [---] [---] [---] + Cage B: [---] [---] [---] + */ + #[test] + fn ut_lind_test_interleaved_regions() { + let _thelock = setup::lock_and_init(); + + let cage_a = create_test_cage(); + let cage_b = create_test_cage(); + + // Setup interleaved regions for Cage A + setup_memory_region(&cage_a, TEST_MEM_START, TEST_MEM_SIZE, PROT_READ | PROT_WRITE); + setup_memory_region(&cage_a, TEST_MEM_START + TEST_MEM_SIZE * 3, TEST_MEM_SIZE, PROT_READ | PROT_WRITE); + setup_memory_region(&cage_a, TEST_MEM_START + TEST_MEM_SIZE * 5, TEST_MEM_SIZE, PROT_READ | PROT_WRITE); + + // Setup interleaved regions for Cage B + setup_memory_region(&cage_b, TEST_MEM_START + TEST_MEM_SIZE, TEST_MEM_SIZE, PROT_READ | PROT_WRITE); + setup_memory_region(&cage_b, TEST_MEM_START + TEST_MEM_SIZE * 4, TEST_MEM_SIZE, PROT_READ | PROT_WRITE); + setup_memory_region(&cage_b, TEST_MEM_START + TEST_MEM_SIZE * 6, TEST_MEM_SIZE, PROT_READ | PROT_WRITE); + + // Verify all regions are accessible + verify_memory_access(&cage_a, TEST_MEM_START, TEST_MEM_SIZE, PROT_READ | PROT_WRITE); + verify_memory_access(&cage_a, TEST_MEM_START + TEST_MEM_SIZE * 3, TEST_MEM_SIZE, PROT_READ | PROT_WRITE); + verify_memory_access(&cage_a, TEST_MEM_START + TEST_MEM_SIZE * 5, TEST_MEM_SIZE, PROT_READ | PROT_WRITE); + + verify_memory_access(&cage_b, TEST_MEM_START + TEST_MEM_SIZE, TEST_MEM_SIZE, PROT_READ | PROT_WRITE); + verify_memory_access(&cage_b, TEST_MEM_START + TEST_MEM_SIZE * 4, TEST_MEM_SIZE, PROT_READ | PROT_WRITE); + verify_memory_access(&cage_b, TEST_MEM_START + TEST_MEM_SIZE * 6, TEST_MEM_SIZE, PROT_READ | PROT_WRITE); + + // Test cleanup + assert_eq!(cage_a.exit_syscall(EXIT_SUCCESS), EXIT_SUCCESS); + verify_memory_cleanup(cage_a.cageid); + + // Verify B's regions still accessible + verify_memory_access(&cage_b, TEST_MEM_START + TEST_MEM_SIZE, TEST_MEM_SIZE, PROT_READ | PROT_WRITE); + verify_memory_access(&cage_b, TEST_MEM_START + TEST_MEM_SIZE * 4, TEST_MEM_SIZE, PROT_READ | PROT_WRITE); + verify_memory_access(&cage_b, TEST_MEM_START + TEST_MEM_SIZE * 6, TEST_MEM_SIZE, PROT_READ | PROT_WRITE); + + assert_eq!(cage_b.exit_syscall(EXIT_SUCCESS), EXIT_SUCCESS); + verify_memory_cleanup(cage_b.cageid); + lindrustfinalize(); + } + + /* + Test circular shared memory dependencies + + Layout: + Cage A → Cage B + ↑ ↓ + Cage C + */ + #[test] + fn ut_lind_test_circular_dependencies() { + let _thelock = setup::lock_and_init(); + + let cage_a = create_test_cage(); + let cage_b = create_test_cage(); + let cage_c = create_test_cage(); + + // Setup circular shared memory regions + setup_memory_region(&cage_a, TEST_MEM_START, TEST_MEM_SIZE, PROT_READ | PROT_WRITE); + setup_memory_region(&cage_b, TEST_MEM_START + TEST_MEM_SIZE, TEST_MEM_SIZE, PROT_READ | PROT_WRITE); + setup_memory_region(&cage_c, TEST_MEM_START + TEST_MEM_SIZE * 2, TEST_MEM_SIZE, PROT_READ | PROT_WRITE); + + // Verify initial access + verify_memory_access(&cage_a, TEST_MEM_START, TEST_MEM_SIZE, PROT_READ | PROT_WRITE); + verify_memory_access(&cage_b, TEST_MEM_START + TEST_MEM_SIZE, TEST_MEM_SIZE, PROT_READ | PROT_WRITE); + verify_memory_access(&cage_c, TEST_MEM_START + TEST_MEM_SIZE * 2, TEST_MEM_SIZE, PROT_READ | PROT_WRITE); + + // Test cleanup in different orders + assert_eq!(cage_b.exit_syscall(EXIT_SUCCESS), EXIT_SUCCESS); + verify_memory_cleanup(cage_b.cageid); + + verify_memory_access(&cage_a, TEST_MEM_START, TEST_MEM_SIZE, PROT_READ | PROT_WRITE); + verify_memory_access(&cage_c, TEST_MEM_START + TEST_MEM_SIZE * 2, TEST_MEM_SIZE, PROT_READ | PROT_WRITE); + + assert_eq!(cage_c.exit_syscall(EXIT_SUCCESS), EXIT_SUCCESS); + verify_memory_cleanup(cage_c.cageid); + + verify_memory_access(&cage_a, TEST_MEM_START, TEST_MEM_SIZE, PROT_READ | PROT_WRITE); + + assert_eq!(cage_a.exit_syscall(EXIT_SUCCESS), EXIT_SUCCESS); + verify_memory_cleanup(cage_a.cageid); + lindrustfinalize(); + } + + /* + Test splitting shared memory regions + + Initial: + [----------------] + + After Split: + [----] [----] [----] + */ + #[test] + fn ut_lind_test_split_regions() { + let _thelock = setup::lock_and_init(); + + let cage = create_test_cage(); + + // Setup initial large region + setup_memory_region(&cage, TEST_MEM_START, TEST_MEM_SIZE * 3, PROT_READ | PROT_WRITE); + verify_memory_access(&cage, TEST_MEM_START, TEST_MEM_SIZE * 3, PROT_READ | PROT_WRITE); + + // Split into three regions with different permissions + let mut vmmap = cage.vmmap.write(); + vmmap.unmap_memory(TEST_MEM_START + TEST_MEM_SIZE, TEST_MEM_SIZE); + + // Verify split regions + verify_memory_access(&cage, TEST_MEM_START, TEST_MEM_SIZE, PROT_READ | PROT_WRITE); + verify_memory_access(&cage, TEST_MEM_START + TEST_MEM_SIZE * 2, TEST_MEM_SIZE, PROT_READ | PROT_WRITE); + + assert!(vmmap.get_region(TEST_MEM_START + TEST_MEM_SIZE).is_none(), + "Middle region should be unmapped"); + + assert_eq!(cage.exit_syscall(EXIT_SUCCESS), EXIT_SUCCESS); + verify_memory_cleanup(cage.cageid); + lindrustfinalize(); + } + + /* + Test overlapping regions with different permissions + + Layout: + Cage A: [RW-][R--][RWX] + Cage B: [R--][RWX][RW-] + */ + #[test] + fn ut_lind_test_mixed_permissions() { + let _thelock = setup::lock_and_init(); + + let cage_a = create_test_cage(); + let cage_b = create_test_cage(); + + // Setup regions with different permissions for Cage A + setup_memory_region(&cage_a, TEST_MEM_START, TEST_MEM_SIZE, PROT_READ | PROT_WRITE); + setup_memory_region(&cage_a, TEST_MEM_START + TEST_MEM_SIZE, TEST_MEM_SIZE, PROT_READ); + setup_memory_region(&cage_a, TEST_MEM_START + TEST_MEM_SIZE * 2, TEST_MEM_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC); + + // Setup regions with different permissions for Cage B + setup_memory_region(&cage_b, TEST_MEM_START, TEST_MEM_SIZE, PROT_READ); + setup_memory_region(&cage_b, TEST_MEM_START + TEST_MEM_SIZE, TEST_MEM_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC); + setup_memory_region(&cage_b, TEST_MEM_START + TEST_MEM_SIZE * 2, TEST_MEM_SIZE, PROT_READ | PROT_WRITE); + + // Verify permissions + verify_memory_access(&cage_a, TEST_MEM_START, TEST_MEM_SIZE, PROT_READ | PROT_WRITE); + verify_memory_access(&cage_a, TEST_MEM_START + TEST_MEM_SIZE, TEST_MEM_SIZE, PROT_READ); + verify_memory_access(&cage_a, TEST_MEM_START + TEST_MEM_SIZE * 2, TEST_MEM_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC); + + verify_memory_access(&cage_b, TEST_MEM_START, TEST_MEM_SIZE, PROT_READ); + verify_memory_access(&cage_b, TEST_MEM_START + TEST_MEM_SIZE, TEST_MEM_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC); + verify_memory_access(&cage_b, TEST_MEM_START + TEST_MEM_SIZE * 2, TEST_MEM_SIZE, PROT_READ | PROT_WRITE); + + // Test cleanup + assert_eq!(cage_a.exit_syscall(EXIT_SUCCESS), EXIT_SUCCESS); + verify_memory_cleanup(cage_a.cageid); + + assert_eq!(cage_b.exit_syscall(EXIT_SUCCESS), EXIT_SUCCESS); + verify_memory_cleanup(cage_b.cageid); + lindrustfinalize(); + } + + /* + Test memory boundary conditions + + Layout: + Cage A: [----] + Cage B: [----] (exactly adjacent) + */ + #[test] + fn ut_lind_test_boundary_cases() { + let _thelock = setup::lock_and_init(); + + let cage_a = create_test_cage(); + let cage_b = create_test_cage(); + + // Setup adjacent regions + setup_memory_region(&cage_a, TEST_MEM_START, TEST_MEM_SIZE, PROT_READ | PROT_WRITE); + setup_memory_region(&cage_b, TEST_MEM_START + TEST_MEM_SIZE, TEST_MEM_SIZE, PROT_READ | PROT_WRITE); + + // Verify each region + verify_memory_access(&cage_a, TEST_MEM_START, TEST_MEM_SIZE, PROT_READ | PROT_WRITE); + verify_memory_access(&cage_b, TEST_MEM_START + TEST_MEM_SIZE, TEST_MEM_SIZE, PROT_READ | PROT_WRITE); + + // Test boundary protection + let vmmap_a = cage_a.vmmap.read(); + let vmmap_b = cage_b.vmmap.read(); + + assert!(vmmap_a.get_region(TEST_MEM_START + TEST_MEM_SIZE).is_none(), + "Cage A should not access Cage B's memory"); + assert!(vmmap_b.get_region(TEST_MEM_START).is_none(), + "Cage B should not access Cage A's memory"); + + // Test cleanup + assert_eq!(cage_a.exit_syscall(EXIT_SUCCESS), EXIT_SUCCESS); + verify_memory_cleanup(cage_a.cageid); + + verify_memory_access(&cage_b, TEST_MEM_START + TEST_MEM_SIZE, TEST_MEM_SIZE, PROT_READ | PROT_WRITE); + + assert_eq!(cage_b.exit_syscall(EXIT_SUCCESS), EXIT_SUCCESS); + verify_memory_cleanup(cage_b.cageid); + lindrustfinalize(); + } + + /* + Test dynamic memory region growth + + Initial: + Cage A: [----] + Cage B: [----] + + After Growth: + Cage A: [--------] + Cage B: [----] + */ + #[test] + fn ut_lind_test_dynamic_growth() { + let _thelock = setup::lock_and_init(); + + let cage_a = create_test_cage(); + let cage_b = create_test_cage(); + + // Initial setup + setup_memory_region(&cage_a, TEST_MEM_START, TEST_MEM_SIZE, PROT_READ | PROT_WRITE); + setup_memory_region(&cage_b, TEST_MEM_START + TEST_MEM_SIZE, TEST_MEM_SIZE, PROT_READ | PROT_WRITE); + + // Verify initial state + verify_memory_access(&cage_a, TEST_MEM_START, TEST_MEM_SIZE, PROT_READ | PROT_WRITE); + verify_memory_access(&cage_b, TEST_MEM_START + TEST_MEM_SIZE, TEST_MEM_SIZE, PROT_READ | PROT_WRITE); + + // Grow cage_a's region + let mut vmmap = cage_a.vmmap.write(); + vmmap.map_memory(TEST_MEM_START, TEST_MEM_SIZE * 2, PROT_READ | PROT_WRITE); + + // Verify growth + verify_memory_access(&cage_a, TEST_MEM_START, TEST_MEM_SIZE * 2, PROT_READ | PROT_WRITE); + verify_memory_access(&cage_b, TEST_MEM_START + TEST_MEM_SIZE, TEST_MEM_SIZE, PROT_READ | PROT_WRITE); + + // Cleanup + assert_eq!(cage_a.exit_syscall(EXIT_SUCCESS), EXIT_SUCCESS); + verify_memory_cleanup(cage_a.cageid); + + assert_eq!(cage_b.exit_syscall(EXIT_SUCCESS), EXIT_SUCCESS); + verify_memory_cleanup(cage_b.cageid); + lindrustfinalize(); + } + + /* + Test invalid memory operations + + Cases: + 1. Zero-sized region + 2. Invalid permissions + 3. Overlapping with invalid permissions + 4. Out of bounds access + */ + #[test] + fn ut_lind_test_invalid_memory_operations() { + let _thelock = setup::lock_and_init(); + + let cage = create_test_cage(); + + // Test zero-sized region + assert!(cage.vmmap.write().map_memory(TEST_MEM_START, 0, PROT_READ).is_err()); + + // Test invalid permissions + assert!(cage.vmmap.write().map_memory(TEST_MEM_START, TEST_MEM_SIZE, 0xFF).is_err()); + + // Test valid setup + setup_memory_region(&cage, TEST_MEM_START, TEST_MEM_SIZE, PROT_READ | PROT_WRITE); + + // Test overlapping with invalid permissions + assert!(cage.vmmap.write().map_memory(TEST_MEM_START, TEST_MEM_SIZE, 0xFF).is_err()); + + assert_eq!(cage.exit_syscall(EXIT_SUCCESS), EXIT_SUCCESS); + verify_memory_cleanup(cage.cageid); + lindrustfinalize(); + } + + /* + Test concurrent memory access + + Layout: + Multiple cages accessing same memory regions + */ + #[test] + fn ut_lind_test_concurrent_access() { + let _thelock = setup::lock_and_init(); + + use std::sync::Arc; + use std::thread; + + let cage_count = 5; + let cages: Vec> = (0..cage_count) + .map(|_| Arc::new(create_test_cage())) + .collect(); + + // Setup shared region + for cage in &cages { + setup_memory_region(&cage, TEST_MEM_START, TEST_MEM_SIZE, PROT_READ | PROT_WRITE); + } + + // Concurrent access + let handles: Vec<_> = cages.iter().map(|cage| { + let cage = Arc::clone(cage); + thread::spawn(move || { + verify_memory_access(&cage, TEST_MEM_START, TEST_MEM_SIZE, PROT_READ | PROT_WRITE); + }) + }).collect(); + + // Wait for all threads + for handle in handles { + handle.join().unwrap(); + } + + // Cleanup + for cage in cages { + assert_eq!(cage.exit_syscall(EXIT_SUCCESS), EXIT_SUCCESS); + verify_memory_cleanup(cage.cageid); + } + lindrustfinalize(); + } + + /* + Test overlapping regions with conflicting permissions + + Layout: + Initial: + Cage A: [RW-][-W-][RWX] + Cage B: [R--][--X][RW-] + | | | + v v v + Result: [R--][---][RW-] (most restrictive permissions win) + */ + #[test] + fn ut_lind_test_overlapping_permissions_conflict() { + let _thelock = setup::lock_and_init(); + + let cage_a = create_test_cage(); + let cage_b = create_test_cage(); + + // Setup overlapping regions with different permissions + setup_memory_region(&cage_a, TEST_MEM_START, TEST_MEM_SIZE, PROT_READ | PROT_WRITE).unwrap(); + setup_memory_region(&cage_a, TEST_MEM_START + TEST_MEM_SIZE, TEST_MEM_SIZE, PROT_WRITE).unwrap(); + setup_memory_region(&cage_a, TEST_MEM_START + TEST_MEM_SIZE * 2, TEST_MEM_SIZE, + PROT_READ | PROT_WRITE | PROT_EXEC).unwrap(); + + // Try to set conflicting permissions + let result = setup_memory_region(&cage_b, TEST_MEM_START, TEST_MEM_SIZE, PROT_READ); + assert!(result.is_err(), "Should not allow conflicting permissions"); + + // Cleanup + assert_eq!(cage_a.exit_syscall(EXIT_SUCCESS), EXIT_SUCCESS); + verify_memory_cleanup(cage_a.cageid); + + assert_eq!(cage_b.exit_syscall(EXIT_SUCCESS), EXIT_SUCCESS); + verify_memory_cleanup(cage_b.cageid); + lindrustfinalize(); + } + + /* + Test maximum number of shared regions + + Layout: + Cage A: [1][2][3]...[MAX] + Cage B: [1][2][3]...[MAX] + | | | | + Shared Regions + */ + #[test] + fn ut_lind_test_memory_sharing_limits() { + let _thelock = setup::lock_and_init(); + + let cage_a = create_test_cage(); + let cage_b = create_test_cage(); + + const MAX_REGIONS: usize = 10; // Adjust based on system limits + let mut regions = Vec::new(); + + // Try to create maximum number of shared regions + for i in 0..MAX_REGIONS { + let start = TEST_MEM_START + (i * TEST_MEM_SIZE); + let result = setup_memory_region(&cage_a, start, TEST_MEM_SIZE, PROT_READ | PROT_WRITE); + if result.is_ok() { + regions.push(start); + } else { + println!("Max regions reached at {}", i); + break; + } + } + + // Verify all regions are accessible + for &start in ®ions { + verify_memory_access(&cage_a, start, TEST_MEM_SIZE, PROT_READ | PROT_WRITE); + } + + // Cleanup + assert_eq!(cage_a.exit_syscall(EXIT_SUCCESS), EXIT_SUCCESS); + verify_memory_cleanup(cage_a.cageid); + + assert_eq!(cage_b.exit_syscall(EXIT_SUCCESS), EXIT_SUCCESS); + verify_memory_cleanup(cage_b.cageid); + lindrustfinalize(); + } + + /* + Test concurrent map/unmap operations + + Layout: + Thread 1: [Map][Unmap][Map ] + Thread 2: [ Map ][Unmap ] + Thread 3: [ Unmap ][ Map ] + Time -> ------------------> + */ + #[test] + fn ut_lind_test_concurrent_mapping_unmapping() { + let _thelock = setup::lock_and_init(); + + use std::sync::Arc; + use std::thread; + use std::sync::Barrier; + + let cage = Arc::new(create_test_cage()); + let barrier = Arc::new(Barrier::new(3)); + + // Setup initial region + setup_memory_region(&cage, TEST_MEM_START, TEST_MEM_SIZE, PROT_READ | PROT_WRITE).unwrap(); + + // Create threads for concurrent operations + let handles: Vec<_> = (0..3).map(|i| { + let cage = Arc::clone(&cage); + let barrier = Arc::clone(&barrier); + + thread::spawn(move || { + barrier.wait(); + match i { + 0 => { + // Thread 1: Map -> Unmap -> Map + setup_memory_region(&cage, TEST_MEM_START + TEST_MEM_SIZE, + TEST_MEM_SIZE, PROT_READ | PROT_WRITE).unwrap(); + cage.vmmap.write().unmap_memory(TEST_MEM_START + TEST_MEM_SIZE, TEST_MEM_SIZE); + setup_memory_region(&cage, TEST_MEM_START + TEST_MEM_SIZE * 2, + TEST_MEM_SIZE, PROT_READ | PROT_WRITE).unwrap(); + }, + 1 => { + // Thread 2: Map larger region -> Unmap portion + setup_memory_region(&cage, TEST_MEM_START + TEST_MEM_SIZE * 3, + TEST_MEM_SIZE * 2, PROT_READ | PROT_WRITE).unwrap(); + cage.vmmap.write().unmap_memory(TEST_MEM_START + TEST_MEM_SIZE * 4, TEST_MEM_SIZE); + }, + _ => { + // Thread 3: Unmap -> Map different region + cage.vmmap.write().unmap_memory(TEST_MEM_START, TEST_MEM_SIZE); + setup_memory_region(&cage, TEST_MEM_START + TEST_MEM_SIZE * 5, + TEST_MEM_SIZE, PROT_READ | PROT_WRITE).unwrap(); + } + } + }) + }).collect(); + + // Wait for all threads + for handle in handles { + handle.join().unwrap(); + } + + // Verify final state + let vmmap = cage.vmmap.read(); + assert!(vmmap.get_region(TEST_MEM_START).is_none(), "Region should be unmapped"); + assert!(vmmap.get_region(TEST_MEM_START + TEST_MEM_SIZE * 2).is_some(), + "Region should be mapped"); + assert!(vmmap.get_region(TEST_MEM_START + TEST_MEM_SIZE * 3).is_some(), + "Region should be mapped"); + assert!(vmmap.get_region(TEST_MEM_START + TEST_MEM_SIZE * 5).is_some(), + "Region should be mapped"); + + // Cleanup + assert_eq!(Arc::try_unwrap(cage).unwrap().exit_syscall(EXIT_SUCCESS), EXIT_SUCCESS); + lindrustfinalize(); + } + + // Helper functions + fn create_test_cage() -> Cage { + let cage_id = interface::get_new_cage_id(); + let cage = Cage::new(cage_id); + interface::cagetable_insert(cage_id, cage.clone()); + cage + } + + fn verify_memory_cleanup(cage_id: u64) { + // Check if cage exists in cagetable + assert!(interface::cagetable_lookup(cage_id).is_none(), + "Cage still exists in cagetable after cleanup"); + + // Verify fd table cleanup + assert!(fdtables::get_fdtable_for_cage(cage_id).is_none(), + "FD table still exists after cleanup"); + + // Verify all memory regions are unmapped + assert!(interface::get_memory_regions(cage_id).is_empty(), + "Memory regions still exist after cleanup"); + } + + fn setup_memory_region(cage: &Cage, start: usize, size: usize, permissions: u32) -> Result<(), &'static str> { + if size == 0 { + return Err("Memory region size must be positive"); + } + if permissions & (PROT_READ | PROT_WRITE | PROT_EXEC) != permissions { + return Err("Invalid permissions specified"); + } + + let mut vmmap = cage.vmmap.write(); + vmmap.map_memory(start, size, permissions) + .map_err(|_| "Failed to map memory region") + } + + fn verify_memory_access(cage: &Cage, start: usize, size: usize, expected_perms: u32) { + assert!(size > 0, "Memory region size must be positive"); + + let vmmap = cage.vmmap.read(); + let region = vmmap.get_region(start) + .expect("Memory region not found"); + + assert_eq!(region.permissions, expected_perms, + "Incorrect permissions for memory region"); + assert!(region.contains_range(start, size), + "Memory region does not contain expected range"); + + // Verify boundaries + assert!(region.start <= start, "Region start boundary incorrect"); + assert!(region.start + region.size >= start + size, "Region end boundary incorrect"); + } +} \ No newline at end of file From bd567d7ac38bd2e36ea800c709193c5d7e14607a Mon Sep 17 00:00:00 2001 From: Chinmay Shringi Date: Wed, 4 Dec 2024 12:32:16 -0500 Subject: [PATCH 07/66] fix: rm commented import --- src/RawPOSIX/src/tests/sys_tests.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/RawPOSIX/src/tests/sys_tests.rs b/src/RawPOSIX/src/tests/sys_tests.rs index 22260b38c..4414fe820 100644 --- a/src/RawPOSIX/src/tests/sys_tests.rs +++ b/src/RawPOSIX/src/tests/sys_tests.rs @@ -7,7 +7,6 @@ pub mod sys_tests { use super::super::*; use crate::interface; use crate::constants::DEFAULT_UID; - // use crate::safeposix::cage::{FileDescriptor::*, *}; use crate::safeposix::{cage::*, dispatcher::*, filesystem}; #[test] From 51901796e55a4940214e20c8a60bbda4dd9fce1b Mon Sep 17 00:00:00 2001 From: Chinmay Shringi Date: Wed, 4 Dec 2024 12:35:55 -0500 Subject: [PATCH 08/66] refactor: rm commented imports --- src/RawPOSIX/src/safeposix/syscalls/fs_calls.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/RawPOSIX/src/safeposix/syscalls/fs_calls.rs b/src/RawPOSIX/src/safeposix/syscalls/fs_calls.rs index 353e6eec0..ad67b3474 100644 --- a/src/RawPOSIX/src/safeposix/syscalls/fs_calls.rs +++ b/src/RawPOSIX/src/safeposix/syscalls/fs_calls.rs @@ -1,10 +1,6 @@ #![allow(dead_code)] use std::fs; -// Removed these since we'll import from constants directly -// use super::fs_constants; -// use super::fs_constants::*; -// use super::sys_constants; // Add constants imports use crate::constants::{ From 7a39e8a514f2ac1e9c7dad080202526df9cd25c1 Mon Sep 17 00:00:00 2001 From: Chinmay Shringi Date: Wed, 4 Dec 2024 12:37:07 -0500 Subject: [PATCH 09/66] refactor: rm comments --- src/RawPOSIX/src/safeposix/mod.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/RawPOSIX/src/safeposix/mod.rs b/src/RawPOSIX/src/safeposix/mod.rs index 2f4c3760d..249dcdd32 100644 --- a/src/RawPOSIX/src/safeposix/mod.rs +++ b/src/RawPOSIX/src/safeposix/mod.rs @@ -4,4 +4,3 @@ pub mod filesystem; pub mod shm; pub mod syscalls; pub mod vmmap; -// pub mod vmmap_constants; From b430229781c348afaf4cf1632d3afdf359d12ae0 Mon Sep 17 00:00:00 2001 From: Chinmay Shringi Date: Sun, 8 Dec 2024 20:52:34 -0500 Subject: [PATCH 10/66] feat: add check_and_convert_addr --- src/RawPOSIX/src/interface/mem.rs | 24 ++- src/RawPOSIX/src/safeposix/dispatcher.rs | 248 ++++++++++++++++++----- 2 files changed, 217 insertions(+), 55 deletions(-) diff --git a/src/RawPOSIX/src/interface/mem.rs b/src/RawPOSIX/src/interface/mem.rs index df0fc40f8..3ac6d3742 100644 --- a/src/RawPOSIX/src/interface/mem.rs +++ b/src/RawPOSIX/src/interface/mem.rs @@ -1,9 +1,13 @@ -use libc::{MAP_ANONYMOUS, MAP_FIXED, MAP_PRIVATE, PROT_EXEC}; +use crate::constants::{ + MAP_ANONYMOUS, MAP_FIXED, MAP_PRIVATE, PROT_EXEC, +}; use crate::safeposix::cage::{MemoryBackingType, Vmmap, VmmapOps, MAP_SHARED, PAGESHIFT, PAGESIZE, PROT_NONE, PROT_READ, PROT_WRITE}; use crate::interface::{cagetable_getref, syscall_error, Errno}; +use std::result::Result; + // heap is placed at the very top of the memory pub const HEAP_ENTRY_INDEX: u32 = 0; @@ -226,3 +230,21 @@ pub fn sbrk_handler(cageid: u64, brk: u32) -> i32 { (PAGESIZE * heap.npages) as i32 } + +pub fn check_and_convert_addr(cageid: u64, user_addr: u64) -> Result { + let cage = cagetable_getref(cageid); + let mut vmmap = cage.vmmap.write(); // Changed to write() since check_addr_mapping needs &mut self + + // Convert address to page number + let page_num = (user_addr >> PAGESHIFT) as u32; + + // Use existing check_addr_mapping function + // We use 1 page and PROT_READ since we just want to verify the address is valid + if vmmap.check_addr_mapping(page_num, 1, PROT_READ).is_none() { + return Err(Errno::EFAULT); + } + + // If valid, convert user address to system address + let sys_addr = vmmap.user_to_sys(user_addr as i32) as u64; + Ok(sys_addr) +} diff --git a/src/RawPOSIX/src/safeposix/dispatcher.rs b/src/RawPOSIX/src/safeposix/dispatcher.rs index 751fb616d..d5312b017 100644 --- a/src/RawPOSIX/src/safeposix/dispatcher.rs +++ b/src/RawPOSIX/src/safeposix/dispatcher.rs @@ -213,7 +213,10 @@ pub fn lind_syscall_api( WRITEV_SYSCALL => { let fd = arg1 as i32; - let iovec = (start_address + arg2) as *const interface::IovecStruct; + let iovec = match check_and_convert_addr(cageid, start_address + arg2) { + Ok(addr) => addr as *const interface::IovecStruct, + Err(errno) => return syscall_error(errno, "writev", "invalid iovec address"), + }; let iovcnt = arg3 as i32; interface::cagetable_getref(cageid) @@ -240,7 +243,10 @@ pub fn lind_syscall_api( PREAD_SYSCALL => { let fd = arg1 as i32; - let buf = (start_address + arg2) as *mut u8; + let buf = match check_and_convert_addr(cageid, start_address + arg2) { + Ok(addr) => addr as *mut u8, + Err(errno) => return syscall_error(errno, "pread", "invalid buffer address"), + }; let count = arg3 as usize; let offset = arg4 as i64; @@ -250,7 +256,10 @@ pub fn lind_syscall_api( READ_SYSCALL => { let fd = arg1 as i32; - let buf = (start_address + arg2) as *mut u8; + let buf = match check_and_convert_addr(cageid, start_address + arg2) { + Ok(addr) => addr as *mut u8, + Err(errno) => return syscall_error(errno, "read", "invalid buffer address"), + }; let count = arg3 as usize; interface::cagetable_getref(cageid) @@ -265,9 +274,12 @@ pub fn lind_syscall_api( } ACCESS_SYSCALL => { - let path = match interface::types::get_cstr(start_address + arg1) { - Ok(path_str) => path_str, - Err(_) => return -1, // Handle error appropriately, return an error code + let path = match check_and_convert_addr(cageid, start_address + arg1) { + Ok(addr) => match interface::types::get_cstr(addr) { + Ok(path_str) => path_str, + Err(_) => return -1, + }, + Err(errno) => return syscall_error(errno, "access", "invalid path address"), }; let amode = arg2 as i32; @@ -276,9 +288,12 @@ pub fn lind_syscall_api( } OPEN_SYSCALL => { - let path = match interface::types::get_cstr(start_address + arg1) { - Ok(path_str) => path_str, - Err(_) => return -1, // Handle error appropriately, return an error code + let path = match check_and_convert_addr(cageid, start_address + arg1) { + Ok(addr) => match interface::types::get_cstr(addr) { + Ok(path_str) => path_str, + Err(_) => return -1, + }, + Err(errno) => return syscall_error(errno, "open", "invalid path address"), }; let flags = arg2 as i32; let mode = arg3 as u32; @@ -298,8 +313,10 @@ pub fn lind_syscall_api( CONNECT_SYSCALL => { let fd = arg1 as i32; - let addrlen = arg3 as u32; - let addr = get_onearg!(interface::get_sockaddr(arg2, addrlen)); + let addr = match check_and_convert_addr(cageid, start_address + arg2) { + Ok(addr) => interface::get_sockaddr(addr, arg3 as u32).unwrap(), + Err(errno) => return syscall_error(errno, "connect", "invalid address"), + }; let remoteaddr = match Ok::<&interface::GenSockaddr, i32>(&addr) { Ok(addr) => addr, @@ -311,8 +328,10 @@ pub fn lind_syscall_api( BIND_SYSCALL => { let fd = arg1 as i32; - let addrlen = arg3 as u32; - let addr = interface::get_sockaddr(start_address + arg2, addrlen).unwrap(); + let addr = match check_and_convert_addr(cageid, start_address + arg2) { + Ok(addr) => interface::get_sockaddr(addr, arg3 as u32).unwrap(), + Err(errno) => return syscall_error(errno, "bind", "invalid address"), + }; let localaddr = match Ok::<&interface::GenSockaddr, i32>(&addr) { Ok(addr) => addr, Err(_) => panic!("Failed to get sockaddr"), // Handle error appropriately @@ -333,7 +352,15 @@ pub fn lind_syscall_api( let rv = interface::cagetable_getref(cageid) .accept_syscall(arg1 as i32, &mut Some(&mut addr)); if rv >= 0 { - interface::copy_out_sockaddr((start_address + arg2), (start_address + arg3), addr); + let addr2_addr = match check_and_convert_addr(cageid, start_address + arg2) { + Ok(addr) => addr, + Err(errno) => return syscall_error(errno, "accept", "invalid address buffer"), + }; + let len_addr = match check_and_convert_addr(cageid, start_address + arg3) { + Ok(addr) => addr, + Err(errno) => return syscall_error(errno, "accept", "invalid length buffer"), + }; + interface::copy_out_sockaddr(addr2_addr, len_addr, addr); } rv } else { @@ -368,8 +395,14 @@ pub fn lind_syscall_api( } RENAME_SYSCALL => { - let old_ptr = (start_address + arg1) as *const u8; - let new_ptr = (start_address + arg2) as *const u8; + let old_ptr = match check_and_convert_addr(cageid, start_address + arg1) { + Ok(addr) => addr as *const u8, + Err(errno) => return syscall_error(errno, "rename", "invalid old path address"), + }; + let new_ptr = match check_and_convert_addr(cageid, start_address + arg2) { + Ok(addr) => addr as *const u8, + Err(errno) => return syscall_error(errno, "rename", "invalid new path address"), + }; // Convert the raw pointers to `&str` let old = unsafe { @@ -384,7 +417,10 @@ pub fn lind_syscall_api( } XSTAT_SYSCALL => { - let fd_ptr = (start_address + arg1) as *const u8; + let fd_ptr = match check_and_convert_addr(cageid, start_address + arg1) { + Ok(addr) => addr as *const u8, + Err(errno) => return syscall_error(errno, "xstat", "invalid path address"), + }; let buf = match interface::get_statdatastruct(start_address + arg2) { Ok(val) => val, Err(errno) => { @@ -401,10 +437,13 @@ pub fn lind_syscall_api( } MKDIR_SYSCALL => { - let fd_ptr = (start_address + arg1) as *const u8; + let fd_ptr = match check_and_convert_addr(cageid, start_address + arg1) { + Ok(addr) => addr as *const u8, + Err(errno) => return syscall_error(errno, "mkdir", "invalid path address"), + }; let mode = arg2 as u32; - let fd= unsafe { + let fd = unsafe { CStr::from_ptr(fd_ptr as *const i8).to_str().unwrap() }; @@ -413,9 +452,12 @@ pub fn lind_syscall_api( } RMDIR_SYSCALL => { - let fd_ptr = (start_address + arg1) as *const u8; + let fd_ptr = match check_and_convert_addr(cageid, start_address + arg1) { + Ok(addr) => addr as *const u8, + Err(errno) => return syscall_error(errno, "rmdir", "invalid path address"), + }; - let fd= unsafe { + let fd = unsafe { CStr::from_ptr(fd_ptr as *const i8).to_str().unwrap() }; @@ -431,14 +473,20 @@ pub fn lind_syscall_api( } CHDIR_SYSCALL => { - let path = interface::types::get_cstr(start_address + arg1).unwrap(); + let path = match check_and_convert_addr(cageid, start_address + arg1) { + Ok(addr) => interface::types::get_cstr(addr).unwrap(), + Err(errno) => return syscall_error(errno, "chdir", "invalid path address"), + }; interface::cagetable_getref(cageid) .chdir_syscall(path) } GETCWD_SYSCALL => { - let buf = (start_address + arg1) as *mut u8; + let buf = match check_and_convert_addr(cageid, start_address + arg1) { + Ok(addr) => addr as *mut u8, + Err(errno) => return syscall_error(errno, "getcwd", "invalid buffer address"), + }; let bufsize = arg2 as u32; let ret = interface::cagetable_getref(cageid) @@ -449,15 +497,21 @@ pub fn lind_syscall_api( FSTATFS_SYSCALL => { let fd = arg1 as i32; - let buf = interface::get_fsdatastruct(start_address + arg2).unwrap(); + let buf = match check_and_convert_addr(cageid, start_address + arg2) { + Ok(addr) => interface::get_fsdatastruct(addr).unwrap(), + Err(errno) => return syscall_error(errno, "fstatfs", "invalid buffer address"), + }; interface::cagetable_getref(cageid) .fstatfs_syscall(fd, buf) } CHMOD_SYSCALL => { - let fd_ptr = (start_address + arg1) as *const u8; - let fd= unsafe { + let fd_ptr = match check_and_convert_addr(cageid, start_address + arg1) { + Ok(addr) => addr as *const u8, + Err(errno) => return syscall_error(errno, "chmod", "invalid path address"), + }; + let fd = unsafe { CStr::from_ptr(fd_ptr as *const i8).to_str().unwrap() }; let mode = arg2 as u32; @@ -496,14 +550,20 @@ pub fn lind_syscall_api( FXSTAT_SYSCALL => { let fd = arg1 as i32; - let buf = interface::get_statdatastruct(start_address + arg2).unwrap(); + let buf = match check_and_convert_addr(cageid, start_address + arg2) { + Ok(addr) => interface::get_statdatastruct(addr).unwrap(), + Err(errno) => return syscall_error(errno, "fxstat", "invalid buffer address"), + }; interface::cagetable_getref(cageid) .fstat_syscall(fd, buf) } UNLINK_SYSCALL => { - let fd_ptr = (start_address + arg1) as *const u8; + let fd_ptr = match check_and_convert_addr(cageid, start_address + arg1) { + Ok(addr) => addr as *const u8, + Err(errno) => return syscall_error(errno, "unlink", "invalid path address"), + }; let fd = unsafe { CStr::from_ptr(fd_ptr as *const i8).to_str().unwrap() @@ -514,10 +574,16 @@ pub fn lind_syscall_api( } LINK_SYSCALL => { - let old_ptr = (start_address + arg1) as *const u8; - let new_ptr = (start_address + arg1) as *const u8; + let old_ptr = match check_and_convert_addr(cageid, start_address + arg1) { + Ok(addr) => addr as *const u8, + Err(errno) => return syscall_error(errno, "link", "invalid old path address"), + }; + let new_ptr = match check_and_convert_addr(cageid, start_address + arg2) { + Ok(addr) => addr as *const u8, + Err(errno) => return syscall_error(errno, "link", "invalid new path address"), + }; - let old_fd= unsafe { + let old_fd = unsafe { CStr::from_ptr(old_ptr as *const i8).to_str().unwrap() }; let new_fd = unsafe { @@ -547,7 +613,10 @@ pub fn lind_syscall_api( } TRUNCATE_SYSCALL => { - let fd_ptr = (start_address + arg1) as *const u8; + let fd_ptr = match check_and_convert_addr(cageid, start_address + arg1) { + Ok(addr) => addr as *const u8, + Err(errno) => return syscall_error(errno, "truncate", "invalid path address"), + }; let length = arg2 as isize; let fd = unsafe { @@ -568,7 +637,10 @@ pub fn lind_syscall_api( GETDENTS_SYSCALL => { let virtual_fd = arg1 as i32; - let buf = (start_address + arg2) as *mut u8; + let buf = match check_and_convert_addr(cageid, start_address + arg2) { + Ok(addr) => addr as *mut u8, + Err(errno) => return syscall_error(errno, "getdents", "invalid buffer address"), + }; let nbytes = arg3 as u32; interface::cagetable_getref(cageid) @@ -576,7 +648,10 @@ pub fn lind_syscall_api( } STATFS_SYSCALL => { - let fd_ptr = (start_address + arg1) as *const u8; + let fd_ptr = match check_and_convert_addr(cageid, start_address + arg1) { + Ok(addr) => addr as *const u8, + Err(errno) => return syscall_error(errno, "statfs", "invalid path address"), + }; let rposix_databuf = interface::get_fsdatastruct(start_address + arg2).unwrap(); let fd = unsafe { @@ -598,7 +673,10 @@ pub fn lind_syscall_api( RECV_SYSCALL => { let fd = arg1 as i32; - let buf = (start_address + arg2) as *mut u8; + let buf = match check_and_convert_addr(cageid, start_address + arg2) { + Ok(addr) => addr as *mut u8, + Err(errno) => return syscall_error(errno, "recv", "invalid buffer address"), + }; let buflen = arg3 as usize; let flag = arg4 as i32; @@ -621,7 +699,10 @@ pub fn lind_syscall_api( RECVFROM_SYSCALL => { let fd = arg1 as i32; - let buf = (start_address + arg2) as *mut u8; + let buf = match check_and_convert_addr(cageid, start_address + arg2) { + Ok(addr) => addr as *mut u8, + Err(errno) => return syscall_error(errno, "recvfrom", "invalid buffer address"), + }; let buflen = arg3 as usize; let flag = arg4 as i32; let nullity1 = interface::arg_nullity(arg5); @@ -668,7 +749,10 @@ pub fn lind_syscall_api( SHMAT_SYSCALL => { let shmid = arg1 as i32; - let shmaddr = (start_address + arg2) as *mut u8; + let shmaddr = match check_and_convert_addr(cageid, start_address + arg2) { + Ok(addr) => addr as *mut u8, + Err(errno) => return syscall_error(errno, "shmat", "invalid shared memory address"), + }; let shmflg = arg3 as i32; interface::cagetable_getref(cageid) @@ -676,7 +760,10 @@ pub fn lind_syscall_api( } SHMDT_SYSCALL => { - let shmaddr = (start_address + arg1) as *mut u8; + let shmaddr = match check_and_convert_addr(cageid, start_address + arg1) { + Ok(addr) => addr as *mut u8, + Err(errno) => return syscall_error(errno, "shmdt", "invalid shared memory address"), + }; interface::cagetable_getref(cageid) .shmdt_syscall(shmaddr) @@ -785,7 +872,10 @@ pub fn lind_syscall_api( PWRITE_SYSCALL => { let virtual_fd = arg1 as i32; - let buf = (start_address + arg2) as *const u8; + let buf = match check_and_convert_addr(cageid, start_address + arg2) { + Ok(addr) => addr as *const u8, + Err(errno) => return syscall_error(errno, "pwrite", "invalid buffer address"), + }; let count = arg3 as usize; let offset = arg4 as i64; @@ -844,7 +934,10 @@ pub fn lind_syscall_api( let virtual_fd = arg1 as i32; let level = arg2 as i32; let optname = arg3 as i32; - let optval = (start_address + arg4) as *mut u8; + let optval = match check_and_convert_addr(cageid, start_address + arg4) { + Ok(addr) => addr as *const u8, + Err(errno) => return syscall_error(errno, "setsockopt", "invalid optval address"), + }; let optlen = arg5 as u32; interface::cagetable_getref(cageid) @@ -866,7 +959,10 @@ pub fn lind_syscall_api( SEND_SYSCALL => { let virtual_fd = arg1 as i32; - let buf = (start_address + arg4) as *const u8; + let buf = match check_and_convert_addr(cageid, start_address + arg2) { + Ok(addr) => addr as *const u8, + Err(errno) => return syscall_error(errno, "send", "invalid buffer address"), + }; let buflen = arg3 as usize; let flags = arg4 as i32; @@ -892,7 +988,10 @@ pub fn lind_syscall_api( } GETHOSTNAME_SYSCALL => { - let name = (start_address + arg1) as *mut u8; + let name = match check_and_convert_addr(cageid, start_address + arg1) { + Ok(addr) => addr as *mut u8, + Err(errno) => return syscall_error(errno, "gethostname", "invalid name address"), + }; let len = arg2 as isize; let ret = interface::cagetable_getref(cageid) .gethostname_syscall(name, len); @@ -900,7 +999,10 @@ pub fn lind_syscall_api( } GETIFADDRS_SYSCALL => { - let buf = (start_address + arg1) as *mut u8; + let buf = match check_and_convert_addr(cageid, start_address + arg1) { + Ok(addr) => addr, + Err(errno) => return syscall_error(errno, "getifaddrs", "invalid address"), + }; let count = arg2 as usize; interface::cagetable_getref(cageid) .getifaddrs_syscall(buf, count) @@ -938,14 +1040,20 @@ pub fn lind_syscall_api( } PIPE_SYSCALL => { - let pipe = interface::get_pipearray(start_address + arg1).unwrap(); + let pipe = match check_and_convert_addr(cageid, start_address + arg1) { + Ok(addr) => interface::get_pipearray(addr).unwrap(), + Err(errno) => return syscall_error(errno, "pipe", "invalid pipe address"), + }; interface::cagetable_getref(cageid) .pipe_syscall(pipe) } PIPE2_SYSCALL => { - let pipe = interface::get_pipearray(start_address + arg1).unwrap(); + let pipe = match check_and_convert_addr(cageid, start_address + arg1) { + Ok(addr) => interface::get_pipearray(addr).unwrap(), + Err(errno) => return syscall_error(errno, "pipe2", "invalid pipe address"), + }; let flag = arg2 as i32; interface::cagetable_getref(cageid) @@ -954,6 +1062,14 @@ pub fn lind_syscall_api( GETSOCKNAME_SYSCALL => { let fd = arg1 as i32; + let name_addr = match check_and_convert_addr(cageid, start_address + arg2) { + Ok(addr) => addr, + Err(errno) => return syscall_error(errno, "getsockname", "invalid name address"), + }; + let namelen_addr = match check_and_convert_addr(cageid, start_address + arg3) { + Ok(addr) => addr, + Err(errno) => return syscall_error(errno, "getsockname", "invalid length address"), + }; let mut addr = interface::GenSockaddr::V4(interface::SockaddrV4::default()); //value doesn't matter @@ -969,7 +1085,7 @@ pub fn lind_syscall_api( .getsockname_syscall(fd, &mut Some(&mut addr)); if rv >= 0 { - interface::copy_out_sockaddr(start_address + arg2, start_address + arg3, addr); + interface::copy_out_sockaddr(name_addr, namelen_addr, addr); } rv } @@ -979,7 +1095,10 @@ pub fn lind_syscall_api( let level = arg2 as i32; let optname = arg3 as i32; - let optval_ptr = (start_address + arg4) as *mut i32; + let optval_ptr = match check_and_convert_addr(cageid, start_address + arg4) { + Ok(addr) => addr as *mut i32, + Err(errno) => return syscall_error(errno, "getsockopt", "invalid optval address"), + }; let optval = unsafe { &mut *optval_ptr }; interface::cagetable_getref(cageid) @@ -990,7 +1109,10 @@ pub fn lind_syscall_api( let domain = arg1 as i32; let _type = arg2 as i32; let protocol = arg3 as i32; - let virtual_socket_vector = interface::get_sockpair(start_address + arg4).unwrap(); + let virtual_socket_vector = match check_and_convert_addr(cageid, start_address + arg4) { + Ok(addr) => interface::get_sockpair(addr).unwrap(), + Err(errno) => return syscall_error(errno, "socketpair", "invalid socket vector address"), + }; interface::cagetable_getref(cageid) .socketpair_syscall(domain, _type, protocol, virtual_socket_vector) @@ -998,7 +1120,10 @@ pub fn lind_syscall_api( POLL_SYSCALL => { let nfds = arg2 as u64; - let pollfds = interface::get_pollstruct_slice(start_address + arg1, nfds as usize).unwrap(); + let pollfds = match check_and_convert_addr(cageid, start_address + arg1) { + Ok(addr) => interface::get_pollstruct_slice(addr, nfds as usize).unwrap(), + Err(errno) => return syscall_error(errno, "poll", "invalid fds address"), + }; let timeout = arg3 as i32; interface::cagetable_getref(cageid) @@ -1017,7 +1142,10 @@ pub fn lind_syscall_api( } FUTEX_SYSCALL => { - let uaddr = (start_address + arg1) as u64; + let uaddr = match check_and_convert_addr(cageid, start_address + arg1) { + Ok(addr) => addr as u64, + Err(errno) => return syscall_error(errno, "futex", "invalid uaddr address"), + }; let futex_op = arg2 as u32; let val = arg3 as u32; let timeout = arg4 as u32; @@ -1031,15 +1159,24 @@ pub fn lind_syscall_api( NANOSLEEP_TIME64_SYSCALL => { let clockid = arg1 as u32; let flags = arg2 as i32; - let req = (start_address + arg3) as usize; - let rem = (start_address + arg4) as usize; + let req = match check_and_convert_addr(cageid, start_address + arg3) { + Ok(addr) => addr as usize, + Err(errno) => return syscall_error(errno, "nanosleep", "invalid req address"), + }; + let rem = match check_and_convert_addr(cageid, start_address + arg4) { + Ok(addr) => addr as usize, + Err(errno) => return syscall_error(errno, "nanosleep", "invalid rem address"), + }; interface::cagetable_getref(cageid) .nanosleep_time64_syscall(clockid, flags, req, rem) } WAIT_SYSCALL => { - let mut status = interface::get_i32_ref(start_address + arg1).unwrap(); + let mut status = match check_and_convert_addr(cageid, start_address + arg1) { + Ok(addr) => interface::get_i32_ref(addr).unwrap(), + Err(errno) => return syscall_error(errno, "wait", "invalid status address"), + }; interface::cagetable_getref(cageid) .wait_syscall(&mut status) @@ -1047,7 +1184,10 @@ pub fn lind_syscall_api( WAITPID_SYSCALL => { let pid = arg1 as i32; - let mut status = interface::get_i32_ref(start_address + arg2).unwrap(); + let mut status = match check_and_convert_addr(cageid, start_address + arg2) { + Ok(addr) => interface::get_i32_ref(addr).unwrap(), + Err(errno) => return syscall_error(errno, "waitpid", "invalid status address"), + }; let options = arg3 as i32; interface::cagetable_getref(cageid) From 4189fcfe84e44a73b42a3e085d9f0b0e100d5ae7 Mon Sep 17 00:00:00 2001 From: Chinmay Shringi Date: Tue, 10 Dec 2024 16:28:13 -0500 Subject: [PATCH 11/66] feat: update cage in syscall --- src/RawPOSIX/src/interface/mem.rs | 19 +- src/RawPOSIX/src/safeposix/dispatcher.rs | 466 ++++++++++++----------- 2 files changed, 244 insertions(+), 241 deletions(-) diff --git a/src/RawPOSIX/src/interface/mem.rs b/src/RawPOSIX/src/interface/mem.rs index 3ac6d3742..a17eb4ff0 100644 --- a/src/RawPOSIX/src/interface/mem.rs +++ b/src/RawPOSIX/src/interface/mem.rs @@ -231,20 +231,17 @@ pub fn sbrk_handler(cageid: u64, brk: u32) -> i32 { (PAGESIZE * heap.npages) as i32 } -pub fn check_and_convert_addr(cageid: u64, user_addr: u64) -> Result { - let cage = cagetable_getref(cageid); - let mut vmmap = cage.vmmap.write(); // Changed to write() since check_addr_mapping needs &mut self + +pub fn check_and_convert_addr_ext(cage: &Cage, arg: u64, length: usize, prot: i32) -> Result { + let vmmap = cage.vmmap.read(); - // Convert address to page number - let page_num = (user_addr >> PAGESHIFT) as u32; + let page_num = (arg >> PAGESHIFT) as u32; + let end_page = ((arg + length as u64 + PAGESIZE as u64 - 1) >> PAGESHIFT) as u32; + let npages = end_page - page_num; - // Use existing check_addr_mapping function - // We use 1 page and PROT_READ since we just want to verify the address is valid - if vmmap.check_addr_mapping(page_num, 1, PROT_READ).is_none() { + if vmmap.check_addr_mapping(page_num, npages, prot).is_none() { return Err(Errno::EFAULT); } - // If valid, convert user address to system address - let sys_addr = vmmap.user_to_sys(user_addr as i32) as u64; - Ok(sys_addr) + Ok(vmmap.base_addr as u64 + arg) } diff --git a/src/RawPOSIX/src/safeposix/dispatcher.rs b/src/RawPOSIX/src/safeposix/dispatcher.rs index d5312b017..8c5dc3e9b 100644 --- a/src/RawPOSIX/src/safeposix/dispatcher.rs +++ b/src/RawPOSIX/src/safeposix/dispatcher.rs @@ -205,22 +205,24 @@ pub fn lind_syscall_api( let ret = match call_number { WRITE_SYSCALL => { let fd = arg1 as i32; - let buf = (start_address + arg2) as *const u8; let count = arg3 as usize; - interface::cagetable_getref(cageid) - .write_syscall(fd, buf, count) + let cage = interface::cagetable_getref(cageid); + let buf = match check_and_convert_addr_ext(&cage, arg2, count, PROT_WRITE) { + Ok(addr) => addr as *const u8, + Err(errno) => return syscall_error(errno, "write", "invalid buffer address"), + }; + cage.write_syscall(fd, buf, count) } WRITEV_SYSCALL => { let fd = arg1 as i32; - let iovec = match check_and_convert_addr(cageid, start_address + arg2) { + let cage = interface::cagetable_getref(cageid); + let iovec = match check_and_convert_addr_ext(&cage, arg2, size_of::(), PROT_READ) { Ok(addr) => addr as *const interface::IovecStruct, Err(errno) => return syscall_error(errno, "writev", "invalid iovec address"), }; let iovcnt = arg3 as i32; - - interface::cagetable_getref(cageid) - .writev_syscall(fd, iovec, iovcnt) + cage.writev_syscall(fd, iovec, iovcnt) } MUNMAP_SYSCALL => { @@ -242,28 +244,26 @@ pub fn lind_syscall_api( } PREAD_SYSCALL => { - let fd = arg1 as i32; - let buf = match check_and_convert_addr(cageid, start_address + arg2) { + let count = arg3 as usize; + let cage = interface::cagetable_getref(cageid); + let buf = match check_and_convert_addr_ext(&cage, arg2, count, PROT_READ) { Ok(addr) => addr as *mut u8, Err(errno) => return syscall_error(errno, "pread", "invalid buffer address"), }; - let count = arg3 as usize; let offset = arg4 as i64; - interface::cagetable_getref(cageid) - .pread_syscall(fd, buf, count, offset) + cage.pread_syscall(fd, buf, count, offset) } READ_SYSCALL => { - let fd = arg1 as i32; - let buf = match check_and_convert_addr(cageid, start_address + arg2) { + let count = arg3 as usize; + let cage = interface::cagetable_getref(cageid); + let buf = match check_and_convert_addr_ext(&cage, arg2, count, PROT_READ) { Ok(addr) => addr as *mut u8, Err(errno) => return syscall_error(errno, "read", "invalid buffer address"), }; - let count = arg3 as usize; - interface::cagetable_getref(cageid) - .read_syscall(fd, buf, count) + cage.read_syscall(fd, buf, count) } CLOSE_SYSCALL => { @@ -274,8 +274,9 @@ pub fn lind_syscall_api( } ACCESS_SYSCALL => { - let path = match check_and_convert_addr(cageid, start_address + arg1) { - Ok(addr) => match interface::types::get_cstr(addr) { + let cage = interface::cagetable_getref(cageid); + let path = match check_and_convert_addr_ext(&cage, arg1, 1, PROT_READ) { + Ok(addr) => match interface::types::get_cstr(addr as *const u8) { Ok(path_str) => path_str, Err(_) => return -1, }, @@ -283,13 +284,13 @@ pub fn lind_syscall_api( }; let amode = arg2 as i32; - interface::cagetable_getref(cageid) - .access_syscall(path, amode) + cage.access_syscall(path, amode) } OPEN_SYSCALL => { - let path = match check_and_convert_addr(cageid, start_address + arg1) { - Ok(addr) => match interface::types::get_cstr(addr) { + let cage = interface::cagetable_getref(cageid); + let path = match check_and_convert_addr_ext(&cage, arg1, 1, PROT_READ) { + Ok(addr) => match interface::types::get_cstr(addr as *const u8) { Ok(path_str) => path_str, Err(_) => return -1, }, @@ -298,8 +299,7 @@ pub fn lind_syscall_api( let flags = arg2 as i32; let mode = arg3 as u32; - interface::cagetable_getref(cageid) - .open_syscall(path, flags, mode) + cage.open_syscall(path, flags, mode) } SOCKET_SYSCALL => { @@ -313,8 +313,12 @@ pub fn lind_syscall_api( CONNECT_SYSCALL => { let fd = arg1 as i32; - let addr = match check_and_convert_addr(cageid, start_address + arg2) { - Ok(addr) => interface::get_sockaddr(addr, arg3 as u32).unwrap(), + let cage = interface::cagetable_getref(cageid); + let addr = match check_and_convert_addr_ext(&cage, arg2, arg3 as usize, PROT_READ) { + Ok(addr) => match interface::get_sockaddr(addr as *const u8, arg3 as u32) { + Ok(sockaddr) => sockaddr, + Err(_) => return syscall_error(Errno::EINVAL, "connect", "invalid sockaddr format"), + }, Err(errno) => return syscall_error(errno, "connect", "invalid address"), }; @@ -322,45 +326,46 @@ pub fn lind_syscall_api( Ok(addr) => addr, Err(_) => panic!("Failed to get sockaddr"), // Handle error appropriately }; - interface::cagetable_getref(cageid) - .connect_syscall(fd, remoteaddr) + cage.connect_syscall(fd, remoteaddr) } BIND_SYSCALL => { let fd = arg1 as i32; - let addr = match check_and_convert_addr(cageid, start_address + arg2) { - Ok(addr) => interface::get_sockaddr(addr, arg3 as u32).unwrap(), + let cage = interface::cagetable_getref(cageid); + let addr = match check_and_convert_addr_ext(&cage, arg2, arg3 as usize, PROT_READ) { + Ok(addr) => match interface::get_sockaddr(addr as *const u8, arg3 as u32) { + Ok(sockaddr) => sockaddr, + Err(_) => return syscall_error(Errno::EINVAL, "bind", "invalid sockaddr format"), + }, Err(errno) => return syscall_error(errno, "bind", "invalid address"), }; let localaddr = match Ok::<&interface::GenSockaddr, i32>(&addr) { Ok(addr) => addr, Err(_) => panic!("Failed to get sockaddr"), // Handle error appropriately }; - interface::cagetable_getref(cageid) - .bind_syscall(fd, localaddr) + cage.bind_syscall(fd, localaddr) } ACCEPT_SYSCALL => { let mut addr = interface::GenSockaddr::V4(interface::SockaddrV4::default()); //value doesn't matter let nullity1 = interface::arg_nullity(arg2); let nullity2 = interface::arg_nullity(arg3); + let cage = interface::cagetable_getref(cageid); if nullity1 && nullity2 { - interface::cagetable_getref(cageid) - .accept_syscall(arg1 as i32, &mut Some(&mut addr)) + cage.accept_syscall(arg1 as i32, &mut Some(&mut addr)) } else if !(nullity1 || nullity2) { - let rv = interface::cagetable_getref(cageid) - .accept_syscall(arg1 as i32, &mut Some(&mut addr)); + let rv = cage.accept_syscall(arg1 as i32, &mut Some(&mut addr)); if rv >= 0 { - let addr2_addr = match check_and_convert_addr(cageid, start_address + arg2) { + let addr2_addr = match check_and_convert_addr_ext(&cage, arg2, arg3 as usize, PROT_WRITE) { Ok(addr) => addr, Err(errno) => return syscall_error(errno, "accept", "invalid address buffer"), }; - let len_addr = match check_and_convert_addr(cageid, start_address + arg3) { + let len_addr = match check_and_convert_addr_ext(&cage, arg3, std::mem::size_of::(), PROT_WRITE) { Ok(addr) => addr, Err(errno) => return syscall_error(errno, "accept", "invalid length buffer"), }; - interface::copy_out_sockaddr(addr2_addr, len_addr, addr); + interface::copy_out_sockaddr(addr2_addr as *mut u8, len_addr as *mut u8, addr); } rv } else { @@ -395,74 +400,70 @@ pub fn lind_syscall_api( } RENAME_SYSCALL => { - let old_ptr = match check_and_convert_addr(cageid, start_address + arg1) { - Ok(addr) => addr as *const u8, + let cage = interface::cagetable_getref(cageid); + let old_path = match check_and_convert_addr_ext(&cage, arg1, 1, PROT_READ) { + Ok(addr) => match interface::types::get_cstr(addr) { + Ok(path_str) => path_str, + Err(_) => return -1, + }, Err(errno) => return syscall_error(errno, "rename", "invalid old path address"), }; - let new_ptr = match check_and_convert_addr(cageid, start_address + arg2) { - Ok(addr) => addr as *const u8, + let new_path = match check_and_convert_addr_ext(&cage, arg2, 1, PROT_READ) { + Ok(addr) => match interface::types::get_cstr(addr) { + Ok(path_str) => path_str, + Err(_) => return -1, + }, Err(errno) => return syscall_error(errno, "rename", "invalid new path address"), }; - // Convert the raw pointers to `&str` - let old = unsafe { - CStr::from_ptr(old_ptr as *const i8).to_str().unwrap() - }; - let new = unsafe { - CStr::from_ptr(new_ptr as *const i8).to_str().unwrap() - }; - - interface::cagetable_getref(cageid) - .rename_syscall(old, new) + cage.rename_syscall(old_path, new_path) } XSTAT_SYSCALL => { - let fd_ptr = match check_and_convert_addr(cageid, start_address + arg1) { - Ok(addr) => addr as *const u8, + let cage = interface::cagetable_getref(cageid); + let path = match check_and_convert_addr_ext(&cage, arg1, 1, PROT_READ) { + Ok(addr) => match interface::types::get_cstr(addr) { + Ok(path_str) => path_str, + Err(_) => return -1, + }, Err(errno) => return syscall_error(errno, "xstat", "invalid path address"), }; - let buf = match interface::get_statdatastruct(start_address + arg2) { - Ok(val) => val, - Err(errno) => { - return errno; - } - }; - - let fd = unsafe { - CStr::from_ptr(fd_ptr as *const i8).to_str().unwrap() + let buf = match check_and_convert_addr_ext(&cage, arg2, std::mem::size_of::(), PROT_WRITE) { + Ok(addr) => match interface::get_statdatastruct(addr) { + Ok(val) => val, + Err(errno) => return errno, + }, + Err(errno) => return syscall_error(errno, "xstat", "invalid stat buffer address"), }; - - interface::cagetable_getref(cageid) - .stat_syscall(fd, buf) + + cage.stat_syscall(path, buf) } MKDIR_SYSCALL => { - let fd_ptr = match check_and_convert_addr(cageid, start_address + arg1) { - Ok(addr) => addr as *const u8, + let cage = interface::cagetable_getref(cageid); + let path = match check_and_convert_addr_ext(&cage, arg1, 1, PROT_READ) { + Ok(addr) => match interface::types::get_cstr(addr) { + Ok(path_str) => path_str, + Err(_) => return -1, + }, Err(errno) => return syscall_error(errno, "mkdir", "invalid path address"), }; let mode = arg2 as u32; - - let fd = unsafe { - CStr::from_ptr(fd_ptr as *const i8).to_str().unwrap() - }; - interface::cagetable_getref(cageid) - .mkdir_syscall(fd, mode) + cage.mkdir_syscall(path, mode) } RMDIR_SYSCALL => { - let fd_ptr = match check_and_convert_addr(cageid, start_address + arg1) { - Ok(addr) => addr as *const u8, + let cage = interface::cagetable_getref(cageid); + let path = match check_and_convert_addr_ext(&cage, arg1, 1, PROT_READ) { + Ok(addr) => match interface::types::get_cstr(addr) { + Ok(path_str) => path_str, + Err(_) => return -1, + }, Err(errno) => return syscall_error(errno, "rmdir", "invalid path address"), }; - - let fd = unsafe { - CStr::from_ptr(fd_ptr as *const i8).to_str().unwrap() - }; - interface::cagetable_getref(cageid) - .rmdir_syscall(fd) + cage.rmdir_syscall(path) } FCHDIR_SYSCALL => { @@ -473,51 +474,57 @@ pub fn lind_syscall_api( } CHDIR_SYSCALL => { - let path = match check_and_convert_addr(cageid, start_address + arg1) { - Ok(addr) => interface::types::get_cstr(addr).unwrap(), + let cage = interface::cagetable_getref(cageid); + let path = match check_and_convert_addr_ext(&cage, arg1, 1, PROT_READ) { + Ok(addr) => match interface::types::get_cstr(addr) { + Ok(path_str) => path_str, + Err(_) => return -1, + }, Err(errno) => return syscall_error(errno, "chdir", "invalid path address"), }; - interface::cagetable_getref(cageid) - .chdir_syscall(path) + cage.chdir_syscall(path) } GETCWD_SYSCALL => { - let buf = match check_and_convert_addr(cageid, start_address + arg1) { + let bufsize = arg2 as usize; + let cage = interface::cagetable_getref(cageid); + let buf = match check_and_convert_addr_ext(&cage, arg1, bufsize, PROT_WRITE) { Ok(addr) => addr as *mut u8, Err(errno) => return syscall_error(errno, "getcwd", "invalid buffer address"), }; - let bufsize = arg2 as u32; - let ret = interface::cagetable_getref(cageid) - .getcwd_syscall(buf, bufsize); + let ret = cage.getcwd_syscall(buf, bufsize as u32); if ret == 0 { return arg1 as i32; } ret } FSTATFS_SYSCALL => { let fd = arg1 as i32; - let buf = match check_and_convert_addr(cageid, start_address + arg2) { - Ok(addr) => interface::get_fsdatastruct(addr).unwrap(), + let cage = interface::cagetable_getref(cageid); + let buf = match check_and_convert_addr_ext(&cage, arg2, std::mem::size_of::(), PROT_WRITE) { + Ok(addr) => match interface::get_fsdatastruct(addr) { + Ok(val) => val, + Err(errno) => return errno, + }, Err(errno) => return syscall_error(errno, "fstatfs", "invalid buffer address"), }; - interface::cagetable_getref(cageid) - .fstatfs_syscall(fd, buf) + cage.fstatfs_syscall(fd, buf) } CHMOD_SYSCALL => { - let fd_ptr = match check_and_convert_addr(cageid, start_address + arg1) { - Ok(addr) => addr as *const u8, + let cage = interface::cagetable_getref(cageid); + let path = match check_and_convert_addr_ext(&cage, arg1, 1, PROT_READ) { + Ok(addr) => match interface::types::get_cstr(addr) { + Ok(path_str) => path_str, + Err(_) => return -1, + }, Err(errno) => return syscall_error(errno, "chmod", "invalid path address"), }; - let fd = unsafe { - CStr::from_ptr(fd_ptr as *const i8).to_str().unwrap() - }; let mode = arg2 as u32; - interface::cagetable_getref(cageid) - .chmod_syscall(fd, mode) + cage.chmod_syscall(path, mode) } DUP_SYSCALL => { @@ -550,48 +557,47 @@ pub fn lind_syscall_api( FXSTAT_SYSCALL => { let fd = arg1 as i32; - let buf = match check_and_convert_addr(cageid, start_address + arg2) { + let cage = interface::cagetable_getref(cageid); + let buf = match check_and_convert_addr_ext(&cage, arg2, std::mem::size_of::(), PROT_WRITE) { Ok(addr) => interface::get_statdatastruct(addr).unwrap(), Err(errno) => return syscall_error(errno, "fxstat", "invalid buffer address"), }; - interface::cagetable_getref(cageid) - .fstat_syscall(fd, buf) + cage.fstat_syscall(fd, buf) } UNLINK_SYSCALL => { - let fd_ptr = match check_and_convert_addr(cageid, start_address + arg1) { - Ok(addr) => addr as *const u8, + let cage = interface::cagetable_getref(cageid); + let path = match check_and_convert_addr_ext(&cage, arg1, 1, PROT_READ) { + Ok(addr) => match interface::types::get_cstr(addr) { + Ok(path_str) => path_str, + Err(_) => return -1, + }, Err(errno) => return syscall_error(errno, "unlink", "invalid path address"), }; - let fd = unsafe { - CStr::from_ptr(fd_ptr as *const i8).to_str().unwrap() - }; - - interface::cagetable_getref(cageid) - .unlink_syscall(fd) + cage.unlink_syscall(path) } LINK_SYSCALL => { - let old_ptr = match check_and_convert_addr(cageid, start_address + arg1) { - Ok(addr) => addr as *const u8, + let cage = interface::cagetable_getref(cageid); + let old_path = match check_and_convert_addr_ext(&cage, arg1, 1, PROT_READ) { + Ok(addr) => match interface::types::get_cstr(addr) { + Ok(path_str) => path_str, + Err(_) => return -1, + }, Err(errno) => return syscall_error(errno, "link", "invalid old path address"), }; - let new_ptr = match check_and_convert_addr(cageid, start_address + arg2) { - Ok(addr) => addr as *const u8, + + let new_path = match check_and_convert_addr_ext(&cage, arg2, 1, PROT_READ) { + Ok(addr) => match interface::types::get_cstr(addr) { + Ok(path_str) => path_str, + Err(_) => return -1, + }, Err(errno) => return syscall_error(errno, "link", "invalid new path address"), }; - - let old_fd = unsafe { - CStr::from_ptr(old_ptr as *const i8).to_str().unwrap() - }; - let new_fd = unsafe { - CStr::from_ptr(new_ptr as *const i8).to_str().unwrap() - }; - interface::cagetable_getref(cageid) - .link_syscall(old_fd, new_fd) + cage.link_syscall(old_path, new_path) } LSEEK_SYSCALL => { @@ -613,18 +619,17 @@ pub fn lind_syscall_api( } TRUNCATE_SYSCALL => { - let fd_ptr = match check_and_convert_addr(cageid, start_address + arg1) { - Ok(addr) => addr as *const u8, + let cage = interface::cagetable_getref(cageid); + let path = match check_and_convert_addr_ext(&cage, arg1, 1, PROT_READ) { + Ok(addr) => match interface::types::get_cstr(addr) { + Ok(path_str) => path_str, + Err(_) => return -1, + }, Err(errno) => return syscall_error(errno, "truncate", "invalid path address"), }; let length = arg2 as isize; - let fd = unsafe { - CStr::from_ptr(fd_ptr as *const i8).to_str().unwrap() - }; - - interface::cagetable_getref(cageid) - .truncate_syscall(fd, length) + cage.truncate_syscall(path, length) } FTRUNCATE_SYSCALL => { @@ -637,29 +642,32 @@ pub fn lind_syscall_api( GETDENTS_SYSCALL => { let virtual_fd = arg1 as i32; - let buf = match check_and_convert_addr(cageid, start_address + arg2) { + let nbytes = arg3 as u32; + let cage = interface::cagetable_getref(cageid); + let buf = match check_and_convert_addr_ext(&cage, arg2, nbytes as usize, PROT_WRITE) { Ok(addr) => addr as *mut u8, Err(errno) => return syscall_error(errno, "getdents", "invalid buffer address"), }; - let nbytes = arg3 as u32; - interface::cagetable_getref(cageid) - .getdents_syscall(virtual_fd, buf, nbytes) + cage.getdents_syscall(virtual_fd, buf, nbytes) } STATFS_SYSCALL => { - let fd_ptr = match check_and_convert_addr(cageid, start_address + arg1) { - Ok(addr) => addr as *const u8, + let cage = interface::cagetable_getref(cageid); + let path = match check_and_convert_addr_ext(&cage, arg1, 1, PROT_READ) { + Ok(addr) => match interface::types::get_cstr(addr) { + Ok(path_str) => path_str, + Err(_) => return -1, + }, Err(errno) => return syscall_error(errno, "statfs", "invalid path address"), }; - let rposix_databuf = interface::get_fsdatastruct(start_address + arg2).unwrap(); - let fd = unsafe { - CStr::from_ptr(fd_ptr as *const i8).to_str().unwrap() - }; + let rposix_databuf = match check_and_convert_addr_ext(&cage, arg2, size_of::(), PROT_WRITE) { + Ok(addr) => interface::get_fsdatastruct(addr).unwrap(), + Err(errno) => return syscall_error(errno, "statfs", "invalid stat buffer address"), + }; - interface::cagetable_getref(cageid) - .statfs_syscall(fd, rposix_databuf) + cage.statfs_syscall(&path, rposix_databuf) } FCNTL_SYSCALL => { @@ -672,51 +680,50 @@ pub fn lind_syscall_api( } RECV_SYSCALL => { - let fd = arg1 as i32; - let buf = match check_and_convert_addr(cageid, start_address + arg2) { + let count = arg3 as usize; + let cage = interface::cagetable_getref(cageid); + let buf = match check_and_convert_addr_ext(&cage, arg2, count, PROT_WRITE) { Ok(addr) => addr as *mut u8, Err(errno) => return syscall_error(errno, "recv", "invalid buffer address"), }; - let buflen = arg3 as usize; let flag = arg4 as i32; - interface::cagetable_getref(cageid) - .recv_syscall(fd, buf, buflen, flag) + cage.recv_syscall(fd, buf, count, flag) } SENDTO_SYSCALL => { - let fd = arg1 as i32; - let buf = (start_address + arg2) as *const u8; - let buflen = arg3 as usize; + let count = arg3 as usize; + let cage = interface::cagetable_getref(cageid); + let buf = match check_and_convert_addr_ext(&cage, arg2, count, PROT_READ) { + Ok(addr) => addr as *const u8, + Err(errno) => return syscall_error(errno, "sendto", "invalid buffer address"), + }; let flag = arg4 as i32; let addrlen = arg6 as u32; let addr = interface::get_sockaddr(start_address + arg5, addrlen).unwrap(); - interface::cagetable_getref(cageid) - .sendto_syscall(fd, buf, buflen, flag, &addr) + cage.sendto_syscall(fd, buf, count, flag, &addr) } RECVFROM_SYSCALL => { - let fd = arg1 as i32; - let buf = match check_and_convert_addr(cageid, start_address + arg2) { + let count = arg3 as usize; + let cage = interface::cagetable_getref(cageid); + let buf = match check_and_convert_addr_ext(&cage, arg2, count, PROT_WRITE) { Ok(addr) => addr as *mut u8, Err(errno) => return syscall_error(errno, "recvfrom", "invalid buffer address"), }; - let buflen = arg3 as usize; let flag = arg4 as i32; let nullity1 = interface::arg_nullity(arg5); let nullity2 = interface::arg_nullity(arg6); if nullity1 && nullity2 { - interface::cagetable_getref(cageid) - .recvfrom_syscall(fd, buf, buflen, flag, &mut None) - } + cage.recvfrom_syscall(fd, buf, count, flag, &mut None) + } else if !(nullity1 || nullity2) { let mut newsockaddr = interface::GenSockaddr::V4(interface::SockaddrV4::default()); //dummy value, rust would complain if we used an uninitialized value here - let rv = interface::cagetable_getref(cageid) - .recvfrom_syscall(fd, buf, buflen, flag, &mut Some(&mut newsockaddr)); + let rv = cage.recvfrom_syscall(fd, buf, count, flag, &mut Some(&mut newsockaddr)); if rv >= 0 { interface::copy_out_sockaddr(start_address + arg5, start_address + arg6, newsockaddr); } @@ -749,24 +756,24 @@ pub fn lind_syscall_api( SHMAT_SYSCALL => { let shmid = arg1 as i32; - let shmaddr = match check_and_convert_addr(cageid, start_address + arg2) { + let cage = interface::cagetable_getref(cageid); + let shmaddr = match check_and_convert_addr_ext(&cage, arg2, 1, PROT_READ | PROT_WRITE) { Ok(addr) => addr as *mut u8, Err(errno) => return syscall_error(errno, "shmat", "invalid shared memory address"), }; let shmflg = arg3 as i32; - interface::cagetable_getref(cageid) - .shmat_syscall(shmid, shmaddr, shmflg) + cage.shmat_syscall(shmid, shmaddr, shmflg) } SHMDT_SYSCALL => { - let shmaddr = match check_and_convert_addr(cageid, start_address + arg1) { + let cage = interface::cagetable_getref(cageid); + let shmaddr = match check_and_convert_addr_ext(&cage, arg1, 1, PROT_READ | PROT_WRITE) { Ok(addr) => addr as *mut u8, Err(errno) => return syscall_error(errno, "shmdt", "invalid shared memory address"), }; - interface::cagetable_getref(cageid) - .shmdt_syscall(shmaddr) + cage.shmdt_syscall(shmaddr) } MUTEX_DESTROY_SYSCALL => { @@ -871,16 +878,16 @@ pub fn lind_syscall_api( } PWRITE_SYSCALL => { - let virtual_fd = arg1 as i32; - let buf = match check_and_convert_addr(cageid, start_address + arg2) { + let count = arg3 as usize; + let cage = interface::cagetable_getref(cageid); + let buf = match check_and_convert_addr_ext(&cage, arg2, count, PROT_READ) { Ok(addr) => addr as *const u8, Err(errno) => return syscall_error(errno, "pwrite", "invalid buffer address"), }; - let count = arg3 as usize; + let virtual_fd = arg1 as i32; let offset = arg4 as i64; - interface::cagetable_getref(cageid) - .pwrite_syscall(virtual_fd, buf, count, offset) + cage.pwrite_syscall(virtual_fd, buf, count, offset) } GETUID_SYSCALL => { @@ -934,14 +941,14 @@ pub fn lind_syscall_api( let virtual_fd = arg1 as i32; let level = arg2 as i32; let optname = arg3 as i32; - let optval = match check_and_convert_addr(cageid, start_address + arg4) { + let optlen = arg5 as u32; + let cage = interface::cagetable_getref(cageid); + let optval = match check_and_convert_addr_ext(&cage, arg4, optlen as usize, PROT_READ) { Ok(addr) => addr as *const u8, Err(errno) => return syscall_error(errno, "setsockopt", "invalid optval address"), }; - let optlen = arg5 as u32; - interface::cagetable_getref(cageid) - .setsockopt_syscall( virtual_fd, level, optname, optval, optlen) + cage.setsockopt_syscall(virtual_fd, level, optname, optval, optlen) } SHUTDOWN_SYSCALL => { @@ -958,16 +965,15 @@ pub fn lind_syscall_api( } SEND_SYSCALL => { - let virtual_fd = arg1 as i32; - let buf = match check_and_convert_addr(cageid, start_address + arg2) { + let count = arg3 as usize; + let cage = interface::cagetable_getref(cageid); + let buf = match check_and_convert_addr_ext(&cage, arg2, count, PROT_READ) { Ok(addr) => addr as *const u8, Err(errno) => return syscall_error(errno, "send", "invalid buffer address"), }; - let buflen = arg3 as usize; let flags = arg4 as i32; - interface::cagetable_getref(cageid) - .send_syscall( virtual_fd, buf, buflen, flags) + cage.send_syscall(fd, buf, count, flags) } LISTEN_SYSCALL => { @@ -988,24 +994,23 @@ pub fn lind_syscall_api( } GETHOSTNAME_SYSCALL => { - let name = match check_and_convert_addr(cageid, start_address + arg1) { + let len = arg2 as usize; + let cage = interface::cagetable_getref(cageid); + let name = match check_and_convert_addr_ext(&cage, arg1, len, PROT_WRITE) { Ok(addr) => addr as *mut u8, Err(errno) => return syscall_error(errno, "gethostname", "invalid name address"), }; - let len = arg2 as isize; - let ret = interface::cagetable_getref(cageid) - .gethostname_syscall(name, len); - ret - } + cage.gethostname_syscall(name, len as isize) + } GETIFADDRS_SYSCALL => { - let buf = match check_and_convert_addr(cageid, start_address + arg1) { + let count = arg2 as usize; + let cage = interface::cagetable_getref(cageid); + let buf = match check_and_convert_addr_ext(&cage, arg1, count, PROT_WRITE) { Ok(addr) => addr, Err(errno) => return syscall_error(errno, "getifaddrs", "invalid address"), }; - let count = arg2 as usize; - interface::cagetable_getref(cageid) - .getifaddrs_syscall(buf, count) + cage.getifaddrs_syscall(buf, count) } KILL_SYSCALL => { @@ -1040,33 +1045,34 @@ pub fn lind_syscall_api( } PIPE_SYSCALL => { - let pipe = match check_and_convert_addr(cageid, start_address + arg1) { + let cage = interface::cagetable_getref(cageid); + let pipe = match check_and_convert_addr_ext(&cage, arg1, 8, PROT_WRITE) { Ok(addr) => interface::get_pipearray(addr).unwrap(), Err(errno) => return syscall_error(errno, "pipe", "invalid pipe address"), }; - interface::cagetable_getref(cageid) - .pipe_syscall(pipe) + cage.pipe_syscall(pipe) } PIPE2_SYSCALL => { - let pipe = match check_and_convert_addr(cageid, start_address + arg1) { + let cage = interface::cagetable_getref(cageid); + let pipe = match check_and_convert_addr_ext(&cage, arg1, 8, PROT_WRITE) { Ok(addr) => interface::get_pipearray(addr).unwrap(), Err(errno) => return syscall_error(errno, "pipe2", "invalid pipe address"), }; let flag = arg2 as i32; - interface::cagetable_getref(cageid) - .pipe2_syscall(pipe, flag) + cage.pipe2_syscall(pipe, flag) } GETSOCKNAME_SYSCALL => { let fd = arg1 as i32; - let name_addr = match check_and_convert_addr(cageid, start_address + arg2) { + let cage = interface::cagetable_getref(cageid); + let name_addr = match check_and_convert_addr_ext(&cage, arg2, 16, PROT_WRITE) { Ok(addr) => addr, Err(errno) => return syscall_error(errno, "getsockname", "invalid name address"), }; - let namelen_addr = match check_and_convert_addr(cageid, start_address + arg3) { + let namelen_addr = match check_and_convert_addr_ext(&cage, arg3, 4, PROT_WRITE) { Ok(addr) => addr, Err(errno) => return syscall_error(errno, "getsockname", "invalid length address"), }; @@ -1081,8 +1087,7 @@ pub fn lind_syscall_api( ); } - let rv = interface::cagetable_getref(cageid) - .getsockname_syscall(fd, &mut Some(&mut addr)); + let rv = cage.getsockname_syscall(fd, &mut Some(&mut addr)); if rv >= 0 { interface::copy_out_sockaddr(name_addr, namelen_addr, addr); @@ -1094,40 +1099,40 @@ pub fn lind_syscall_api( let virtual_fd = arg1 as i32; let level = arg2 as i32; let optname = arg3 as i32; + let cage = interface::cagetable_getref(cageid); - let optval_ptr = match check_and_convert_addr(cageid, start_address + arg4) { + let optval_ptr = match check_and_convert_addr_ext(&cage, arg4, 4, PROT_WRITE) { Ok(addr) => addr as *mut i32, Err(errno) => return syscall_error(errno, "getsockopt", "invalid optval address"), }; let optval = unsafe { &mut *optval_ptr }; - interface::cagetable_getref(cageid) - .getsockopt_syscall(virtual_fd, level, optname, optval) + cage.getsockopt_syscall(virtual_fd, level, optname, optval) } SOCKETPAIR_SYSCALL => { let domain = arg1 as i32; let _type = arg2 as i32; let protocol = arg3 as i32; - let virtual_socket_vector = match check_and_convert_addr(cageid, start_address + arg4) { + let cage = interface::cagetable_getref(cageid); + let virtual_socket_vector = match check_and_convert_addr_ext(&cage, arg4, 8, PROT_WRITE) { Ok(addr) => interface::get_sockpair(addr).unwrap(), Err(errno) => return syscall_error(errno, "socketpair", "invalid socket vector address"), }; - interface::cagetable_getref(cageid) - .socketpair_syscall(domain, _type, protocol, virtual_socket_vector) + cage.socketpair_syscall(domain, _type, protocol, virtual_socket_vector) } POLL_SYSCALL => { let nfds = arg2 as u64; - let pollfds = match check_and_convert_addr(cageid, start_address + arg1) { + let cage = interface::cagetable_getref(cageid); + let pollfds = match check_and_convert_addr_ext(&cage, arg1, (nfds * 8) as usize, PROT_READ | PROT_WRITE) { Ok(addr) => interface::get_pollstruct_slice(addr, nfds as usize).unwrap(), Err(errno) => return syscall_error(errno, "poll", "invalid fds address"), }; let timeout = arg3 as i32; - interface::cagetable_getref(cageid) - .poll_syscall(pollfds, nfds, timeout) + cage.poll_syscall(pollfds, nfds, timeout) } GETPID_SYSCALL => { @@ -1142,8 +1147,9 @@ pub fn lind_syscall_api( } FUTEX_SYSCALL => { - let uaddr = match check_and_convert_addr(cageid, start_address + arg1) { - Ok(addr) => addr as u64, + let cage = interface::cagetable_getref(cageid); + let uaddr = match check_and_convert_addr_ext(&cage, arg1, 4, PROT_READ | PROT_WRITE) { + Ok(addr) => addr, Err(errno) => return syscall_error(errno, "futex", "invalid uaddr address"), }; let futex_op = arg2 as u32; @@ -1152,46 +1158,46 @@ pub fn lind_syscall_api( let uaddr2 = arg5 as u32; let val3 = arg6 as u32; - interface::cagetable_getref(cageid) - .futex_syscall(uaddr, futex_op, val, timeout, uaddr2, val3) + cage.futex_syscall(uaddr, futex_op, val, timeout, uaddr2, val3) } NANOSLEEP_TIME64_SYSCALL => { let clockid = arg1 as u32; let flags = arg2 as i32; - let req = match check_and_convert_addr(cageid, start_address + arg3) { + let cage = interface::cagetable_getref(cageid); + + let req = match check_and_convert_addr_ext(&cage, arg3, 16, PROT_READ) { Ok(addr) => addr as usize, Err(errno) => return syscall_error(errno, "nanosleep", "invalid req address"), }; - let rem = match check_and_convert_addr(cageid, start_address + arg4) { - Ok(addr) => addr as usize, + let rem = match check_and_convert_addr_ext(&cage, arg4, 16, PROT_WRITE) { + Ok(addr) => addr as usize, Err(errno) => return syscall_error(errno, "nanosleep", "invalid rem address"), }; - interface::cagetable_getref(cageid) - .nanosleep_time64_syscall(clockid, flags, req, rem) + cage.nanosleep_time64_syscall(clockid, flags, req, rem) } WAIT_SYSCALL => { - let mut status = match check_and_convert_addr(cageid, start_address + arg1) { + let cage = interface::cagetable_getref(cageid); + let status = match check_and_convert_addr_ext(&cage, arg1, 4, PROT_WRITE) { Ok(addr) => interface::get_i32_ref(addr).unwrap(), Err(errno) => return syscall_error(errno, "wait", "invalid status address"), }; - interface::cagetable_getref(cageid) - .wait_syscall(&mut status) + cage.wait_syscall(status) } WAITPID_SYSCALL => { let pid = arg1 as i32; - let mut status = match check_and_convert_addr(cageid, start_address + arg2) { + let cage = interface::cagetable_getref(cageid); + let status = match check_and_convert_addr_ext(&cage, arg2, 4, PROT_WRITE) { Ok(addr) => interface::get_i32_ref(addr).unwrap(), - Err(errno) => return syscall_error(errno, "waitpid", "invalid status address"), + Err(errno) => return syscall_error(errno, "waitpid", "invalid status address"), }; let options = arg3 as i32; - interface::cagetable_getref(cageid) - .waitpid_syscall(pid, &mut status, options) + cage.waitpid_syscall(pid, status, options) } From a6502f68fcad54afe2a0fcbab23d34429c56e652 Mon Sep 17 00:00:00 2001 From: Chinmay Shringi Date: Tue, 10 Dec 2024 16:29:27 -0500 Subject: [PATCH 12/66] feat: added check addr convert comment --- src/RawPOSIX/src/interface/mem.rs | 34 +++++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/src/RawPOSIX/src/interface/mem.rs b/src/RawPOSIX/src/interface/mem.rs index a17eb4ff0..6bc0cf783 100644 --- a/src/RawPOSIX/src/interface/mem.rs +++ b/src/RawPOSIX/src/interface/mem.rs @@ -232,16 +232,42 @@ pub fn sbrk_handler(cageid: u64, brk: u32) -> i32 { } +/// Validates and converts a virtual memory address to a physical address with protection checks +/// +/// This function performs several critical memory management operations: +/// 1. Validates that the requested memory region is properly mapped +/// 2. Checks protection flags match the requested access +/// 3. Converts virtual addresses to physical addresses +/// +/// # Arguments +/// * `cage` - Reference to the memory cage containing the virtual memory map +/// * `arg` - Virtual memory address to check and convert +/// * `length` - Length of the memory region being accessed +/// * `prot` - Protection flags to validate (read/write/execute) +/// +/// # Returns +/// * `Ok(u64)` - Physical memory address if validation succeeds +/// * `Err(Errno)` - EFAULT if memory access would be invalid +/// +/// # Memory Safety +/// This is a critical security function that prevents invalid memory accesses by: +/// - Ensuring addresses are properly aligned to pages +/// - Validating all pages in the region are mapped with correct permissions +/// - Preventing access outside of allocated memory regions pub fn check_and_convert_addr_ext(cage: &Cage, arg: u64, length: usize, prot: i32) -> Result { + // Get read lock on virtual memory map let vmmap = cage.vmmap.read(); - let page_num = (arg >> PAGESHIFT) as u32; - let end_page = ((arg + length as u64 + PAGESIZE as u64 - 1) >> PAGESHIFT) as u32; - let npages = end_page - page_num; + // Calculate page numbers for start and end of region + let page_num = (arg >> PAGESHIFT) as u32; // Starting page number + let end_page = ((arg + length as u64 + PAGESIZE as u64 - 1) >> PAGESHIFT) as u32; // Ending page number (rounded up) + let npages = end_page - page_num; // Total number of pages spanned + // Validate memory mapping and permissions if vmmap.check_addr_mapping(page_num, npages, prot).is_none() { - return Err(Errno::EFAULT); + return Err(Errno::EFAULT); // Return error if mapping invalid } + // Convert to physical address by adding base address Ok(vmmap.base_addr as u64 + arg) } From 63879bab355e49fb3c3c34ae151f2107fcf4ed93 Mon Sep 17 00:00:00 2001 From: Chinmay Shringi Date: Tue, 10 Dec 2024 16:44:37 -0500 Subject: [PATCH 13/66] feat: add comments --- src/RawPOSIX/src/safeposix/vmmap.rs | 422 +++++++++++++++++++++++----- 1 file changed, 359 insertions(+), 63 deletions(-) diff --git a/src/RawPOSIX/src/safeposix/vmmap.rs b/src/RawPOSIX/src/safeposix/vmmap.rs index 368c2880a..731dfd048 100644 --- a/src/RawPOSIX/src/safeposix/vmmap.rs +++ b/src/RawPOSIX/src/safeposix/vmmap.rs @@ -9,7 +9,12 @@ use nodit::{interval::ie, Interval}; /// Used to identify whether the vmmap entry is backed anonymously, /// by an fd, or by a shared memory segment - +/// +/// This enum represents different types of memory backing: +/// - None: Used as a placeholder when no backing type is available +/// - Anonymous: Memory not backed by any file (e.g. heap allocations) +/// - SharedMemory: Memory backed by a shared memory segment, identified by shmid +/// - FileDescriptor: Memory backed by a file, identified by file descriptor #[allow(dead_code)] #[derive(Clone, Copy, PartialEq, Eq, Debug)] pub enum MemoryBackingType { @@ -24,16 +29,16 @@ pub enum MemoryBackingType { /// permissions, file offset, file size, shared memory ID, and backing fields to distinguish memory types. #[derive(Clone, PartialEq, Eq, Debug)] pub struct VmmapEntry { - pub page_num: u32, /* base virtual addr >> NACL_PAGESHIFT */ - pub npages: u32, /* number of pages */ - pub prot: i32, /* mprotect attribute */ - pub maxprot: i32, - pub flags: i32, /* mapping flags */ - pub removed: bool, /* flag set in fn Update(); */ - pub file_offset: i64, /* offset into desc */ - pub file_size: i64, /* backing store size */ - pub cage_id: u64, - pub backing: MemoryBackingType, + pub page_num: u32, // Base virtual address shifted right by NACL_PAGESHIFT + pub npages: u32, // Number of pages in this mapping + pub prot: i32, // Current memory protection flags (read/write/execute) + pub maxprot: i32, // Maximum allowed protection flags + pub flags: i32, // Memory mapping flags (shared/private/fixed/anonymous) + pub removed: bool, // Flag indicating if entry has been marked for removal + pub file_offset: i64, // Offset into the backing file/device + pub file_size: i64, // Size of the backing store + pub cage_id: u64, // Identifier for the security cage + pub backing: MemoryBackingType, // Type of memory backing for this region } @@ -41,6 +46,21 @@ pub struct VmmapEntry { // Constructor to create a new VmmapEntry #[allow(dead_code)] impl VmmapEntry { + /// Creates a new VmmapEntry with the specified parameters + /// + /// Arguments: + /// - page_num: Starting page number of the memory region + /// - npages: Number of pages in the memory region + /// - prot: Initial protection flags for the pages + /// - maxprot: Maximum allowed protection flags + /// - flags: Memory mapping flags + /// - removed: Whether this entry is marked for removal + /// - file_offset: Offset into the backing file/device + /// - file_size: Size of the backing store + /// - cage_id: Security cage identifier + /// - backing: Type of memory backing + /// + /// Returns a new VmmapEntry instance initialized with the provided values pub fn new( page_num: u32, npages: u32, @@ -53,6 +73,7 @@ impl VmmapEntry { cage_id: u64, //This is the cage id to refer to for file backings backing: MemoryBackingType, ) -> Self { + // Create and return a new VmmapEntry with the provided values return VmmapEntry { page_num, npages, @@ -71,26 +92,41 @@ impl VmmapEntry { // this is effectively whatever mode the file was opened with // we need this because we shouldnt be able to change filed backed mappings // to have protections exceeding that of the file + /// Gets the maximum protection flags allowed for file-backed memory mappings + /// + /// Arguments: + /// - cage_id: Security cage identifier + /// - virtual_fd: Virtual file descriptor + /// + /// Returns the maximum protection flags as an i32, based on the file's mode fn get_max_prot(&self, cage_id: u64, virtual_fd: u64) -> i32 { - + // Translate the virtual file descriptor to a real one let wrappedvfd = fdtables::translate_virtual_fd(cage_id, virtual_fd as u64); if wrappedvfd.is_err() { return syscall_error(Errno::EBADF, "fstat", "Bad File Descriptor"); } let vfd = wrappedvfd.unwrap(); - // Declare statbuf by ourselves + // Get file stats using fstat let mut libc_statbuf: libc::stat = unsafe { std::mem::zeroed() }; let libcret = unsafe { libc::fstat(vfd.underfd as i32, &mut libc_statbuf) }; + // Return the file mode which contains protection flags libc_statbuf.st_mode as i32 } } -// VmmapOps trait provides an interface that can be shared by different virtual memory management implementations, -// allowing different Vmmap versions to share the same interface. +/// VmmapOps trait provides an interface that can be shared by different virtual memory management implementations, +/// allowing different Vmmap versions to share the same interface. +/// +/// This trait defines the core operations that any virtual memory map implementation must support: +/// - Adding/removing memory mappings +/// - Updating protection flags +/// - Searching for free space +/// - Querying existing mappings +/// - Iterating over memory regions #[allow(dead_code)] pub trait VmmapOps { @@ -198,6 +234,12 @@ pub trait VmmapOps { ) -> Option>; } +/// Represents a virtual memory map that manages memory regions and their attributes +/// +/// Fields: +/// - entries: NoditMap storing the memory regions indexed by page number +/// - cached_entry: Optional cached entry for performance optimization +/// - base_address: Optional base address for WASM memory #[derive(Clone, PartialEq, Eq, Debug)] pub struct Vmmap { pub entries: NoditMap, VmmapEntry>, // Keyed by `page_num` @@ -209,7 +251,9 @@ pub struct Vmmap { #[allow(dead_code)] impl Vmmap { + /// Creates a new empty virtual memory map pub fn new() -> Self { + // Initialize a new Vmmap with empty entries and no cached entry or base address Vmmap { entries: NoditMap::new(), cached_entry: None, @@ -217,25 +261,58 @@ impl Vmmap { } } - // Method to round page number up to the nearest multiple of pages_per_map + /// Rounds up a page number to the nearest multiple of pages_per_map + /// + /// Arguments: + /// - npages: Number of pages to round up + /// - pages_per_map: Alignment requirement in pages + /// + /// Returns the rounded up page number fn round_page_num_up_to_map_multiple(&self, npages: u32, pages_per_map: u32) -> u32 { + // Add (pages_per_map - 1) to npages and mask off lower bits to round up (npages + pages_per_map - 1) & !(pages_per_map - 1) } - // Method to truncate page number down to the nearest multiple of pages_per_map + /// Truncates a page number down to the nearest multiple of pages_per_map + /// + /// Arguments: + /// - npages: Number of pages to truncate + /// - pages_per_map: Alignment requirement in pages + /// + /// Returns the truncated page number fn trunc_page_num_down_to_map_multiple(&self, npages: u32, pages_per_map: u32) -> u32 { + // Mask off lower bits to truncate down to multiple npages & !(pages_per_map - 1) } + /// Sets the base address for WASM memory + /// + /// Arguments: + /// - base_address: The base address to set pub fn set_base_address(&mut self, base_address: i64) { + // Store the provided base address self.base_address = Some(base_address); } + /// Converts a user address to a system address + /// + /// Arguments: + /// - address: User space address to convert + /// + /// Returns the corresponding system address pub fn user_to_sys(&self, address: i32) -> i64 { + // Add base address to user address to get system address address as i64 + self.base_address.unwrap() } + /// Converts a system address to a user address + /// + /// Arguments: + /// - address: System address to convert + /// + /// Returns the corresponding user space address pub fn sys_to_user(&self, address: i64) -> i32 { + // Subtract base address from system address to get user address (address as i64 - self.base_address.unwrap()) as i32 } @@ -262,7 +339,19 @@ impl Vmmap { } impl VmmapOps for Vmmap { + /// Adds a new entry to the virtual memory map + /// + /// This function inserts a new VmmapEntry into the memory map data structure. + /// The entry is inserted with strict bounds checking to ensure memory safety. + /// + /// Arguments: + /// - vmmap_entry_ref: The VmmapEntry to add containing page numbers, permissions, etc. + /// + /// The interval is created from: + /// - Start: vmmap_entry_ref.page_num + /// - End: vmmap_entry_ref.page_num + vmmap_entry_ref.npages (inclusive) fn add_entry(&mut self, vmmap_entry_ref: VmmapEntry) { + // Create interval from page range and insert entry with strict bounds checking let _ = self.entries.insert_strict( // pages x to y, y included ie( @@ -273,7 +362,25 @@ impl VmmapOps for Vmmap { ); } - // Method to add an entry with override, using update method + /// Adds a new entry to the virtual memory map with overwrite capability + /// + /// This function creates and inserts a new VmmapEntry, overwriting any existing + /// entries that overlap with the specified page range. + /// + /// Arguments: + /// - page_num: Starting page number for the mapping + /// - npages: Number of pages to map + /// - prot: Current protection flags (read/write/execute) + /// - maxprot: Maximum allowed protection flags + /// - flags: Mapping flags (shared/private/fixed/anonymous) + /// - backing: Type of memory backing (Anonymous/SharedMemory/FileDescriptor) + /// - file_offset: Offset into backing file/device + /// - file_size: Size of backing store + /// - cage_id: Security cage identifier + /// + /// Returns: + /// - Ok(()) on success + /// - Err(io::Error) on failure fn add_entry_with_overwrite( &mut self, page_num: u32, @@ -286,6 +393,7 @@ impl VmmapOps for Vmmap { file_size: i64, cage_id: u64, ) -> Result<(), io::Error> { + // Call update() to handle the insertion with overwrite capability self.update( page_num, npages, @@ -293,20 +401,31 @@ impl VmmapOps for Vmmap { maxprot, flags, backing, - false, + false, // Not removing file_offset, file_size, cage_id, ) } + /// Removes a memory mapping from the specified page range + /// /// This function will not return any errors pertaining to the page number not mapping /// to any existing pages, as the remove operation is done on a best efforts basis: /// 1. First an insert overwrite operation with the below page range is performed, causing /// a new interval to be created over the provided page range, appropriately partitioning /// boundary pages. /// 2. This new interval is then deleted, leaving the underlying range unmapped + /// + /// Arguments: + /// - page_num: Starting page number to remove + /// - npages: Number of pages to remove + /// + /// Returns: + /// - Ok(()) on success + /// - Err(io::Error) on failure fn remove_entry(&mut self, page_num: u32, npages: u32) -> Result<(), io::Error> { + // Call update() with remove flag set to true self.update( page_num, npages, @@ -314,14 +433,33 @@ impl VmmapOps for Vmmap { 0, 0, MemoryBackingType::None, - true, + true, // Removing 0, 0, 0, ) } - // Method to update a memory map entry, handling insertion and removal + /// Updates or removes a memory mapping entry + /// + /// This is the core function that handles both insertion and removal of memory mappings. + /// It performs validation and maintains mapping consistency. + /// + /// Arguments: + /// - page_num: Starting page number + /// - npages: Number of pages + /// - prot: Current protection flags + /// - maxprot: Maximum allowed protection + /// - flags: Mapping flags + /// - backing: Type of memory backing + /// - remove: If true, removes the mapping instead of updating + /// - file_offset: Offset into backing file + /// - file_size: Size of backing store + /// - cage_id: Security cage identifier + /// + /// Returns: + /// - Ok(()) on success + /// - Err(io::Error) if npages is 0 or other error occurs fn update( &mut self, page_num: u32, @@ -335,6 +473,7 @@ impl VmmapOps for Vmmap { file_size: i64, cage_id: u64, ) -> Result<(), io::Error> { + // Validate input - number of pages must be non-zero if npages == 0 { return Err(io::Error::new( io::ErrorKind::InvalidInput, @@ -342,10 +481,11 @@ impl VmmapOps for Vmmap { )); } + // Calculate page range let new_region_end_page = page_num + npages; - let new_region_start_page = page_num; // just for ease of understanding + let new_region_start_page = page_num; - // Insert the new entry if not marked for removal + // Create new entry if not removing let new_entry = VmmapEntry { page_num, npages, @@ -358,14 +498,15 @@ impl VmmapOps for Vmmap { removed: false, cage_id, }; + + // Insert new entry, overwriting any existing entries in the range let _ = self .entries .insert_overwrite(ie(new_region_start_page, new_region_end_page), new_entry); + // If removing, delete the entry after insertion if remove { - // strange way to do this, but this is the best using the library we have at hand - // while also maintaining the shrunk down entries - // using remove first, then insert will cause us to lose existing entries + // Remove all entries that overlap with the specified range let _ = self .entries .remove_overlapping(ie(new_region_start_page, new_region_end_page)); @@ -374,16 +515,29 @@ impl VmmapOps for Vmmap { Ok(()) } - // Method to change protection of a memory region - // Modifies protection for existing pages in the region - // Should be able to handle splitting of existing pages when necessary - // Should maintain mapping consistency while changing protections + /// Changes memory protection flags for a range of pages + /// + /// This function modifies the protection flags for existing pages in the specified region. + /// It handles splitting of existing pages when necessary to maintain proper protection boundaries. + /// + /// Arguments: + /// - page_num: Starting page number + /// - npages: Number of pages to modify + /// - new_prot: New protection flags to apply + /// + /// Implementation details: + /// - Handles partial overlaps by splitting entries + /// - Maintains mapping consistency during protection changes + /// - Updates protection flags for fully contained pages fn change_prot(&mut self, page_num: u32, npages: u32, new_prot: i32) { + // Calculate page range let new_region_end_page = page_num + npages; let new_region_start_page = page_num; + // Store intervals that need to be inserted after iteration let mut to_insert = Vec::new(); + // Iterate over overlapping entries for (overlap_interval, entry) in self .entries .overlapping_mut(ie(new_region_start_page, new_region_end_page)) @@ -391,30 +545,51 @@ impl VmmapOps for Vmmap { let mut ent_start = overlap_interval.start(); let ent_end = overlap_interval.end(); + // Case 1: Entry starts before region but extends into it if ent_start < new_region_start_page && ent_end > new_region_start_page { to_insert.push(ie(new_region_start_page, ent_end)); - ent_start = new_region_start_page; // need to update incase next condition is true + ent_start = new_region_start_page; } + + // Case 2: Entry extends beyond region end if ent_start < new_region_end_page && ent_end > new_region_end_page { to_insert.push(ie(ent_start, new_region_end_page)); } else { + // Case 3: Entry is fully contained - update protection entry.prot = new_prot; } } + // Insert new intervals with updated protection for interval in to_insert { + // Get and clone the entry at the start of the interval let mut interval_val = self.entries.get_at_point(interval.start()).unwrap().clone(); + // Update protection interval_val.prot = new_prot; + // Insert the new interval let _ = self.entries.insert_overwrite(interval, interval_val); } } - // Method to check if a mapping exists + /// Checks if a memory mapping exists with specified protection + /// + /// Verifies if a continuous mapping exists for the given page range + /// and checks if the requested protection flags are compatible. + /// + /// Arguments: + /// - page_num: Starting page number to check + /// - npages: Number of pages to verify + /// - prot: Required protection flags + /// + /// Returns: + /// - true if mapping exists with compatible protection + /// - false if mapping doesn't exist or protection is incompatible fn check_existing_mapping(&self, page_num: u32, npages: u32, prot: i32) -> bool { + // Calculate end page and create interval for region let region_end_page = page_num + npages; let region_interval = ie(page_num, region_end_page); - // If no overlap, return false + // Case 1: No overlapping entries exist if !self.entries.overlaps(region_interval) { return false; } @@ -426,20 +601,20 @@ impl VmmapOps for Vmmap { let ent_end_page = entry.page_num + entry.npages; let flags = entry.maxprot; - // Case 1: Fully inside the existing entry + // Case 2: Region is fully inside existing entry if entry.page_num <= current_page && region_end_page <= ent_end_page { return (prot & !flags) == 0; } - // Case 2: Overlaps with the current entry + // Case 3: Region overlaps with current entry if entry.page_num <= current_page && current_page < ent_end_page { if (prot & !flags) != 0 { return false; } - current_page = ent_end_page; // Move to the next region + current_page = ent_end_page; // Move to next region } - // Case 3: If there's a gap (no backing store), return false + // Case 4: Gap between entries if current_page < entry.page_num { return false; } @@ -448,92 +623,154 @@ impl VmmapOps for Vmmap { false } - // Method to check address mapping, using cached entry if possible + /// Checks address mapping with caching optimization + /// + /// Verifies memory mapping and protection flags for a page range, + /// using a cached entry when possible for better performance. + /// + /// Arguments: + /// - page_num: Starting page number + /// - npages: Number of pages to check + /// - prot: Required protection flags + /// + /// Returns: + /// - Some(end_page) if mapping exists and protection is compatible + /// - None if mapping invalid or protection incompatible + /// + /// Implementation details: + /// - Uses cached entry for quick lookups + /// - Enforces PROT_READ when other protections are set + /// - Handles partial overlaps and gaps fn check_addr_mapping(&mut self, page_num: u32, npages: u32, prot: i32) -> Option { + // Calculate end page of region let region_end_page = page_num + npages; - // First, check if the cached entry can be used + // Case 1: Check cached entry first for performance if let Some(ref cached_entry) = self.cached_entry { let ent_end_page = cached_entry.page_num + cached_entry.npages; let mut flags = cached_entry.prot; - // If the protection is not PROT_NONE, enforce PROT_READ + // Enforce PROT_READ if any protection exists if flags & (PROT_EXEC | PROT_READ | PROT_WRITE) != PROT_NONE { flags |= PROT_READ; } + // Check if region is inside cached entry with compatible protection if cached_entry.page_num <= page_num && region_end_page <= ent_end_page { if prot & !flags == 0 { - return Some(ent_end_page); // Mapping found inside the cached entry + return Some(ent_end_page); } } } - // If no cached entry, check the overlapping regions in memory map + // Case 2: Check overlapping entries if cache miss let mut current_page = page_num; for (_, entry) in self.entries.overlapping(ie(page_num, region_end_page)) { let ent_end_page = entry.page_num + entry.npages; let mut flags = entry.prot; - // If the protection is not PROT_NONE, enforce PROT_READ + // Enforce PROT_READ if any protection exists if flags & (PROT_EXEC | PROT_READ | PROT_WRITE) != PROT_NONE { flags |= PROT_READ; } + // Case 2a: Region fully inside entry if entry.page_num <= current_page && region_end_page <= ent_end_page { - // Mapping is fully inside the current entry - self.cached_entry = Some(entry.clone()); // Cache the entry + self.cached_entry = Some(entry.clone()); // Update cache if prot & !flags == 0 { return Some(ent_end_page); } - } else if entry.page_num <= current_page && current_page < ent_end_page { - // Mapping overlaps with this entry + } + // Case 2b: Partial overlap + else if entry.page_num <= current_page && current_page < ent_end_page { if prot & !flags != 0 { return None; } current_page = ent_end_page; // Move to next region - } else if current_page < entry.page_num { - // There's a gap between entries, return failure + } + // Case 2c: Gap between entries + else if current_page < entry.page_num { return None; } } - // If no valid mapping is found, return None + // Case 3: No valid mapping found None } - //Method to find a page in the memory map + /// Finds a page entry in the memory map + /// + /// Arguments: + /// - page_num: Page number to find + /// + /// Returns: + /// - Some(&VmmapEntry) if page exists + /// - None if page not found fn find_page(&self, page_num: u32) -> Option<&VmmapEntry> { + // Look up entry containing the specified page number self.entries.get_at_point(page_num) } - // Method to find a mutable page in the memory map + + /// Finds a mutable page entry in the memory map + /// + /// Arguments: + /// - page_num: Page number to find + /// + /// Returns: + /// - Some(&mut VmmapEntry) if page exists + /// - None if page not found fn find_page_mut(&mut self, page_num: u32) -> Option<&mut VmmapEntry> { + // Look up mutable entry containing the specified page number self.entries.get_at_point_mut(page_num) } - // Method to get the last entry in the memory map + /// Gets the last entry in the memory map + /// + /// Returns: + /// - Some((interval, entry)) containing the last mapping + /// - None if map is empty fn last_entry(&self) -> Option<(&Interval, &VmmapEntry)> { + // Return the last key-value pair in the map self.entries.last_key_value() } - // Method to get the first entry in the memory map + /// Gets the first entry in the memory map + /// + /// Returns: + /// - Some((interval, entry)) containing the first mapping + /// - None if map is empty fn first_entry(&self) -> Option<(&Interval, &VmmapEntry)> { + // Return the first key-value pair in the map self.entries.first_key_value() } - // Method to iterate over entries in both directions + /// Creates a double-ended iterator over all entries + /// + /// Returns an iterator that can traverse entries in both directions fn double_ended_iter(&self) -> impl DoubleEndedIterator, &VmmapEntry)> { + // Return iterator over all entries self.entries.iter() } - // Method to iterate over mutable entries in both directions + /// Creates a double-ended iterator over all entries with mutable access + /// + /// Returns an iterator that can traverse entries in both directions + /// and modify the entries fn double_ended_iter_mut( &mut self, ) -> impl DoubleEndedIterator, &mut VmmapEntry)> { + // Return mutable iterator over all entries self.entries.iter_mut() } - // Method to iterate over pages, starting from a given page number + /// Creates an iterator over pages starting from a given page number + /// + /// Arguments: + /// - page_num: Starting page number for iteration + /// + /// Returns: + /// - Iterator over entries from page_num to end of map + /// - Empty iterator if map is empty fn find_page_iter( &self, page_num: u32, @@ -546,7 +783,14 @@ impl VmmapOps for Vmmap { } } - // Method to iterate over mutable pages, starting from a given page number + /// Creates a mutable iterator over pages starting from a given page number + /// + /// Arguments: + /// - page_num: Starting page number for iteration + /// + /// Returns: + /// - Mutable iterator over entries from page_num to end of map + /// - Empty iterator if map is empty fn find_page_iter_mut( &mut self, page_num: u32, @@ -560,7 +804,17 @@ impl VmmapOps for Vmmap { } } - // Method to find space in the memory map + /// Finds available space in the memory map for a new mapping + /// + /// Searches for a gap between existing mappings that can accommodate + /// the requested number of pages. + /// + /// Arguments: + /// - npages: Number of pages needed + /// + /// Returns: + /// - Some(Interval) containing the found space + /// - None if no suitable space found fn find_space(&self, npages: u32) -> Option> { let start = self.first_entry(); let end = self.last_entry(); @@ -586,7 +840,18 @@ impl VmmapOps for Vmmap { None } - // Method to find space above a hint + /// Finds available space above a hint address + /// + /// Searches for a gap that can accommodate the requested pages, + /// starting from the hint address. + /// + /// Arguments: + /// - npages: Number of pages needed + /// - hint: Starting address to search from + /// + /// Returns: + /// - Some(Interval) containing the found space + /// - None if no suitable space found fn find_space_above_hint(&self, npages: u32, hint: u32) -> Option> { let start = hint; let end = self.last_entry(); @@ -608,7 +873,22 @@ impl VmmapOps for Vmmap { None } - // Method to find map space, rounding page numbers up to the nearest multiple of pages_per_map + /// Finds space for a mapping with alignment constraints + /// + /// Searches for available space that satisfies both size and + /// alignment requirements specified by pages_per_map. + /// + /// Arguments: + /// - num_pages: Number of pages needed + /// - pages_per_map: Alignment requirement in pages + /// + /// Returns: + /// - Some(Interval) containing aligned space + /// - None if no suitable space found + /// + /// Implementation details: + /// - Rounds page numbers up to alignment boundaries + /// - Handles alignment constraints for start and end addresses fn find_map_space(&self, num_pages: u32, pages_per_map: u32) -> Option> { let start = self.first_entry(); let end = self.last_entry(); @@ -641,7 +921,24 @@ impl VmmapOps for Vmmap { None } - // Method to find map space with a hint, rounding page numbers up to the nearest multiple of pages_per_map + /// Finds aligned space above a hint address + /// + /// Searches for available space that satisfies both size and + /// alignment requirements, starting from the hint address. + /// + /// Arguments: + /// - num_pages: Number of pages needed + /// - pages_per_map: Alignment requirement in pages + /// - hint: Starting address to search from + /// + /// Returns: + /// - Some(Interval) containing aligned space + /// - None if no suitable space found + /// + /// Implementation details: + /// - Rounds page numbers up to alignment boundaries + /// - Handles alignment constraints for start and end addresses + /// - Searches only above the hint address fn find_map_space_with_hint( &self, num_pages: u32, @@ -675,4 +972,3 @@ impl VmmapOps for Vmmap { None } } - From 23e500ee8b1a85d561242ce09db3e8492575bd13 Mon Sep 17 00:00:00 2001 From: Chinmay Shringi Date: Sat, 21 Dec 2024 13:31:38 -0500 Subject: [PATCH 14/66] feat: build fixes --- src/RawPOSIX/src/safeposix/cage.rs | 10 +++++++--- src/RawPOSIX/src/safeposix/dispatcher.rs | 5 +++++ src/RawPOSIX/src/safeposix/syscalls/sys_calls.rs | 4 ++++ 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/src/RawPOSIX/src/safeposix/cage.rs b/src/RawPOSIX/src/safeposix/cage.rs index ef20f0bf8..415c3e3cb 100644 --- a/src/RawPOSIX/src/safeposix/cage.rs +++ b/src/RawPOSIX/src/safeposix/cage.rs @@ -8,7 +8,7 @@ use crate::constants::{ MAP_SHARED, MAP_PRIVATE, }; -// Going to get the datatypes and errnos from the cage file from now on +//going to get the datatypes and errnos from the cage file from now on pub use crate::interface::errnos::{syscall_error, Errno}; pub use crate::interface::types::{ @@ -16,8 +16,12 @@ pub use crate::interface::types::{ }; use super::filesystem::normpath; - +pub use super::syscalls::fs_constants::*; +pub use super::syscalls::net_constants::*; +pub use super::syscalls::sys_constants::*; pub use super::vmmap::*; +pub use super::vmmap_constants::*; + pub use crate::interface::CAGE_TABLE; #[derive(Debug, Clone, Copy)] @@ -83,7 +87,7 @@ pub struct Cage { // its parent cage's zombies list pub zombies: interface::RustLock>, pub child_num: interface::RustAtomicU64 - pub vmmap: Vmmap, + pub vmmap: interface::RustLock, } impl Cage { diff --git a/src/RawPOSIX/src/safeposix/dispatcher.rs b/src/RawPOSIX/src/safeposix/dispatcher.rs index 3b2ab00e9..8c5dc3e9b 100644 --- a/src/RawPOSIX/src/safeposix/dispatcher.rs +++ b/src/RawPOSIX/src/safeposix/dispatcher.rs @@ -161,6 +161,9 @@ pub extern "C" fn rustposix_thread_init(cageid: u64, signalflag: u64) { cage.sigset .insert(pthreadid, interface::RustAtomicU64::new(0)); } + + cage.pendingsigset + .insert(pthreadid, interface::RustAtomicU64::new(0)); interface::signalflag_set(signalflag); } @@ -1320,6 +1323,7 @@ pub fn lindrustinit(verbosity: isize) { thread_table: interface::RustHashMap::new(), signalhandler: interface::RustHashMap::new(), sigset: interface::RustHashMap::new(), + pendingsigset: interface::RustHashMap::new(), main_threadid: interface::RustAtomicU64::new(0), interval_timer: interface::IntervalTimer::new(0), vmmap: interface::RustLock::new(Vmmap::new()) // Initialize empty virtual memory map for new process @@ -1361,6 +1365,7 @@ pub fn lindrustinit(verbosity: isize) { thread_table: interface::RustHashMap::new(), signalhandler: interface::RustHashMap::new(), sigset: interface::RustHashMap::new(), + pendingsigset: interface::RustHashMap::new(), main_threadid: interface::RustAtomicU64::new(0), interval_timer: interface::IntervalTimer::new(1), vmmap: interface::RustLock::new(Vmmap::new()) // Initialize empty virtual memory map for new process diff --git a/src/RawPOSIX/src/safeposix/syscalls/sys_calls.rs b/src/RawPOSIX/src/safeposix/syscalls/sys_calls.rs index 6d60ebfea..0fc738a3c 100644 --- a/src/RawPOSIX/src/safeposix/syscalls/sys_calls.rs +++ b/src/RawPOSIX/src/safeposix/syscalls/sys_calls.rs @@ -177,6 +177,7 @@ impl Cage { thread_table: interface::RustHashMap::new(), signalhandler: self.signalhandler.clone(), sigset: newsigset, + pendingsigset: interface::RustHashMap::new(), main_threadid: interface::RustAtomicU64::new(0), interval_timer: interface::IntervalTimer::new(child_cageid), vmmap: interface::RustLock::new(Vmmap::new()) // Initialize empty virtual memory map for new process @@ -187,6 +188,7 @@ impl Cage { // increment child counter for parent self.child_num.fetch_add(1, interface::RustAtomicOrdering::SeqCst); + let shmtable = &SHM_METADATA.shmtable; //update fields for shared mappings in cage for rev_mapping in cageobj.rev_shm.lock().iter() { @@ -259,6 +261,7 @@ impl Cage { thread_table: interface::RustHashMap::new(), signalhandler: interface::RustHashMap::new(), sigset: newsigset, + pendingsigset: interface::RustHashMap::new(), main_threadid: interface::RustAtomicU64::new(0), interval_timer: self.interval_timer.clone_with_new_cageid(child_cageid), vmmap: interface::RustLock::new(Vmmap::new()) // Fresh clean vmmap @@ -312,6 +315,7 @@ impl Cage { status } + //------------------------------------WAITPID SYSCALL------------------------------------ /* * waitpid() will return the cageid of waited cage, or 0 when WNOHANG is set and there is no cage already exited From d9e67e1f8b37829e9886dce63c6838725002b4a7 Mon Sep 17 00:00:00 2001 From: Chinmay Shringi Date: Sat, 21 Dec 2024 19:07:50 +0000 Subject: [PATCH 15/66] feat: fixed build errors --- src/RawPOSIX/src/constants/fs_constants.rs | 15 ++------- src/RawPOSIX/src/interface/mem.rs | 12 ++++--- src/RawPOSIX/src/safeposix/cage.rs | 10 +++--- src/RawPOSIX/src/safeposix/dispatcher.rs | 32 +++++++++++-------- src/RawPOSIX/src/safeposix/shm.rs | 4 +-- .../src/safeposix/syscalls/sys_calls.rs | 4 +-- src/RawPOSIX/src/safeposix/vmmap.rs | 4 ++- src/safeposix/shm.rs | 19 +++++++++++ 8 files changed, 59 insertions(+), 41 deletions(-) create mode 100644 src/safeposix/shm.rs diff --git a/src/RawPOSIX/src/constants/fs_constants.rs b/src/RawPOSIX/src/constants/fs_constants.rs index 79a1cf04e..e4d53d840 100644 --- a/src/RawPOSIX/src/constants/fs_constants.rs +++ b/src/RawPOSIX/src/constants/fs_constants.rs @@ -110,17 +110,11 @@ pub const LOCK_EX: i32 = 2; pub const LOCK_UN: i32 = 8; pub const LOCK_NB: i32 = 4; //for mmap/munmap syscall -pub const MAP_SHARED: i32 = 1; -pub const MAP_PRIVATE: i32 = 2; -pub const MAP_FIXED: i32 = 16; -pub const MAP_ANONYMOUS: i32 = 32; +pub const MAP_FIXED: u32 = 16; +pub const MAP_ANONYMOUS: u32 = 32; pub const MAP_HUGE_SHIFT: i32 = 26; pub const MAP_HUGETLB: i32 = 262144; -pub const PROT_NONE: i32 = 0; -pub const PROT_READ: i32 = 1; -pub const PROT_WRITE: i32 = 2; -pub const PROT_EXEC: i32 = 4; pub const SEEK_SET: i32 = 0; // Seek from beginning of file pub const SEEK_CUR: i32 = 1; // Seek from current position @@ -170,9 +164,7 @@ pub const MAP_SHARED: u32 = 0x01; // Share changes with other processes pub const MAP_PRIVATE: u32 = 0x02; // Changes are private to this process pub const MAP_SHARING_MASK: u32 = 0x03; // Mask to isolate sharing bits -pub const MAP_FIXED: u32 = 0x10; // Interpret address exactly pub const MAP_ANON: u32 = 0x20; // Don't use a file descriptor -pub const MAP_ANONYMOUS: u32 = MAP_ANON; // Linux alias for MAP_ANON // ===== Page Size Constants ===== // Note: These values are architecture-dependent @@ -197,6 +189,3 @@ pub const MREMAP_FIXED: u32 = 0x02; // New address is specified exactly // Source: include/uapi/asm-generic/fcntl.h // NOTE: These should probably be moved to fs_constants.rs pub const O_ACCMODE: i32 = 0o003; // Mask for file access modes -pub const O_RDONLY: i32 = 0o0; // Open read-only -pub const O_WRONLY: i32 = 0o1; // Open write-only -pub const O_RDWR: i32 = 0o2; // Open read-write diff --git a/src/RawPOSIX/src/interface/mem.rs b/src/RawPOSIX/src/interface/mem.rs index 6bc0cf783..3a0b1a779 100644 --- a/src/RawPOSIX/src/interface/mem.rs +++ b/src/RawPOSIX/src/interface/mem.rs @@ -2,10 +2,11 @@ use crate::constants::{ MAP_ANONYMOUS, MAP_FIXED, MAP_PRIVATE, PROT_EXEC, }; -use crate::safeposix::cage::{MemoryBackingType, Vmmap, VmmapOps, MAP_SHARED, PAGESHIFT, PAGESIZE, PROT_NONE, PROT_READ, PROT_WRITE}; +use crate::safeposix::vmmap::{MemoryBackingType, Vmmap, VmmapOps}; +use crate::constants::{MAP_SHARED, PROT_NONE, PROT_READ, PROT_WRITE, PAGESHIFT, PAGESIZE}; use crate::interface::{cagetable_getref, syscall_error, Errno}; - +use crate::safeposix::cage::Cage; use std::result::Result; // heap is placed at the very top of the memory @@ -88,7 +89,7 @@ pub fn mmap_handler(cageid: u64, addr: *mut u8, len: usize, mut prot: i32, mut f let cage = cagetable_getref(cageid); // only these four flags are allowed - let allowed_flags = (MAP_FIXED as i32 | MAP_SHARED as i32 | MAP_PRIVATE as i32 | MAP_ANONYMOUS as i32); + let allowed_flags = MAP_FIXED as i32 | MAP_SHARED as i32 | MAP_PRIVATE as i32 | MAP_ANONYMOUS as i32; if flags & !allowed_flags > 0 { // truncate flag to remove flags that are not allowed flags &= allowed_flags; @@ -256,7 +257,8 @@ pub fn sbrk_handler(cageid: u64, brk: u32) -> i32 { /// - Preventing access outside of allocated memory regions pub fn check_and_convert_addr_ext(cage: &Cage, arg: u64, length: usize, prot: i32) -> Result { // Get read lock on virtual memory map - let vmmap = cage.vmmap.read(); + // TODO: need to add change here based on the protection, currently fixed for build error + let mut vmmap = cage.vmmap.write(); // Calculate page numbers for start and end of region let page_num = (arg >> PAGESHIFT) as u32; // Starting page number @@ -269,5 +271,5 @@ pub fn check_and_convert_addr_ext(cage: &Cage, arg: u64, length: usize, prot: i3 } // Convert to physical address by adding base address - Ok(vmmap.base_addr as u64 + arg) + Ok(vmmap.base_address.unwrap() as u64 + arg) } diff --git a/src/RawPOSIX/src/safeposix/cage.rs b/src/RawPOSIX/src/safeposix/cage.rs index 415c3e3cb..78de79c95 100644 --- a/src/RawPOSIX/src/safeposix/cage.rs +++ b/src/RawPOSIX/src/safeposix/cage.rs @@ -16,11 +16,8 @@ pub use crate::interface::types::{ }; use super::filesystem::normpath; -pub use super::syscalls::fs_constants::*; -pub use super::syscalls::net_constants::*; -pub use super::syscalls::sys_constants::*; +use crate::constants::*; pub use super::vmmap::*; -pub use super::vmmap_constants::*; pub use crate::interface::CAGE_TABLE; @@ -70,6 +67,9 @@ pub struct Cage { // currently blocked for the corresponding thread in the cage. Interacts with sigprocmask_syscall() to // block / unblock / replace the signal mask for a thread. pub sigset: interface::RustHashMap, + // pendingsigset is a mapping of thread IDs to atomic signal sets representing signals that are pending + // for each thread + pub pendingsigset: interface::RustHashMap, // The kernel thread id of the main thread of current cage, used because when we want to send signals, // we want to send to the main thread pub main_threadid: interface::RustAtomicU64, @@ -86,7 +86,7 @@ pub struct Cage { // and cage struct is cleaned up, but its exit status are inserted along with its cage id into the end of // its parent cage's zombies list pub zombies: interface::RustLock>, - pub child_num: interface::RustAtomicU64 + pub child_num: interface::RustAtomicU64, pub vmmap: interface::RustLock, } diff --git a/src/RawPOSIX/src/safeposix/dispatcher.rs b/src/RawPOSIX/src/safeposix/dispatcher.rs index 8c5dc3e9b..ecdfbe34e 100644 --- a/src/RawPOSIX/src/safeposix/dispatcher.rs +++ b/src/RawPOSIX/src/safeposix/dispatcher.rs @@ -137,7 +137,8 @@ use crate::interface::types; use crate::interface::{SigactionStruct, StatData}; use crate::{fdtables, interface}; use crate::interface::errnos::*; -use crate::constants::{O_RDONLY, O_WRONLY}; +use crate::constants::*; +use crate::interface::check_and_convert_addr_ext; macro_rules! get_onearg { ($arg: expr) => { @@ -244,6 +245,7 @@ pub fn lind_syscall_api( } PREAD_SYSCALL => { + let fd = arg1 as i32; let count = arg3 as usize; let cage = interface::cagetable_getref(cageid); let buf = match check_and_convert_addr_ext(&cage, arg2, count, PROT_READ) { @@ -256,6 +258,7 @@ pub fn lind_syscall_api( } READ_SYSCALL => { + let fd = arg1 as i32; let count = arg3 as usize; let cage = interface::cagetable_getref(cageid); let buf = match check_and_convert_addr_ext(&cage, arg2, count, PROT_READ) { @@ -276,7 +279,7 @@ pub fn lind_syscall_api( ACCESS_SYSCALL => { let cage = interface::cagetable_getref(cageid); let path = match check_and_convert_addr_ext(&cage, arg1, 1, PROT_READ) { - Ok(addr) => match interface::types::get_cstr(addr as *const u8) { + Ok(addr) => match interface::types::get_cstr(addr as u64) { Ok(path_str) => path_str, Err(_) => return -1, }, @@ -290,7 +293,7 @@ pub fn lind_syscall_api( OPEN_SYSCALL => { let cage = interface::cagetable_getref(cageid); let path = match check_and_convert_addr_ext(&cage, arg1, 1, PROT_READ) { - Ok(addr) => match interface::types::get_cstr(addr as *const u8) { + Ok(addr) => match interface::types::get_cstr(addr as u64) { Ok(path_str) => path_str, Err(_) => return -1, }, @@ -315,7 +318,7 @@ pub fn lind_syscall_api( let fd = arg1 as i32; let cage = interface::cagetable_getref(cageid); let addr = match check_and_convert_addr_ext(&cage, arg2, arg3 as usize, PROT_READ) { - Ok(addr) => match interface::get_sockaddr(addr as *const u8, arg3 as u32) { + Ok(addr) => match interface::get_sockaddr(addr as u64, arg3 as u32) { Ok(sockaddr) => sockaddr, Err(_) => return syscall_error(Errno::EINVAL, "connect", "invalid sockaddr format"), }, @@ -333,7 +336,7 @@ pub fn lind_syscall_api( let fd = arg1 as i32; let cage = interface::cagetable_getref(cageid); let addr = match check_and_convert_addr_ext(&cage, arg2, arg3 as usize, PROT_READ) { - Ok(addr) => match interface::get_sockaddr(addr as *const u8, arg3 as u32) { + Ok(addr) => match interface::get_sockaddr(addr as u64, arg3 as u32) { Ok(sockaddr) => sockaddr, Err(_) => return syscall_error(Errno::EINVAL, "bind", "invalid sockaddr format"), }, @@ -365,7 +368,7 @@ pub fn lind_syscall_api( Ok(addr) => addr, Err(errno) => return syscall_error(errno, "accept", "invalid length buffer"), }; - interface::copy_out_sockaddr(addr2_addr as *mut u8, len_addr as *mut u8, addr); + interface::copy_out_sockaddr(addr2_addr as u64, len_addr as u64, addr); } rv } else { @@ -498,11 +501,10 @@ pub fn lind_syscall_api( if ret == 0 { return arg1 as i32; } ret } - FSTATFS_SYSCALL => { let fd = arg1 as i32; let cage = interface::cagetable_getref(cageid); - let buf = match check_and_convert_addr_ext(&cage, arg2, std::mem::size_of::(), PROT_WRITE) { + let buf = match check_and_convert_addr_ext(&cage, arg2, 1, PROT_WRITE) { Ok(addr) => match interface::get_fsdatastruct(addr) { Ok(val) => val, Err(errno) => return errno, @@ -662,7 +664,7 @@ pub fn lind_syscall_api( Err(errno) => return syscall_error(errno, "statfs", "invalid path address"), }; - let rposix_databuf = match check_and_convert_addr_ext(&cage, arg2, size_of::(), PROT_WRITE) { + let rposix_databuf = match check_and_convert_addr_ext(&cage, arg2, 1, PROT_WRITE) { Ok(addr) => interface::get_fsdatastruct(addr).unwrap(), Err(errno) => return syscall_error(errno, "statfs", "invalid stat buffer address"), }; @@ -680,6 +682,7 @@ pub fn lind_syscall_api( } RECV_SYSCALL => { + let fd = arg1 as i32; let count = arg3 as usize; let cage = interface::cagetable_getref(cageid); let buf = match check_and_convert_addr_ext(&cage, arg2, count, PROT_WRITE) { @@ -692,6 +695,7 @@ pub fn lind_syscall_api( } SENDTO_SYSCALL => { + let fd = arg1 as i32; let count = arg3 as usize; let cage = interface::cagetable_getref(cageid); let buf = match check_and_convert_addr_ext(&cage, arg2, count, PROT_READ) { @@ -707,6 +711,7 @@ pub fn lind_syscall_api( } RECVFROM_SYSCALL => { + let fd = arg1 as i32; let count = arg3 as usize; let cage = interface::cagetable_getref(cageid); let buf = match check_and_convert_addr_ext(&cage, arg2, count, PROT_WRITE) { @@ -944,7 +949,7 @@ pub fn lind_syscall_api( let optlen = arg5 as u32; let cage = interface::cagetable_getref(cageid); let optval = match check_and_convert_addr_ext(&cage, arg4, optlen as usize, PROT_READ) { - Ok(addr) => addr as *const u8, + Ok(addr) => addr as *mut u8, Err(errno) => return syscall_error(errno, "setsockopt", "invalid optval address"), }; @@ -965,6 +970,7 @@ pub fn lind_syscall_api( } SEND_SYSCALL => { + let fd = arg1 as i32; let count = arg3 as usize; let cage = interface::cagetable_getref(cageid); let buf = match check_and_convert_addr_ext(&cage, arg2, count, PROT_READ) { @@ -1007,7 +1013,7 @@ pub fn lind_syscall_api( let count = arg2 as usize; let cage = interface::cagetable_getref(cageid); let buf = match check_and_convert_addr_ext(&cage, arg1, count, PROT_WRITE) { - Ok(addr) => addr, + Ok(addr) => addr as *mut u8, Err(errno) => return syscall_error(errno, "getifaddrs", "invalid address"), }; cage.getifaddrs_syscall(buf, count) @@ -1326,7 +1332,7 @@ pub fn lindrustinit(verbosity: isize) { pendingsigset: interface::RustHashMap::new(), main_threadid: interface::RustAtomicU64::new(0), interval_timer: interface::IntervalTimer::new(0), - vmmap: interface::RustLock::new(Vmmap::new()) // Initialize empty virtual memory map for new process + vmmap: interface::RustLock::new(Vmmap::new()), // Initialize empty virtual memory map for new process zombies: interface::RustLock::new(vec![]), child_num: interface::RustAtomicU64::new(0), }; @@ -1368,7 +1374,7 @@ pub fn lindrustinit(verbosity: isize) { pendingsigset: interface::RustHashMap::new(), main_threadid: interface::RustAtomicU64::new(0), interval_timer: interface::IntervalTimer::new(1), - vmmap: interface::RustLock::new(Vmmap::new()) // Initialize empty virtual memory map for new process + vmmap: interface::RustLock::new(Vmmap::new()), // Initialize empty virtual memory map for new process zombies: interface::RustLock::new(vec![]), child_num: interface::RustAtomicU64::new(0), }; diff --git a/src/RawPOSIX/src/safeposix/shm.rs b/src/RawPOSIX/src/safeposix/shm.rs index 5df5c7421..e03296581 100644 --- a/src/RawPOSIX/src/safeposix/shm.rs +++ b/src/RawPOSIX/src/safeposix/shm.rs @@ -95,7 +95,7 @@ impl ShmSegment { shmaddr, self.size as usize, prot, - MAP_SHARED | MAP_FIXED, + (MAP_SHARED as i32) | (MAP_FIXED as i32), fobjfdno, 0, ) @@ -108,7 +108,7 @@ impl ShmSegment { shmaddr, self.size as usize, PROT_NONE, - MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, + (MAP_PRIVATE as i32) | (MAP_ANONYMOUS as i32) | (MAP_FIXED as i32), -1, 0, ); diff --git a/src/RawPOSIX/src/safeposix/syscalls/sys_calls.rs b/src/RawPOSIX/src/safeposix/syscalls/sys_calls.rs index 0fc738a3c..300c4a9e3 100644 --- a/src/RawPOSIX/src/safeposix/syscalls/sys_calls.rs +++ b/src/RawPOSIX/src/safeposix/syscalls/sys_calls.rs @@ -180,7 +180,7 @@ impl Cage { pendingsigset: interface::RustHashMap::new(), main_threadid: interface::RustAtomicU64::new(0), interval_timer: interface::IntervalTimer::new(child_cageid), - vmmap: interface::RustLock::new(Vmmap::new()) // Initialize empty virtual memory map for new process + vmmap: interface::RustLock::new(Vmmap::new()), // Initialize empty virtual memory map for new process zombies: interface::RustLock::new(vec![]), child_num: interface::RustAtomicU64::new(0), }; @@ -264,7 +264,7 @@ impl Cage { pendingsigset: interface::RustHashMap::new(), main_threadid: interface::RustAtomicU64::new(0), interval_timer: self.interval_timer.clone_with_new_cageid(child_cageid), - vmmap: interface::RustLock::new(Vmmap::new()) // Fresh clean vmmap + vmmap: interface::RustLock::new(Vmmap::new()), // Fresh clean vmmap // when a process exec-ed, its child relationship should be perserved zombies: interface::RustLock::new(cloned_zombies), child_num: interface::RustAtomicU64::new(child_num), diff --git a/src/RawPOSIX/src/safeposix/vmmap.rs b/src/RawPOSIX/src/safeposix/vmmap.rs index 731dfd048..189de5117 100644 --- a/src/RawPOSIX/src/safeposix/vmmap.rs +++ b/src/RawPOSIX/src/safeposix/vmmap.rs @@ -6,7 +6,9 @@ use crate::constants::{ use std::io; use nodit::NoditMap; use nodit::{interval::ie, Interval}; - +use crate::fdtables; +use crate::safeposix::cage::syscall_error; +use crate::safeposix::cage::Errno; /// Used to identify whether the vmmap entry is backed anonymously, /// by an fd, or by a shared memory segment /// diff --git a/src/safeposix/shm.rs b/src/safeposix/shm.rs new file mode 100644 index 000000000..565449424 --- /dev/null +++ b/src/safeposix/shm.rs @@ -0,0 +1,19 @@ +// In map_shm function +interface::libc_mmap( + shmaddr, + self.size as usize, + prot, + ((MAP_SHARED as i32) | (MAP_FIXED as i32)), // Cast each flag to i32 before combining + fobjfdno, + 0, +) + +// In unmap_shm function +interface::libc_mmap( + shmaddr, + self.size as usize, + PROT_NONE, + ((MAP_PRIVATE as i32) | (MAP_ANONYMOUS as i32) | (MAP_FIXED as i32)), // Cast each flag to i32 before combining + -1, + 0, +); \ No newline at end of file From d072008b7f006f6955c32815cc7faa7b689fa169 Mon Sep 17 00:00:00 2001 From: Chinmay Shringi Date: Sat, 21 Dec 2024 19:19:45 +0000 Subject: [PATCH 16/66] feat: removed pendingsigset --- src/RawPOSIX/src/safeposix/cage.rs | 3 --- src/RawPOSIX/src/safeposix/dispatcher.rs | 4 ---- src/RawPOSIX/src/safeposix/syscalls/sys_calls.rs | 2 -- 3 files changed, 9 deletions(-) diff --git a/src/RawPOSIX/src/safeposix/cage.rs b/src/RawPOSIX/src/safeposix/cage.rs index 78de79c95..32cabbb22 100644 --- a/src/RawPOSIX/src/safeposix/cage.rs +++ b/src/RawPOSIX/src/safeposix/cage.rs @@ -67,9 +67,6 @@ pub struct Cage { // currently blocked for the corresponding thread in the cage. Interacts with sigprocmask_syscall() to // block / unblock / replace the signal mask for a thread. pub sigset: interface::RustHashMap, - // pendingsigset is a mapping of thread IDs to atomic signal sets representing signals that are pending - // for each thread - pub pendingsigset: interface::RustHashMap, // The kernel thread id of the main thread of current cage, used because when we want to send signals, // we want to send to the main thread pub main_threadid: interface::RustAtomicU64, diff --git a/src/RawPOSIX/src/safeposix/dispatcher.rs b/src/RawPOSIX/src/safeposix/dispatcher.rs index ecdfbe34e..e1c903f1b 100644 --- a/src/RawPOSIX/src/safeposix/dispatcher.rs +++ b/src/RawPOSIX/src/safeposix/dispatcher.rs @@ -163,8 +163,6 @@ pub extern "C" fn rustposix_thread_init(cageid: u64, signalflag: u64) { .insert(pthreadid, interface::RustAtomicU64::new(0)); } - cage.pendingsigset - .insert(pthreadid, interface::RustAtomicU64::new(0)); interface::signalflag_set(signalflag); } @@ -1329,7 +1327,6 @@ pub fn lindrustinit(verbosity: isize) { thread_table: interface::RustHashMap::new(), signalhandler: interface::RustHashMap::new(), sigset: interface::RustHashMap::new(), - pendingsigset: interface::RustHashMap::new(), main_threadid: interface::RustAtomicU64::new(0), interval_timer: interface::IntervalTimer::new(0), vmmap: interface::RustLock::new(Vmmap::new()), // Initialize empty virtual memory map for new process @@ -1371,7 +1368,6 @@ pub fn lindrustinit(verbosity: isize) { thread_table: interface::RustHashMap::new(), signalhandler: interface::RustHashMap::new(), sigset: interface::RustHashMap::new(), - pendingsigset: interface::RustHashMap::new(), main_threadid: interface::RustAtomicU64::new(0), interval_timer: interface::IntervalTimer::new(1), vmmap: interface::RustLock::new(Vmmap::new()), // Initialize empty virtual memory map for new process diff --git a/src/RawPOSIX/src/safeposix/syscalls/sys_calls.rs b/src/RawPOSIX/src/safeposix/syscalls/sys_calls.rs index 300c4a9e3..d153b6669 100644 --- a/src/RawPOSIX/src/safeposix/syscalls/sys_calls.rs +++ b/src/RawPOSIX/src/safeposix/syscalls/sys_calls.rs @@ -177,7 +177,6 @@ impl Cage { thread_table: interface::RustHashMap::new(), signalhandler: self.signalhandler.clone(), sigset: newsigset, - pendingsigset: interface::RustHashMap::new(), main_threadid: interface::RustAtomicU64::new(0), interval_timer: interface::IntervalTimer::new(child_cageid), vmmap: interface::RustLock::new(Vmmap::new()), // Initialize empty virtual memory map for new process @@ -261,7 +260,6 @@ impl Cage { thread_table: interface::RustHashMap::new(), signalhandler: interface::RustHashMap::new(), sigset: newsigset, - pendingsigset: interface::RustHashMap::new(), main_threadid: interface::RustAtomicU64::new(0), interval_timer: self.interval_timer.clone_with_new_cageid(child_cageid), vmmap: interface::RustLock::new(Vmmap::new()), // Fresh clean vmmap From ee7fd89a380e17c999491052eb17b4ea7b2a2e83 Mon Sep 17 00:00:00 2001 From: Qianxi Chen Date: Thu, 26 Dec 2024 21:04:14 +0000 Subject: [PATCH 17/66] integrate mmap into pthread --- src/RawPOSIX/src/interface/mem.rs | 5 ++ .../src/safeposix/syscalls/sys_calls.rs | 2 +- src/glibc/malloc/malloc.c | 4 +- src/glibc/misc/sbrk.c | 69 ++++++++++--------- src/glibc/nptl/allocatestack.c | 28 ++++---- src/glibc/nptl/pthread_create.c | 3 +- .../crates/lind-multi-process/src/lib.rs | 9 +-- .../crates/wasmtime/src/runtime/vm/memory.rs | 4 ++ .../src/runtime/vm/threads/shared_memory.rs | 4 +- src/wasmtime/src/commands/run.rs | 25 +++++-- 10 files changed, 93 insertions(+), 60 deletions(-) diff --git a/src/RawPOSIX/src/interface/mem.rs b/src/RawPOSIX/src/interface/mem.rs index 3a0b1a779..38cae0449 100644 --- a/src/RawPOSIX/src/interface/mem.rs +++ b/src/RawPOSIX/src/interface/mem.rs @@ -96,21 +96,25 @@ pub fn mmap_handler(cageid: u64, addr: *mut u8, len: usize, mut prot: i32, mut f } if prot & PROT_EXEC > 0 { + println!("mmap syscall error 1!"); return syscall_error(Errno::EINVAL, "mmap", "PROT_EXEC is not allowed"); } // check if the provided address is multiple of pages let rounded_addr = round_up_page(addr as u64); if rounded_addr != addr as u64 { + println!("mmap syscall error 2!"); return syscall_error(Errno::EINVAL, "mmap", "address it not aligned"); } // offset should be non-negative and multiple of pages if off < 0 { + println!("mmap syscall error 3!"); return syscall_error(Errno::EINVAL, "mmap", "offset cannot be negative"); } let rounded_off = round_up_page(off as u64); if rounded_off != off as u64 { + println!("mmap syscall error 4!"); return syscall_error(Errno::EINVAL, "mmap", "offset it not aligned"); } @@ -267,6 +271,7 @@ pub fn check_and_convert_addr_ext(cage: &Cage, arg: u64, length: usize, prot: i3 // Validate memory mapping and permissions if vmmap.check_addr_mapping(page_num, npages, prot).is_none() { + println!("invalid address: {}", arg); return Err(Errno::EFAULT); // Return error if mapping invalid } diff --git a/src/RawPOSIX/src/safeposix/syscalls/sys_calls.rs b/src/RawPOSIX/src/safeposix/syscalls/sys_calls.rs index d153b6669..0a43f6485 100644 --- a/src/RawPOSIX/src/safeposix/syscalls/sys_calls.rs +++ b/src/RawPOSIX/src/safeposix/syscalls/sys_calls.rs @@ -179,7 +179,7 @@ impl Cage { sigset: newsigset, main_threadid: interface::RustAtomicU64::new(0), interval_timer: interface::IntervalTimer::new(child_cageid), - vmmap: interface::RustLock::new(Vmmap::new()), // Initialize empty virtual memory map for new process + vmmap: interface::RustLock::new(new_vmmap), // Initialize empty virtual memory map for new process zombies: interface::RustLock::new(vec![]), child_num: interface::RustAtomicU64::new(0), }; diff --git a/src/glibc/malloc/malloc.c b/src/glibc/malloc/malloc.c index b6ea1547f..fab05ab51 100644 --- a/src/glibc/malloc/malloc.c +++ b/src/glibc/malloc/malloc.c @@ -4444,8 +4444,8 @@ _int_malloc (mstate av, size_t bytes) victim = av->top; size = chunksize (victim); - if (__glibc_unlikely (size > av->system_mem)) - malloc_printerr ("malloc(): corrupted top size"); + // if (__glibc_unlikely (size > av->system_mem)) + // malloc_printerr ("malloc(): corrupted top size"); if ((unsigned long) (size) >= (unsigned long) (nb + MINSIZE)) { diff --git a/src/glibc/misc/sbrk.c b/src/glibc/misc/sbrk.c index f055f37cf..8b4a340b7 100644 --- a/src/glibc/misc/sbrk.c +++ b/src/glibc/misc/sbrk.c @@ -24,6 +24,8 @@ #include #include #include +#include +#include /* Defined in brk.c. */ // This is the "virtual brk" exposed to the caller @@ -41,39 +43,42 @@ extern void *__curbrk; void * __sbrk (intptr_t increment) { - __curbrk = __builtin_wasm_memory_size(0) * PAGESIZE; + return MAKE_SYSCALL(176, "syscall|sbrk", (uint64_t) increment, NOTUSED, NOTUSED, NOTUSED, NOTUSED, NOTUSED); + // __curbrk = __builtin_wasm_memory_size(0) * PAGESIZE; - // sbrk(0) returns the current memory size. - if (increment == 0) { - // The wasm spec doesn't guarantee that memory.grow of 0 always succeeds. - return __curbrk; - } - - // FIXME: now two threads calling this sbrk simultaneously - // will lead to the corruption of __curbrk, so we should move - // this implementation into the runtime, and protect the __curbrk - // with mutex (i.e. preventing two sbrk to be executed at the same time) - - void * linear_mem_end = __builtin_wasm_memory_size(0) * PAGESIZE; - void * old_break = __curbrk; - void * new_break = old_break + increment; - - if (new_break <= linear_mem_end) { - // In this case, we don't need to grow linear mem - __curbrk = new_break; - return old_break; - } - - // Now we need to grow linear mem - int new_pages = (new_break - linear_mem_end) / PAGESIZE; - - if (__builtin_wasm_memory_grow(0, new_pages) < 0) { - errno = ENOMEM; - return (void *)-1; - } - - __curbrk = new_break; - return old_break; + // // sbrk(0) returns the current memory size. + // if (increment == 0) { + // // The wasm spec doesn't guarantee that memory.grow of 0 always succeeds. + // return __curbrk; + // } + + // // FIXME: now two threads calling this sbrk simultaneously + // // will lead to the corruption of __curbrk, so we should move + // // this implementation into the runtime, and protect the __curbrk + // // with mutex (i.e. preventing two sbrk to be executed at the same time) + + // void * linear_mem_end = __builtin_wasm_memory_size(0) * PAGESIZE; + // void * old_break = __curbrk; + // void * new_break = old_break + increment; + + // if (new_break <= linear_mem_end) { + // // In this case, we don't need to grow linear mem + // __curbrk = new_break; + // return old_break; + // } + + // // Now we need to grow linear mem + // // int new_pages = (new_break - linear_mem_end) / PAGESIZE; + // int new_pages = (new_break - linear_mem_end + PAGESIZE - 1) / PAGESIZE; + + // MAKE_SYSCALL(176, "syscall|sbrk", (uint64_t) increment, NOTUSED, NOTUSED, NOTUSED, NOTUSED, NOTUSED); + // if (__builtin_wasm_memory_grow(0, new_pages) < 0) { + // errno = ENOMEM; + // return (void *)-1; + // } + + // __curbrk = new_break; + // return old_break; } // void * diff --git a/src/glibc/nptl/allocatestack.c b/src/glibc/nptl/allocatestack.c index c1d3bb4c3..29ba4a124 100644 --- a/src/glibc/nptl/allocatestack.c +++ b/src/glibc/nptl/allocatestack.c @@ -324,8 +324,7 @@ allocate_stack (const struct pthread_attr *attr, struct pthread **pdp, size_t reported_guardsize; size_t reqsize; void *mem; - const int prot = (PROT_READ | PROT_WRITE - | ((GL(dl_stack_flags) & PF_X) ? PROT_EXEC : 0)); + const int prot = (PROT_READ | PROT_WRITE); /* Adjust the stack size for alignment. */ size &= ~tls_static_align_m1; @@ -363,8 +362,9 @@ allocate_stack (const struct pthread_attr *attr, struct pthread **pdp, /* If a guard page is required, avoid committing memory by first allocate with PROT_NONE and then reserve with required permission excluding the guard page. */ - // mem = __mmap (NULL, size, (guardsize == 0) ? prot : PROT_NONE, - // MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, -1, 0); + printf("size: %d\n", size); + mem = __mmap (NULL, size, (guardsize == 0) ? prot : PROT_NONE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); // Replacement mmap with malloc - Dennis // BUG: changed the malloc size to 16416 (1/4 of the original) @@ -372,8 +372,8 @@ allocate_stack (const struct pthread_attr *attr, struct pthread **pdp, // automatically grow the memory if memory is running out. // Once the issue is fixed, we might be able to change the size // back - Qianxi Chen - size = 16416; - void* mem = malloc(size); + // size = 16416; + // void* mem = malloc(size); if (mem == NULL) { // Handle memory allocation failure @@ -440,16 +440,16 @@ allocate_stack (const struct pthread_attr *attr, struct pthread **pdp, pd->setxid_futex = -1; /* Allocate the DTV for this thread. */ - if (_dl_allocate_tls (TLS_TPADJ (pd)) == NULL) - { - /* Something went wrong. */ - assert (errno == ENOMEM); + // if (_dl_allocate_tls (TLS_TPADJ (pd)) == NULL) + // { + // /* Something went wrong. */ + // assert (errno == ENOMEM); - /* Free the stack memory we just allocated. */ - (void) __munmap (mem, size); + // /* Free the stack memory we just allocated. */ + // (void) __munmap (mem, size); - return errno; - } + // return errno; + // } /* Prepare to modify global data. */ diff --git a/src/glibc/nptl/pthread_create.c b/src/glibc/nptl/pthread_create.c index fe661c24e..8c3eea9cf 100644 --- a/src/glibc/nptl/pthread_create.c +++ b/src/glibc/nptl/pthread_create.c @@ -342,12 +342,13 @@ static int create_thread (struct pthread *pd, const struct pthread_attr *attr, unsigned char *stack = 0; + printf("stacksize: %d\n", stacksize); struct clone_args *args = (void *)pd->stackblock + pd->stackblock_size - sizeof(struct clone_args) - TLS_TCB_SIZE; memset(args, 0, sizeof(struct clone_args)); args->flags = clone_flags; args->stack = stackaddr; args->stack = stackaddr + pd->stackblock_size - sizeof(struct clone_args) - TLS_TCB_SIZE; - args->stack_size = 16416 - sizeof(struct clone_args) - TLS_TCB_SIZE; + args->stack_size = stacksize - sizeof(struct clone_args) - TLS_TCB_SIZE; args->child_tid = &pd->tid; int ret = __clone_internal(args, &start_thread, pd); diff --git a/src/wasmtime/crates/lind-multi-process/src/lib.rs b/src/wasmtime/crates/lind-multi-process/src/lib.rs index 7ed699835..e98d87aee 100644 --- a/src/wasmtime/crates/lind-multi-process/src/lib.rs +++ b/src/wasmtime/crates/lind-multi-process/src/lib.rs @@ -334,6 +334,7 @@ impl, stack_addr: i32, stack_size: i32, child_tid: u64 ) -> Result { + println!("-----stack_addr: {}, stack_size: {}", stack_addr, stack_size); // get the base address of the memory let handle = caller.as_context().0.instance(InstanceId::from_index(0)); let defined_memory = handle.get_memory(MemoryIndex::from_u32(0)); diff --git a/src/wasmtime/crates/wasmtime/src/runtime/vm/memory.rs b/src/wasmtime/crates/wasmtime/src/runtime/vm/memory.rs index d36ea1dc6..8075aaa5d 100644 --- a/src/wasmtime/crates/wasmtime/src/runtime/vm/memory.rs +++ b/src/wasmtime/crates/wasmtime/src/runtime/vm/memory.rs @@ -84,6 +84,7 @@ pub trait RuntimeLinearMemory: Send + Sync { delta_pages: u64, mut store: Option<&mut dyn Store>, ) -> Result, Error> { + println!("memory grow: {}", delta_pages); let old_byte_size = self.byte_size(); // Wasm spec: when growing by 0 pages, always return the current size. @@ -221,6 +222,8 @@ impl MmapMemory { mut maximum: Option, memory_image: Option<&Arc>, ) -> Result { + println!("-----minimum: {}, maximum: {:?}", minimum, maximum); + maximum = Some(2147483648); // It's a programmer error for these two configuration values to exceed // the host available address space, so panic if such a configuration is // found (mostly an issue for hypothetical 32-bit hosts). @@ -325,6 +328,7 @@ impl RuntimeLinearMemory for MmapMemory { } fn grow_to(&mut self, new_size: usize) -> Result<()> { + println!("-----grow to {}", new_size); assert!(usize_is_multiple_of_host_page_size(self.offset_guard_size)); assert!(usize_is_multiple_of_host_page_size(self.pre_guard_size)); assert!(usize_is_multiple_of_host_page_size(self.mmap.len())); diff --git a/src/wasmtime/crates/wasmtime/src/runtime/vm/threads/shared_memory.rs b/src/wasmtime/crates/wasmtime/src/runtime/vm/threads/shared_memory.rs index b62ce1f54..3e7e84327 100644 --- a/src/wasmtime/crates/wasmtime/src/runtime/vm/threads/shared_memory.rs +++ b/src/wasmtime/crates/wasmtime/src/runtime/vm/threads/shared_memory.rs @@ -31,8 +31,10 @@ struct SharedMemoryInner { impl SharedMemory { /// Construct a new [`SharedMemory`]. pub fn new(plan: MemoryPlan) -> Result { + println!("-----create new memory!"); let (minimum_bytes, maximum_bytes) = Memory::limit_new(&plan, None)?; - let mmap_memory = MmapMemory::new(&plan, minimum_bytes, maximum_bytes, None)?; + let mut mmap_memory = MmapMemory::new(&plan, minimum_bytes, maximum_bytes, None)?; + mmap_memory.grow_to(2147483648); Self::wrap(&plan, Box::new(mmap_memory), plan.memory) } diff --git a/src/wasmtime/src/commands/run.rs b/src/wasmtime/src/commands/run.rs index 4edf5047b..7f05b9fdd 100644 --- a/src/wasmtime/src/commands/run.rs +++ b/src/wasmtime/src/commands/run.rs @@ -18,7 +18,7 @@ use std::sync::atomic::AtomicU64; use std::sync::{Arc, Mutex}; use std::thread; use wasi_common::sync::{ambient_authority, Dir, TcpListener, WasiCtxBuilder}; -use wasmtime::{AsContextMut, Engine, Func, Module, Store, StoreLimits, Val, ValType}; +use wasmtime::{AsContext, AsContextMut, Engine, Func, Module, Store, StoreLimits, Val, ValType}; use wasmtime_wasi::WasiView; use wasmtime_lind_utils::LindCageManager; @@ -183,6 +183,8 @@ impl RunCommand { // new cage is created lind_manager.increment(); + rawposix::safeposix::dispatcher::lind_cage_vmmap_init(1); + // Pre-emptively initialize and install a Tokio runtime ambiently in the // environment when executing the module. Without this whenever a WASI // call is made that needs to block on a future a Tokio runtime is @@ -192,7 +194,7 @@ impl RunCommand { // operations that block in the CLI since the CLI doesn't use async to // invoke WebAssembly. let result = wasmtime_wasi::runtime::with_ambient_tokio_runtime(|| { - self.load_main_module(&mut store, &mut linker, &main, modules) + self.load_main_module(&mut store, &mut linker, &main, modules, 1) .with_context(|| { format!( "failed to run main module `{}`", @@ -203,14 +205,19 @@ impl RunCommand { // Load the main wasm module. match result { - Ok(_) => { + Ok(res) => { + let mut code = 0; + let retval = res.get(0).unwrap(); + if let Val::I32(res) = retval { + code = *res; + } // exit the cage lind_syscall_api( 1, 30 as u32, 0, 0, - 0 as u64, + code as u64, 0, 0, 0, @@ -359,6 +366,8 @@ impl RunCommand { } } + rawposix::safeposix::dispatcher::lind_cage_vmmap_init(pid as u64); + // Pre-emptively initialize and install a Tokio runtime ambiently in the // environment when executing the module. Without this whenever a WASI // call is made that needs to block on a future a Tokio runtime is @@ -368,7 +377,7 @@ impl RunCommand { // operations that block in the CLI since the CLI doesn't use async to // invoke WebAssembly. let result = wasmtime_wasi::runtime::with_ambient_tokio_runtime(|| { - self.load_main_module(&mut store, &mut linker, &main, modules) + self.load_main_module(&mut store, &mut linker, &main, modules, pid as u64) .with_context(|| { format!( "failed to run child module `{}`", @@ -511,6 +520,7 @@ impl RunCommand { linker: &mut CliLinker, module: &RunTarget, modules: Vec<(String, Module)>, + pid: u64, ) -> Result> { // The main module might be allowed to have unknown imports, which // should be defined as traps: @@ -572,6 +582,11 @@ impl RunCommand { let mut stack_pointer = instance.get_stack_pointer(store.as_context_mut()).unwrap(); store.as_context_mut().set_stack_base(stack_pointer as u64); + let handle = store.as_context().0.instance(wasmtime::InstanceId::from_index(0)); + let defined_memory = handle.get_memory(wasmtime_environ::MemoryIndex::from_u32(0)); + let memory_base = defined_memory.base as i64; + rawposix::safeposix::dispatcher::set_base_address(pid, memory_base); + match func { Some(func) => self.invoke_func(store, func), None => Ok(vec![]), From d126835b03679aaf1a6f490a4d602a087e18701f Mon Sep 17 00:00:00 2001 From: Chinmay Shringi <31031919+ChinmayShringi@users.noreply.github.com> Date: Fri, 27 Dec 2024 20:32:53 -0500 Subject: [PATCH 18/66] Syscall security nacl alignment (#70) * feat: update WRITE_SYSCALL * feat: update WRITEV_SYSCALL * feat: update MUNMAP_SYSCALL * feat: update MUNMAP_SYSCALL * feat: update MMAP_SYSCALL * feat: update MMAP_SYSCALL * feat: update PREAD_SYSCALL * feat: update READ_SYSCALL * feat: update * feat: update ACCESS_SYSCALL * feat: OPEN_SYSCALL * feat: update CONNECT_SYSCALL * feat: update BIND_SYSCALL * feat: ACCEPT_SYSCALL * feat: EXEC_SYSCALL * feat: update EXIT_SYSCALL * feat: SELECT_SYSCALL * feat: updaet RENAME_SYSCALL * feat: update XSTAT_SYSCALL * feat: MKDIR_SYSCALL * feat: updaet RMDIR_SYSCALL * feat: FCHDIR_SYSCALL * feat: CHDIR_SYSCALL * feat: GETCWD_SYSCALL * feat: FSTATFS_SYSCALL * feat: CHMOD_SYSCALL * feat: DUP_SYSCALL * feat: DUP2_SYSCALL * feat: FCHMOD_SYSCALL * feat: FXSTAT_SYSCALL * feat: UNLINK_SYSCALL * feat: LINK_SYSCALL * feat: LSEEK_SYSCALL * feat: IOCTL_SYSCALL * feat: TRUNCATE_SYSCALL * feat: FTRUNCATE_SYSCALL * feat: GETDENTS_SYSCALL * feat: STATFS_SYSCALL * feat: FCNTL_SYSCALL * feat: RECV_SYSCALL * feat: SENDTO_SYSCALL * feat: RECVFROM_SYSCALL * feat: FLOCK_SYSCALL * feat: SHMGET_SYSCALL * feat: SHMAT_SYSCALL * feat: SHMDT_SYSCALL * feat: MUTEX_DESTROY_SYSCALL * feat: MUTEX_LOCK_SYSCALL * feat: MUTEX_TRYLOCK_SYSCALL * feat: MUTEX_UNLOCK_SYSCALL * feat: COND_DESTROY_SYSCALL * feat: COND_WAIT_SYSCALL * feat: COND_BROADCAST_SYSCALL * next COND_SIGNAL_SYSCALL * feat: SEM_INIT_SYSCALL * feat: SEM_WAIT_SYSCALL * feat: SEM_TRYWAIT_SYSCALL * feat: SEM_POST_SYSCALL * feat: SEM_DESTROY_SYSCALL * feat: SEM_GETVALUE_SYSCALL * feat: PWRITE_SYSCALL * feat: EPOLL_CTL_SYSCALL * feat: GETGID * feat: EPOLL_CREATE_SYSCALL * feat: SETSOCKOPT_SYSCALL * feat: SHUTDOWN_SYSCALL * feat: SEND_SYSCALL * feat: GETHOSTNAME_SYSCALL * feat: GETIFADDRS_SYSCALL * feat: PIPE_SYSCALL * feat: PIPE2_SYSCALL update * feat: update GETSOCKNAME_SYSCALL * feat: update GETSOCKOPT_SYSCALL * feat: SOCKETPAIR_SYSCALL * feat: update POLL_SYSCALL * feat: update FUTEX_SYSCALL * feat: NANOSLEEP_TIME64_SYSCALL * feat: update WAIT_SYSCALL * feat: update WAITPID_SYSCALL * feat: update comments * feat: delete nacl fiile * feat: temp commit * Revert "feat: temp commit" This reverts commit 134c222510901fa4e54b71834c1e2412eaa7d7aa. --- src/RawPOSIX/src/safeposix/dispatcher.rs | 1002 +++++++++++++++++++--- 1 file changed, 897 insertions(+), 105 deletions(-) diff --git a/src/RawPOSIX/src/safeposix/dispatcher.rs b/src/RawPOSIX/src/safeposix/dispatcher.rs index e1c903f1b..478b70ede 100644 --- a/src/RawPOSIX/src/safeposix/dispatcher.rs +++ b/src/RawPOSIX/src/safeposix/dispatcher.rs @@ -203,79 +203,197 @@ pub fn lind_syscall_api( let ret = match call_number { WRITE_SYSCALL => { + // NaCl equivalent: NaClSysWrite + // Handles writing data from user buffer to file descriptor + + // Get file descriptor - same as NaCl's first argument handling let fd = arg1 as i32; - let count = arg3 as usize; + + // Security: Clamp count to prevent integer overflow attacks + // NaCl uses similar bounds checking via MAX_IO_BUFFER_BYTES + let count = std::cmp::min(arg3 as usize, i32::MAX as usize); + if count == 0 { + return 0; // Early return for zero-length writes (NaCl behavior) + } + + // Get cage reference for memory operations + // NaCl equivalent: struct NaClApp *nap = natp->nap let cage = interface::cagetable_getref(cageid); - let buf = match check_and_convert_addr_ext(&cage, arg2, count, PROT_WRITE) { + + // Validate and convert user buffer address to system address + // NaCl: Uses NaClUserToSysAddrRangeProt with similar protection flags + // PROT_READ is correct because write() reads FROM the buffer + let buf = match check_and_convert_addr_ext(&cage, arg2, count, PROT_READ) { Ok(addr) => addr as *const u8, - Err(errno) => return syscall_error(errno, "write", "invalid buffer address"), + Err(errno) => { + return syscall_error( + errno, + "write", + "buffer access violation or invalid address" + ); + } }; + + // Perform write operation through cage abstraction cage.write_syscall(fd, buf, count) } WRITEV_SYSCALL => { + // NaCl equivalent: NaClSysWritev let fd = arg1 as i32; + let iovcnt = arg3 as i32; + + // NaCl validates count first + if iovcnt <= 0 { + return syscall_error( + Errno::EINVAL, + "writev", + "invalid iovec count" + ); + } + let cage = interface::cagetable_getref(cageid); - let iovec = match check_and_convert_addr_ext(&cage, arg2, size_of::(), PROT_READ) { + + // Validate the iovec array address first + // This matches NaCl's validation order + let iov_base = match check_and_convert_addr_ext( + &cage, + arg2, + (iovcnt as usize) * std::mem::size_of::(), + PROT_READ + ) { Ok(addr) => addr as *const interface::IovecStruct, - Err(errno) => return syscall_error(errno, "writev", "invalid iovec address"), + Err(errno) => { + return syscall_error( + errno, + "writev", + "invalid iovec array address" + ); + } }; - let iovcnt = arg3 as i32; - cage.writev_syscall(fd, iovec, iovcnt) + + // NaCl validates each iovec entry's buffer - we do this in writev_syscall + // The actual write operation is delegated to the cage implementation + cage.writev_syscall(fd, iov_base, iovcnt) } MUNMAP_SYSCALL => { + // NaCl equivalent: NaClSysMunmap let addr = arg1 as *mut u8; - let len = arg2 as usize; + let length = arg2 as usize; + let cage = interface::cagetable_getref(cageid); + + // TODO(Security): Need to implement the following NaCl-style security checks: + // 1. is_page_aligned() - Checks if address is page-aligned (4KB boundaries) + // Reference: NaCl checks this via NaClIsAllocPageMultiple + // + // 2. round_to_page_size() - Rounds length up to nearest page size + // Reference: NaCl uses NaClRoundAllocPage + // + // 3. contains_executable_pages() - Prevents unmapping executable pages + // Reference: NaCl uses NaClSysCommonAddrRangeContainsExecutablePages + // + // These functions might help in the interface module. - interface::munmap_handler(cageid, addr, len) + if length == 0 { + return syscall_error( + Errno::EINVAL, + "munmap", + "length cannot be zero" + ); + } + + // Perform the unmapping operation + interface::munmap_handler(cageid, addr, length) } MMAP_SYSCALL => { + // NaCl equivalent: NaClSysMmap let addr = arg1 as *mut u8; let len = arg2 as usize; - let mut prot = arg3 as i32; - let mut flags = arg4 as i32; - let mut fildes = arg5 as i32; + let prot = arg3 as i32; + let flags = arg4 as i32; + let fd = arg5 as i32; let off = arg6 as i64; - - interface::mmap_handler(cageid, addr, len, prot, flags, fildes, off) + + // Basic length validation, similar to NaCl + if len == 0 { + return syscall_error( + Errno::EINVAL, + "mmap", + "length cannot be zero" + ); + } + + // TODO(Security): Need NaClSysCommonMmapCheck equivalent to validate: + // - W^X protection checks (write XOR execute) + // - Address space limit checks (see NaCl's check at addr_bits) + // - Overflow checks for length + offset + // - Page alignment validation when MAP_FIXED is used + // Reference: NaCl implementation in nacl_syscall_common.c:1756 + + // Force MAP_FIXED as NaCl does + let flags = flags | MAP_FIXED as i32; + + // Turn off PROT_EXEC for non-code pages + // NaCl does this to prevent execution of data pages + let prot = prot & !PROT_EXEC; + + interface::mmap_handler(cageid, addr, len, prot, flags, fd, off) } PREAD_SYSCALL => { + // NaCl equivalent: NaClSysPread let fd = arg1 as i32; let count = arg3 as usize; + let offset = arg4 as i64; let cage = interface::cagetable_getref(cageid); - let buf = match check_and_convert_addr_ext(&cage, arg2, count, PROT_READ) { + + // Validate and convert user buffer address + // NaCl uses NaClUserToSysAddr with PROT_WRITE since pread writes TO the buffer + let buf = match check_and_convert_addr_ext(&cage, arg2, count, PROT_WRITE) { Ok(addr) => addr as *mut u8, Err(errno) => return syscall_error(errno, "pread", "invalid buffer address"), }; - let offset = arg4 as i64; - + cage.pread_syscall(fd, buf, count, offset) } READ_SYSCALL => { + // NaCl equivalent: NaClSysRead let fd = arg1 as i32; let count = arg3 as usize; let cage = interface::cagetable_getref(cageid); - let buf = match check_and_convert_addr_ext(&cage, arg2, count, PROT_READ) { + + // Validate and convert user buffer address + // Using PROT_WRITE since read() writes TO the buffer + // NaCl: Uses NaClUserToSysAddr with similar validation + let buf = match check_and_convert_addr_ext(&cage, arg2, count, PROT_WRITE) { Ok(addr) => addr as *mut u8, Err(errno) => return syscall_error(errno, "read", "invalid buffer address"), }; + // File descriptor validation and actual read operation + // handled by cage implementation (similar to NaCl's ndp->vtbl->Read) cage.read_syscall(fd, buf, count) } CLOSE_SYSCALL => { + // NaCl equivalent: NaClSysClose let fd = arg1 as i32; + // File descriptor validation and close operation handled by cage + // Similar to NaCl's ndp->vtbl->Close after NaClGetDesc validation interface::cagetable_getref(cageid) .close_syscall(fd) } ACCESS_SYSCALL => { + // NaCl equivalent: NaClSysAccess let cage = interface::cagetable_getref(cageid); + + // Validate and convert path string from user space + // NaCl: Uses NaClCopyInFromUser with MAXPATHLEN check let path = match check_and_convert_addr_ext(&cage, arg1, 1, PROT_READ) { Ok(addr) => match interface::types::get_cstr(addr as u64) { Ok(path_str) => path_str, @@ -285,11 +403,17 @@ pub fn lind_syscall_api( }; let amode = arg2 as i32; + // Perform access check through cage implementation + // Similar to NaCl's lind_access call cage.access_syscall(path, amode) } OPEN_SYSCALL => { + // NaCl equivalent: NaClSysOpen let cage = interface::cagetable_getref(cageid); + + // Validate and convert path string from user space + // NaCl: Uses NaClCopyInFromUser with MAXPATHLEN check let path = match check_and_convert_addr_ext(&cage, arg1, 1, PROT_READ) { Ok(addr) => match interface::types::get_cstr(addr as u64) { Ok(path_str) => path_str, @@ -299,22 +423,32 @@ pub fn lind_syscall_api( }; let flags = arg2 as i32; let mode = arg3 as u32; - + + // Perform open operation through cage implementation + // Similar to NaCl's lind_open call cage.open_syscall(path, flags, mode) } SOCKET_SYSCALL => { + // NaCl equivalent: NaClSysSocket let domain = arg1 as i32; let socktype = arg2 as i32; let protocol = arg3 as i32; + // Perform socket operation through cage implementation + // Domain, type, and protocol validation handled by cage layer + // Similar to NaCl's lind_socket call interface::cagetable_getref(cageid) .socket_syscall(domain, socktype, protocol) } CONNECT_SYSCALL => { + // NaCl equivalent: NaClSysConnect let fd = arg1 as i32; let cage = interface::cagetable_getref(cageid); + + // Validate and convert sockaddr from user space + // NaCl: Uses NaClCopyInFromUser for sockaddr validation let addr = match check_and_convert_addr_ext(&cage, arg2, arg3 as usize, PROT_READ) { Ok(addr) => match interface::get_sockaddr(addr as u64, arg3 as u32) { Ok(sockaddr) => sockaddr, @@ -323,16 +457,24 @@ pub fn lind_syscall_api( Err(errno) => return syscall_error(errno, "connect", "invalid address"), }; + // Convert to reference for connect operation let remoteaddr = match Ok::<&interface::GenSockaddr, i32>(&addr) { Ok(addr) => addr, - Err(_) => panic!("Failed to get sockaddr"), // Handle error appropriately + Err(_) => return syscall_error(Errno::EFAULT, "connect", "sockaddr conversion failed"), }; + + // Perform connect operation through cage implementation + // File descriptor validation handled by cage layer cage.connect_syscall(fd, remoteaddr) } BIND_SYSCALL => { + // NaCl equivalent: NaClSysBind let fd = arg1 as i32; let cage = interface::cagetable_getref(cageid); + + // Validate and convert sockaddr from user space + // NaCl: Uses NaClCopyInFromUser for sockaddr validation let addr = match check_and_convert_addr_ext(&cage, arg2, arg3 as usize, PROT_READ) { Ok(addr) => match interface::get_sockaddr(addr as u64, arg3 as u32) { Ok(sockaddr) => sockaddr, @@ -340,28 +482,40 @@ pub fn lind_syscall_api( }, Err(errno) => return syscall_error(errno, "bind", "invalid address"), }; + + // Convert to reference for bind operation let localaddr = match Ok::<&interface::GenSockaddr, i32>(&addr) { Ok(addr) => addr, - Err(_) => panic!("Failed to get sockaddr"), // Handle error appropriately + Err(_) => return syscall_error(Errno::EFAULT, "bind", "sockaddr conversion failed"), }; + + // Perform bind operation through cage implementation + // File descriptor validation handled by cage layer cage.bind_syscall(fd, localaddr) } ACCEPT_SYSCALL => { - let mut addr = interface::GenSockaddr::V4(interface::SockaddrV4::default()); //value doesn't matter + // NaCl equivalent: NaClSysAccept + let mut addr = interface::GenSockaddr::V4(interface::SockaddrV4::default()); let nullity1 = interface::arg_nullity(arg2); let nullity2 = interface::arg_nullity(arg3); let cage = interface::cagetable_getref(cageid); - + + // Handle NULL address case (both NULL) if nullity1 && nullity2 { cage.accept_syscall(arg1 as i32, &mut Some(&mut addr)) - } else if !(nullity1 || nullity2) { + } + // Handle non-NULL case (both non-NULL) + else if !(nullity1 || nullity2) { + // Perform accept operation first let rv = cage.accept_syscall(arg1 as i32, &mut Some(&mut addr)); if rv >= 0 { + // NaCl: Similar to NaClCopyOutToUser for sockaddr let addr2_addr = match check_and_convert_addr_ext(&cage, arg2, arg3 as usize, PROT_WRITE) { Ok(addr) => addr, Err(errno) => return syscall_error(errno, "accept", "invalid address buffer"), }; + // NaCl: Similar to NaClCopyOutToUser for addrlen let len_addr = match check_and_convert_addr_ext(&cage, arg3, std::mem::size_of::(), PROT_WRITE) { Ok(addr) => addr, Err(errno) => return syscall_error(errno, "accept", "invalid length buffer"), @@ -369,7 +523,9 @@ pub fn lind_syscall_api( interface::copy_out_sockaddr(addr2_addr as u64, len_addr as u64, addr); } rv - } else { + } + // Handle invalid case (one NULL, one non-NULL) + else { syscall_error( Errno::EINVAL, "accept", @@ -379,56 +535,104 @@ pub fn lind_syscall_api( } EXEC_SYSCALL => { + // NaCl equivalent: NaClSysExec let child_cageid = arg1 as u64; + + // Perform exec operation through cage implementation + // Child cage validation handled by cage layer interface::cagetable_getref(cageid) .exec_syscall(child_cageid) } EXIT_SYSCALL => { + // NaCl equivalent: NaClSysExit let status = arg1 as i32; + + // Perform exit operation through cage implementation + // Cleanup handled by cage layer interface::cagetable_getref(cageid) .exit_syscall(status) } SELECT_SYSCALL => { + // NaCl equivalent: NaClSysSelect let nfds = arg1 as i32; - let readfds = interface::get_fdset(arg2).unwrap(); - let writefds = interface::get_fdset(arg3).unwrap(); - let errorfds = interface::get_fdset(arg4).unwrap(); - let rposix_timeout = interface::duration_fromtimeval(arg5).unwrap(); + + // Get and validate fd sets + // NaCl: Uses NaClCopyInFromUser for fd_set validation + let readfds = match interface::get_fdset(arg2) { + Ok(fds) => fds, + Err(_) => return syscall_error(Errno::EFAULT, "select", "invalid readfds"), + }; + let writefds = match interface::get_fdset(arg3) { + Ok(fds) => fds, + Err(_) => return syscall_error(Errno::EFAULT, "select", "invalid writefds"), + }; + let errorfds = match interface::get_fdset(arg4) { + Ok(fds) => fds, + Err(_) => return syscall_error(Errno::EFAULT, "select", "invalid errorfds"), + }; + + // Get and validate timeout + // NaCl: Uses NaClCopyInFromUser for timeval validation + let rposix_timeout = match interface::duration_fromtimeval(arg5) { + Ok(timeout) => timeout, + Err(_) => return syscall_error(Errno::EFAULT, "select", "invalid timeout"), + }; + + // Perform select operation through cage implementation + // Results are handled by the interface layer interface::cagetable_getref(cageid) .select_syscall(nfds, readfds, writefds, errorfds, rposix_timeout) } RENAME_SYSCALL => { + // NaCl equivalent: NaClSysRename let cage = interface::cagetable_getref(cageid); + + // Validate and convert old path from user space + // NaCl: Uses NaClCopyInFromUser with MAXPATHLEN check let old_path = match check_and_convert_addr_ext(&cage, arg1, 1, PROT_READ) { Ok(addr) => match interface::types::get_cstr(addr) { Ok(path_str) => path_str, - Err(_) => return -1, + Err(_) => return syscall_error(Errno::EFAULT, "rename", "invalid old path string"), }, Err(errno) => return syscall_error(errno, "rename", "invalid old path address"), }; + + // Validate and convert new path from user space + // NaCl: Uses NaClCopyInFromUser with MAXPATHLEN check let new_path = match check_and_convert_addr_ext(&cage, arg2, 1, PROT_READ) { Ok(addr) => match interface::types::get_cstr(addr) { Ok(path_str) => path_str, - Err(_) => return -1, + Err(_) => return syscall_error(Errno::EFAULT, "rename", "invalid new path string"), }, Err(errno) => return syscall_error(errno, "rename", "invalid new path address"), }; + // Perform rename operation through cage implementation cage.rename_syscall(old_path, new_path) } XSTAT_SYSCALL => { + // NaCl equivalent: NaClSysStat let cage = interface::cagetable_getref(cageid); + + // Validate and convert path string from user space + // NaCl: Uses NaClCopyInFromUser with MAXPATHLEN check + // Using PROT_READ because we need to read the path string FROM user space + // (stat takes the path as input, we don't write to it) let path = match check_and_convert_addr_ext(&cage, arg1, 1, PROT_READ) { Ok(addr) => match interface::types::get_cstr(addr) { Ok(path_str) => path_str, - Err(_) => return -1, + Err(_) => return syscall_error(Errno::EFAULT, "xstat", "invalid path string"), }, Err(errno) => return syscall_error(errno, "xstat", "invalid path address"), }; + + // Validate stat buffer and prepare for writing + // NaCl: Allocates buffer and uses NaClCopyOutToUser + // Using PROT_WRITE because stat() writes the results TO this user space buffer let buf = match check_and_convert_addr_ext(&cage, arg2, std::mem::size_of::(), PROT_WRITE) { Ok(addr) => match interface::get_statdatastruct(addr) { Ok(val) => val, @@ -437,71 +641,110 @@ pub fn lind_syscall_api( Err(errno) => return syscall_error(errno, "xstat", "invalid stat buffer address"), }; + // Perform stat operation through cage implementation + // Results written directly to user buffer by cage layer cage.stat_syscall(path, buf) } MKDIR_SYSCALL => { + // NaCl equivalent: NaClSysMkdir let cage = interface::cagetable_getref(cageid); + + // Validate and convert path string from user space + // NaCl: Uses NaClCopyInFromUser with MAXPATHLEN check + // Using PROT_READ because we need to read the path string FROM user space + // (mkdir takes the path as input, we don't write to it) let path = match check_and_convert_addr_ext(&cage, arg1, 1, PROT_READ) { Ok(addr) => match interface::types::get_cstr(addr) { Ok(path_str) => path_str, - Err(_) => return -1, + Err(_) => return syscall_error(Errno::EFAULT, "mkdir", "invalid path string"), }, Err(errno) => return syscall_error(errno, "mkdir", "invalid path address"), }; let mode = arg2 as u32; - + + // Perform mkdir operation through cage implementation cage.mkdir_syscall(path, mode) } RMDIR_SYSCALL => { + // NaCl equivalent: NaClSysRmdir let cage = interface::cagetable_getref(cageid); + + // Validate and convert path string from user space + // NaCl: Uses NaClCopyInFromUser with MAXPATHLEN check + // Using PROT_READ because we need to read the path string FROM user space + // (rmdir takes the path as input, we don't write to it) let path = match check_and_convert_addr_ext(&cage, arg1, 1, PROT_READ) { Ok(addr) => match interface::types::get_cstr(addr) { Ok(path_str) => path_str, - Err(_) => return -1, + Err(_) => return syscall_error(Errno::EFAULT, "rmdir", "invalid path string"), }, Err(errno) => return syscall_error(errno, "rmdir", "invalid path address"), }; + // Perform rmdir operation through cage implementation cage.rmdir_syscall(path) } FCHDIR_SYSCALL => { + // NaCl equivalent: NaClSysFchdir let fd = arg1 as i32; + // Perform fchdir operation through cage implementation + // File descriptor validation handled by cage layer interface::cagetable_getref(cageid) .fchdir_syscall(fd) } CHDIR_SYSCALL => { let cage = interface::cagetable_getref(cageid); + + // Validate and convert path string from user space + // NaCl: Uses NaClCopyInFromUser with MAXPATHLEN check + // Using PROT_READ because we need to read the path string FROM user space + // (chdir takes the path as input, we don't write to it) let path = match check_and_convert_addr_ext(&cage, arg1, 1, PROT_READ) { Ok(addr) => match interface::types::get_cstr(addr) { Ok(path_str) => path_str, - Err(_) => return -1, + Err(_) => return syscall_error(Errno::EFAULT, "chdir", "invalid path string"), }, Err(errno) => return syscall_error(errno, "chdir", "invalid path address"), }; + // Perform chdir operation through cage implementation cage.chdir_syscall(path) } GETCWD_SYSCALL => { + // NaCl equivalent: NaClSysGetcwd let bufsize = arg2 as usize; let cage = interface::cagetable_getref(cageid); + + // Validate buffer for writing + // NaCl: Uses NaClCopyOutToUser + // Using PROT_WRITE because getcwd() writes the current working directory path + // TO this user space buffer let buf = match check_and_convert_addr_ext(&cage, arg1, bufsize, PROT_WRITE) { Ok(addr) => addr as *mut u8, Err(errno) => return syscall_error(errno, "getcwd", "invalid buffer address"), }; - + + // Perform getcwd operation through cage implementation + // On success (ret == 0), return the buffer address like NaCl does let ret = cage.getcwd_syscall(buf, bufsize as u32); if ret == 0 { return arg1 as i32; } ret } FSTATFS_SYSCALL => { + // NaCl equivalent: NaClSysFstatfs let fd = arg1 as i32; let cage = interface::cagetable_getref(cageid); + + // Validate buffer for writing filesystem information + // NaCl: Uses NaClCopyOutToUser + // Using PROT_WRITE because fstatfs() writes filesystem information + // TO this user space buffer let buf = match check_and_convert_addr_ext(&cage, arg2, 1, PROT_WRITE) { Ok(addr) => match interface::get_fsdatastruct(addr) { Ok(val) => val, @@ -510,93 +753,138 @@ pub fn lind_syscall_api( Err(errno) => return syscall_error(errno, "fstatfs", "invalid buffer address"), }; + // Perform fstatfs operation through cage implementation + // File descriptor validation and actual operation handled by cage layer cage.fstatfs_syscall(fd, buf) } CHMOD_SYSCALL => { let cage = interface::cagetable_getref(cageid); + + // Validate and convert path string from user space + // NaCl: Uses NaClCopyInFromUser with MAXPATHLEN check + // Using PROT_READ because we need to read the path string FROM user space + // (chmod takes the path as input, we don't write to it) let path = match check_and_convert_addr_ext(&cage, arg1, 1, PROT_READ) { Ok(addr) => match interface::types::get_cstr(addr) { Ok(path_str) => path_str, - Err(_) => return -1, + Err(_) => return syscall_error(Errno::EFAULT, "chmod", "invalid path string"), }, Err(errno) => return syscall_error(errno, "chmod", "invalid path address"), }; let mode = arg2 as u32; - + + // Perform chmod operation through cage implementation cage.chmod_syscall(path, mode) } DUP_SYSCALL => { + // NaCl equivalent: NaClSysDup let fd = arg1 as i32; + + // Convert second argument to Option if it's within valid range + // This is an extension to NaCl's implementation to support both dup and dup2 let fd2: Option = if arg1 <= i32::MAX as u64 { Some(arg1 as i32) } else { None }; - + + // Perform dup operation through cage implementation + // File descriptor validation handled by cage layer interface::cagetable_getref(cageid) .dup_syscall(fd, fd2) } DUP2_SYSCALL => { + // NaCl equivalent: NaClSysDup2 let fd = arg1 as i32; let fd2 = arg2 as i32; + // Perform dup2 operation through cage implementation + // File descriptor validation handled by cage layer interface::cagetable_getref(cageid) .dup2_syscall(fd, fd2) } FCHMOD_SYSCALL => { + // NaCl equivalent: NaClSysFchmod let fd = arg1 as i32; let mode = arg2 as u32; - + + // Perform fchmod operation through cage implementation + // File descriptor validation handled by cage layer interface::cagetable_getref(cageid) .fchmod_syscall(fd, mode) } FXSTAT_SYSCALL => { + // NaCl equivalent: NaClSysFstat let fd = arg1 as i32; let cage = interface::cagetable_getref(cageid); + + // Validate stat buffer and prepare for writing + // NaCl: Uses NaClCopyOutToUser + // Using PROT_WRITE because fstat() writes the results TO this user space buffer let buf = match check_and_convert_addr_ext(&cage, arg2, std::mem::size_of::(), PROT_WRITE) { - Ok(addr) => interface::get_statdatastruct(addr).unwrap(), + Ok(addr) => match interface::get_statdatastruct(addr) { + Ok(val) => val, + Err(errno) => return syscall_error(Errno::EFAULT, "fxstat", "invalid stat data format"), + }, Err(errno) => return syscall_error(errno, "fxstat", "invalid buffer address"), }; + // Perform fstat operation through cage implementation + // File descriptor validation and actual operation handled by cage layer cage.fstat_syscall(fd, buf) } UNLINK_SYSCALL => { + // NaCl equivalent: NaClSysUnlink let cage = interface::cagetable_getref(cageid); + + // Validate and convert path string from user space + // NaCl: Uses NaClCopyInFromUser with MAXPATHLEN check + // Using PROT_READ because we need to read the path string FROM user space + // (unlink takes the path as input, we don't write to it) let path = match check_and_convert_addr_ext(&cage, arg1, 1, PROT_READ) { Ok(addr) => match interface::types::get_cstr(addr) { Ok(path_str) => path_str, - Err(_) => return -1, + Err(_) => return syscall_error(Errno::EFAULT, "unlink", "invalid path string"), }, Err(errno) => return syscall_error(errno, "unlink", "invalid path address"), }; + // Perform unlink operation through cage implementation cage.unlink_syscall(path) } LINK_SYSCALL => { let cage = interface::cagetable_getref(cageid); + + // Validate and convert old path string from user space + // NaCl: Uses NaClCopyInFromUser with MAXPATHLEN check + // Using PROT_READ because we need to read the path string FROM user space let old_path = match check_and_convert_addr_ext(&cage, arg1, 1, PROT_READ) { Ok(addr) => match interface::types::get_cstr(addr) { Ok(path_str) => path_str, - Err(_) => return -1, + Err(_) => return syscall_error(Errno::EFAULT, "link", "invalid old path string"), }, Err(errno) => return syscall_error(errno, "link", "invalid old path address"), }; + // Validate and convert new path string from user space + // NaCl: Uses NaClCopyInFromUser with MAXPATHLEN check + // Using PROT_READ because we need to read the path string FROM user space let new_path = match check_and_convert_addr_ext(&cage, arg2, 1, PROT_READ) { Ok(addr) => match interface::types::get_cstr(addr) { Ok(path_str) => path_str, - Err(_) => return -1, + Err(_) => return syscall_error(Errno::EFAULT, "link", "invalid new path string"), }, Err(errno) => return syscall_error(errno, "link", "invalid new path address"), }; - + + // Perform link operation through cage implementation cage.link_syscall(old_path, new_path) } @@ -604,7 +892,14 @@ pub fn lind_syscall_api( let virtual_fd = arg1 as i32; let offset = arg2 as isize; let whence = arg3 as i32; - + + // Perform lseek operation through cage implementation + // File descriptor validation and bounds checking handled by cage layer + // + // Implementation differences from NaCl: + // 1. No memory protection flags needed as we're only dealing with integer values + // 2. File descriptor validation handled by cage layer + // 3. Simple and straightforward implementation as no memory operations are involved interface::cagetable_getref(cageid) .lseek_syscall(virtual_fd, offset, whence) } @@ -614,28 +909,54 @@ pub fn lind_syscall_api( let request = arg2 as u64; let ptrunion = (start_address + arg3) as *mut u8; + // Perform ioctl operation through cage implementation + // Note: Like NaCl, we restrict ioctl operations for security + // + // Implementation differences from NaCl: + // 1. Uses raw pointer arithmetic for argument handling + // 2. File descriptor validation handled by cage layer + // 3. Request validation and security checks handled by cage layer + // 4. Memory protection handled at the cage level rather than dispatcher interface::cagetable_getref(cageid) .ioctl_syscall(virtual_fd, request, ptrunion) } TRUNCATE_SYSCALL => { let cage = interface::cagetable_getref(cageid); + + // Validate and convert path string from user space + // NaCl: Uses NaClCopyInFromUser with MAXPATHLEN check + // Using PROT_READ because we need to read the path string FROM user space let path = match check_and_convert_addr_ext(&cage, arg1, 1, PROT_READ) { Ok(addr) => match interface::types::get_cstr(addr) { Ok(path_str) => path_str, - Err(_) => return -1, + Err(_) => return syscall_error(Errno::EFAULT, "truncate", "invalid path string"), }, Err(errno) => return syscall_error(errno, "truncate", "invalid path address"), }; let length = arg2 as isize; - + + // Perform truncate operation through cage implementation + // + // Implementation differences from NaCl: + // 1. Uses Rust's type system for memory safety instead of manual allocation + // 2. Path validation handled by helper functions + // 3. No explicit cleanup needed due to Rust's ownership system + // 4. Uses PROT_READ since we're only reading the path from user space cage.truncate_syscall(path, length) } FTRUNCATE_SYSCALL => { let virtual_fd = arg1 as i32; let length = arg2 as isize; - + + // Perform ftruncate operation through cage implementation + // File descriptor validation handled by cage layer + // + // Implementation differences from NaCl: + // 1. No memory protection flags needed as we're only dealing with integer values + // 2. File descriptor validation handled by cage layer + // 3. Simple and straightforward implementation as no memory operations are involved interface::cagetable_getref(cageid) .ftruncate_syscall(virtual_fd, length) } @@ -644,29 +965,58 @@ pub fn lind_syscall_api( let virtual_fd = arg1 as i32; let nbytes = arg3 as u32; let cage = interface::cagetable_getref(cageid); + + // Validate buffer for writing directory entries + // NaCl: Uses NaClCopyOutToUser + // Using PROT_WRITE because getdents() writes directory entries TO this user space buffer let buf = match check_and_convert_addr_ext(&cage, arg2, nbytes as usize, PROT_WRITE) { Ok(addr) => addr as *mut u8, Err(errno) => return syscall_error(errno, "getdents", "invalid buffer address"), }; - + + // Perform getdents operation through cage implementation + // File descriptor validation handled by cage layer + // + // Implementation differences from NaCl: + // 1. Uses Rust's type system for memory safety instead of manual allocation + // 2. Buffer validation handled by helper functions + // 3. No explicit cleanup needed due to Rust's ownership system + // 4. Uses PROT_WRITE since we're writing directory entries to user space cage.getdents_syscall(virtual_fd, buf, nbytes) } STATFS_SYSCALL => { let cage = interface::cagetable_getref(cageid); + + // Validate and convert path string from user space + // NaCl: Uses NaClCopyInFromUser with MAXPATHLEN check + // Using PROT_READ because we need to read the path string FROM user space let path = match check_and_convert_addr_ext(&cage, arg1, 1, PROT_READ) { Ok(addr) => match interface::types::get_cstr(addr) { Ok(path_str) => path_str, - Err(_) => return -1, + Err(_) => return syscall_error(Errno::EFAULT, "statfs", "invalid path string"), }, Err(errno) => return syscall_error(errno, "statfs", "invalid path address"), }; + // Validate buffer for writing filesystem information + // NaCl: Uses NaClCopyOutToUser + // Using PROT_WRITE because statfs() writes filesystem information TO this user space buffer let rposix_databuf = match check_and_convert_addr_ext(&cage, arg2, 1, PROT_WRITE) { - Ok(addr) => interface::get_fsdatastruct(addr).unwrap(), + Ok(addr) => match interface::get_fsdatastruct(addr) { + Ok(val) => val, + Err(errno) => return syscall_error(Errno::EFAULT, "statfs", "invalid stat buffer format"), + }, Err(errno) => return syscall_error(errno, "statfs", "invalid stat buffer address"), }; + // Perform statfs operation through cage implementation + // + // Implementation differences from NaCl: + // 1. Uses Rust's type system for memory safety instead of manual allocation + // 2. Path and buffer validation handled by helper functions + // 3. No explicit cleanup needed due to Rust's ownership system + // 4. Uses appropriate PROT flags for reading path and writing filesystem data cage.statfs_syscall(&path, rposix_databuf) } @@ -674,7 +1024,15 @@ pub fn lind_syscall_api( let virtual_fd = arg1 as i32; let cmd = arg2 as i32; let arg = arg3 as i32; - + + // Perform fcntl operation through cage implementation + // File descriptor validation and command validation handled by cage layer + // + // Implementation differences from NaCl: + // 1. No memory protection flags needed as we're only dealing with integer values + // 2. File descriptor validation handled by cage layer + // 3. Command validation handled by cage layer + // 4. Simple and straightforward implementation as no memory operations are involved interface::cagetable_getref(cageid) .fcntl_syscall(virtual_fd, cmd, arg) } @@ -683,12 +1041,24 @@ pub fn lind_syscall_api( let fd = arg1 as i32; let count = arg3 as usize; let cage = interface::cagetable_getref(cageid); + + // Validate buffer for writing received data + // NaCl: Uses NaClCopyOutToUser + // Using PROT_WRITE because recv() writes received data TO this user space buffer let buf = match check_and_convert_addr_ext(&cage, arg2, count, PROT_WRITE) { Ok(addr) => addr as *mut u8, Err(errno) => return syscall_error(errno, "recv", "invalid buffer address"), }; let flag = arg4 as i32; - + + // Perform recv operation through cage implementation + // File descriptor validation handled by cage layer + // + // Implementation differences from NaCl: + // 1. Uses Rust's type system for memory safety instead of manual allocation + // 2. Buffer validation handled by helper functions + // 3. No explicit cleanup needed due to Rust's ownership system + // 4. Uses PROT_WRITE since we're writing received data to user space cage.recv_syscall(fd, buf, count, flag) } @@ -696,15 +1066,32 @@ pub fn lind_syscall_api( let fd = arg1 as i32; let count = arg3 as usize; let cage = interface::cagetable_getref(cageid); + + // Validate buffer for reading data to send + // NaCl: Uses NaClCopyInFromUser + // Using PROT_READ because we need to read the data FROM user space let buf = match check_and_convert_addr_ext(&cage, arg2, count, PROT_READ) { Ok(addr) => addr as *const u8, Err(errno) => return syscall_error(errno, "sendto", "invalid buffer address"), }; let flag = arg4 as i32; - + + // Get and validate socket address + // NaCl: Uses NaClCopyInFromUser for sockaddr validation let addrlen = arg6 as u32; - let addr = interface::get_sockaddr(start_address + arg5, addrlen).unwrap(); - + let addr = match interface::get_sockaddr(start_address + arg5, addrlen) { + Ok(addr) => addr, + Err(_) => return syscall_error(Errno::EFAULT, "sendto", "invalid socket address"), + }; + + // Perform sendto operation through cage implementation + // File descriptor validation handled by cage layer + // + // Implementation differences from NaCl: + // 1. Uses Rust's type system for memory safety instead of manual allocation + // 2. Buffer and address validation handled by helper functions + // 3. No explicit cleanup needed due to Rust's ownership system + // 4. Uses PROT_READ since we're reading data from user space cage.sendto_syscall(fd, buf, count, flag, &addr) } @@ -712,26 +1099,39 @@ pub fn lind_syscall_api( let fd = arg1 as i32; let count = arg3 as usize; let cage = interface::cagetable_getref(cageid); + + // Validate buffer for writing received data + // NaCl: Uses NaClCopyOutToUser + // Using PROT_WRITE because recvfrom() writes received data TO this user space buffer let buf = match check_and_convert_addr_ext(&cage, arg2, count, PROT_WRITE) { Ok(addr) => addr as *mut u8, Err(errno) => return syscall_error(errno, "recvfrom", "invalid buffer address"), }; let flag = arg4 as i32; + + // Check if address and length arguments are provided let nullity1 = interface::arg_nullity(arg5); let nullity2 = interface::arg_nullity(arg6); - + + // Handle different cases based on address arguments if nullity1 && nullity2 { + // Both address and length are NULL - simple receive cage.recvfrom_syscall(fd, buf, count, flag, &mut None) } else if !(nullity1 || nullity2) { - let mut newsockaddr = interface::GenSockaddr::V4(interface::SockaddrV4::default()); //dummy value, rust would complain if we used an uninitialized value here - + // Both address and length are provided + // Create a default sockaddr to store the sender's address + let mut newsockaddr = interface::GenSockaddr::V4(interface::SockaddrV4::default()); + + // Perform recvfrom operation let rv = cage.recvfrom_syscall(fd, buf, count, flag, &mut Some(&mut newsockaddr)); if rv >= 0 { + // Copy address information back to user space on success interface::copy_out_sockaddr(start_address + arg5, start_address + arg6, newsockaddr); } rv } else { + // Invalid case: one argument is NULL while the other isn't syscall_error( Errno::EINVAL, "recvfrom", @@ -743,7 +1143,15 @@ pub fn lind_syscall_api( FLOCK_SYSCALL => { let virtual_fd = arg1 as i32; let operation = arg2 as i32; - + + // Perform flock operation through cage implementation + // File descriptor validation handled by cage layer + // + // Implementation differences from NaCl: + // 1. No memory protection flags needed as we're only dealing with integer values + // 2. File descriptor validation handled by cage layer + // 3. Operation validation handled by cage layer + // 4. Simple and straightforward implementation as no memory operations are involved interface::cagetable_getref(cageid) .flock_syscall(virtual_fd, operation) } @@ -752,64 +1160,127 @@ pub fn lind_syscall_api( let key = arg1 as i32; let size = arg2 as usize; let shmfig = arg3 as i32; - + + // Perform shmget operation through cage implementation + // + // Implementation differences from NaCl: + // 1. No memory protection flags needed as we're only dealing with integer values + // 2. Shared memory validation handled by cage layer + // 3. Simple and straightforward implementation as no memory operations are involved + // 4. Size validation handled by cage layer interface::cagetable_getref(cageid) .shmget_syscall(key, size, shmfig) } - SHMAT_SYSCALL => { let shmid = arg1 as i32; let cage = interface::cagetable_getref(cageid); + + // Validate shared memory address + // NaCl: Uses NaClIsValidAddress + // Using both PROT_READ and PROT_WRITE since shared memory needs both access types let shmaddr = match check_and_convert_addr_ext(&cage, arg2, 1, PROT_READ | PROT_WRITE) { Ok(addr) => addr as *mut u8, Err(errno) => return syscall_error(errno, "shmat", "invalid shared memory address"), }; let shmflg = arg3 as i32; - + + // Perform shmat operation through cage implementation + // + // Implementation differences from NaCl: + // 1. Uses Rust's memory safety features for address validation + // 2. Uses PROT_READ | PROT_WRITE for shared memory access + // 3. Address validation handled by helper function + // 4. Shared memory operations handled by cage layer cage.shmat_syscall(shmid, shmaddr, shmflg) } SHMDT_SYSCALL => { let cage = interface::cagetable_getref(cageid); + + // Validate shared memory address + // NaCl: Uses NaClIsValidAddress + // Using both PROT_READ and PROT_WRITE since shared memory needs both access types let shmaddr = match check_and_convert_addr_ext(&cage, arg1, 1, PROT_READ | PROT_WRITE) { Ok(addr) => addr as *mut u8, Err(errno) => return syscall_error(errno, "shmdt", "invalid shared memory address"), }; + // Perform shmdt operation through cage implementation + // + // Implementation differences from NaCl: + // 1. Uses Rust's memory safety features for address validation + // 2. Uses PROT_READ | PROT_WRITE for shared memory access + // 3. Address validation handled by helper function + // 4. Shared memory operations handled by cage layer cage.shmdt_syscall(shmaddr) } MUTEX_DESTROY_SYSCALL => { let mutex_handle = arg1 as i32; - + + // Perform mutex destroy operation through cage implementation + // + // Implementation differences from NaCl: + // 1. No memory protection flags needed as we're only dealing with integer values + // 2. Mutex handle validation handled by cage layer + // 3. Simple and straightforward implementation as no memory operations are involved + // 4. Thread safety handled by Rust's type system interface::cagetable_getref(cageid) .mutex_destroy_syscall(mutex_handle) } MUTEX_LOCK_SYSCALL => { let mutex_handle = arg1 as i32; - + + // Perform mutex lock operation through cage implementation + // + // Implementation differences from NaCl: + // 1. No memory protection flags needed as we're only dealing with integer values + // 2. Mutex handle validation handled by cage layer + // 3. Simple and straightforward implementation as no memory operations are involved + // 4. Thread safety handled by Rust's type system interface::cagetable_getref(cageid) .mutex_lock_syscall(mutex_handle) } MUTEX_TRYLOCK_SYSCALL => { let mutex_handle = arg1 as i32; - + + // Perform mutex trylock operation through cage implementation + // + // Implementation differences from NaCl: + // 1. No memory protection flags needed as we're only dealing with integer values + // 2. Mutex handle validation handled by cage layer + // 3. Simple and straightforward implementation as no memory operations are involved + // 4. Thread safety handled by Rust's type system interface::cagetable_getref(cageid) .mutex_trylock_syscall(mutex_handle) } MUTEX_UNLOCK_SYSCALL => { let mutex_handle = arg1 as i32; - + + // Perform mutex unlock operation through cage implementation + // + // Implementation differences from NaCl: + // 1. No memory protection flags needed as we're only dealing with integer values + // 2. Mutex handle validation handled by cage layer + // 3. Simple and straightforward implementation as no memory operations are involved + // 4. Thread safety handled by Rust's type system interface::cagetable_getref(cageid) .mutex_unlock_syscall(mutex_handle) } COND_DESTROY_SYSCALL => { let cv_handle = arg1 as i32; - + + // Perform condition variable destroy operation through cage implementation + // + // Implementation differences from NaCl: + // 1. No memory protection flags needed as we're only dealing with integer values + // 2. Condition variable handle validation handled by cage layer + // 3. Simple and straightforward implementation as no memory operations are involved + // 4. Thread safety handled by Rust's type system interface::cagetable_getref(cageid) .cond_destroy_syscall(cv_handle) } @@ -817,21 +1288,42 @@ pub fn lind_syscall_api( COND_WAIT_SYSCALL => { let cv_handle = arg1 as i32; let mutex_handle = arg2 as i32; - + + // Perform condition variable wait operation through cage implementation + // + // Implementation differences from NaCl: + // 1. No memory protection flags needed as we're only dealing with integer values + // 2. Condition variable and mutex handle validation handled by cage layer + // 3. Simple and straightforward implementation as no memory operations are involved + // 4. Thread safety handled by Rust's type system interface::cagetable_getref(cageid) .cond_wait_syscall(cv_handle, mutex_handle) } COND_BROADCAST_SYSCALL => { let cv_handle = arg1 as i32; - + + // Perform condition variable broadcast operation through cage implementation + // + // Implementation differences from NaCl: + // 1. No memory protection flags needed as we're only dealing with integer values + // 2. Condition variable handle validation handled by cage layer + // 3. Simple and straightforward implementation as no memory operations are involved + // 4. Thread safety handled by Rust's type system interface::cagetable_getref(cageid) .cond_broadcast_syscall(cv_handle) } COND_SIGNAL_SYSCALL => { let cv_handle = arg1 as i32; - + + // Perform condition variable signal operation through cage implementation + // + // Implementation differences from NaCl: + // 1. No memory protection flags needed as we're only dealing with integer values + // 2. Condition variable handle validation handled by cage layer + // 3. Simple and straightforward implementation as no memory operations are involved + // 4. Thread safety handled by Rust's type system interface::cagetable_getref(cageid) .cond_signal_syscall(cv_handle) } @@ -840,42 +1332,84 @@ pub fn lind_syscall_api( let sem_handle = arg1 as u32; let pshared = arg2 as i32; let value = arg3 as u32; - + + // Perform semaphore initialization operation through cage implementation + // + // Implementation differences from NaCl: + // 1. No memory protection flags needed as we're only dealing with integer values + // 2. Semaphore handle validation handled by cage layer + // 3. Simple and straightforward implementation as no memory operations are involved + // 4. Thread safety handled by Rust's type system interface::cagetable_getref(cageid) .sem_init_syscall(sem_handle, pshared, value) } SEM_WAIT_SYSCALL => { let sem_handle = arg1 as u32; - + + // Perform semaphore wait operation through cage implementation + // + // Implementation differences from NaCl: + // 1. No memory protection flags needed as we're only dealing with integer values + // 2. Semaphore handle validation handled by cage layer + // 3. Simple and straightforward implementation as no memory operations are involved + // 4. Thread safety handled by Rust's type system interface::cagetable_getref(cageid) .sem_wait_syscall(sem_handle) } SEM_TRYWAIT_SYSCALL => { let sem_handle = arg1 as u32; - + + // Perform semaphore try wait operation through cage implementation + // + // Implementation differences from NaCl: + // 1. No memory protection flags needed as we're only dealing with integer values + // 2. Semaphore handle validation handled by cage layer + // 3. Simple and straightforward implementation as no memory operations are involved + // 4. Thread safety handled by Rust's type system interface::cagetable_getref(cageid) .sem_trywait_syscall(sem_handle) } SEM_POST_SYSCALL => { let sem_handle = arg1 as u32; - + + // Perform semaphore post operation through cage implementation + // + // Implementation differences from NaCl: + // 1. No memory protection flags needed as we're only dealing with integer values + // 2. Semaphore handle validation handled by cage layer + // 3. Simple and straightforward implementation as no memory operations are involved + // 4. Thread safety handled by Rust's type system interface::cagetable_getref(cageid) .sem_post_syscall(sem_handle) } SEM_DESTROY_SYSCALL => { let sem_handle = arg1 as u32; - + + // Perform semaphore destroy operation through cage implementation + // + // Implementation differences from NaCl: + // 1. No memory protection flags needed as we're only dealing with integer values + // 2. Semaphore handle validation handled by cage layer + // 3. Simple and straightforward implementation as no memory operations are involved + // 4. Thread safety handled by Rust's type system interface::cagetable_getref(cageid) .sem_destroy_syscall(sem_handle) } SEM_GETVALUE_SYSCALL => { let sem_handle = arg1 as u32; - + + // Perform semaphore get value operation through cage implementation + // + // Implementation differences from NaCl: + // 1. No memory protection flags needed as we're only dealing with integer values + // 2. Semaphore handle validation handled by cage layer + // 3. Simple and straightforward implementation as no memory operations are involved + // 4. Thread safety handled by Rust's type system interface::cagetable_getref(cageid) .sem_getvalue_syscall(sem_handle) } @@ -883,32 +1417,67 @@ pub fn lind_syscall_api( PWRITE_SYSCALL => { let count = arg3 as usize; let cage = interface::cagetable_getref(cageid); + + // Validate buffer for reading data to write + // NaCl: Uses NaClIsValidAddress + // Using PROT_READ because we need to read the data FROM user space let buf = match check_and_convert_addr_ext(&cage, arg2, count, PROT_READ) { Ok(addr) => addr as *const u8, Err(errno) => return syscall_error(errno, "pwrite", "invalid buffer address"), }; let virtual_fd = arg1 as i32; let offset = arg4 as i64; - + + // Perform pwrite operation through cage implementation + // + // Implementation differences from NaCl: + // 1. Uses Rust's memory safety features for buffer validation + // 2. Uses PROT_READ since we're reading data from user space + // 3. Buffer validation handled by helper function + // 4. File descriptor validation handled by cage layer cage.pwrite_syscall(virtual_fd, buf, count, offset) } GETUID_SYSCALL => { + // Get real user ID through cage implementation + // + // Implementation differences from NaCl: + // 1. No memory protection flags needed as we're only returning an integer value + // 2. Simple and straightforward implementation with no validation needed + // 3. User ID management handled by cage layer interface::cagetable_getref(cageid) .getuid_syscall() } - + GETEUID_SYSCALL => { + // Get effective user ID through cage implementation + // + // Implementation differences from NaCl: + // 1. No memory protection flags needed as we're only returning an integer value + // 2. Simple and straightforward implementation with no validation needed + // 3. User ID management handled by cage layer interface::cagetable_getref(cageid) .geteuid_syscall() } - + GETGID_SYSCALL => { + // Get real group ID through cage implementation + // + // Implementation differences from NaCl: + // 1. No memory protection flags needed as we're only returning an integer value + // 2. Simple and straightforward implementation with no validation needed + // 3. Group ID management handled by cage layer interface::cagetable_getref(cageid) .getgid_syscall() } - + GETEGID_SYSCALL => { + // Get effective group ID through cage implementation + // + // Implementation differences from NaCl: + // 1. No memory protection flags needed as we're only returning an integer value + // 2. Simple and straightforward implementation with no validation needed + // 3. Group ID management handled by cage layer interface::cagetable_getref(cageid) .getegid_syscall() } @@ -916,6 +1485,13 @@ pub fn lind_syscall_api( EPOLL_CREATE_SYSCALL => { let size = arg1 as i32; + // Perform epoll create operation through cage implementation + // + // Implementation differences from NaCl: + // 1. No memory protection flags needed as we're only dealing with integer values + // 2. Size validation handled by cage layer + // 3. Simple and straightforward implementation as no memory operations are involved + // 4. File descriptor management handled by cage layer interface::cagetable_getref(cageid) .epoll_create_syscall(size) } @@ -924,8 +1500,19 @@ pub fn lind_syscall_api( let virtual_epfd = arg1 as i32; let op = arg2 as i32; let virtual_fd = arg3 as i32; + + // Validate and convert epoll_event structure + // NaCl: Uses NaClIsValidAddress for epoll_event validation + // Note: get_epollevent handles the validation and conversion internally let epollevent = interface::get_epollevent(arg4).unwrap(); - + + // Perform epoll_ctl operation through cage implementation + // + // Implementation differences from NaCl: + // 1. Uses Rust's type system for epoll_event validation + // 2. Event structure validation handled by helper function + // 3. File descriptor validation handled by cage layer + // 4. Operation validation handled by cage layer interface::cagetable_getref(cageid) .epoll_ctl_syscall(virtual_epfd, op, virtual_fd, epollevent) } @@ -946,11 +1533,22 @@ pub fn lind_syscall_api( let optname = arg3 as i32; let optlen = arg5 as u32; let cage = interface::cagetable_getref(cageid); + + // Validate buffer for reading socket option value + // NaCl: Uses NaClIsValidAddress + // Using PROT_READ because we need to read the option value FROM user space let optval = match check_and_convert_addr_ext(&cage, arg4, optlen as usize, PROT_READ) { Ok(addr) => addr as *mut u8, Err(errno) => return syscall_error(errno, "setsockopt", "invalid optval address"), }; + // Perform setsockopt operation through cage implementation + // + // Implementation differences from NaCl: + // 1. Uses Rust's memory safety features for buffer validation + // 2. Uses PROT_READ since we're reading option value from user space + // 3. Buffer validation handled by helper function + // 4. File descriptor validation handled by cage layer cage.setsockopt_syscall(virtual_fd, level, optname, optval, optlen) } @@ -958,8 +1556,15 @@ pub fn lind_syscall_api( let virtual_fd = arg1 as i32; let how = arg2 as i32; + // Perform shutdown operation through cage implementation + // + // Implementation differences from NaCl: + // 1. No memory protection flags needed as we're only dealing with integer values + // 2. File descriptor validation handled by cage layer + // 3. Simple and straightforward implementation as no memory operations are involved + // 4. Shutdown mode validation handled by cage layer interface::cagetable_getref(cageid) - .shutdown_syscall( virtual_fd, how) + .shutdown_syscall(virtual_fd, how) } GETPPID_SYSCALL => { @@ -971,12 +1576,23 @@ pub fn lind_syscall_api( let fd = arg1 as i32; let count = arg3 as usize; let cage = interface::cagetable_getref(cageid); + + // Validate buffer for reading data to send + // NaCl: Uses NaClIsValidAddress + // Using PROT_READ because we need to read the data FROM user space let buf = match check_and_convert_addr_ext(&cage, arg2, count, PROT_READ) { Ok(addr) => addr as *const u8, Err(errno) => return syscall_error(errno, "send", "invalid buffer address"), }; let flags = arg4 as i32; - + + // Perform send operation through cage implementation + // + // Implementation differences from NaCl: + // 1. Uses Rust's memory safety features for buffer validation + // 2. Uses PROT_READ since we're reading data from user space + // 3. Buffer validation handled by helper function + // 4. File descriptor validation handled by cage layer cage.send_syscall(fd, buf, count, flags) } @@ -1000,20 +1616,44 @@ pub fn lind_syscall_api( GETHOSTNAME_SYSCALL => { let len = arg2 as usize; let cage = interface::cagetable_getref(cageid); + + // Validate buffer for writing hostname + // NaCl: Uses NaClIsValidAddress + // Using PROT_WRITE because gethostname() writes hostname TO this user space buffer let name = match check_and_convert_addr_ext(&cage, arg1, len, PROT_WRITE) { Ok(addr) => addr as *mut u8, Err(errno) => return syscall_error(errno, "gethostname", "invalid name address"), }; + + // Perform gethostname operation through cage implementation + // + // Implementation differences from NaCl: + // 1. Uses Rust's memory safety features for buffer validation + // 2. Uses PROT_WRITE since we're writing hostname to user space + // 3. Buffer validation handled by helper function + // 4. Length validation handled by cage layer cage.gethostname_syscall(name, len as isize) } GETIFADDRS_SYSCALL => { let count = arg2 as usize; let cage = interface::cagetable_getref(cageid); + + // Validate buffer for writing interface addresses + // NaCl: Uses NaClIsValidAddress + // Using PROT_WRITE because getifaddrs() writes interface data TO user space buffer let buf = match check_and_convert_addr_ext(&cage, arg1, count, PROT_WRITE) { Ok(addr) => addr as *mut u8, Err(errno) => return syscall_error(errno, "getifaddrs", "invalid address"), }; + + // Perform getifaddrs operation through cage implementation + // + // Implementation differences from NaCl: + // 1. Uses Rust's memory safety features for buffer validation + // 2. Uses PROT_WRITE since we're writing interface data to user space + // 3. Buffer validation handled by helper function + // 4. Size validation handled by cage layer cage.getifaddrs_syscall(buf, count) } @@ -1050,39 +1690,79 @@ pub fn lind_syscall_api( PIPE_SYSCALL => { let cage = interface::cagetable_getref(cageid); + + // Validate buffer for writing pipe file descriptors + // NaCl: Uses NaClIsValidAddress + // Using PROT_WRITE because pipe() writes two fds TO this user space buffer + // Size is 8 bytes for two integers (file descriptors) let pipe = match check_and_convert_addr_ext(&cage, arg1, 8, PROT_WRITE) { - Ok(addr) => interface::get_pipearray(addr).unwrap(), + Ok(addr) => match interface::get_pipearray(addr) { + Ok(pipe_array) => pipe_array, + Err(_) => return syscall_error(Errno::EFAULT, "pipe", "failed to get pipe array"), + }, Err(errno) => return syscall_error(errno, "pipe", "invalid pipe address"), }; - + + // Perform pipe operation through cage implementation + // + // Implementation differences from NaCl: + // 1. Uses Rust's memory safety features for buffer validation + // 2. Uses PROT_WRITE since pipe writes fds to user space + // 3. Two-step validation: memory region first, then array conversion + // 4. File descriptor management handled by cage layer cage.pipe_syscall(pipe) } PIPE2_SYSCALL => { let cage = interface::cagetable_getref(cageid); + + // Validate buffer for writing pipe file descriptors + // NaCl: Uses NaClIsValidAddress + // Using PROT_WRITE because pipe2() writes two fds TO this user space buffer + // Size is 8 bytes for two integers (file descriptors) let pipe = match check_and_convert_addr_ext(&cage, arg1, 8, PROT_WRITE) { - Ok(addr) => interface::get_pipearray(addr).unwrap(), + Ok(addr) => match interface::get_pipearray(addr) { + Ok(pipe_array) => pipe_array, + Err(_) => return syscall_error(Errno::EFAULT, "pipe2", "failed to get pipe array"), + }, Err(errno) => return syscall_error(errno, "pipe2", "invalid pipe address"), }; let flag = arg2 as i32; - + + // Perform pipe2 operation through cage implementation + // + // Implementation differences from NaCl: + // 1. Uses Rust's memory safety features for buffer validation + // 2. Uses PROT_WRITE since pipe2 writes fds to user space + // 3. Two-step validation: memory region first, then array conversion + // 4. File descriptor management handled by cage layer cage.pipe2_syscall(pipe, flag) } GETSOCKNAME_SYSCALL => { let fd = arg1 as i32; let cage = interface::cagetable_getref(cageid); + + // Validate buffer for writing socket address + // NaCl: Uses NaClIsValidAddress + // Using PROT_WRITE because getsockname() writes address TO user space let name_addr = match check_and_convert_addr_ext(&cage, arg2, 16, PROT_WRITE) { Ok(addr) => addr, Err(errno) => return syscall_error(errno, "getsockname", "invalid name address"), }; + + // Validate buffer for writing address length + // NaCl: Uses NaClIsValidAddress + // Using PROT_WRITE because getsockname() writes length TO user space let namelen_addr = match check_and_convert_addr_ext(&cage, arg3, 4, PROT_WRITE) { Ok(addr) => addr, Err(errno) => return syscall_error(errno, "getsockname", "invalid length address"), }; - - let mut addr = interface::GenSockaddr::V4(interface::SockaddrV4::default()); //value doesn't matter - + + // Initialize default socket address structure + let mut addr = interface::GenSockaddr::V4(interface::SockaddrV4::default()); + + // Check for null pointers if interface::arg_nullity(arg2) || interface::arg_nullity(arg3) { return syscall_error( Errno::EINVAL, @@ -1090,9 +1770,17 @@ pub fn lind_syscall_api( "Either the address or the length were null", ); } - + + // Perform getsockname operation through cage implementation + // + // Implementation differences from NaCl: + // 1. Uses Rust's memory safety features for buffer validation + // 2. Uses PROT_WRITE since we're writing data to user space + // 3. Separate validation for address and length buffers + // 4. Explicit null pointer checks let rv = cage.getsockname_syscall(fd, &mut Some(&mut addr)); - + + // Copy out the address if operation was successful if rv >= 0 { interface::copy_out_sockaddr(name_addr, namelen_addr, addr); } @@ -1104,13 +1792,24 @@ pub fn lind_syscall_api( let level = arg2 as i32; let optname = arg3 as i32; let cage = interface::cagetable_getref(cageid); - + + // Validate buffer for writing socket option value + // NaCl: Uses NaClIsValidAddress + // Using PROT_WRITE because getsockopt() writes option value TO user space + // Size is 4 bytes for an integer value let optval_ptr = match check_and_convert_addr_ext(&cage, arg4, 4, PROT_WRITE) { Ok(addr) => addr as *mut i32, Err(errno) => return syscall_error(errno, "getsockopt", "invalid optval address"), }; let optval = unsafe { &mut *optval_ptr }; - + + // Perform getsockopt operation through cage implementation + // + // Implementation differences from NaCl: + // 1. Uses Rust's memory safety features for buffer validation + // 2. Uses PROT_WRITE since we're writing option value to user space + // 3. Buffer validation handled by helper function + // 4. File descriptor and option validation handled by cage layer cage.getsockopt_syscall(virtual_fd, level, optname, optval) } @@ -1119,23 +1818,55 @@ pub fn lind_syscall_api( let _type = arg2 as i32; let protocol = arg3 as i32; let cage = interface::cagetable_getref(cageid); + + // Validate buffer for writing socket pair file descriptors + // NaCl: Uses NaClIsValidAddress + // Using PROT_WRITE because socketpair() writes two fds TO this user space buffer + // Size is 8 bytes for two integers (file descriptors) let virtual_socket_vector = match check_and_convert_addr_ext(&cage, arg4, 8, PROT_WRITE) { - Ok(addr) => interface::get_sockpair(addr).unwrap(), + Ok(addr) => match interface::get_sockpair(addr) { + Ok(sock_pair) => sock_pair, + Err(_) => return syscall_error(Errno::EFAULT, "socketpair", "failed to get socket pair array"), + }, Err(errno) => return syscall_error(errno, "socketpair", "invalid socket vector address"), }; - + + // Perform socketpair operation through cage implementation + // + // Implementation differences from NaCl: + // 1. Uses Rust's memory safety features for buffer validation + // 2. Uses PROT_WRITE since socketpair writes fds to user space + // 3. Two-step validation: memory region first, then array conversion + // 4. Socket domain and type validation handled by cage layer cage.socketpair_syscall(domain, _type, protocol, virtual_socket_vector) } POLL_SYSCALL => { let nfds = arg2 as u64; let cage = interface::cagetable_getref(cageid); + + // Validate buffer for reading and writing poll file descriptors + // NaCl: Uses NaClIsValidAddress + // Using PROT_READ | PROT_WRITE because: + // - READ: poll needs to read the fds and events to monitor + // - WRITE: poll needs to write back the returned events + // Size is nfds * 8 (size of pollfd struct) let pollfds = match check_and_convert_addr_ext(&cage, arg1, (nfds * 8) as usize, PROT_READ | PROT_WRITE) { - Ok(addr) => interface::get_pollstruct_slice(addr, nfds as usize).unwrap(), + Ok(addr) => match interface::get_pollstruct_slice(addr, nfds as usize) { + Ok(poll_array) => poll_array, + Err(_) => return syscall_error(Errno::EFAULT, "poll", "failed to get poll array"), + }, Err(errno) => return syscall_error(errno, "poll", "invalid fds address"), }; let timeout = arg3 as i32; - + + // Perform poll operation through cage implementation + // + // Implementation differences from NaCl: + // 1. Uses Rust's memory safety features for buffer validation + // 2. Uses both PROT_READ and PROT_WRITE since poll both reads and writes + // 3. Two-step validation: memory region first, then array conversion + // 4. File descriptor validation handled by cage layer cage.poll_syscall(pollfds, nfds, timeout) } @@ -1152,16 +1883,31 @@ pub fn lind_syscall_api( FUTEX_SYSCALL => { let cage = interface::cagetable_getref(cageid); + + // Validate buffer for futex operations + // NaCl: Uses NaClIsValidAddress + // Using PROT_READ | PROT_WRITE because: + // - READ: futex needs to read current value + // - WRITE: futex may modify the value depending on operation let uaddr = match check_and_convert_addr_ext(&cage, arg1, 4, PROT_READ | PROT_WRITE) { Ok(addr) => addr, Err(errno) => return syscall_error(errno, "futex", "invalid uaddr address"), }; + + // Convert remaining arguments let futex_op = arg2 as u32; let val = arg3 as u32; let timeout = arg4 as u32; let uaddr2 = arg5 as u32; let val3 = arg6 as u32; - + + // Perform futex operation through cage implementation + // + // Implementation differences from NaCl: + // 1. Uses Rust's memory safety features for buffer validation + // 2. Uses both PROT_READ and PROT_WRITE since futex both reads and may write + // 3. Buffer validation handled by helper function + // 4. Operation validation handled by cage layer cage.futex_syscall(uaddr, futex_op, val, timeout, uaddr2, val3) } @@ -1170,37 +1916,83 @@ pub fn lind_syscall_api( let flags = arg2 as i32; let cage = interface::cagetable_getref(cageid); + // Validate buffer for reading requested sleep time + // NaCl: Uses NaClIsValidAddress + // Using PROT_READ because we need to read the requested time FROM user space + // Size is 16 bytes for timespec64 structure let req = match check_and_convert_addr_ext(&cage, arg3, 16, PROT_READ) { Ok(addr) => addr as usize, Err(errno) => return syscall_error(errno, "nanosleep", "invalid req address"), }; + + // Validate buffer for writing remaining time + // NaCl: Uses NaClIsValidAddress + // Using PROT_WRITE because nanosleep writes remaining time TO user space + // Size is 16 bytes for timespec64 structure let rem = match check_and_convert_addr_ext(&cage, arg4, 16, PROT_WRITE) { Ok(addr) => addr as usize, Err(errno) => return syscall_error(errno, "nanosleep", "invalid rem address"), }; + // Perform nanosleep operation through cage implementation + // + // Implementation differences from NaCl: + // 1. Uses Rust's memory safety features for buffer validation + // 2. Uses PROT_READ for req and PROT_WRITE for rem + // 3. Separate validation for request and remaining time buffers + // 4. Additional parameters for clock ID and flags (time64 version) cage.nanosleep_time64_syscall(clockid, flags, req, rem) } WAIT_SYSCALL => { let cage = interface::cagetable_getref(cageid); + + // Validate buffer for writing process status + // NaCl: Uses NaClIsValidAddress + // Using PROT_WRITE because wait() writes status information TO user space + // Size is 4 bytes for status integer let status = match check_and_convert_addr_ext(&cage, arg1, 4, PROT_WRITE) { - Ok(addr) => interface::get_i32_ref(addr).unwrap(), + Ok(addr) => match interface::get_i32_ref(addr) { + Ok(status_ref) => status_ref, + Err(_) => return syscall_error(Errno::EFAULT, "wait", "failed to get status reference"), + }, Err(errno) => return syscall_error(errno, "wait", "invalid status address"), }; - + + // Perform wait operation through cage implementation + // + // Implementation differences from NaCl: + // 1. Uses Rust's memory safety features for buffer validation + // 2. Uses PROT_WRITE since wait writes status to user space + // 3. Two-step validation: memory region first, then reference creation + // 4. Process status handling managed by cage layer cage.wait_syscall(status) } WAITPID_SYSCALL => { let pid = arg1 as i32; let cage = interface::cagetable_getref(cageid); + + // Validate buffer for writing process status + // NaCl: Uses NaClIsValidAddress + // Using PROT_WRITE because waitpid() writes status information TO user space + // Size is 4 bytes for status integer let status = match check_and_convert_addr_ext(&cage, arg2, 4, PROT_WRITE) { - Ok(addr) => interface::get_i32_ref(addr).unwrap(), + Ok(addr) => match interface::get_i32_ref(addr) { + Ok(status_ref) => status_ref, + Err(_) => return syscall_error(Errno::EFAULT, "waitpid", "failed to get status reference"), + }, Err(errno) => return syscall_error(errno, "waitpid", "invalid status address"), }; let options = arg3 as i32; + // Perform waitpid operation through cage implementation + // + // Implementation differences from NaCl: + // 1. Uses Rust's memory safety features for buffer validation + // 2. Uses PROT_WRITE since waitpid writes status to user space + // 3. Two-step validation: memory region first, then reference creation + // 4. Process status handling managed by cage layer cage.waitpid_syscall(pid, status, options) } From aeb0ed019f95bf4ea900f8fe8141fe1acda45713 Mon Sep 17 00:00:00 2001 From: Chinmay Shringi Date: Sat, 28 Dec 2024 21:57:20 -0500 Subject: [PATCH 19/66] fix: remove comments --- src/RawPOSIX/src/safeposix/dispatcher.rs | 29 ------------------------ 1 file changed, 29 deletions(-) diff --git a/src/RawPOSIX/src/safeposix/dispatcher.rs b/src/RawPOSIX/src/safeposix/dispatcher.rs index 478b70ede..5328d2375 100644 --- a/src/RawPOSIX/src/safeposix/dispatcher.rs +++ b/src/RawPOSIX/src/safeposix/dispatcher.rs @@ -203,7 +203,6 @@ pub fn lind_syscall_api( let ret = match call_number { WRITE_SYSCALL => { - // NaCl equivalent: NaClSysWrite // Handles writing data from user buffer to file descriptor // Get file descriptor - same as NaCl's first argument handling @@ -217,7 +216,6 @@ pub fn lind_syscall_api( } // Get cage reference for memory operations - // NaCl equivalent: struct NaClApp *nap = natp->nap let cage = interface::cagetable_getref(cageid); // Validate and convert user buffer address to system address @@ -239,7 +237,6 @@ pub fn lind_syscall_api( } WRITEV_SYSCALL => { - // NaCl equivalent: NaClSysWritev let fd = arg1 as i32; let iovcnt = arg3 as i32; @@ -278,7 +275,6 @@ pub fn lind_syscall_api( } MUNMAP_SYSCALL => { - // NaCl equivalent: NaClSysMunmap let addr = arg1 as *mut u8; let length = arg2 as usize; let cage = interface::cagetable_getref(cageid); @@ -308,7 +304,6 @@ pub fn lind_syscall_api( } MMAP_SYSCALL => { - // NaCl equivalent: NaClSysMmap let addr = arg1 as *mut u8; let len = arg2 as usize; let prot = arg3 as i32; @@ -343,7 +338,6 @@ pub fn lind_syscall_api( } PREAD_SYSCALL => { - // NaCl equivalent: NaClSysPread let fd = arg1 as i32; let count = arg3 as usize; let offset = arg4 as i64; @@ -360,7 +354,6 @@ pub fn lind_syscall_api( } READ_SYSCALL => { - // NaCl equivalent: NaClSysRead let fd = arg1 as i32; let count = arg3 as usize; let cage = interface::cagetable_getref(cageid); @@ -379,7 +372,6 @@ pub fn lind_syscall_api( } CLOSE_SYSCALL => { - // NaCl equivalent: NaClSysClose let fd = arg1 as i32; // File descriptor validation and close operation handled by cage @@ -389,7 +381,6 @@ pub fn lind_syscall_api( } ACCESS_SYSCALL => { - // NaCl equivalent: NaClSysAccess let cage = interface::cagetable_getref(cageid); // Validate and convert path string from user space @@ -409,7 +400,6 @@ pub fn lind_syscall_api( } OPEN_SYSCALL => { - // NaCl equivalent: NaClSysOpen let cage = interface::cagetable_getref(cageid); // Validate and convert path string from user space @@ -430,7 +420,6 @@ pub fn lind_syscall_api( } SOCKET_SYSCALL => { - // NaCl equivalent: NaClSysSocket let domain = arg1 as i32; let socktype = arg2 as i32; let protocol = arg3 as i32; @@ -443,7 +432,6 @@ pub fn lind_syscall_api( } CONNECT_SYSCALL => { - // NaCl equivalent: NaClSysConnect let fd = arg1 as i32; let cage = interface::cagetable_getref(cageid); @@ -469,7 +457,6 @@ pub fn lind_syscall_api( } BIND_SYSCALL => { - // NaCl equivalent: NaClSysBind let fd = arg1 as i32; let cage = interface::cagetable_getref(cageid); @@ -495,7 +482,6 @@ pub fn lind_syscall_api( } ACCEPT_SYSCALL => { - // NaCl equivalent: NaClSysAccept let mut addr = interface::GenSockaddr::V4(interface::SockaddrV4::default()); let nullity1 = interface::arg_nullity(arg2); let nullity2 = interface::arg_nullity(arg3); @@ -535,7 +521,6 @@ pub fn lind_syscall_api( } EXEC_SYSCALL => { - // NaCl equivalent: NaClSysExec let child_cageid = arg1 as u64; // Perform exec operation through cage implementation @@ -545,7 +530,6 @@ pub fn lind_syscall_api( } EXIT_SYSCALL => { - // NaCl equivalent: NaClSysExit let status = arg1 as i32; // Perform exit operation through cage implementation @@ -555,7 +539,6 @@ pub fn lind_syscall_api( } SELECT_SYSCALL => { - // NaCl equivalent: NaClSysSelect let nfds = arg1 as i32; // Get and validate fd sets @@ -587,7 +570,6 @@ pub fn lind_syscall_api( } RENAME_SYSCALL => { - // NaCl equivalent: NaClSysRename let cage = interface::cagetable_getref(cageid); // Validate and convert old path from user space @@ -615,7 +597,6 @@ pub fn lind_syscall_api( } XSTAT_SYSCALL => { - // NaCl equivalent: NaClSysStat let cage = interface::cagetable_getref(cageid); // Validate and convert path string from user space @@ -647,7 +628,6 @@ pub fn lind_syscall_api( } MKDIR_SYSCALL => { - // NaCl equivalent: NaClSysMkdir let cage = interface::cagetable_getref(cageid); // Validate and convert path string from user space @@ -668,7 +648,6 @@ pub fn lind_syscall_api( } RMDIR_SYSCALL => { - // NaCl equivalent: NaClSysRmdir let cage = interface::cagetable_getref(cageid); // Validate and convert path string from user space @@ -688,7 +667,6 @@ pub fn lind_syscall_api( } FCHDIR_SYSCALL => { - // NaCl equivalent: NaClSysFchdir let fd = arg1 as i32; // Perform fchdir operation through cage implementation @@ -717,7 +695,6 @@ pub fn lind_syscall_api( } GETCWD_SYSCALL => { - // NaCl equivalent: NaClSysGetcwd let bufsize = arg2 as usize; let cage = interface::cagetable_getref(cageid); @@ -737,7 +714,6 @@ pub fn lind_syscall_api( ret } FSTATFS_SYSCALL => { - // NaCl equivalent: NaClSysFstatfs let fd = arg1 as i32; let cage = interface::cagetable_getref(cageid); @@ -779,7 +755,6 @@ pub fn lind_syscall_api( } DUP_SYSCALL => { - // NaCl equivalent: NaClSysDup let fd = arg1 as i32; // Convert second argument to Option if it's within valid range @@ -797,7 +772,6 @@ pub fn lind_syscall_api( } DUP2_SYSCALL => { - // NaCl equivalent: NaClSysDup2 let fd = arg1 as i32; let fd2 = arg2 as i32; @@ -808,7 +782,6 @@ pub fn lind_syscall_api( } FCHMOD_SYSCALL => { - // NaCl equivalent: NaClSysFchmod let fd = arg1 as i32; let mode = arg2 as u32; @@ -819,7 +792,6 @@ pub fn lind_syscall_api( } FXSTAT_SYSCALL => { - // NaCl equivalent: NaClSysFstat let fd = arg1 as i32; let cage = interface::cagetable_getref(cageid); @@ -840,7 +812,6 @@ pub fn lind_syscall_api( } UNLINK_SYSCALL => { - // NaCl equivalent: NaClSysUnlink let cage = interface::cagetable_getref(cageid); // Validate and convert path string from user space From eb9338ab9a38a004523cb3044ee801a79382c42e Mon Sep 17 00:00:00 2001 From: Chinmay Shringi Date: Sat, 28 Dec 2024 21:58:31 -0500 Subject: [PATCH 20/66] fix: rm security --- src/RawPOSIX/src/safeposix/dispatcher.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/RawPOSIX/src/safeposix/dispatcher.rs b/src/RawPOSIX/src/safeposix/dispatcher.rs index 5328d2375..797b83c9c 100644 --- a/src/RawPOSIX/src/safeposix/dispatcher.rs +++ b/src/RawPOSIX/src/safeposix/dispatcher.rs @@ -208,7 +208,6 @@ pub fn lind_syscall_api( // Get file descriptor - same as NaCl's first argument handling let fd = arg1 as i32; - // Security: Clamp count to prevent integer overflow attacks // NaCl uses similar bounds checking via MAX_IO_BUFFER_BYTES let count = std::cmp::min(arg3 as usize, i32::MAX as usize); if count == 0 { From 7ff9858533833145d17757488ac0e6569f88f677 Mon Sep 17 00:00:00 2001 From: Chinmay Shringi Date: Sat, 28 Dec 2024 21:59:39 -0500 Subject: [PATCH 21/66] fix: rm todo --- src/RawPOSIX/src/safeposix/dispatcher.rs | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/src/RawPOSIX/src/safeposix/dispatcher.rs b/src/RawPOSIX/src/safeposix/dispatcher.rs index 797b83c9c..86e08a4e4 100644 --- a/src/RawPOSIX/src/safeposix/dispatcher.rs +++ b/src/RawPOSIX/src/safeposix/dispatcher.rs @@ -278,18 +278,6 @@ pub fn lind_syscall_api( let length = arg2 as usize; let cage = interface::cagetable_getref(cageid); - // TODO(Security): Need to implement the following NaCl-style security checks: - // 1. is_page_aligned() - Checks if address is page-aligned (4KB boundaries) - // Reference: NaCl checks this via NaClIsAllocPageMultiple - // - // 2. round_to_page_size() - Rounds length up to nearest page size - // Reference: NaCl uses NaClRoundAllocPage - // - // 3. contains_executable_pages() - Prevents unmapping executable pages - // Reference: NaCl uses NaClSysCommonAddrRangeContainsExecutablePages - // - // These functions might help in the interface module. - if length == 0 { return syscall_error( Errno::EINVAL, @@ -319,12 +307,6 @@ pub fn lind_syscall_api( ); } - // TODO(Security): Need NaClSysCommonMmapCheck equivalent to validate: - // - W^X protection checks (write XOR execute) - // - Address space limit checks (see NaCl's check at addr_bits) - // - Overflow checks for length + offset - // - Page alignment validation when MAP_FIXED is used - // Reference: NaCl implementation in nacl_syscall_common.c:1756 // Force MAP_FIXED as NaCl does let flags = flags | MAP_FIXED as i32; @@ -2070,7 +2052,6 @@ pub fn lindrustinit(verbosity: isize) { let _ = interface::VERBOSE.set(verbosity); //assigned to suppress unused result warning interface::cagetable_init(); - // TODO: needs to add close() that handling im-pipe fdtables::register_close_handlers(FDKIND_KERNEL, fdtables::NULL_FUNC, kernel_close); let utilcage = Cage { From 29d1d1d817a6bdfec070b09836858c09a9b85e15 Mon Sep 17 00:00:00 2001 From: Chinmay Shringi Date: Sat, 28 Dec 2024 22:00:51 -0500 Subject: [PATCH 22/66] revert: err panic --- src/RawPOSIX/src/safeposix/dispatcher.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/RawPOSIX/src/safeposix/dispatcher.rs b/src/RawPOSIX/src/safeposix/dispatcher.rs index 86e08a4e4..133741d37 100644 --- a/src/RawPOSIX/src/safeposix/dispatcher.rs +++ b/src/RawPOSIX/src/safeposix/dispatcher.rs @@ -429,7 +429,7 @@ pub fn lind_syscall_api( // Convert to reference for connect operation let remoteaddr = match Ok::<&interface::GenSockaddr, i32>(&addr) { Ok(addr) => addr, - Err(_) => return syscall_error(Errno::EFAULT, "connect", "sockaddr conversion failed"), + Err(_) => panic!("Failed to get sockaddr"), // Handle error appropriately }; // Perform connect operation through cage implementation From a244d12305be14b9dd608b279d5a04591f273d98 Mon Sep 17 00:00:00 2001 From: Chinmay Shringi Date: Sat, 28 Dec 2024 22:02:28 -0500 Subject: [PATCH 23/66] fix: revert todo --- src/RawPOSIX/src/safeposix/dispatcher.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/RawPOSIX/src/safeposix/dispatcher.rs b/src/RawPOSIX/src/safeposix/dispatcher.rs index 133741d37..306b3fa6c 100644 --- a/src/RawPOSIX/src/safeposix/dispatcher.rs +++ b/src/RawPOSIX/src/safeposix/dispatcher.rs @@ -454,7 +454,7 @@ pub fn lind_syscall_api( // Convert to reference for bind operation let localaddr = match Ok::<&interface::GenSockaddr, i32>(&addr) { Ok(addr) => addr, - Err(_) => return syscall_error(Errno::EFAULT, "bind", "sockaddr conversion failed"), + Err(_) => panic!("Failed to get sockaddr"), // Handle error appropriately }; // Perform bind operation through cage implementation @@ -2051,7 +2051,8 @@ pub fn lindgetsighandler(cageid: u64, signo: i32) -> u32 { pub fn lindrustinit(verbosity: isize) { let _ = interface::VERBOSE.set(verbosity); //assigned to suppress unused result warning interface::cagetable_init(); - + + // TODO: needs to add close() that handling im-pipe fdtables::register_close_handlers(FDKIND_KERNEL, fdtables::NULL_FUNC, kernel_close); let utilcage = Cage { From f184378acace9b7d3cd6f03465d4b1cef88a41e8 Mon Sep 17 00:00:00 2001 From: Chinmay Shringi Date: Sat, 28 Dec 2024 22:27:57 -0500 Subject: [PATCH 24/66] fix: rm nacl comments --- src/RawPOSIX/src/safeposix/dispatcher.rs | 386 ++--------------------- 1 file changed, 27 insertions(+), 359 deletions(-) diff --git a/src/RawPOSIX/src/safeposix/dispatcher.rs b/src/RawPOSIX/src/safeposix/dispatcher.rs index 306b3fa6c..5c4c7b99b 100644 --- a/src/RawPOSIX/src/safeposix/dispatcher.rs +++ b/src/RawPOSIX/src/safeposix/dispatcher.rs @@ -205,20 +205,19 @@ pub fn lind_syscall_api( WRITE_SYSCALL => { // Handles writing data from user buffer to file descriptor - // Get file descriptor - same as NaCl's first argument handling + // Get file descriptor let fd = arg1 as i32; - // NaCl uses similar bounds checking via MAX_IO_BUFFER_BYTES + // Check bounds using MAX_IO_BUFFER_BYTES let count = std::cmp::min(arg3 as usize, i32::MAX as usize); if count == 0 { - return 0; // Early return for zero-length writes (NaCl behavior) + return 0; // Early return for zero-length writes } // Get cage reference for memory operations let cage = interface::cagetable_getref(cageid); // Validate and convert user buffer address to system address - // NaCl: Uses NaClUserToSysAddrRangeProt with similar protection flags // PROT_READ is correct because write() reads FROM the buffer let buf = match check_and_convert_addr_ext(&cage, arg2, count, PROT_READ) { Ok(addr) => addr as *const u8, @@ -239,7 +238,7 @@ pub fn lind_syscall_api( let fd = arg1 as i32; let iovcnt = arg3 as i32; - // NaCl validates count first + // Validate count first if iovcnt <= 0 { return syscall_error( Errno::EINVAL, @@ -251,7 +250,6 @@ pub fn lind_syscall_api( let cage = interface::cagetable_getref(cageid); // Validate the iovec array address first - // This matches NaCl's validation order let iov_base = match check_and_convert_addr_ext( &cage, arg2, @@ -268,7 +266,6 @@ pub fn lind_syscall_api( } }; - // NaCl validates each iovec entry's buffer - we do this in writev_syscall // The actual write operation is delegated to the cage implementation cage.writev_syscall(fd, iov_base, iovcnt) } @@ -298,7 +295,7 @@ pub fn lind_syscall_api( let fd = arg5 as i32; let off = arg6 as i64; - // Basic length validation, similar to NaCl + // Basic length validation if len == 0 { return syscall_error( Errno::EINVAL, @@ -307,12 +304,10 @@ pub fn lind_syscall_api( ); } - - // Force MAP_FIXED as NaCl does + // Force MAP_FIXED let flags = flags | MAP_FIXED as i32; // Turn off PROT_EXEC for non-code pages - // NaCl does this to prevent execution of data pages let prot = prot & !PROT_EXEC; interface::mmap_handler(cageid, addr, len, prot, flags, fd, off) @@ -325,7 +320,7 @@ pub fn lind_syscall_api( let cage = interface::cagetable_getref(cageid); // Validate and convert user buffer address - // NaCl uses NaClUserToSysAddr with PROT_WRITE since pread writes TO the buffer + // Using PROT_WRITE since pread writes TO the buffer let buf = match check_and_convert_addr_ext(&cage, arg2, count, PROT_WRITE) { Ok(addr) => addr as *mut u8, Err(errno) => return syscall_error(errno, "pread", "invalid buffer address"), @@ -341,14 +336,13 @@ pub fn lind_syscall_api( // Validate and convert user buffer address // Using PROT_WRITE since read() writes TO the buffer - // NaCl: Uses NaClUserToSysAddr with similar validation let buf = match check_and_convert_addr_ext(&cage, arg2, count, PROT_WRITE) { Ok(addr) => addr as *mut u8, Err(errno) => return syscall_error(errno, "read", "invalid buffer address"), }; // File descriptor validation and actual read operation - // handled by cage implementation (similar to NaCl's ndp->vtbl->Read) + // handled by cage implementation cage.read_syscall(fd, buf, count) } @@ -356,7 +350,6 @@ pub fn lind_syscall_api( let fd = arg1 as i32; // File descriptor validation and close operation handled by cage - // Similar to NaCl's ndp->vtbl->Close after NaClGetDesc validation interface::cagetable_getref(cageid) .close_syscall(fd) } @@ -365,7 +358,6 @@ pub fn lind_syscall_api( let cage = interface::cagetable_getref(cageid); // Validate and convert path string from user space - // NaCl: Uses NaClCopyInFromUser with MAXPATHLEN check let path = match check_and_convert_addr_ext(&cage, arg1, 1, PROT_READ) { Ok(addr) => match interface::types::get_cstr(addr as u64) { Ok(path_str) => path_str, @@ -376,7 +368,6 @@ pub fn lind_syscall_api( let amode = arg2 as i32; // Perform access check through cage implementation - // Similar to NaCl's lind_access call cage.access_syscall(path, amode) } @@ -384,7 +375,6 @@ pub fn lind_syscall_api( let cage = interface::cagetable_getref(cageid); // Validate and convert path string from user space - // NaCl: Uses NaClCopyInFromUser with MAXPATHLEN check let path = match check_and_convert_addr_ext(&cage, arg1, 1, PROT_READ) { Ok(addr) => match interface::types::get_cstr(addr as u64) { Ok(path_str) => path_str, @@ -396,7 +386,6 @@ pub fn lind_syscall_api( let mode = arg3 as u32; // Perform open operation through cage implementation - // Similar to NaCl's lind_open call cage.open_syscall(path, flags, mode) } @@ -407,7 +396,6 @@ pub fn lind_syscall_api( // Perform socket operation through cage implementation // Domain, type, and protocol validation handled by cage layer - // Similar to NaCl's lind_socket call interface::cagetable_getref(cageid) .socket_syscall(domain, socktype, protocol) } @@ -417,7 +405,6 @@ pub fn lind_syscall_api( let cage = interface::cagetable_getref(cageid); // Validate and convert sockaddr from user space - // NaCl: Uses NaClCopyInFromUser for sockaddr validation let addr = match check_and_convert_addr_ext(&cage, arg2, arg3 as usize, PROT_READ) { Ok(addr) => match interface::get_sockaddr(addr as u64, arg3 as u32) { Ok(sockaddr) => sockaddr, @@ -442,7 +429,6 @@ pub fn lind_syscall_api( let cage = interface::cagetable_getref(cageid); // Validate and convert sockaddr from user space - // NaCl: Uses NaClCopyInFromUser for sockaddr validation let addr = match check_and_convert_addr_ext(&cage, arg2, arg3 as usize, PROT_READ) { Ok(addr) => match interface::get_sockaddr(addr as u64, arg3 as u32) { Ok(sockaddr) => sockaddr, @@ -477,12 +463,10 @@ pub fn lind_syscall_api( // Perform accept operation first let rv = cage.accept_syscall(arg1 as i32, &mut Some(&mut addr)); if rv >= 0 { - // NaCl: Similar to NaClCopyOutToUser for sockaddr let addr2_addr = match check_and_convert_addr_ext(&cage, arg2, arg3 as usize, PROT_WRITE) { Ok(addr) => addr, Err(errno) => return syscall_error(errno, "accept", "invalid address buffer"), }; - // NaCl: Similar to NaClCopyOutToUser for addrlen let len_addr = match check_and_convert_addr_ext(&cage, arg3, std::mem::size_of::(), PROT_WRITE) { Ok(addr) => addr, Err(errno) => return syscall_error(errno, "accept", "invalid length buffer"), @@ -523,7 +507,6 @@ pub fn lind_syscall_api( let nfds = arg1 as i32; // Get and validate fd sets - // NaCl: Uses NaClCopyInFromUser for fd_set validation let readfds = match interface::get_fdset(arg2) { Ok(fds) => fds, Err(_) => return syscall_error(Errno::EFAULT, "select", "invalid readfds"), @@ -538,7 +521,6 @@ pub fn lind_syscall_api( }; // Get and validate timeout - // NaCl: Uses NaClCopyInFromUser for timeval validation let rposix_timeout = match interface::duration_fromtimeval(arg5) { Ok(timeout) => timeout, Err(_) => return syscall_error(Errno::EFAULT, "select", "invalid timeout"), @@ -554,7 +536,6 @@ pub fn lind_syscall_api( let cage = interface::cagetable_getref(cageid); // Validate and convert old path from user space - // NaCl: Uses NaClCopyInFromUser with MAXPATHLEN check let old_path = match check_and_convert_addr_ext(&cage, arg1, 1, PROT_READ) { Ok(addr) => match interface::types::get_cstr(addr) { Ok(path_str) => path_str, @@ -564,7 +545,6 @@ pub fn lind_syscall_api( }; // Validate and convert new path from user space - // NaCl: Uses NaClCopyInFromUser with MAXPATHLEN check let new_path = match check_and_convert_addr_ext(&cage, arg2, 1, PROT_READ) { Ok(addr) => match interface::types::get_cstr(addr) { Ok(path_str) => path_str, @@ -581,7 +561,6 @@ pub fn lind_syscall_api( let cage = interface::cagetable_getref(cageid); // Validate and convert path string from user space - // NaCl: Uses NaClCopyInFromUser with MAXPATHLEN check // Using PROT_READ because we need to read the path string FROM user space // (stat takes the path as input, we don't write to it) let path = match check_and_convert_addr_ext(&cage, arg1, 1, PROT_READ) { @@ -593,7 +572,6 @@ pub fn lind_syscall_api( }; // Validate stat buffer and prepare for writing - // NaCl: Allocates buffer and uses NaClCopyOutToUser // Using PROT_WRITE because stat() writes the results TO this user space buffer let buf = match check_and_convert_addr_ext(&cage, arg2, std::mem::size_of::(), PROT_WRITE) { Ok(addr) => match interface::get_statdatastruct(addr) { @@ -612,7 +590,6 @@ pub fn lind_syscall_api( let cage = interface::cagetable_getref(cageid); // Validate and convert path string from user space - // NaCl: Uses NaClCopyInFromUser with MAXPATHLEN check // Using PROT_READ because we need to read the path string FROM user space // (mkdir takes the path as input, we don't write to it) let path = match check_and_convert_addr_ext(&cage, arg1, 1, PROT_READ) { @@ -632,7 +609,6 @@ pub fn lind_syscall_api( let cage = interface::cagetable_getref(cageid); // Validate and convert path string from user space - // NaCl: Uses NaClCopyInFromUser with MAXPATHLEN check // Using PROT_READ because we need to read the path string FROM user space // (rmdir takes the path as input, we don't write to it) let path = match check_and_convert_addr_ext(&cage, arg1, 1, PROT_READ) { @@ -660,7 +636,6 @@ pub fn lind_syscall_api( let cage = interface::cagetable_getref(cageid); // Validate and convert path string from user space - // NaCl: Uses NaClCopyInFromUser with MAXPATHLEN check // Using PROT_READ because we need to read the path string FROM user space // (chdir takes the path as input, we don't write to it) let path = match check_and_convert_addr_ext(&cage, arg1, 1, PROT_READ) { @@ -680,7 +655,6 @@ pub fn lind_syscall_api( let cage = interface::cagetable_getref(cageid); // Validate buffer for writing - // NaCl: Uses NaClCopyOutToUser // Using PROT_WRITE because getcwd() writes the current working directory path // TO this user space buffer let buf = match check_and_convert_addr_ext(&cage, arg1, bufsize, PROT_WRITE) { @@ -689,7 +663,7 @@ pub fn lind_syscall_api( }; // Perform getcwd operation through cage implementation - // On success (ret == 0), return the buffer address like NaCl does + // On success (ret == 0), return the buffer address let ret = cage.getcwd_syscall(buf, bufsize as u32); if ret == 0 { return arg1 as i32; } ret @@ -699,7 +673,6 @@ pub fn lind_syscall_api( let cage = interface::cagetable_getref(cageid); // Validate buffer for writing filesystem information - // NaCl: Uses NaClCopyOutToUser // Using PROT_WRITE because fstatfs() writes filesystem information // TO this user space buffer let buf = match check_and_convert_addr_ext(&cage, arg2, 1, PROT_WRITE) { @@ -719,7 +692,6 @@ pub fn lind_syscall_api( let cage = interface::cagetable_getref(cageid); // Validate and convert path string from user space - // NaCl: Uses NaClCopyInFromUser with MAXPATHLEN check // Using PROT_READ because we need to read the path string FROM user space // (chmod takes the path as input, we don't write to it) let path = match check_and_convert_addr_ext(&cage, arg1, 1, PROT_READ) { @@ -739,7 +711,6 @@ pub fn lind_syscall_api( let fd = arg1 as i32; // Convert second argument to Option if it's within valid range - // This is an extension to NaCl's implementation to support both dup and dup2 let fd2: Option = if arg1 <= i32::MAX as u64 { Some(arg1 as i32) } else { @@ -777,7 +748,6 @@ pub fn lind_syscall_api( let cage = interface::cagetable_getref(cageid); // Validate stat buffer and prepare for writing - // NaCl: Uses NaClCopyOutToUser // Using PROT_WRITE because fstat() writes the results TO this user space buffer let buf = match check_and_convert_addr_ext(&cage, arg2, std::mem::size_of::(), PROT_WRITE) { Ok(addr) => match interface::get_statdatastruct(addr) { @@ -796,7 +766,6 @@ pub fn lind_syscall_api( let cage = interface::cagetable_getref(cageid); // Validate and convert path string from user space - // NaCl: Uses NaClCopyInFromUser with MAXPATHLEN check // Using PROT_READ because we need to read the path string FROM user space // (unlink takes the path as input, we don't write to it) let path = match check_and_convert_addr_ext(&cage, arg1, 1, PROT_READ) { @@ -815,7 +784,6 @@ pub fn lind_syscall_api( let cage = interface::cagetable_getref(cageid); // Validate and convert old path string from user space - // NaCl: Uses NaClCopyInFromUser with MAXPATHLEN check // Using PROT_READ because we need to read the path string FROM user space let old_path = match check_and_convert_addr_ext(&cage, arg1, 1, PROT_READ) { Ok(addr) => match interface::types::get_cstr(addr) { @@ -826,7 +794,6 @@ pub fn lind_syscall_api( }; // Validate and convert new path string from user space - // NaCl: Uses NaClCopyInFromUser with MAXPATHLEN check // Using PROT_READ because we need to read the path string FROM user space let new_path = match check_and_convert_addr_ext(&cage, arg2, 1, PROT_READ) { Ok(addr) => match interface::types::get_cstr(addr) { @@ -847,11 +814,6 @@ pub fn lind_syscall_api( // Perform lseek operation through cage implementation // File descriptor validation and bounds checking handled by cage layer - // - // Implementation differences from NaCl: - // 1. No memory protection flags needed as we're only dealing with integer values - // 2. File descriptor validation handled by cage layer - // 3. Simple and straightforward implementation as no memory operations are involved interface::cagetable_getref(cageid) .lseek_syscall(virtual_fd, offset, whence) } @@ -862,13 +824,7 @@ pub fn lind_syscall_api( let ptrunion = (start_address + arg3) as *mut u8; // Perform ioctl operation through cage implementation - // Note: Like NaCl, we restrict ioctl operations for security - // - // Implementation differences from NaCl: - // 1. Uses raw pointer arithmetic for argument handling - // 2. File descriptor validation handled by cage layer - // 3. Request validation and security checks handled by cage layer - // 4. Memory protection handled at the cage level rather than dispatcher + // Note: We restrict ioctl operations for security interface::cagetable_getref(cageid) .ioctl_syscall(virtual_fd, request, ptrunion) } @@ -877,7 +833,6 @@ pub fn lind_syscall_api( let cage = interface::cagetable_getref(cageid); // Validate and convert path string from user space - // NaCl: Uses NaClCopyInFromUser with MAXPATHLEN check // Using PROT_READ because we need to read the path string FROM user space let path = match check_and_convert_addr_ext(&cage, arg1, 1, PROT_READ) { Ok(addr) => match interface::types::get_cstr(addr) { @@ -889,12 +844,6 @@ pub fn lind_syscall_api( let length = arg2 as isize; // Perform truncate operation through cage implementation - // - // Implementation differences from NaCl: - // 1. Uses Rust's type system for memory safety instead of manual allocation - // 2. Path validation handled by helper functions - // 3. No explicit cleanup needed due to Rust's ownership system - // 4. Uses PROT_READ since we're only reading the path from user space cage.truncate_syscall(path, length) } @@ -904,11 +853,6 @@ pub fn lind_syscall_api( // Perform ftruncate operation through cage implementation // File descriptor validation handled by cage layer - // - // Implementation differences from NaCl: - // 1. No memory protection flags needed as we're only dealing with integer values - // 2. File descriptor validation handled by cage layer - // 3. Simple and straightforward implementation as no memory operations are involved interface::cagetable_getref(cageid) .ftruncate_syscall(virtual_fd, length) } @@ -919,7 +863,6 @@ pub fn lind_syscall_api( let cage = interface::cagetable_getref(cageid); // Validate buffer for writing directory entries - // NaCl: Uses NaClCopyOutToUser // Using PROT_WRITE because getdents() writes directory entries TO this user space buffer let buf = match check_and_convert_addr_ext(&cage, arg2, nbytes as usize, PROT_WRITE) { Ok(addr) => addr as *mut u8, @@ -928,12 +871,6 @@ pub fn lind_syscall_api( // Perform getdents operation through cage implementation // File descriptor validation handled by cage layer - // - // Implementation differences from NaCl: - // 1. Uses Rust's type system for memory safety instead of manual allocation - // 2. Buffer validation handled by helper functions - // 3. No explicit cleanup needed due to Rust's ownership system - // 4. Uses PROT_WRITE since we're writing directory entries to user space cage.getdents_syscall(virtual_fd, buf, nbytes) } @@ -941,7 +878,6 @@ pub fn lind_syscall_api( let cage = interface::cagetable_getref(cageid); // Validate and convert path string from user space - // NaCl: Uses NaClCopyInFromUser with MAXPATHLEN check // Using PROT_READ because we need to read the path string FROM user space let path = match check_and_convert_addr_ext(&cage, arg1, 1, PROT_READ) { Ok(addr) => match interface::types::get_cstr(addr) { @@ -952,7 +888,6 @@ pub fn lind_syscall_api( }; // Validate buffer for writing filesystem information - // NaCl: Uses NaClCopyOutToUser // Using PROT_WRITE because statfs() writes filesystem information TO this user space buffer let rposix_databuf = match check_and_convert_addr_ext(&cage, arg2, 1, PROT_WRITE) { Ok(addr) => match interface::get_fsdatastruct(addr) { @@ -963,12 +898,6 @@ pub fn lind_syscall_api( }; // Perform statfs operation through cage implementation - // - // Implementation differences from NaCl: - // 1. Uses Rust's type system for memory safety instead of manual allocation - // 2. Path and buffer validation handled by helper functions - // 3. No explicit cleanup needed due to Rust's ownership system - // 4. Uses appropriate PROT flags for reading path and writing filesystem data cage.statfs_syscall(&path, rposix_databuf) } @@ -979,12 +908,6 @@ pub fn lind_syscall_api( // Perform fcntl operation through cage implementation // File descriptor validation and command validation handled by cage layer - // - // Implementation differences from NaCl: - // 1. No memory protection flags needed as we're only dealing with integer values - // 2. File descriptor validation handled by cage layer - // 3. Command validation handled by cage layer - // 4. Simple and straightforward implementation as no memory operations are involved interface::cagetable_getref(cageid) .fcntl_syscall(virtual_fd, cmd, arg) } @@ -1005,12 +928,6 @@ pub fn lind_syscall_api( // Perform recv operation through cage implementation // File descriptor validation handled by cage layer - // - // Implementation differences from NaCl: - // 1. Uses Rust's type system for memory safety instead of manual allocation - // 2. Buffer validation handled by helper functions - // 3. No explicit cleanup needed due to Rust's ownership system - // 4. Uses PROT_WRITE since we're writing received data to user space cage.recv_syscall(fd, buf, count, flag) } @@ -1020,7 +937,6 @@ pub fn lind_syscall_api( let cage = interface::cagetable_getref(cageid); // Validate buffer for reading data to send - // NaCl: Uses NaClCopyInFromUser // Using PROT_READ because we need to read the data FROM user space let buf = match check_and_convert_addr_ext(&cage, arg2, count, PROT_READ) { Ok(addr) => addr as *const u8, @@ -1029,7 +945,6 @@ pub fn lind_syscall_api( let flag = arg4 as i32; // Get and validate socket address - // NaCl: Uses NaClCopyInFromUser for sockaddr validation let addrlen = arg6 as u32; let addr = match interface::get_sockaddr(start_address + arg5, addrlen) { Ok(addr) => addr, @@ -1038,12 +953,6 @@ pub fn lind_syscall_api( // Perform sendto operation through cage implementation // File descriptor validation handled by cage layer - // - // Implementation differences from NaCl: - // 1. Uses Rust's type system for memory safety instead of manual allocation - // 2. Buffer and address validation handled by helper functions - // 3. No explicit cleanup needed due to Rust's ownership system - // 4. Uses PROT_READ since we're reading data from user space cage.sendto_syscall(fd, buf, count, flag, &addr) } @@ -1053,7 +962,6 @@ pub fn lind_syscall_api( let cage = interface::cagetable_getref(cageid); // Validate buffer for writing received data - // NaCl: Uses NaClCopyOutToUser // Using PROT_WRITE because recvfrom() writes received data TO this user space buffer let buf = match check_and_convert_addr_ext(&cage, arg2, count, PROT_WRITE) { Ok(addr) => addr as *mut u8, @@ -1098,10 +1006,7 @@ pub fn lind_syscall_api( // Perform flock operation through cage implementation // File descriptor validation handled by cage layer - // - // Implementation differences from NaCl: - // 1. No memory protection flags needed as we're only dealing with integer values - // 2. File descriptor validation handled by cage layer + interface::cagetable_getref(cageid) // 3. Operation validation handled by cage layer // 4. Simple and straightforward implementation as no memory operations are involved interface::cagetable_getref(cageid) @@ -1114,11 +1019,7 @@ pub fn lind_syscall_api( let shmfig = arg3 as i32; // Perform shmget operation through cage implementation - // - // Implementation differences from NaCl: - // 1. No memory protection flags needed as we're only dealing with integer values - // 2. Shared memory validation handled by cage layer - // 3. Simple and straightforward implementation as no memory operations are involved + interface::cagetable_getref(cageid) // 4. Size validation handled by cage layer interface::cagetable_getref(cageid) .shmget_syscall(key, size, shmfig) @@ -1128,7 +1029,6 @@ pub fn lind_syscall_api( let cage = interface::cagetable_getref(cageid); // Validate shared memory address - // NaCl: Uses NaClIsValidAddress // Using both PROT_READ and PROT_WRITE since shared memory needs both access types let shmaddr = match check_and_convert_addr_ext(&cage, arg2, 1, PROT_READ | PROT_WRITE) { Ok(addr) => addr as *mut u8, @@ -1137,12 +1037,6 @@ pub fn lind_syscall_api( let shmflg = arg3 as i32; // Perform shmat operation through cage implementation - // - // Implementation differences from NaCl: - // 1. Uses Rust's memory safety features for address validation - // 2. Uses PROT_READ | PROT_WRITE for shared memory access - // 3. Address validation handled by helper function - // 4. Shared memory operations handled by cage layer cage.shmat_syscall(shmid, shmaddr, shmflg) } @@ -1150,7 +1044,6 @@ pub fn lind_syscall_api( let cage = interface::cagetable_getref(cageid); // Validate shared memory address - // NaCl: Uses NaClIsValidAddress // Using both PROT_READ and PROT_WRITE since shared memory needs both access types let shmaddr = match check_and_convert_addr_ext(&cage, arg1, 1, PROT_READ | PROT_WRITE) { Ok(addr) => addr as *mut u8, @@ -1158,12 +1051,6 @@ pub fn lind_syscall_api( }; // Perform shmdt operation through cage implementation - // - // Implementation differences from NaCl: - // 1. Uses Rust's memory safety features for address validation - // 2. Uses PROT_READ | PROT_WRITE for shared memory access - // 3. Address validation handled by helper function - // 4. Shared memory operations handled by cage layer cage.shmdt_syscall(shmaddr) } @@ -1171,12 +1058,6 @@ pub fn lind_syscall_api( let mutex_handle = arg1 as i32; // Perform mutex destroy operation through cage implementation - // - // Implementation differences from NaCl: - // 1. No memory protection flags needed as we're only dealing with integer values - // 2. Mutex handle validation handled by cage layer - // 3. Simple and straightforward implementation as no memory operations are involved - // 4. Thread safety handled by Rust's type system interface::cagetable_getref(cageid) .mutex_destroy_syscall(mutex_handle) } @@ -1185,12 +1066,6 @@ pub fn lind_syscall_api( let mutex_handle = arg1 as i32; // Perform mutex lock operation through cage implementation - // - // Implementation differences from NaCl: - // 1. No memory protection flags needed as we're only dealing with integer values - // 2. Mutex handle validation handled by cage layer - // 3. Simple and straightforward implementation as no memory operations are involved - // 4. Thread safety handled by Rust's type system interface::cagetable_getref(cageid) .mutex_lock_syscall(mutex_handle) } @@ -1199,12 +1074,6 @@ pub fn lind_syscall_api( let mutex_handle = arg1 as i32; // Perform mutex trylock operation through cage implementation - // - // Implementation differences from NaCl: - // 1. No memory protection flags needed as we're only dealing with integer values - // 2. Mutex handle validation handled by cage layer - // 3. Simple and straightforward implementation as no memory operations are involved - // 4. Thread safety handled by Rust's type system interface::cagetable_getref(cageid) .mutex_trylock_syscall(mutex_handle) } @@ -1213,12 +1082,6 @@ pub fn lind_syscall_api( let mutex_handle = arg1 as i32; // Perform mutex unlock operation through cage implementation - // - // Implementation differences from NaCl: - // 1. No memory protection flags needed as we're only dealing with integer values - // 2. Mutex handle validation handled by cage layer - // 3. Simple and straightforward implementation as no memory operations are involved - // 4. Thread safety handled by Rust's type system interface::cagetable_getref(cageid) .mutex_unlock_syscall(mutex_handle) } @@ -1227,12 +1090,6 @@ pub fn lind_syscall_api( let cv_handle = arg1 as i32; // Perform condition variable destroy operation through cage implementation - // - // Implementation differences from NaCl: - // 1. No memory protection flags needed as we're only dealing with integer values - // 2. Condition variable handle validation handled by cage layer - // 3. Simple and straightforward implementation as no memory operations are involved - // 4. Thread safety handled by Rust's type system interface::cagetable_getref(cageid) .cond_destroy_syscall(cv_handle) } @@ -1240,14 +1097,8 @@ pub fn lind_syscall_api( COND_WAIT_SYSCALL => { let cv_handle = arg1 as i32; let mutex_handle = arg2 as i32; - + // Perform condition variable wait operation through cage implementation - // - // Implementation differences from NaCl: - // 1. No memory protection flags needed as we're only dealing with integer values - // 2. Condition variable and mutex handle validation handled by cage layer - // 3. Simple and straightforward implementation as no memory operations are involved - // 4. Thread safety handled by Rust's type system interface::cagetable_getref(cageid) .cond_wait_syscall(cv_handle, mutex_handle) } @@ -1256,12 +1107,6 @@ pub fn lind_syscall_api( let cv_handle = arg1 as i32; // Perform condition variable broadcast operation through cage implementation - // - // Implementation differences from NaCl: - // 1. No memory protection flags needed as we're only dealing with integer values - // 2. Condition variable handle validation handled by cage layer - // 3. Simple and straightforward implementation as no memory operations are involved - // 4. Thread safety handled by Rust's type system interface::cagetable_getref(cageid) .cond_broadcast_syscall(cv_handle) } @@ -1270,12 +1115,6 @@ pub fn lind_syscall_api( let cv_handle = arg1 as i32; // Perform condition variable signal operation through cage implementation - // - // Implementation differences from NaCl: - // 1. No memory protection flags needed as we're only dealing with integer values - // 2. Condition variable handle validation handled by cage layer - // 3. Simple and straightforward implementation as no memory operations are involved - // 4. Thread safety handled by Rust's type system interface::cagetable_getref(cageid) .cond_signal_syscall(cv_handle) } @@ -1286,12 +1125,6 @@ pub fn lind_syscall_api( let value = arg3 as u32; // Perform semaphore initialization operation through cage implementation - // - // Implementation differences from NaCl: - // 1. No memory protection flags needed as we're only dealing with integer values - // 2. Semaphore handle validation handled by cage layer - // 3. Simple and straightforward implementation as no memory operations are involved - // 4. Thread safety handled by Rust's type system interface::cagetable_getref(cageid) .sem_init_syscall(sem_handle, pshared, value) } @@ -1300,12 +1133,6 @@ pub fn lind_syscall_api( let sem_handle = arg1 as u32; // Perform semaphore wait operation through cage implementation - // - // Implementation differences from NaCl: - // 1. No memory protection flags needed as we're only dealing with integer values - // 2. Semaphore handle validation handled by cage layer - // 3. Simple and straightforward implementation as no memory operations are involved - // 4. Thread safety handled by Rust's type system interface::cagetable_getref(cageid) .sem_wait_syscall(sem_handle) } @@ -1314,12 +1141,6 @@ pub fn lind_syscall_api( let sem_handle = arg1 as u32; // Perform semaphore try wait operation through cage implementation - // - // Implementation differences from NaCl: - // 1. No memory protection flags needed as we're only dealing with integer values - // 2. Semaphore handle validation handled by cage layer - // 3. Simple and straightforward implementation as no memory operations are involved - // 4. Thread safety handled by Rust's type system interface::cagetable_getref(cageid) .sem_trywait_syscall(sem_handle) } @@ -1328,12 +1149,6 @@ pub fn lind_syscall_api( let sem_handle = arg1 as u32; // Perform semaphore post operation through cage implementation - // - // Implementation differences from NaCl: - // 1. No memory protection flags needed as we're only dealing with integer values - // 2. Semaphore handle validation handled by cage layer - // 3. Simple and straightforward implementation as no memory operations are involved - // 4. Thread safety handled by Rust's type system interface::cagetable_getref(cageid) .sem_post_syscall(sem_handle) } @@ -1342,12 +1157,6 @@ pub fn lind_syscall_api( let sem_handle = arg1 as u32; // Perform semaphore destroy operation through cage implementation - // - // Implementation differences from NaCl: - // 1. No memory protection flags needed as we're only dealing with integer values - // 2. Semaphore handle validation handled by cage layer - // 3. Simple and straightforward implementation as no memory operations are involved - // 4. Thread safety handled by Rust's type system interface::cagetable_getref(cageid) .sem_destroy_syscall(sem_handle) } @@ -1356,12 +1165,6 @@ pub fn lind_syscall_api( let sem_handle = arg1 as u32; // Perform semaphore get value operation through cage implementation - // - // Implementation differences from NaCl: - // 1. No memory protection flags needed as we're only dealing with integer values - // 2. Semaphore handle validation handled by cage layer - // 3. Simple and straightforward implementation as no memory operations are involved - // 4. Thread safety handled by Rust's type system interface::cagetable_getref(cageid) .sem_getvalue_syscall(sem_handle) } @@ -1371,7 +1174,6 @@ pub fn lind_syscall_api( let cage = interface::cagetable_getref(cageid); // Validate buffer for reading data to write - // NaCl: Uses NaClIsValidAddress // Using PROT_READ because we need to read the data FROM user space let buf = match check_and_convert_addr_ext(&cage, arg2, count, PROT_READ) { Ok(addr) => addr as *const u8, @@ -1381,55 +1183,27 @@ pub fn lind_syscall_api( let offset = arg4 as i64; // Perform pwrite operation through cage implementation - // - // Implementation differences from NaCl: - // 1. Uses Rust's memory safety features for buffer validation - // 2. Uses PROT_READ since we're reading data from user space - // 3. Buffer validation handled by helper function + interface::cagetable_getref(cageid) // 4. File descriptor validation handled by cage layer cage.pwrite_syscall(virtual_fd, buf, count, offset) } GETUID_SYSCALL => { - // Get real user ID through cage implementation - // - // Implementation differences from NaCl: - // 1. No memory protection flags needed as we're only returning an integer value - // 2. Simple and straightforward implementation with no validation needed - // 3. User ID management handled by cage layer interface::cagetable_getref(cageid) .getuid_syscall() } GETEUID_SYSCALL => { - // Get effective user ID through cage implementation - // - // Implementation differences from NaCl: - // 1. No memory protection flags needed as we're only returning an integer value - // 2. Simple and straightforward implementation with no validation needed - // 3. User ID management handled by cage layer interface::cagetable_getref(cageid) .geteuid_syscall() } GETGID_SYSCALL => { - // Get real group ID through cage implementation - // - // Implementation differences from NaCl: - // 1. No memory protection flags needed as we're only returning an integer value - // 2. Simple and straightforward implementation with no validation needed - // 3. Group ID management handled by cage layer interface::cagetable_getref(cageid) .getgid_syscall() } GETEGID_SYSCALL => { - // Get effective group ID through cage implementation - // - // Implementation differences from NaCl: - // 1. No memory protection flags needed as we're only returning an integer value - // 2. Simple and straightforward implementation with no validation needed - // 3. Group ID management handled by cage layer interface::cagetable_getref(cageid) .getegid_syscall() } @@ -1438,12 +1212,6 @@ pub fn lind_syscall_api( let size = arg1 as i32; // Perform epoll create operation through cage implementation - // - // Implementation differences from NaCl: - // 1. No memory protection flags needed as we're only dealing with integer values - // 2. Size validation handled by cage layer - // 3. Simple and straightforward implementation as no memory operations are involved - // 4. File descriptor management handled by cage layer interface::cagetable_getref(cageid) .epoll_create_syscall(size) } @@ -1454,17 +1222,9 @@ pub fn lind_syscall_api( let virtual_fd = arg3 as i32; // Validate and convert epoll_event structure - // NaCl: Uses NaClIsValidAddress for epoll_event validation - // Note: get_epollevent handles the validation and conversion internally let epollevent = interface::get_epollevent(arg4).unwrap(); // Perform epoll_ctl operation through cage implementation - // - // Implementation differences from NaCl: - // 1. Uses Rust's type system for epoll_event validation - // 2. Event structure validation handled by helper function - // 3. File descriptor validation handled by cage layer - // 4. Operation validation handled by cage layer interface::cagetable_getref(cageid) .epoll_ctl_syscall(virtual_epfd, op, virtual_fd, epollevent) } @@ -1487,7 +1247,6 @@ pub fn lind_syscall_api( let cage = interface::cagetable_getref(cageid); // Validate buffer for reading socket option value - // NaCl: Uses NaClIsValidAddress // Using PROT_READ because we need to read the option value FROM user space let optval = match check_and_convert_addr_ext(&cage, arg4, optlen as usize, PROT_READ) { Ok(addr) => addr as *mut u8, @@ -1495,11 +1254,7 @@ pub fn lind_syscall_api( }; // Perform setsockopt operation through cage implementation - // - // Implementation differences from NaCl: - // 1. Uses Rust's memory safety features for buffer validation - // 2. Uses PROT_READ since we're reading option value from user space - // 3. Buffer validation handled by helper function + interface::cagetable_getref(cageid) // 4. File descriptor validation handled by cage layer cage.setsockopt_syscall(virtual_fd, level, optname, optval, optlen) } @@ -1509,12 +1264,6 @@ pub fn lind_syscall_api( let how = arg2 as i32; // Perform shutdown operation through cage implementation - // - // Implementation differences from NaCl: - // 1. No memory protection flags needed as we're only dealing with integer values - // 2. File descriptor validation handled by cage layer - // 3. Simple and straightforward implementation as no memory operations are involved - // 4. Shutdown mode validation handled by cage layer interface::cagetable_getref(cageid) .shutdown_syscall(virtual_fd, how) } @@ -1530,7 +1279,6 @@ pub fn lind_syscall_api( let cage = interface::cagetable_getref(cageid); // Validate buffer for reading data to send - // NaCl: Uses NaClIsValidAddress // Using PROT_READ because we need to read the data FROM user space let buf = match check_and_convert_addr_ext(&cage, arg2, count, PROT_READ) { Ok(addr) => addr as *const u8, @@ -1539,12 +1287,7 @@ pub fn lind_syscall_api( let flags = arg4 as i32; // Perform send operation through cage implementation - // - // Implementation differences from NaCl: - // 1. Uses Rust's memory safety features for buffer validation - // 2. Uses PROT_READ since we're reading data from user space - // 3. Buffer validation handled by helper function - // 4. File descriptor validation handled by cage layer + interface::cagetable_getref(cageid) cage.send_syscall(fd, buf, count, flags) } @@ -1570,7 +1313,6 @@ pub fn lind_syscall_api( let cage = interface::cagetable_getref(cageid); // Validate buffer for writing hostname - // NaCl: Uses NaClIsValidAddress // Using PROT_WRITE because gethostname() writes hostname TO this user space buffer let name = match check_and_convert_addr_ext(&cage, arg1, len, PROT_WRITE) { Ok(addr) => addr as *mut u8, @@ -1578,12 +1320,6 @@ pub fn lind_syscall_api( }; // Perform gethostname operation through cage implementation - // - // Implementation differences from NaCl: - // 1. Uses Rust's memory safety features for buffer validation - // 2. Uses PROT_WRITE since we're writing hostname to user space - // 3. Buffer validation handled by helper function - // 4. Length validation handled by cage layer cage.gethostname_syscall(name, len as isize) } @@ -1592,7 +1328,6 @@ pub fn lind_syscall_api( let cage = interface::cagetable_getref(cageid); // Validate buffer for writing interface addresses - // NaCl: Uses NaClIsValidAddress // Using PROT_WRITE because getifaddrs() writes interface data TO user space buffer let buf = match check_and_convert_addr_ext(&cage, arg1, count, PROT_WRITE) { Ok(addr) => addr as *mut u8, @@ -1600,12 +1335,7 @@ pub fn lind_syscall_api( }; // Perform getifaddrs operation through cage implementation - // - // Implementation differences from NaCl: - // 1. Uses Rust's memory safety features for buffer validation - // 2. Uses PROT_WRITE since we're writing interface data to user space - // 3. Buffer validation handled by helper function - // 4. Size validation handled by cage layer + interface::cagetable_getref(cageid) cage.getifaddrs_syscall(buf, count) } @@ -1644,7 +1374,6 @@ pub fn lind_syscall_api( let cage = interface::cagetable_getref(cageid); // Validate buffer for writing pipe file descriptors - // NaCl: Uses NaClIsValidAddress // Using PROT_WRITE because pipe() writes two fds TO this user space buffer // Size is 8 bytes for two integers (file descriptors) let pipe = match check_and_convert_addr_ext(&cage, arg1, 8, PROT_WRITE) { @@ -1656,12 +1385,7 @@ pub fn lind_syscall_api( }; // Perform pipe operation through cage implementation - // - // Implementation differences from NaCl: - // 1. Uses Rust's memory safety features for buffer validation - // 2. Uses PROT_WRITE since pipe writes fds to user space - // 3. Two-step validation: memory region first, then array conversion - // 4. File descriptor management handled by cage layer + interface::cagetable_getref(cageid) cage.pipe_syscall(pipe) } @@ -1669,7 +1393,6 @@ pub fn lind_syscall_api( let cage = interface::cagetable_getref(cageid); // Validate buffer for writing pipe file descriptors - // NaCl: Uses NaClIsValidAddress // Using PROT_WRITE because pipe2() writes two fds TO this user space buffer // Size is 8 bytes for two integers (file descriptors) let pipe = match check_and_convert_addr_ext(&cage, arg1, 8, PROT_WRITE) { @@ -1682,12 +1405,7 @@ pub fn lind_syscall_api( let flag = arg2 as i32; // Perform pipe2 operation through cage implementation - // - // Implementation differences from NaCl: - // 1. Uses Rust's memory safety features for buffer validation - // 2. Uses PROT_WRITE since pipe2 writes fds to user space - // 3. Two-step validation: memory region first, then array conversion - // 4. File descriptor management handled by cage layer + interface::cagetable_getref(cageid) cage.pipe2_syscall(pipe, flag) } @@ -1696,7 +1414,6 @@ pub fn lind_syscall_api( let cage = interface::cagetable_getref(cageid); // Validate buffer for writing socket address - // NaCl: Uses NaClIsValidAddress // Using PROT_WRITE because getsockname() writes address TO user space let name_addr = match check_and_convert_addr_ext(&cage, arg2, 16, PROT_WRITE) { Ok(addr) => addr, @@ -1704,7 +1421,6 @@ pub fn lind_syscall_api( }; // Validate buffer for writing address length - // NaCl: Uses NaClIsValidAddress // Using PROT_WRITE because getsockname() writes length TO user space let namelen_addr = match check_and_convert_addr_ext(&cage, arg3, 4, PROT_WRITE) { Ok(addr) => addr, @@ -1724,12 +1440,7 @@ pub fn lind_syscall_api( } // Perform getsockname operation through cage implementation - // - // Implementation differences from NaCl: - // 1. Uses Rust's memory safety features for buffer validation - // 2. Uses PROT_WRITE since we're writing data to user space - // 3. Separate validation for address and length buffers - // 4. Explicit null pointer checks + interface::cagetable_getref(cageid) let rv = cage.getsockname_syscall(fd, &mut Some(&mut addr)); // Copy out the address if operation was successful @@ -1746,7 +1457,6 @@ pub fn lind_syscall_api( let cage = interface::cagetable_getref(cageid); // Validate buffer for writing socket option value - // NaCl: Uses NaClIsValidAddress // Using PROT_WRITE because getsockopt() writes option value TO user space // Size is 4 bytes for an integer value let optval_ptr = match check_and_convert_addr_ext(&cage, arg4, 4, PROT_WRITE) { @@ -1756,12 +1466,7 @@ pub fn lind_syscall_api( let optval = unsafe { &mut *optval_ptr }; // Perform getsockopt operation through cage implementation - // - // Implementation differences from NaCl: - // 1. Uses Rust's memory safety features for buffer validation - // 2. Uses PROT_WRITE since we're writing option value to user space - // 3. Buffer validation handled by helper function - // 4. File descriptor and option validation handled by cage layer + interface::cagetable_getref(cageid) cage.getsockopt_syscall(virtual_fd, level, optname, optval) } @@ -1772,7 +1477,6 @@ pub fn lind_syscall_api( let cage = interface::cagetable_getref(cageid); // Validate buffer for writing socket pair file descriptors - // NaCl: Uses NaClIsValidAddress // Using PROT_WRITE because socketpair() writes two fds TO this user space buffer // Size is 8 bytes for two integers (file descriptors) let virtual_socket_vector = match check_and_convert_addr_ext(&cage, arg4, 8, PROT_WRITE) { @@ -1784,12 +1488,7 @@ pub fn lind_syscall_api( }; // Perform socketpair operation through cage implementation - // - // Implementation differences from NaCl: - // 1. Uses Rust's memory safety features for buffer validation - // 2. Uses PROT_WRITE since socketpair writes fds to user space - // 3. Two-step validation: memory region first, then array conversion - // 4. Socket domain and type validation handled by cage layer + interface::cagetable_getref(cageid) cage.socketpair_syscall(domain, _type, protocol, virtual_socket_vector) } @@ -1798,7 +1497,6 @@ pub fn lind_syscall_api( let cage = interface::cagetable_getref(cageid); // Validate buffer for reading and writing poll file descriptors - // NaCl: Uses NaClIsValidAddress // Using PROT_READ | PROT_WRITE because: // - READ: poll needs to read the fds and events to monitor // - WRITE: poll needs to write back the returned events @@ -1813,12 +1511,7 @@ pub fn lind_syscall_api( let timeout = arg3 as i32; // Perform poll operation through cage implementation - // - // Implementation differences from NaCl: - // 1. Uses Rust's memory safety features for buffer validation - // 2. Uses both PROT_READ and PROT_WRITE since poll both reads and writes - // 3. Two-step validation: memory region first, then array conversion - // 4. File descriptor validation handled by cage layer + interface::cagetable_getref(cageid) cage.poll_syscall(pollfds, nfds, timeout) } @@ -1837,7 +1530,6 @@ pub fn lind_syscall_api( let cage = interface::cagetable_getref(cageid); // Validate buffer for futex operations - // NaCl: Uses NaClIsValidAddress // Using PROT_READ | PROT_WRITE because: // - READ: futex needs to read current value // - WRITE: futex may modify the value depending on operation @@ -1854,12 +1546,7 @@ pub fn lind_syscall_api( let val3 = arg6 as u32; // Perform futex operation through cage implementation - // - // Implementation differences from NaCl: - // 1. Uses Rust's memory safety features for buffer validation - // 2. Uses both PROT_READ and PROT_WRITE since futex both reads and may write - // 3. Buffer validation handled by helper function - // 4. Operation validation handled by cage layer + interface::cagetable_getref(cageid) cage.futex_syscall(uaddr, futex_op, val, timeout, uaddr2, val3) } @@ -1869,7 +1556,6 @@ pub fn lind_syscall_api( let cage = interface::cagetable_getref(cageid); // Validate buffer for reading requested sleep time - // NaCl: Uses NaClIsValidAddress // Using PROT_READ because we need to read the requested time FROM user space // Size is 16 bytes for timespec64 structure let req = match check_and_convert_addr_ext(&cage, arg3, 16, PROT_READ) { @@ -1878,7 +1564,6 @@ pub fn lind_syscall_api( }; // Validate buffer for writing remaining time - // NaCl: Uses NaClIsValidAddress // Using PROT_WRITE because nanosleep writes remaining time TO user space // Size is 16 bytes for timespec64 structure let rem = match check_and_convert_addr_ext(&cage, arg4, 16, PROT_WRITE) { @@ -1887,12 +1572,7 @@ pub fn lind_syscall_api( }; // Perform nanosleep operation through cage implementation - // - // Implementation differences from NaCl: - // 1. Uses Rust's memory safety features for buffer validation - // 2. Uses PROT_READ for req and PROT_WRITE for rem - // 3. Separate validation for request and remaining time buffers - // 4. Additional parameters for clock ID and flags (time64 version) + interface::cagetable_getref(cageid) cage.nanosleep_time64_syscall(clockid, flags, req, rem) } @@ -1900,7 +1580,6 @@ pub fn lind_syscall_api( let cage = interface::cagetable_getref(cageid); // Validate buffer for writing process status - // NaCl: Uses NaClIsValidAddress // Using PROT_WRITE because wait() writes status information TO user space // Size is 4 bytes for status integer let status = match check_and_convert_addr_ext(&cage, arg1, 4, PROT_WRITE) { @@ -1912,12 +1591,7 @@ pub fn lind_syscall_api( }; // Perform wait operation through cage implementation - // - // Implementation differences from NaCl: - // 1. Uses Rust's memory safety features for buffer validation - // 2. Uses PROT_WRITE since wait writes status to user space - // 3. Two-step validation: memory region first, then reference creation - // 4. Process status handling managed by cage layer + interface::cagetable_getref(cageid) cage.wait_syscall(status) } @@ -1926,7 +1600,6 @@ pub fn lind_syscall_api( let cage = interface::cagetable_getref(cageid); // Validate buffer for writing process status - // NaCl: Uses NaClIsValidAddress // Using PROT_WRITE because waitpid() writes status information TO user space // Size is 4 bytes for status integer let status = match check_and_convert_addr_ext(&cage, arg2, 4, PROT_WRITE) { @@ -1939,12 +1612,7 @@ pub fn lind_syscall_api( let options = arg3 as i32; // Perform waitpid operation through cage implementation - // - // Implementation differences from NaCl: - // 1. Uses Rust's memory safety features for buffer validation - // 2. Uses PROT_WRITE since waitpid writes status to user space - // 3. Two-step validation: memory region first, then reference creation - // 4. Process status handling managed by cage layer + interface::cagetable_getref(cageid) cage.waitpid_syscall(pid, status, options) } From d3eeed307665e2a46faee21322e5c6f02791d000 Mon Sep 17 00:00:00 2001 From: Chinmay Shringi Date: Sat, 28 Dec 2024 22:33:12 -0500 Subject: [PATCH 25/66] fix: removed nacl --- src/RawPOSIX/src/safeposix/dispatcher.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/RawPOSIX/src/safeposix/dispatcher.rs b/src/RawPOSIX/src/safeposix/dispatcher.rs index 5c4c7b99b..14f6c1c05 100644 --- a/src/RawPOSIX/src/safeposix/dispatcher.rs +++ b/src/RawPOSIX/src/safeposix/dispatcher.rs @@ -918,7 +918,6 @@ pub fn lind_syscall_api( let cage = interface::cagetable_getref(cageid); // Validate buffer for writing received data - // NaCl: Uses NaClCopyOutToUser // Using PROT_WRITE because recv() writes received data TO this user space buffer let buf = match check_and_convert_addr_ext(&cage, arg2, count, PROT_WRITE) { Ok(addr) => addr as *mut u8, @@ -1019,8 +1018,6 @@ pub fn lind_syscall_api( let shmfig = arg3 as i32; // Perform shmget operation through cage implementation - interface::cagetable_getref(cageid) - // 4. Size validation handled by cage layer interface::cagetable_getref(cageid) .shmget_syscall(key, size, shmfig) } @@ -1184,7 +1181,6 @@ pub fn lind_syscall_api( // Perform pwrite operation through cage implementation interface::cagetable_getref(cageid) - // 4. File descriptor validation handled by cage layer cage.pwrite_syscall(virtual_fd, buf, count, offset) } @@ -1719,7 +1715,7 @@ pub fn lindgetsighandler(cageid: u64, signo: i32) -> u32 { pub fn lindrustinit(verbosity: isize) { let _ = interface::VERBOSE.set(verbosity); //assigned to suppress unused result warning interface::cagetable_init(); - + // TODO: needs to add close() that handling im-pipe fdtables::register_close_handlers(FDKIND_KERNEL, fdtables::NULL_FUNC, kernel_close); From 668dbc781889e816ef5b928faf56fe2fb51b523a Mon Sep 17 00:00:00 2001 From: Chinmay Shringi Date: Sat, 28 Dec 2024 22:34:53 -0500 Subject: [PATCH 26/66] rm: space --- src/RawPOSIX/src/safeposix/dispatcher.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/RawPOSIX/src/safeposix/dispatcher.rs b/src/RawPOSIX/src/safeposix/dispatcher.rs index 14f6c1c05..fca3106d3 100644 --- a/src/RawPOSIX/src/safeposix/dispatcher.rs +++ b/src/RawPOSIX/src/safeposix/dispatcher.rs @@ -1188,17 +1188,17 @@ pub fn lind_syscall_api( interface::cagetable_getref(cageid) .getuid_syscall() } - + GETEUID_SYSCALL => { interface::cagetable_getref(cageid) .geteuid_syscall() } - + GETGID_SYSCALL => { interface::cagetable_getref(cageid) .getgid_syscall() } - + GETEGID_SYSCALL => { interface::cagetable_getref(cageid) .getegid_syscall() From 67c1a5c1ad103dc5c86b95c56a39b35634205e23 Mon Sep 17 00:00:00 2001 From: Chinmay Shringi Date: Sat, 28 Dec 2024 22:45:54 -0500 Subject: [PATCH 27/66] fix: rm interface:cage --- src/RawPOSIX/src/safeposix/dispatcher.rs | 26 ------------------------ 1 file changed, 26 deletions(-) diff --git a/src/RawPOSIX/src/safeposix/dispatcher.rs b/src/RawPOSIX/src/safeposix/dispatcher.rs index fca3106d3..fffdae531 100644 --- a/src/RawPOSIX/src/safeposix/dispatcher.rs +++ b/src/RawPOSIX/src/safeposix/dispatcher.rs @@ -1005,9 +1005,6 @@ pub fn lind_syscall_api( // Perform flock operation through cage implementation // File descriptor validation handled by cage layer - interface::cagetable_getref(cageid) - // 3. Operation validation handled by cage layer - // 4. Simple and straightforward implementation as no memory operations are involved interface::cagetable_getref(cageid) .flock_syscall(virtual_fd, operation) } @@ -1250,8 +1247,6 @@ pub fn lind_syscall_api( }; // Perform setsockopt operation through cage implementation - interface::cagetable_getref(cageid) - // 4. File descriptor validation handled by cage layer cage.setsockopt_syscall(virtual_fd, level, optname, optval, optlen) } @@ -1331,7 +1326,6 @@ pub fn lind_syscall_api( }; // Perform getifaddrs operation through cage implementation - interface::cagetable_getref(cageid) cage.getifaddrs_syscall(buf, count) } @@ -1380,8 +1374,6 @@ pub fn lind_syscall_api( Err(errno) => return syscall_error(errno, "pipe", "invalid pipe address"), }; - // Perform pipe operation through cage implementation - interface::cagetable_getref(cageid) cage.pipe_syscall(pipe) } @@ -1400,8 +1392,6 @@ pub fn lind_syscall_api( }; let flag = arg2 as i32; - // Perform pipe2 operation through cage implementation - interface::cagetable_getref(cageid) cage.pipe2_syscall(pipe, flag) } @@ -1435,8 +1425,6 @@ pub fn lind_syscall_api( ); } - // Perform getsockname operation through cage implementation - interface::cagetable_getref(cageid) let rv = cage.getsockname_syscall(fd, &mut Some(&mut addr)); // Copy out the address if operation was successful @@ -1461,8 +1449,6 @@ pub fn lind_syscall_api( }; let optval = unsafe { &mut *optval_ptr }; - // Perform getsockopt operation through cage implementation - interface::cagetable_getref(cageid) cage.getsockopt_syscall(virtual_fd, level, optname, optval) } @@ -1483,8 +1469,6 @@ pub fn lind_syscall_api( Err(errno) => return syscall_error(errno, "socketpair", "invalid socket vector address"), }; - // Perform socketpair operation through cage implementation - interface::cagetable_getref(cageid) cage.socketpair_syscall(domain, _type, protocol, virtual_socket_vector) } @@ -1506,8 +1490,6 @@ pub fn lind_syscall_api( }; let timeout = arg3 as i32; - // Perform poll operation through cage implementation - interface::cagetable_getref(cageid) cage.poll_syscall(pollfds, nfds, timeout) } @@ -1541,8 +1523,6 @@ pub fn lind_syscall_api( let uaddr2 = arg5 as u32; let val3 = arg6 as u32; - // Perform futex operation through cage implementation - interface::cagetable_getref(cageid) cage.futex_syscall(uaddr, futex_op, val, timeout, uaddr2, val3) } @@ -1567,8 +1547,6 @@ pub fn lind_syscall_api( Err(errno) => return syscall_error(errno, "nanosleep", "invalid rem address"), }; - // Perform nanosleep operation through cage implementation - interface::cagetable_getref(cageid) cage.nanosleep_time64_syscall(clockid, flags, req, rem) } @@ -1586,8 +1564,6 @@ pub fn lind_syscall_api( Err(errno) => return syscall_error(errno, "wait", "invalid status address"), }; - // Perform wait operation through cage implementation - interface::cagetable_getref(cageid) cage.wait_syscall(status) } @@ -1607,8 +1583,6 @@ pub fn lind_syscall_api( }; let options = arg3 as i32; - // Perform waitpid operation through cage implementation - interface::cagetable_getref(cageid) cage.waitpid_syscall(pid, status, options) } From 5b70b4d1bfb8ab24139c188417af8ecd95e32127 Mon Sep 17 00:00:00 2001 From: Qianxi Chen Date: Sun, 29 Dec 2024 07:29:30 +0000 Subject: [PATCH 28/66] implement program break/integrate with glibc/implement file backed mmap --- src/RawPOSIX/src/interface/mem.rs | 165 ++++++++++++------ src/RawPOSIX/src/safeposix/dispatcher.rs | 61 +++++-- .../src/safeposix/syscalls/fs_calls.rs | 13 +- src/RawPOSIX/src/safeposix/vmmap.rs | 147 ++++++++-------- src/glibc/lind_syscall/lind_syscall.c | 30 ++-- src/glibc/nptl/allocatestack.c | 1 + src/glibc/sysdeps/unix/sysv/linux/brk.c | 44 ++--- .../crates/lind-multi-process/src/lib.rs | 31 ++-- src/wasmtime/crates/wasmtime/Cargo.toml | 1 + src/wasmtime/crates/wasmtime/src/runtime.rs | 2 +- .../crates/wasmtime/src/runtime/instance.rs | 86 +++++++++ .../crates/wasmtime/src/runtime/linker.rs | 11 ++ .../crates/wasmtime/src/runtime/vm/memory.rs | 2 +- .../crates/wasmtime/src/runtime/vm/mmap.rs | 4 +- .../src/runtime/vm/threads/shared_memory.rs | 4 +- src/wasmtime/src/commands/run.rs | 14 +- 16 files changed, 404 insertions(+), 212 deletions(-) diff --git a/src/RawPOSIX/src/interface/mem.rs b/src/RawPOSIX/src/interface/mem.rs index 38cae0449..b28e4f00e 100644 --- a/src/RawPOSIX/src/interface/mem.rs +++ b/src/RawPOSIX/src/interface/mem.rs @@ -1,5 +1,5 @@ use crate::constants::{ - MAP_ANONYMOUS, MAP_FIXED, MAP_PRIVATE, PROT_EXEC, + F_GETFL, MAP_ANONYMOUS, MAP_FIXED, MAP_PRIVATE, PROT_EXEC }; use crate::safeposix::vmmap::{MemoryBackingType, Vmmap, VmmapOps}; @@ -29,7 +29,7 @@ pub fn fork_vmmap(parent_vmmap: &Vmmap, child_vmmap: &Vmmap) { // if the entry has PROT_NONE, that means the entry is currently not used if entry.prot == PROT_NONE { continue; } // translate page number to user address - let addr_st = (entry.page_num << PAGESHIFT) as i32; + let addr_st = (entry.page_num << PAGESHIFT) as u32; let addr_len = (entry.npages << PAGESHIFT) as usize; // translate user address to system address @@ -66,7 +66,7 @@ pub fn munmap_handler(cageid: u64, addr: *mut u8, len: usize) -> i32 { } let vmmap = cage.vmmap.read(); - let sysaddr = vmmap.user_to_sys(rounded_addr as i32); + let sysaddr = vmmap.user_to_sys(rounded_addr as u32); drop(vmmap); let rounded_length = round_up_page(len as u64) as usize; @@ -85,9 +85,11 @@ pub fn munmap_handler(cageid: u64, addr: *mut u8, len: usize) -> i32 { 0 } -pub fn mmap_handler(cageid: u64, addr: *mut u8, len: usize, mut prot: i32, mut flags: i32, mut fildes: i32, off: i64) -> i32 { +pub fn mmap_handler(cageid: u64, addr: *mut u8, len: usize, mut prot: i32, mut flags: i32, mut fildes: i32, off: i64) -> u32 { let cage = cagetable_getref(cageid); + let mut maxprot = PROT_READ | PROT_WRITE; + // only these four flags are allowed let allowed_flags = MAP_FIXED as i32 | MAP_SHARED as i32 | MAP_PRIVATE as i32 | MAP_ANONYMOUS as i32; if flags & !allowed_flags > 0 { @@ -97,39 +99,40 @@ pub fn mmap_handler(cageid: u64, addr: *mut u8, len: usize, mut prot: i32, mut f if prot & PROT_EXEC > 0 { println!("mmap syscall error 1!"); - return syscall_error(Errno::EINVAL, "mmap", "PROT_EXEC is not allowed"); + return syscall_error(Errno::EINVAL, "mmap", "PROT_EXEC is not allowed") as u32; } // check if the provided address is multiple of pages let rounded_addr = round_up_page(addr as u64); if rounded_addr != addr as u64 { println!("mmap syscall error 2!"); - return syscall_error(Errno::EINVAL, "mmap", "address it not aligned"); + return syscall_error(Errno::EINVAL, "mmap", "address it not aligned") as u32; } // offset should be non-negative and multiple of pages if off < 0 { println!("mmap syscall error 3!"); - return syscall_error(Errno::EINVAL, "mmap", "offset cannot be negative"); + return syscall_error(Errno::EINVAL, "mmap", "offset cannot be negative") as u32; } let rounded_off = round_up_page(off as u64); if rounded_off != off as u64 { println!("mmap syscall error 4!"); - return syscall_error(Errno::EINVAL, "mmap", "offset it not aligned"); + return syscall_error(Errno::EINVAL, "mmap", "offset it not aligned") as u32; } // round up length to be multiple of pages let rounded_length = round_up_page(len as u64); - let mut useraddr = addr as i32; + let mut useraddr = addr as u32; // if MAP_FIXED is not set, then we need to find an address for the user if flags & MAP_FIXED as i32 == 0 { let mut vmmap = cage.vmmap.write(); let result; // pick an address of appropriate size, anywhere - if addr as usize == 0 { + if useraddr == 0 { result = vmmap.find_map_space(rounded_length as u32 >> PAGESHIFT, 1); + println!("find map space result: {:?}", result); } else { // use address user provided as hint to find address result = vmmap.find_map_space_with_hint(rounded_length as u32 >> PAGESHIFT, 1, addr as u32); @@ -137,11 +140,11 @@ pub fn mmap_handler(cageid: u64, addr: *mut u8, len: usize, mut prot: i32, mut f // did not find desired memory region if result.is_none() { - return syscall_error(Errno::ENOMEM, "mmap", "no memory"); + return syscall_error(Errno::ENOMEM, "mmap", "no memory") as u32; } let space = result.unwrap(); - useraddr = (space.start() << PAGESHIFT) as i32; + useraddr = (space.start() << PAGESHIFT) as u32; } // TODO: validate useraddr (like checking whether within the program break) @@ -150,12 +153,13 @@ pub fn mmap_handler(cageid: u64, addr: *mut u8, len: usize, mut prot: i32, mut f // either MAP_PRIVATE or MAP_SHARED should be set, but not both if (flags & MAP_PRIVATE as i32 == 0) == (flags & MAP_SHARED as i32 == 0) { - return syscall_error(Errno::EINVAL, "mmap", "invalid flags"); + return syscall_error(Errno::EINVAL, "mmap", "invalid flags") as u32; } let vmmap = cage.vmmap.read(); let sysaddr = vmmap.user_to_sys(useraddr); + println!("useraddr: {}, sysaddr: {}", useraddr, sysaddr); drop(vmmap); @@ -167,7 +171,9 @@ pub fn mmap_handler(cageid: u64, addr: *mut u8, len: usize, mut prot: i32, mut f let result = cage.mmap_syscall(sysaddr as *mut u8, rounded_length as usize, prot, flags, fildes, off); let vmmap = cage.vmmap.read(); + println!("sys addr: {}", result); let result = vmmap.sys_to_user(result); + println!("user addr: {}", result); drop(vmmap); if result >= 0 { @@ -177,65 +183,118 @@ pub fn mmap_handler(cageid: u64, addr: *mut u8, len: usize, mut prot: i32, mut f let mut vmmap = cage.vmmap.write(); let backing = { - MemoryBackingType::Anonymous - // TODO: should return backing type accordingly - // if flags & MAP_ANONYMOUS > 0 { - // MemoryBackingType::Anonymous - // } else if flags & MAP_SHARED > 0 { - - // } + if flags as u32 & MAP_ANONYMOUS > 0 { + MemoryBackingType::Anonymous + } else { + // if we are doing file-backed mapping, we need to set maxprot to the file permission + let flags = cage.fcntl_syscall(fildes, F_GETFL, 0); + if flags < 0 { + return syscall_error(Errno::EINVAL, "mmap", "invalid file descriptor") as u32; + } + maxprot &= flags; + MemoryBackingType::FileDescriptor(fildes as u64) + } }; - vmmap.add_entry_with_overwrite((useraddr >> PAGESHIFT) as u32, (rounded_length >> PAGESHIFT) as u32, prot, 0, flags, backing, off, 0, cageid); + + vmmap.add_entry_with_overwrite(useraddr >> PAGESHIFT, (rounded_length >> PAGESHIFT) as u32, prot, maxprot, flags, backing, off, len as i64, cageid); } } - useraddr + useraddr as u32 } -pub fn sbrk_handler(cageid: u64, brk: u32) -> i32 { +pub fn sbrk_handler(cageid: u64, brk: i32) -> u32 { let cage = cagetable_getref(cageid); - let mut vmmap = cage.vmmap.write(); + // get the heap entry + let mut vmmap = cage.vmmap.read(); let heap = vmmap.find_page(HEAP_ENTRY_INDEX).unwrap().clone(); + assert!(heap.npages == vmmap.program_break); + if brk == 0 { - return (PAGESIZE * heap.npages) as i32; + return (PAGESIZE * heap.npages) as u32; } - let brk_page = ((brk + 65536 - 1) / 65536) * 16; + // round up the break to multiple of pages + let brk_page; + if brk < 0 { + brk_page = -((round_up_page(-brk as u64) >> PAGESHIFT) as i32); + } else { + brk_page = (round_up_page(brk as u64) >> PAGESHIFT) as i32; + } - let heap_size = heap.npages; - vmmap.add_entry_with_overwrite(0, heap_size + brk_page, heap.prot, heap.maxprot, heap.flags, heap.backing, heap.file_offset, heap.file_size, heap.cage_id); + drop(vmmap); + + if brk_handler(cageid, ((heap.npages as i32 + brk_page) << PAGESHIFT) as u32) < 0 { + return syscall_error(Errno::ENOMEM, "sbrk", "no memory") as u32; + } + + (PAGESIZE * heap.npages) as u32 +} + +pub fn brk_handler(cageid: u64, brk: u32) -> i32 { + let cage = cagetable_getref(cageid); + + let mut vmmap = cage.vmmap.write(); + let heap = vmmap.find_page(HEAP_ENTRY_INDEX).unwrap().clone(); + + assert!(heap.npages == vmmap.program_break); + + let old_brk_page = heap.npages; + // round up the break to multiple of pages + let brk_page = (round_up_page(brk as u64) >> PAGESHIFT) as u32; + + // TODO: check if brk has enough space + + vmmap.add_entry_with_overwrite(0, brk_page, heap.prot, heap.maxprot, heap.flags, heap.backing, heap.file_offset, heap.file_size, heap.cage_id); - let usr_heap_base = (heap_size * PAGESIZE) as i32; - let sys_heap_base = vmmap.user_to_sys(usr_heap_base)as *mut u8; + let old_heap_end_usr = (old_brk_page * PAGESIZE) as u32; + let old_heap_end_sys = vmmap.user_to_sys(old_heap_end_usr)as *mut u8; + + let new_heap_end_usr = (brk_page * PAGESIZE) as u32; + let new_heap_end_sys = vmmap.user_to_sys(new_heap_end_usr)as *mut u8; + + vmmap.set_program_break(brk_page); drop(vmmap); - // TODO: Currently we are not calling mmap to change prot here - // since this is handled within wasmtime. This will be changed - // later - // let ret = cage.mmap_syscall( - // sys_heap_base, - // (brk_page * PAGESIZE) as usize, - // heap.prot, - // heap.flags | MAP_FIXED, - // -1, - // 0 - // ); - // - // unsafe { - // let val = *sys_heap_base.add(65); - // println!("val: {}", val); - // } - // - // if ret < 0 { - // panic!("sbrk mmap failed"); - // } - - (PAGESIZE * heap.npages) as i32 -} + // if new brk is larger than old brk + // we need to mmap the new region + if brk_page > old_brk_page { + let ret = cage.mmap_syscall( + old_heap_end_sys, + ((brk_page - old_brk_page) * PAGESIZE) as usize, + heap.prot, + (heap.flags as u32 | MAP_FIXED) as i32, + -1, + 0 + ); + + if ret < 0 { + panic!("brk mmap failed"); + } + } + // if we are shrinking the brk + // we need to do something similar to munmap + // to unmap the extra memory + else if brk_page < old_brk_page { + let ret = cage.mmap_syscall( + new_heap_end_sys, + ((old_brk_page - brk_page) * PAGESIZE) as usize, + PROT_NONE, + (MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED) as i32, + -1, + 0 + ); + + if ret < 0 { + panic!("brk mmap failed"); + } + } + 0 +} /// Validates and converts a virtual memory address to a physical address with protection checks /// diff --git a/src/RawPOSIX/src/safeposix/dispatcher.rs b/src/RawPOSIX/src/safeposix/dispatcher.rs index e1c903f1b..b84dcc8cc 100644 --- a/src/RawPOSIX/src/safeposix/dispatcher.rs +++ b/src/RawPOSIX/src/safeposix/dispatcher.rs @@ -201,6 +201,17 @@ pub fn lind_syscall_api( ) -> i32 { let call_number = call_number as i32; + if call_number as i32 != WRITE_SYSCALL { + match call_name { + 0 => { + println!("\x1b[90mcage {} calls UNNAMED ({})\x1b[0m", cageid, call_number); + }, + _ => { + println!("\x1b[90mcage {} calls {} ({})\x1b[0m", cageid, interface::get_cstr(start_address + call_name).unwrap(), call_number); + } + } + } + let ret = match call_number { WRITE_SYSCALL => { let fd = arg1 as i32; @@ -239,7 +250,7 @@ pub fn lind_syscall_api( let mut fildes = arg5 as i32; let off = arg6 as i64; - interface::mmap_handler(cageid, addr, len, prot, flags, fildes, off) + interface::mmap_handler(cageid, addr, len, prot, flags, fildes, off) as i32 } PREAD_SYSCALL => { @@ -1204,33 +1215,51 @@ pub fn lind_syscall_api( cage.waitpid_syscall(pid, status, options) } - SBRK_SYSCALL => { + let brk = arg1 as i32; + + interface::sbrk_handler(cageid, brk) as i32 + } + + BRK_SYSCALL => { let brk = arg1 as u32; - interface::sbrk_handler(cageid, brk) + interface::brk_handler(cageid, brk) } _ => -1, // Return -1 for unknown syscalls }; - ret -} -// initilize the vmmap, invoked by wasmtime -pub fn lind_cage_vmmap_init(cageid: u64) { - let cage = interface::cagetable_getref(cageid); - let mut vmmap = cage.vmmap.write(); - vmmap.add_entry(VmmapEntry::new(0, 0x30, PROT_WRITE | PROT_READ, 0 /* not sure about this field */, (MAP_PRIVATE | MAP_ANONYMOUS) as i32, false, 0, 0, cageid, MemoryBackingType::Anonymous)); - // BUG: currently need to insert an entry at the end to indicate the end of memory space. This should be fixed soon so that - // no dummy entries are required to be inserted - vmmap.add_entry(VmmapEntry::new(1 << 18, 1, PROT_NONE, 0 /* not sure about this field */, (MAP_PRIVATE | MAP_ANONYMOUS) as i32, false, 0, 0, cageid, MemoryBackingType::Anonymous)); + if call_number as i32 != WRITE_SYSCALL { + match call_name { + 0 => { + if ret < 0 { + println!("\x1b[31mcage {} calls UNNAMED ({}) returns {}\x1b[0m", cageid, call_number, ret); + } else { + println!("\x1b[90mcage {} calls UNNAMED ({}) returns {}\x1b[0m", cageid, call_number, ret); + } + }, + _ => { + if ret < 0 { + println!("\x1b[31mcage {} calls {} ({}) returns {}\x1b[0m", cageid, interface::get_cstr(start_address + call_name).unwrap(), call_number, ret); + } else { + println!("\x1b[90mcage {} calls {} ({}) returns {}\x1b[0m", cageid, interface::get_cstr(start_address + call_name).unwrap(), call_number, ret); + } + } + } + } + + ret } // set the wasm linear memory base address to vmmap -pub fn set_base_address(cageid: u64, base_address: i64) { +pub fn init_vmmap_helper(cageid: u64, base_address: usize, program_break: Option) { let cage = interface::cagetable_getref(cageid); let mut vmmap = cage.vmmap.write(); vmmap.set_base_address(base_address); + if program_break.is_some() { + vmmap.set_program_break(program_break.unwrap()); + } } // clone the cage memory. Invoked by wasmtime after cage is forked @@ -1241,6 +1270,10 @@ pub fn fork_vmmap_helper(parent_cageid: u64, child_cageid: u64) { let child_vmmap = child_cage.vmmap.read(); interface::fork_vmmap(&parent_vmmap, &child_vmmap); + + drop(child_vmmap); + let mut child_vmmap = child_cage.vmmap.write(); + child_vmmap.set_program_break(parent_vmmap.program_break); } #[no_mangle] diff --git a/src/RawPOSIX/src/safeposix/syscalls/fs_calls.rs b/src/RawPOSIX/src/safeposix/syscalls/fs_calls.rs index ad67b3474..d47ca4c26 100644 --- a/src/RawPOSIX/src/safeposix/syscalls/fs_calls.rs +++ b/src/RawPOSIX/src/safeposix/syscalls/fs_calls.rs @@ -779,7 +779,8 @@ impl Cage { flags: i32, virtual_fd: i32, off: i64 - ) -> i64 { + ) -> usize { + println!("mmap_syscall: addr: {:?}, len: {}, prot: {} flags: {}, fd: {}, off: {}", addr, len, prot, flags, virtual_fd, off); if virtual_fd != -1 { match fdtables::translate_virtual_fd(self.cageid, virtual_fd as u64) { Ok(kernel_fd) => { @@ -789,13 +790,13 @@ impl Cage { // Check if mmap failed and return the appropriate error if so if ret == -1 { - return syscall_error(Errno::EINVAL, "mmap", "mmap failed with invalid flags") as i64; + return syscall_error(Errno::EINVAL, "mmap", "mmap failed with invalid flags") as usize; } - ret + ret as usize }, Err(_e) => { - return syscall_error(Errno::EBADF, "mmap", "Bad File Descriptor") as i64; + return syscall_error(Errno::EBADF, "mmap", "Bad File Descriptor") as usize; } } } else { @@ -805,10 +806,10 @@ impl Cage { }; // Check if mmap failed and return the appropriate error if so if ret == -1 { - return syscall_error(Errno::EINVAL, "mmap", "mmap failed with invalid flags") as i64; + return syscall_error(Errno::EINVAL, "mmap", "mmap failed with invalid flags") as usize; } - ret + ret as usize } } diff --git a/src/RawPOSIX/src/safeposix/vmmap.rs b/src/RawPOSIX/src/safeposix/vmmap.rs index 189de5117..afe6a8da7 100644 --- a/src/RawPOSIX/src/safeposix/vmmap.rs +++ b/src/RawPOSIX/src/safeposix/vmmap.rs @@ -1,14 +1,16 @@ use crate::constants::{ - PROT_NONE, PROT_READ, PROT_WRITE, PROT_EXEC, - MAP_SHARED, MAP_PRIVATE, MAP_FIXED, MAP_ANONYMOUS, - MAP_FAILED + MAP_ANONYMOUS, MAP_FAILED, MAP_FIXED, MAP_PRIVATE, MAP_SHARED, PAGESHIFT, PROT_EXEC, PROT_NONE, PROT_READ, PROT_WRITE }; use std::io; +use nodit::interval::ii; use nodit::NoditMap; use nodit::{interval::ie, Interval}; use crate::fdtables; use crate::safeposix::cage::syscall_error; use crate::safeposix::cage::Errno; + +const DEFAULT_VMMAP_SIZE: u32 = 1 << (32 - PAGESHIFT); + /// Used to identify whether the vmmap entry is backed anonymously, /// by an fd, or by a shared memory segment /// @@ -247,8 +249,11 @@ pub struct Vmmap { pub entries: NoditMap, VmmapEntry>, // Keyed by `page_num` pub cached_entry: Option, // TODO: is this still needed? // Use Option for safety - pub base_address: Option, // wasm base address. None means uninitialized yet + pub base_address: Option, // wasm base address. None means uninitialized yet + pub start_address: u32, // start address of valid vmmap address range + pub end_address: u32, // end address of valid vmmap address range + pub program_break: u32, // program break (i.e. heap bottom) of the memory } #[allow(dead_code)] @@ -259,7 +264,10 @@ impl Vmmap { Vmmap { entries: NoditMap::new(), cached_entry: None, - base_address: None + base_address: None, + start_address: 0, + end_address: DEFAULT_VMMAP_SIZE, + program_break: 0, } } @@ -291,20 +299,28 @@ impl Vmmap { /// /// Arguments: /// - base_address: The base address to set - pub fn set_base_address(&mut self, base_address: i64) { + pub fn set_base_address(&mut self, base_address: usize) { // Store the provided base address self.base_address = Some(base_address); } + /// Sets the program break for the memory + /// + /// Arguments: + /// - program_break: The program break to set + pub fn set_program_break(&mut self, program_break: u32) { + self.program_break = program_break; + } + /// Converts a user address to a system address /// /// Arguments: /// - address: User space address to convert /// /// Returns the corresponding system address - pub fn user_to_sys(&self, address: i32) -> i64 { + pub fn user_to_sys(&self, address: u32) -> usize { // Add base address to user address to get system address - address as i64 + self.base_address.unwrap() + address as usize + self.base_address.unwrap() } /// Converts a system address to a user address @@ -313,9 +329,9 @@ impl Vmmap { /// - address: System address to convert /// /// Returns the corresponding user space address - pub fn sys_to_user(&self, address: i64) -> i32 { + pub fn sys_to_user(&self, address: usize) -> u32 { // Subtract base address from system address to get user address - (address as i64 - self.base_address.unwrap()) as i32 + (address as usize - self.base_address.unwrap()) as u32 } // Visits each entry in the vmmap, applying a visitor function to each entry @@ -818,24 +834,17 @@ impl VmmapOps for Vmmap { /// - Some(Interval) containing the found space /// - None if no suitable space found fn find_space(&self, npages: u32) -> Option> { - let start = self.first_entry(); - let end = self.last_entry(); + let start = self.start_address; + let end = self.end_address; - if start == None || end == None { - return None; - } else { - let start_unwrapped = start.unwrap().0.start(); - let end_unwrapped = end.unwrap().0.end(); - - let desired_space = npages + 1; // TODO: check if this is correct + let desired_space = npages + 1; // TODO: check if this is correct - for gap in self - .entries - .gaps_trimmed(ie(start_unwrapped, end_unwrapped)) - { - if gap.end() - gap.start() >= desired_space { - return Some(gap); - } + for gap in self + .entries + .gaps_trimmed(ie(start, end)) + { + if gap.end() - gap.start() >= desired_space { + return Some(gap); } } @@ -856,19 +865,13 @@ impl VmmapOps for Vmmap { /// - None if no suitable space found fn find_space_above_hint(&self, npages: u32, hint: u32) -> Option> { let start = hint; - let end = self.last_entry(); + let end = self.end_address; - if end == None { - return None; - } else { - let end_unwrapped = end.unwrap().0.end(); - - let desired_space = npages + 1; // TODO: check if this is correct + let desired_space = npages + 1; // TODO: check if this is correct - for gap in self.entries.gaps_trimmed(ie(start, end_unwrapped)) { - if gap.end() - gap.start() >= desired_space { - return Some(gap); - } + for gap in self.entries.gaps_trimmed(ie(start, end)) { + if gap.end() - gap.start() >= desired_space { + return Some(gap); } } @@ -892,31 +895,27 @@ impl VmmapOps for Vmmap { /// - Rounds page numbers up to alignment boundaries /// - Handles alignment constraints for start and end addresses fn find_map_space(&self, num_pages: u32, pages_per_map: u32) -> Option> { - let start = self.first_entry(); - let end = self.last_entry(); + let start = self.start_address; + let end = self.end_address; - if start == None || end == None { - return None; - } else { - let start_unwrapped = start.unwrap().0.start(); - let end_unwrapped = end.unwrap().0.end(); - - let rounded_num_pages = - self.round_page_num_up_to_map_multiple(num_pages, pages_per_map); + let rounded_num_pages = + self.round_page_num_up_to_map_multiple(num_pages, pages_per_map); + println!("rounded_num_pages: {}", rounded_num_pages); - for gap in self - .entries - .gaps_trimmed(ie(start_unwrapped, end_unwrapped)) - { - let aligned_start_page = - self.trunc_page_num_down_to_map_multiple(gap.start(), pages_per_map); - let aligned_end_page = - self.round_page_num_up_to_map_multiple(gap.end(), pages_per_map); - - let gap_size = aligned_end_page - aligned_start_page; - if gap_size >= rounded_num_pages { - return Some(ie(aligned_end_page - rounded_num_pages, aligned_end_page)); - } + for gap in self + .entries + .gaps_trimmed(ie(start, end)) + { + println!("gap: {:?}", gap); + let aligned_start_page = + self.trunc_page_num_down_to_map_multiple(gap.start(), pages_per_map); + let aligned_end_page = + self.round_page_num_up_to_map_multiple(gap.end(), pages_per_map); + + println!("aligned gap: {} {}", aligned_start_page, aligned_end_page); + let gap_size = aligned_end_page - aligned_start_page; + if gap_size >= rounded_num_pages { + return Some(ie(aligned_end_page - rounded_num_pages, aligned_end_page)); } } @@ -948,26 +947,20 @@ impl VmmapOps for Vmmap { hint: u32, ) -> Option> { let start = hint; - let end = self.last_entry(); + let end = self.end_address; - if end == None { - return None; - } else { - let end_unwrapped = end.unwrap().0.end(); - - let rounded_num_pages = - self.round_page_num_up_to_map_multiple(num_pages, pages_per_map); + let rounded_num_pages = + self.round_page_num_up_to_map_multiple(num_pages, pages_per_map); - for gap in self.entries.gaps_trimmed(ie(start, end_unwrapped)) { - let aligned_start_page = - self.trunc_page_num_down_to_map_multiple(gap.start(), pages_per_map); - let aligned_end_page = - self.round_page_num_up_to_map_multiple(gap.end(), pages_per_map); + for gap in self.entries.gaps_trimmed(ie(start, end)) { + let aligned_start_page = + self.trunc_page_num_down_to_map_multiple(gap.start(), pages_per_map); + let aligned_end_page = + self.round_page_num_up_to_map_multiple(gap.end(), pages_per_map); - let gap_size = aligned_end_page - aligned_start_page; - if gap_size >= rounded_num_pages { - return Some(ie(aligned_end_page - rounded_num_pages, aligned_end_page)); - } + let gap_size = aligned_end_page - aligned_start_page; + if gap_size >= rounded_num_pages { + return Some(ie(aligned_end_page - rounded_num_pages, aligned_end_page)); } } diff --git a/src/glibc/lind_syscall/lind_syscall.c b/src/glibc/lind_syscall/lind_syscall.c index 3acdf6874..321f0056a 100644 --- a/src/glibc/lind_syscall/lind_syscall.c +++ b/src/glibc/lind_syscall/lind_syscall.c @@ -32,15 +32,23 @@ int __imported_wasi_snapshot_preview1_lind_syscall(unsigned int callnumber, unsi // handled here instead int lind_syscall (unsigned int callnumber, unsigned long long callname, unsigned long long arg1, unsigned long long arg2, unsigned long long arg3, unsigned long long arg4, unsigned long long arg5, unsigned long long arg6) { - int ret = __imported_wasi_snapshot_preview1_lind_syscall(callnumber, callname, arg1, arg2, arg3, arg4, arg5, arg6); - // handle the errno - if(ret < 0) - { - errno = -ret; - } - else - { - errno = 0; - } - return ret; + int ret = __imported_wasi_snapshot_preview1_lind_syscall(callnumber, callname, arg1, arg2, arg3, arg4, arg5, arg6); + // handle the errno + // in rawposix, we use -errno as the return value to indicate the error + // but this may cause some issues for mmap syscall, because mmap syscall + // is returning an 32-bit address, which may overflow the int type (i32) + // luckily we can handle this easily because the return value of mmap is always + // multiple of pages (typically 4096) even when overflow, therefore we can distinguish + // the errno and mmap result by simply checking if the return value is + // within the valid errno range + if(ret < 0 && ret > -256) + { + errno = -ret; + return -1; + } + else + { + errno = 0; + } + return ret; } diff --git a/src/glibc/nptl/allocatestack.c b/src/glibc/nptl/allocatestack.c index 29ba4a124..ba6ee8d1c 100644 --- a/src/glibc/nptl/allocatestack.c +++ b/src/glibc/nptl/allocatestack.c @@ -439,6 +439,7 @@ allocate_stack (const struct pthread_attr *attr, struct pthread **pdp, /* Don't allow setxid until cloned. */ pd->setxid_futex = -1; + // BUG: TLS related stuff is not working currently /* Allocate the DTV for this thread. */ // if (_dl_allocate_tls (TLS_TPADJ (pd)) == NULL) // { diff --git a/src/glibc/sysdeps/unix/sysv/linux/brk.c b/src/glibc/sysdeps/unix/sysv/linux/brk.c index bf38c039b..f0e42f01f 100644 --- a/src/glibc/sysdeps/unix/sysv/linux/brk.c +++ b/src/glibc/sysdeps/unix/sysv/linux/brk.c @@ -20,6 +20,7 @@ #include #include #include +#include /* This must be initialized data because commons can't have aliases. */ // This is the "virtual brk" exposed to the caller @@ -39,32 +40,33 @@ weak_alias (__curbrk, ___brk_addr) int __brk (void *addr) { - __curbrk = __builtin_wasm_memory_size(0) * PAGESIZE; + return MAKE_SYSCALL(175, "syscall|brk", (uint64_t) addr, NOTUSED, NOTUSED, NOTUSED, NOTUSED, NOTUSED); +// __curbrk = __builtin_wasm_memory_size(0) * PAGESIZE; - // FIXME: now two threads calling this sbrk simultaneously - // will lead to the corruption of __curbrk, so we should move - // this implementation into the runtime, and protect the __curbrk - // with mutex (i.e. preventing two brk/sbrk to be executed at the same time) +// // FIXME: now two threads calling this sbrk simultaneously +// // will lead to the corruption of __curbrk, so we should move +// // this implementation into the runtime, and protect the __curbrk +// // with mutex (i.e. preventing two brk/sbrk to be executed at the same time) - void * linear_mem_end = __builtin_wasm_memory_size(0) * PAGESIZE; - void * old_break = __curbrk; - void * new_break = addr; +// void * linear_mem_end = __builtin_wasm_memory_size(0) * PAGESIZE; +// void * old_break = __curbrk; +// void * new_break = addr; - if (new_break <= linear_mem_end) { - // In this case, we don't need to grow linear mem - __curbrk = new_break; - return old_break; - } +// if (new_break <= linear_mem_end) { +// // In this case, we don't need to grow linear mem +// __curbrk = new_break; +// return old_break; +// } - // Now we need to grow linear mem - int new_pages = (new_break - linear_mem_end) / PAGESIZE; +// // Now we need to grow linear mem +// int new_pages = (new_break - linear_mem_end) / PAGESIZE; - if (__builtin_wasm_memory_grow(0, new_pages) < 0) { - errno = ENOMEM; - return (void *)-1; - } +// if (__builtin_wasm_memory_grow(0, new_pages) < 0) { +// errno = ENOMEM; +// return (void *)-1; +// } - __curbrk = new_break; - return old_break; +// __curbrk = new_break; +// return old_break; } weak_alias (__brk, brk) diff --git a/src/wasmtime/crates/lind-multi-process/src/lib.rs b/src/wasmtime/crates/lind-multi-process/src/lib.rs index b0557535c..c7b66dfba 100644 --- a/src/wasmtime/crates/lind-multi-process/src/lib.rs +++ b/src/wasmtime/crates/lind-multi-process/src/lib.rs @@ -10,7 +10,7 @@ use std::path::Path; use std::sync::atomic::{AtomicU32, AtomicU64, Ordering}; use std::sync::{Arc, Barrier}; use std::thread; -use wasmtime::{AsContext, AsContextMut, Caller, ExternType, Linker, Module, SharedMemory, Store, Val, OnCalledAction, RewindingReturn, StoreOpaque, InstanceId}; +use wasmtime::{AsContext, AsContextMut, Caller, ExternType, InstanceId, InstantiateType, Linker, Module, OnCalledAction, RewindingReturn, SharedMemory, Store, StoreOpaque, Val}; use wasmtime_environ::MemoryIndex; @@ -323,23 +323,24 @@ impl, ) -> Result { let (instance, start) = Instance::new_raw(store.0, module, imports)?; + + if let Some(start) = start { + instance.start_raw(store, start)?; + } + Ok(instance) + } + + pub(crate) unsafe fn new_started_impl_with_lind( + store: &mut StoreContextMut<'_, T>, + module: &Module, + imports: Imports<'_>, + instantiate_type: InstantiateType, + ) -> Result { + let (instance, start) = Instance::new_raw(store.0, module, imports)?; + + // initialize the memory + // the memory initialization should happen inside microvisor, so we should discard the original + // memory init in wasmtime and do our own initialization here + match instantiate_type { + // InstantiateFirst: this is the first wasm instance + InstantiateType::InstantiateFirst(pid) => { + // if this is the first wasm instance, we need to + // 1. set memory base address + // 2. manually call mmap_syscall to set up the first memory region + let handle = store.0.instance(InstanceId::from_index(0)); + let defined_memory = handle.get_memory(wasmtime_environ::MemoryIndex::from_u32(0)); + let memory_base = defined_memory.base as usize; + rawposix::safeposix::dispatcher::init_vmmap_helper(pid, memory_base, Some(0x30)); + + lind_syscall_api( + pid, + 21, + 0, + memory_base as u64, + 0, // the first memory region starts from 0 + 0x30 << PAGESHIFT, // we allocate 0x30 pages for the first memory region, which is the default value in wasmtime + (PROT_READ | PROT_WRITE) as u64, + (MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED) as u64, + // we need to pass -1 here, but since lind_syscall_api only accepts u64 + // and rust does not directly allow things like -1 as u64, so we end up with this weird thing + (0 - 1) as u64, + 0, + ); + }, + // InstantiateChild: this is the child wasm instance forked by parent + InstantiateType::InstantiateChild { parent_pid, child_pid } => { + // if this is a child, we do not need to specifically set up the first memory region + // since this should be taken care of when we fork the entire memory region from parent + // therefore in this case, we only need to: + // 1. set memory base address + // 2. fork the memory space from parent + let handle = store.0.instance(InstanceId::from_index(0)); + let defined_memory = handle.get_memory(wasmtime_environ::MemoryIndex::from_u32(0)); + let child_address = defined_memory.base as usize; + + rawposix::safeposix::dispatcher::init_vmmap_helper(child_pid, child_address, None); + rawposix::safeposix::dispatcher::fork_vmmap_helper(parent_pid as u64, child_pid); + } + } + if let Some(start) = start { instance.start_raw(store, start)?; } @@ -924,6 +994,22 @@ impl InstancePre { unsafe { Instance::new_started(&mut store, &self.module, imports.as_ref()) } } + pub fn instantiate_with_lind(&self, mut store: impl AsContextMut, instantiate_type: InstantiateType) -> Result { + let mut store = store.as_context_mut(); + let imports = pre_instantiate_raw( + &mut store.0, + &self.module, + &self.items, + self.host_funcs, + &self.func_refs, + )?; + + // This unsafety should be handled by the type-checking performed by the + // constructor of `InstancePre` to assert that all the imports we're passing + // in match the module we're instantiating. + unsafe { Instance::new_started_impl_with_lind(&mut store, &self.module, imports.as_ref(), instantiate_type) } + } + /// Creates a new instance, running the start function asynchronously /// instead of inline. /// diff --git a/src/wasmtime/crates/wasmtime/src/runtime/linker.rs b/src/wasmtime/crates/wasmtime/src/runtime/linker.rs index ab659c2e4..29b3660a4 100644 --- a/src/wasmtime/crates/wasmtime/src/runtime/linker.rs +++ b/src/wasmtime/crates/wasmtime/src/runtime/linker.rs @@ -17,6 +17,7 @@ use hashbrown::hash_map::{Entry, HashMap}; use log::warn; use super::store::StoreInner; +use super::InstantiateType; /// Structure used to link wasm modules/instances together. /// @@ -1127,6 +1128,16 @@ impl Linker { .instantiate(store) } + pub fn instantiate_with_lind( + &self, + mut store: impl AsContextMut, + module: &Module, + instantiate_type: InstantiateType, + ) -> Result { + self._instantiate_pre(module, Some(store.as_context_mut().0))? + .instantiate_with_lind(store, instantiate_type) + } + /// Attempts to instantiate the `module` provided. This is the same as /// [`Linker::instantiate`], except for async `Store`s. #[cfg(feature = "async")] diff --git a/src/wasmtime/crates/wasmtime/src/runtime/vm/memory.rs b/src/wasmtime/crates/wasmtime/src/runtime/vm/memory.rs index 8075aaa5d..ddbe7cb0f 100644 --- a/src/wasmtime/crates/wasmtime/src/runtime/vm/memory.rs +++ b/src/wasmtime/crates/wasmtime/src/runtime/vm/memory.rs @@ -223,7 +223,7 @@ impl MmapMemory { memory_image: Option<&Arc>, ) -> Result { println!("-----minimum: {}, maximum: {:?}", minimum, maximum); - maximum = Some(2147483648); + maximum = Some(4294967296); // It's a programmer error for these two configuration values to exceed // the host available address space, so panic if such a configuration is // found (mostly an issue for hypothetical 32-bit hosts). diff --git a/src/wasmtime/crates/wasmtime/src/runtime/vm/mmap.rs b/src/wasmtime/crates/wasmtime/src/runtime/vm/mmap.rs index 2d955d5eb..5e7ef93df 100644 --- a/src/wasmtime/crates/wasmtime/src/runtime/vm/mmap.rs +++ b/src/wasmtime/crates/wasmtime/src/runtime/vm/mmap.rs @@ -99,7 +99,9 @@ impl Mmap { assert!(len <= self.len()); assert!(start <= self.len() - len); - self.sys.make_accessible(start, len) + // lind-wasm: mmap prot is managed by rawposix + // self.sys.make_accessible(start, len) + Ok(()) } /// Return the allocated memory as a slice of u8. diff --git a/src/wasmtime/crates/wasmtime/src/runtime/vm/threads/shared_memory.rs b/src/wasmtime/crates/wasmtime/src/runtime/vm/threads/shared_memory.rs index 3e7e84327..774dffe07 100644 --- a/src/wasmtime/crates/wasmtime/src/runtime/vm/threads/shared_memory.rs +++ b/src/wasmtime/crates/wasmtime/src/runtime/vm/threads/shared_memory.rs @@ -34,7 +34,9 @@ impl SharedMemory { println!("-----create new memory!"); let (minimum_bytes, maximum_bytes) = Memory::limit_new(&plan, None)?; let mut mmap_memory = MmapMemory::new(&plan, minimum_bytes, maximum_bytes, None)?; - mmap_memory.grow_to(2147483648); + if minimum_bytes < 4294967296 { + mmap_memory.grow_to(4294967296); + } Self::wrap(&plan, Box::new(mmap_memory), plan.memory) } diff --git a/src/wasmtime/src/commands/run.rs b/src/wasmtime/src/commands/run.rs index e9182ad6e..047db1e19 100644 --- a/src/wasmtime/src/commands/run.rs +++ b/src/wasmtime/src/commands/run.rs @@ -9,6 +9,7 @@ use crate::common::{Profile, RunCommon, RunTarget}; use anyhow::{anyhow, bail, Context as _, Error, Result}; use clap::Parser; +use rawposix::constants::{MAP_ANONYMOUS, MAP_FIXED, MAP_PRIVATE, PAGESHIFT, PROT_READ, PROT_WRITE}; use rawposix::safeposix::dispatcher::lind_syscall_api; use wasmtime_lind_multi_process::{LindCtx, LindHost}; use wasmtime_lind_common::LindCommonCtx; @@ -18,7 +19,7 @@ use std::sync::atomic::AtomicU64; use std::sync::{Arc, Mutex}; use std::thread; use wasi_common::sync::{ambient_authority, Dir, TcpListener, WasiCtxBuilder}; -use wasmtime::{AsContext, AsContextMut, Engine, Func, Module, Store, StoreLimits, Val, ValType}; +use wasmtime::{AsContext, AsContextMut, Engine, Func, InstantiateType, Module, Store, StoreLimits, Val, ValType}; use wasmtime_wasi::WasiView; use wasmtime_lind_utils::LindCageManager; @@ -183,8 +184,6 @@ impl RunCommand { // new cage is created lind_manager.increment(); - rawposix::safeposix::dispatcher::lind_cage_vmmap_init(1); - // Pre-emptively initialize and install a Tokio runtime ambiently in the // environment when executing the module. Without this whenever a WASI // call is made that needs to block on a future a Tokio runtime is @@ -366,8 +365,6 @@ impl RunCommand { } } - rawposix::safeposix::dispatcher::lind_cage_vmmap_init(pid as u64); - // Pre-emptively initialize and install a Tokio runtime ambiently in the // environment when executing the module. Without this whenever a WASI // call is made that needs to block on a future a Tokio runtime is @@ -554,7 +551,7 @@ impl RunCommand { let result = match linker { CliLinker::Core(linker) => { let module = module.unwrap_core(); - let instance = linker.instantiate(&mut *store, &module).context(format!( + let instance = linker.instantiate_with_lind(&mut *store, &module, InstantiateType::InstantiateFirst(pid)).context(format!( "failed to instantiate {:?}", self.module_and_args[0] ))?; @@ -584,11 +581,6 @@ impl RunCommand { store.as_context_mut().set_stack_base(stack_pointer as u64); store.as_context_mut().set_stack_top(stack_low as u64); - let handle = store.as_context().0.instance(wasmtime::InstanceId::from_index(0)); - let defined_memory = handle.get_memory(wasmtime_environ::MemoryIndex::from_u32(0)); - let memory_base = defined_memory.base as i64; - rawposix::safeposix::dispatcher::set_base_address(pid, memory_base); - match func { Some(func) => self.invoke_func(store, func), None => Ok(vec![]), From c5b75a6d9b6dd8b96961f7f3b9281670242c3e28 Mon Sep 17 00:00:00 2001 From: Chinmay Shringi Date: Sun, 29 Dec 2024 20:20:23 +0000 Subject: [PATCH 29/66] fix: rm interface --- src/RawPOSIX/src/safeposix/dispatcher.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/RawPOSIX/src/safeposix/dispatcher.rs b/src/RawPOSIX/src/safeposix/dispatcher.rs index fffdae531..1c7bfb2a7 100644 --- a/src/RawPOSIX/src/safeposix/dispatcher.rs +++ b/src/RawPOSIX/src/safeposix/dispatcher.rs @@ -1176,8 +1176,6 @@ pub fn lind_syscall_api( let virtual_fd = arg1 as i32; let offset = arg4 as i64; - // Perform pwrite operation through cage implementation - interface::cagetable_getref(cageid) cage.pwrite_syscall(virtual_fd, buf, count, offset) } @@ -1277,8 +1275,6 @@ pub fn lind_syscall_api( }; let flags = arg4 as i32; - // Perform send operation through cage implementation - interface::cagetable_getref(cageid) cage.send_syscall(fd, buf, count, flags) } From 5dab647ed1245d424bbda2b5891acc52656a6363 Mon Sep 17 00:00:00 2001 From: Chinmay Shringi Date: Sun, 29 Dec 2024 20:36:42 +0000 Subject: [PATCH 30/66] feat: added address check --- src/RawPOSIX/src/safeposix/dispatcher.rs | 71 +++++++++++++++++------- 1 file changed, 51 insertions(+), 20 deletions(-) diff --git a/src/RawPOSIX/src/safeposix/dispatcher.rs b/src/RawPOSIX/src/safeposix/dispatcher.rs index 1c7bfb2a7..a212565d8 100644 --- a/src/RawPOSIX/src/safeposix/dispatcher.rs +++ b/src/RawPOSIX/src/safeposix/dispatcher.rs @@ -504,32 +504,63 @@ pub fn lind_syscall_api( } SELECT_SYSCALL => { + // Get the number of file descriptors to check (highest fd + 1) let nfds = arg1 as i32; - - // Get and validate fd sets - let readfds = match interface::get_fdset(arg2) { - Ok(fds) => fds, - Err(_) => return syscall_error(Errno::EFAULT, "select", "invalid readfds"), + // Get reference to the cage for memory operations + let cage = interface::cagetable_getref(cageid); + + // Validate and convert readfds buffer + // 1. check_and_convert_addr_ext validates memory access and converts user address to system address + // 2. PROT_READ | PROT_WRITE because select() both reads from and modifies the fd_sets + // 3. get_fdset converts the raw memory into an fd_set structure + let readfds = match check_and_convert_addr_ext(&cage, arg2, std::mem::size_of::(), PROT_READ | PROT_WRITE) { + Ok(addr) => match interface::get_fdset(addr) { + Ok(fds) => fds, + Err(_) => return syscall_error(Errno::EFAULT, "select", "failed to get readfds"), + }, + Err(errno) => return syscall_error(errno, "select", "invalid readfds address"), }; - let writefds = match interface::get_fdset(arg3) { - Ok(fds) => fds, - Err(_) => return syscall_error(Errno::EFAULT, "select", "invalid writefds"), + + // Validate and convert writefds buffer + // Similar to readfds, this fd_set indicates which descriptors to check for write-ready status + // The fd_set will be modified to show which descriptors are actually write-ready + let writefds = match check_and_convert_addr_ext(&cage, arg3, std::mem::size_of::(), PROT_READ | PROT_WRITE) { + Ok(addr) => match interface::get_fdset(addr) { + Ok(fds) => fds, + Err(_) => return syscall_error(Errno::EFAULT, "select", "failed to get writefds"), + }, + Err(errno) => return syscall_error(errno, "select", "invalid writefds address"), }; - let errorfds = match interface::get_fdset(arg4) { - Ok(fds) => fds, - Err(_) => return syscall_error(Errno::EFAULT, "select", "invalid errorfds"), + + // Validate and convert errorfds buffer (also called exceptfds in some implementations) + // This fd_set is used to monitor for exceptional conditions (like out-of-band data) + // Also requires both read and write access as select() modifies it + let errorfds = match check_and_convert_addr_ext(&cage, arg4, std::mem::size_of::(), PROT_READ | PROT_WRITE) { + Ok(addr) => match interface::get_fdset(addr) { + Ok(fds) => fds, + Err(_) => return syscall_error(Errno::EFAULT, "select", "failed to get errorfds"), + }, + Err(errno) => return syscall_error(errno, "select", "invalid errorfds address"), }; - - // Get and validate timeout - let rposix_timeout = match interface::duration_fromtimeval(arg5) { - Ok(timeout) => timeout, - Err(_) => return syscall_error(Errno::EFAULT, "select", "invalid timeout"), + + // Validate and convert timeout buffer + // 1. Only needs PROT_READ as the timeout value is not modified by select() + // 2. duration_fromtimeval converts the timeval structure to a Duration + // 3. This specifies how long select() should block waiting for activity + let rposix_timeout = match check_and_convert_addr_ext(&cage, arg5, std::mem::size_of::(), PROT_READ) { + Ok(addr) => match interface::duration_fromtimeval(addr) { + Ok(timeout) => timeout, + Err(_) => return syscall_error(Errno::EFAULT, "select", "failed to get timeout"), + }, + Err(errno) => return syscall_error(errno, "select", "invalid timeout address"), }; - // Perform select operation through cage implementation - // Results are handled by the interface layer - interface::cagetable_getref(cageid) - .select_syscall(nfds, readfds, writefds, errorfds, rposix_timeout) + // Delegate to the cage's select implementation + // This will: + // 1. Monitor the specified file descriptors for activity + // 2. Modify the fd_sets to indicate which descriptors are ready + // 3. Return the number of ready descriptors or an error code + cage.select_syscall(nfds, readfds, writefds, errorfds, rposix_timeout) } RENAME_SYSCALL => { From e86a5d60fda838616d490039d7876ea4672fcb31 Mon Sep 17 00:00:00 2001 From: Chinmay Shringi Date: Sun, 29 Dec 2024 20:48:07 +0000 Subject: [PATCH 31/66] feat: removed warnings --- src/RawPOSIX/src/interface/mem.rs | 26 ++++++++++++------- src/RawPOSIX/src/interface/types.rs | 3 ++- src/RawPOSIX/src/lib.rs | 3 ++- src/RawPOSIX/src/safeposix/dispatcher.rs | 1 + .../src/safeposix/syscalls/fs_calls.rs | 3 ++- .../src/safeposix/syscalls/net_calls.rs | 12 +++++---- .../src/safeposix/syscalls/sys_calls.rs | 3 ++- src/RawPOSIX/src/safeposix/vmmap.rs | 3 ++- 8 files changed, 35 insertions(+), 19 deletions(-) diff --git a/src/RawPOSIX/src/interface/mem.rs b/src/RawPOSIX/src/interface/mem.rs index 3a0b1a779..8f9eded3a 100644 --- a/src/RawPOSIX/src/interface/mem.rs +++ b/src/RawPOSIX/src/interface/mem.rs @@ -21,8 +21,9 @@ pub fn round_up_page(length: u64) -> u64 { } pub fn fork_vmmap(parent_vmmap: &Vmmap, child_vmmap: &Vmmap) { - let parent_base = parent_vmmap.base_address.unwrap(); - let child_base = child_vmmap.base_address.unwrap(); + // added _ to suppress the warning + let _parent_base = parent_vmmap.base_address.unwrap(); + let _child_base = child_vmmap.base_address.unwrap(); // iterate through each vmmap entry for (_interval, entry) in parent_vmmap.entries.iter() { @@ -39,7 +40,8 @@ pub fn fork_vmmap(parent_vmmap: &Vmmap, child_vmmap: &Vmmap) { // for shared memory, we are using mremap to fork shared memory // See "man 2 mremap" for description of what MREMAP_MAYMOVE does with old_size=0 // when old_address points to a shared mapping - let result = unsafe { libc::mremap(parent_st as *mut libc::c_void, 0, addr_len, libc::MREMAP_MAYMOVE | libc::MREMAP_FIXED, child_st as *mut libc::c_void) }; + // added _ to suppress the warning + let _result = unsafe { libc::mremap(parent_st as *mut libc::c_void, 0, addr_len, libc::MREMAP_MAYMOVE | libc::MREMAP_FIXED, child_st as *mut libc::c_void) }; } else { unsafe { // temporarily enable write on child's memory region to write parent data @@ -80,12 +82,14 @@ pub fn munmap_handler(cageid: u64, addr: *mut u8, len: usize) -> i32 { let mut vmmap = cage.vmmap.write(); - vmmap.remove_entry(rounded_addr as u32 >> PAGESHIFT, len as u32 >> PAGESHIFT); + // added _ to suppress the warning + let _ = vmmap.remove_entry(rounded_addr as u32 >> PAGESHIFT, len as u32 >> PAGESHIFT); 0 } -pub fn mmap_handler(cageid: u64, addr: *mut u8, len: usize, mut prot: i32, mut flags: i32, mut fildes: i32, off: i64) -> i32 { +// removed mut from prot to avoid warning +pub fn mmap_handler(cageid: u64, addr: *mut u8, len: usize, prot: i32, mut flags: i32, mut fildes: i32, off: i64) -> i32 { let cage = cagetable_getref(cageid); // only these four flags are allowed @@ -120,7 +124,8 @@ pub fn mmap_handler(cageid: u64, addr: *mut u8, len: usize, mut prot: i32, mut f let mut useraddr = addr as i32; // if MAP_FIXED is not set, then we need to find an address for the user if flags & MAP_FIXED as i32 == 0 { - let mut vmmap = cage.vmmap.write(); + // removed mut from vmmap to avoid warning + let vmmap = cage.vmmap.write(); let result; // pick an address of appropriate size, anywhere @@ -181,7 +186,7 @@ pub fn mmap_handler(cageid: u64, addr: *mut u8, len: usize, mut prot: i32, mut f // } }; - vmmap.add_entry_with_overwrite((useraddr >> PAGESHIFT) as u32, (rounded_length >> PAGESHIFT) as u32, prot, 0, flags, backing, off, 0, cageid); + let _ = vmmap.add_entry_with_overwrite((useraddr >> PAGESHIFT) as u32, (rounded_length >> PAGESHIFT) as u32, prot, 0, flags, backing, off, 0, cageid); } } @@ -201,10 +206,13 @@ pub fn sbrk_handler(cageid: u64, brk: u32) -> i32 { let brk_page = ((brk + 65536 - 1) / 65536) * 16; let heap_size = heap.npages; - vmmap.add_entry_with_overwrite(0, heap_size + brk_page, heap.prot, heap.maxprot, heap.flags, heap.backing, heap.file_offset, heap.file_size, heap.cage_id); + // added _ to suppress the warning + let _ = vmmap.add_entry_with_overwrite(0, heap_size + brk_page, heap.prot, heap.maxprot, heap.flags, heap.backing, heap.file_offset, heap.file_size, heap.cage_id); let usr_heap_base = (heap_size * PAGESIZE) as i32; - let sys_heap_base = vmmap.user_to_sys(usr_heap_base)as *mut u8; + + // added _ to suppress the warning + let _sys_heap_base = vmmap.user_to_sys(usr_heap_base)as *mut u8; drop(vmmap); diff --git a/src/RawPOSIX/src/interface/types.rs b/src/RawPOSIX/src/interface/types.rs index e5b545f21..277bed96b 100644 --- a/src/RawPOSIX/src/interface/types.rs +++ b/src/RawPOSIX/src/interface/types.rs @@ -462,7 +462,8 @@ pub fn get_sockaddr(generic_argument: u64, addrlen: u32) -> Result { + // added _ to suppress the warning + _val => { return Err(syscall_error( Errno::EOPNOTSUPP, "dispatcher", diff --git a/src/RawPOSIX/src/lib.rs b/src/RawPOSIX/src/lib.rs index 29e66e4a8..57d451d85 100644 --- a/src/RawPOSIX/src/lib.rs +++ b/src/RawPOSIX/src/lib.rs @@ -1,4 +1,5 @@ -#![feature(lazy_cell)] +// Rm for warning this line since lazy_cell is now stable +// #![feature(lazy_cell)] #![feature(rustc_private)] //for private crate imports for tests #![feature(vec_into_raw_parts)] #![feature(thread_local)] diff --git a/src/RawPOSIX/src/safeposix/dispatcher.rs b/src/RawPOSIX/src/safeposix/dispatcher.rs index a212565d8..3465f6b2d 100644 --- a/src/RawPOSIX/src/safeposix/dispatcher.rs +++ b/src/RawPOSIX/src/safeposix/dispatcher.rs @@ -140,6 +140,7 @@ use crate::interface::errnos::*; use crate::constants::*; use crate::interface::check_and_convert_addr_ext; +#[allow(unused_macros)] macro_rules! get_onearg { ($arg: expr) => { match (move || Ok($arg?))() { diff --git a/src/RawPOSIX/src/safeposix/syscalls/fs_calls.rs b/src/RawPOSIX/src/safeposix/syscalls/fs_calls.rs index ad67b3474..708980925 100644 --- a/src/RawPOSIX/src/safeposix/syscalls/fs_calls.rs +++ b/src/RawPOSIX/src/safeposix/syscalls/fs_calls.rs @@ -783,8 +783,9 @@ impl Cage { if virtual_fd != -1 { match fdtables::translate_virtual_fd(self.cageid, virtual_fd as u64) { Ok(kernel_fd) => { + // removed parenthesises to avoid warning let ret = unsafe { - (libc::mmap(addr as *mut c_void, len, prot, flags, kernel_fd.underfd as i32, off) as i64) + libc::mmap(addr as *mut c_void, len, prot, flags, kernel_fd.underfd as i32, off) as i64 }; // Check if mmap failed and return the appropriate error if so diff --git a/src/RawPOSIX/src/safeposix/syscalls/net_calls.rs b/src/RawPOSIX/src/safeposix/syscalls/net_calls.rs index e0f1dd4d8..23351a858 100644 --- a/src/RawPOSIX/src/safeposix/syscalls/net_calls.rs +++ b/src/RawPOSIX/src/safeposix/syscalls/net_calls.rs @@ -518,7 +518,8 @@ impl Cage { let mut fdkindset = HashSet::new(); fdkindset.insert(FDKIND_KERNEL); - let (selectbittables, unparsedtables, mappingtable) + // added _ to suppress the warning + let (selectbittables, _unparsedtables, mappingtable) = fdtables::prepare_bitmasks_for_select( self.cageid, nfds as u64, @@ -546,8 +547,8 @@ impl Cage { .get(2) .and_then(|table| table.get(&FDKIND_KERNEL).cloned()) .unwrap_or((0, fdtables::_init_fd_set())); - - let mut realnewnfds = readnfd.max(writenfd).max(errornfd); + // removed mut from realnewnfds to avoid warning + let realnewnfds = readnfd.max(writenfd).max(errornfd); // Ensured that null_mut is used if the Option is None for fd_set parameters. @@ -565,8 +566,9 @@ impl Cage { return handle_errno(errno, "select"); } - let mut unreal_read = HashSet::new(); - let mut unreal_write = HashSet::new(); + // removed mut from unreal_read and unreal_write to avoid warning + let unreal_read = HashSet::new(); + let unreal_write = HashSet::new(); // Revert result let (read_flags, read_result) = fdtables::get_one_virtual_bitmask_from_select_result( diff --git a/src/RawPOSIX/src/safeposix/syscalls/sys_calls.rs b/src/RawPOSIX/src/safeposix/syscalls/sys_calls.rs index d153b6669..f16761960 100644 --- a/src/RawPOSIX/src/safeposix/syscalls/sys_calls.rs +++ b/src/RawPOSIX/src/safeposix/syscalls/sys_calls.rs @@ -150,7 +150,8 @@ impl Cage { new_semtable.insert((*pair.key()).clone(), pair.value().clone()); } let parent_vmmap = self.vmmap.read(); - let new_vmmap = parent_vmmap.clone(); + // added _ to suppress the warning + let _new_vmmap = parent_vmmap.clone(); let cageobj = Cage { cageid: child_cageid, diff --git a/src/RawPOSIX/src/safeposix/vmmap.rs b/src/RawPOSIX/src/safeposix/vmmap.rs index 189de5117..c7a91fa0c 100644 --- a/src/RawPOSIX/src/safeposix/vmmap.rs +++ b/src/RawPOSIX/src/safeposix/vmmap.rs @@ -111,7 +111,8 @@ impl VmmapEntry { // Get file stats using fstat let mut libc_statbuf: libc::stat = unsafe { std::mem::zeroed() }; - let libcret = unsafe { + // added _ to suppress the warning + let _libcret = unsafe { libc::fstat(vfd.underfd as i32, &mut libc_statbuf) }; From 85e5e3e4218c8f24dda5ccf2aae5301576c49463 Mon Sep 17 00:00:00 2001 From: Chinmay Shringi Date: Sun, 29 Dec 2024 20:54:22 +0000 Subject: [PATCH 32/66] revert: fxstat error --- src/RawPOSIX/src/safeposix/dispatcher.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/RawPOSIX/src/safeposix/dispatcher.rs b/src/RawPOSIX/src/safeposix/dispatcher.rs index 3465f6b2d..d49eea47c 100644 --- a/src/RawPOSIX/src/safeposix/dispatcher.rs +++ b/src/RawPOSIX/src/safeposix/dispatcher.rs @@ -782,10 +782,7 @@ pub fn lind_syscall_api( // Validate stat buffer and prepare for writing // Using PROT_WRITE because fstat() writes the results TO this user space buffer let buf = match check_and_convert_addr_ext(&cage, arg2, std::mem::size_of::(), PROT_WRITE) { - Ok(addr) => match interface::get_statdatastruct(addr) { - Ok(val) => val, - Err(errno) => return syscall_error(Errno::EFAULT, "fxstat", "invalid stat data format"), - }, + Ok(addr) => interface::get_statdatastruct(addr).unwrap(), Err(errno) => return syscall_error(errno, "fxstat", "invalid buffer address"), }; From 3d725afc975fde1f30169cbc35615367680fa8de Mon Sep 17 00:00:00 2001 From: Chinmay Shringi Date: Sun, 29 Dec 2024 16:34:56 -0500 Subject: [PATCH 33/66] Revert "feat: removed warnings" This reverts commit e86a5d60fda838616d490039d7876ea4672fcb31. --- src/RawPOSIX/src/interface/mem.rs | 26 +++++++------------ src/RawPOSIX/src/interface/types.rs | 3 +-- src/RawPOSIX/src/lib.rs | 3 +-- src/RawPOSIX/src/safeposix/dispatcher.rs | 1 - .../src/safeposix/syscalls/fs_calls.rs | 3 +-- .../src/safeposix/syscalls/net_calls.rs | 12 ++++----- .../src/safeposix/syscalls/sys_calls.rs | 3 +-- src/RawPOSIX/src/safeposix/vmmap.rs | 3 +-- 8 files changed, 19 insertions(+), 35 deletions(-) diff --git a/src/RawPOSIX/src/interface/mem.rs b/src/RawPOSIX/src/interface/mem.rs index 8f9eded3a..3a0b1a779 100644 --- a/src/RawPOSIX/src/interface/mem.rs +++ b/src/RawPOSIX/src/interface/mem.rs @@ -21,9 +21,8 @@ pub fn round_up_page(length: u64) -> u64 { } pub fn fork_vmmap(parent_vmmap: &Vmmap, child_vmmap: &Vmmap) { - // added _ to suppress the warning - let _parent_base = parent_vmmap.base_address.unwrap(); - let _child_base = child_vmmap.base_address.unwrap(); + let parent_base = parent_vmmap.base_address.unwrap(); + let child_base = child_vmmap.base_address.unwrap(); // iterate through each vmmap entry for (_interval, entry) in parent_vmmap.entries.iter() { @@ -40,8 +39,7 @@ pub fn fork_vmmap(parent_vmmap: &Vmmap, child_vmmap: &Vmmap) { // for shared memory, we are using mremap to fork shared memory // See "man 2 mremap" for description of what MREMAP_MAYMOVE does with old_size=0 // when old_address points to a shared mapping - // added _ to suppress the warning - let _result = unsafe { libc::mremap(parent_st as *mut libc::c_void, 0, addr_len, libc::MREMAP_MAYMOVE | libc::MREMAP_FIXED, child_st as *mut libc::c_void) }; + let result = unsafe { libc::mremap(parent_st as *mut libc::c_void, 0, addr_len, libc::MREMAP_MAYMOVE | libc::MREMAP_FIXED, child_st as *mut libc::c_void) }; } else { unsafe { // temporarily enable write on child's memory region to write parent data @@ -82,14 +80,12 @@ pub fn munmap_handler(cageid: u64, addr: *mut u8, len: usize) -> i32 { let mut vmmap = cage.vmmap.write(); - // added _ to suppress the warning - let _ = vmmap.remove_entry(rounded_addr as u32 >> PAGESHIFT, len as u32 >> PAGESHIFT); + vmmap.remove_entry(rounded_addr as u32 >> PAGESHIFT, len as u32 >> PAGESHIFT); 0 } -// removed mut from prot to avoid warning -pub fn mmap_handler(cageid: u64, addr: *mut u8, len: usize, prot: i32, mut flags: i32, mut fildes: i32, off: i64) -> i32 { +pub fn mmap_handler(cageid: u64, addr: *mut u8, len: usize, mut prot: i32, mut flags: i32, mut fildes: i32, off: i64) -> i32 { let cage = cagetable_getref(cageid); // only these four flags are allowed @@ -124,8 +120,7 @@ pub fn mmap_handler(cageid: u64, addr: *mut u8, len: usize, prot: i32, mut flags let mut useraddr = addr as i32; // if MAP_FIXED is not set, then we need to find an address for the user if flags & MAP_FIXED as i32 == 0 { - // removed mut from vmmap to avoid warning - let vmmap = cage.vmmap.write(); + let mut vmmap = cage.vmmap.write(); let result; // pick an address of appropriate size, anywhere @@ -186,7 +181,7 @@ pub fn mmap_handler(cageid: u64, addr: *mut u8, len: usize, prot: i32, mut flags // } }; - let _ = vmmap.add_entry_with_overwrite((useraddr >> PAGESHIFT) as u32, (rounded_length >> PAGESHIFT) as u32, prot, 0, flags, backing, off, 0, cageid); + vmmap.add_entry_with_overwrite((useraddr >> PAGESHIFT) as u32, (rounded_length >> PAGESHIFT) as u32, prot, 0, flags, backing, off, 0, cageid); } } @@ -206,13 +201,10 @@ pub fn sbrk_handler(cageid: u64, brk: u32) -> i32 { let brk_page = ((brk + 65536 - 1) / 65536) * 16; let heap_size = heap.npages; - // added _ to suppress the warning - let _ = vmmap.add_entry_with_overwrite(0, heap_size + brk_page, heap.prot, heap.maxprot, heap.flags, heap.backing, heap.file_offset, heap.file_size, heap.cage_id); + vmmap.add_entry_with_overwrite(0, heap_size + brk_page, heap.prot, heap.maxprot, heap.flags, heap.backing, heap.file_offset, heap.file_size, heap.cage_id); let usr_heap_base = (heap_size * PAGESIZE) as i32; - - // added _ to suppress the warning - let _sys_heap_base = vmmap.user_to_sys(usr_heap_base)as *mut u8; + let sys_heap_base = vmmap.user_to_sys(usr_heap_base)as *mut u8; drop(vmmap); diff --git a/src/RawPOSIX/src/interface/types.rs b/src/RawPOSIX/src/interface/types.rs index 277bed96b..e5b545f21 100644 --- a/src/RawPOSIX/src/interface/types.rs +++ b/src/RawPOSIX/src/interface/types.rs @@ -462,8 +462,7 @@ pub fn get_sockaddr(generic_argument: u64, addrlen: u32) -> Result { + val => { return Err(syscall_error( Errno::EOPNOTSUPP, "dispatcher", diff --git a/src/RawPOSIX/src/lib.rs b/src/RawPOSIX/src/lib.rs index 57d451d85..29e66e4a8 100644 --- a/src/RawPOSIX/src/lib.rs +++ b/src/RawPOSIX/src/lib.rs @@ -1,5 +1,4 @@ -// Rm for warning this line since lazy_cell is now stable -// #![feature(lazy_cell)] +#![feature(lazy_cell)] #![feature(rustc_private)] //for private crate imports for tests #![feature(vec_into_raw_parts)] #![feature(thread_local)] diff --git a/src/RawPOSIX/src/safeposix/dispatcher.rs b/src/RawPOSIX/src/safeposix/dispatcher.rs index d49eea47c..482e1f079 100644 --- a/src/RawPOSIX/src/safeposix/dispatcher.rs +++ b/src/RawPOSIX/src/safeposix/dispatcher.rs @@ -140,7 +140,6 @@ use crate::interface::errnos::*; use crate::constants::*; use crate::interface::check_and_convert_addr_ext; -#[allow(unused_macros)] macro_rules! get_onearg { ($arg: expr) => { match (move || Ok($arg?))() { diff --git a/src/RawPOSIX/src/safeposix/syscalls/fs_calls.rs b/src/RawPOSIX/src/safeposix/syscalls/fs_calls.rs index 708980925..ad67b3474 100644 --- a/src/RawPOSIX/src/safeposix/syscalls/fs_calls.rs +++ b/src/RawPOSIX/src/safeposix/syscalls/fs_calls.rs @@ -783,9 +783,8 @@ impl Cage { if virtual_fd != -1 { match fdtables::translate_virtual_fd(self.cageid, virtual_fd as u64) { Ok(kernel_fd) => { - // removed parenthesises to avoid warning let ret = unsafe { - libc::mmap(addr as *mut c_void, len, prot, flags, kernel_fd.underfd as i32, off) as i64 + (libc::mmap(addr as *mut c_void, len, prot, flags, kernel_fd.underfd as i32, off) as i64) }; // Check if mmap failed and return the appropriate error if so diff --git a/src/RawPOSIX/src/safeposix/syscalls/net_calls.rs b/src/RawPOSIX/src/safeposix/syscalls/net_calls.rs index 23351a858..e0f1dd4d8 100644 --- a/src/RawPOSIX/src/safeposix/syscalls/net_calls.rs +++ b/src/RawPOSIX/src/safeposix/syscalls/net_calls.rs @@ -518,8 +518,7 @@ impl Cage { let mut fdkindset = HashSet::new(); fdkindset.insert(FDKIND_KERNEL); - // added _ to suppress the warning - let (selectbittables, _unparsedtables, mappingtable) + let (selectbittables, unparsedtables, mappingtable) = fdtables::prepare_bitmasks_for_select( self.cageid, nfds as u64, @@ -547,8 +546,8 @@ impl Cage { .get(2) .and_then(|table| table.get(&FDKIND_KERNEL).cloned()) .unwrap_or((0, fdtables::_init_fd_set())); - // removed mut from realnewnfds to avoid warning - let realnewnfds = readnfd.max(writenfd).max(errornfd); + + let mut realnewnfds = readnfd.max(writenfd).max(errornfd); // Ensured that null_mut is used if the Option is None for fd_set parameters. @@ -566,9 +565,8 @@ impl Cage { return handle_errno(errno, "select"); } - // removed mut from unreal_read and unreal_write to avoid warning - let unreal_read = HashSet::new(); - let unreal_write = HashSet::new(); + let mut unreal_read = HashSet::new(); + let mut unreal_write = HashSet::new(); // Revert result let (read_flags, read_result) = fdtables::get_one_virtual_bitmask_from_select_result( diff --git a/src/RawPOSIX/src/safeposix/syscalls/sys_calls.rs b/src/RawPOSIX/src/safeposix/syscalls/sys_calls.rs index f16761960..d153b6669 100644 --- a/src/RawPOSIX/src/safeposix/syscalls/sys_calls.rs +++ b/src/RawPOSIX/src/safeposix/syscalls/sys_calls.rs @@ -150,8 +150,7 @@ impl Cage { new_semtable.insert((*pair.key()).clone(), pair.value().clone()); } let parent_vmmap = self.vmmap.read(); - // added _ to suppress the warning - let _new_vmmap = parent_vmmap.clone(); + let new_vmmap = parent_vmmap.clone(); let cageobj = Cage { cageid: child_cageid, diff --git a/src/RawPOSIX/src/safeposix/vmmap.rs b/src/RawPOSIX/src/safeposix/vmmap.rs index c7a91fa0c..189de5117 100644 --- a/src/RawPOSIX/src/safeposix/vmmap.rs +++ b/src/RawPOSIX/src/safeposix/vmmap.rs @@ -111,8 +111,7 @@ impl VmmapEntry { // Get file stats using fstat let mut libc_statbuf: libc::stat = unsafe { std::mem::zeroed() }; - // added _ to suppress the warning - let _libcret = unsafe { + let libcret = unsafe { libc::fstat(vfd.underfd as i32, &mut libc_statbuf) }; From b391388bedfed78a468f1ad8d9e0c1457b1ae527 Mon Sep 17 00:00:00 2001 From: Chinmay Shringi Date: Sun, 29 Dec 2024 20:28:39 -0500 Subject: [PATCH 34/66] rm: duplicate comment --- src/RawPOSIX/src/safeposix/vmmap.rs | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/src/RawPOSIX/src/safeposix/vmmap.rs b/src/RawPOSIX/src/safeposix/vmmap.rs index 189de5117..d24e6fd7e 100644 --- a/src/RawPOSIX/src/safeposix/vmmap.rs +++ b/src/RawPOSIX/src/safeposix/vmmap.rs @@ -90,17 +90,13 @@ impl VmmapEntry { }; } - // get maximum protection for file based mappings - // this is effectively whatever mode the file was opened with - // we need this because we shouldnt be able to change filed backed mappings - // to have protections exceeding that of the file - /// Gets the maximum protection flags allowed for file-backed memory mappings - /// - /// Arguments: - /// - cage_id: Security cage identifier - /// - virtual_fd: Virtual file descriptor - /// - /// Returns the maximum protection flags as an i32, based on the file's mode + // Gets the maximum protection flags allowed for file-backed memory mappings + // + // Arguments: + // - cage_id: Security cage identifier + // - virtual_fd: Virtual file descriptor + // + // Returns the maximum protection flags as an i32, based on the file's mode fn get_max_prot(&self, cage_id: u64, virtual_fd: u64) -> i32 { // Translate the virtual file descriptor to a real one let wrappedvfd = fdtables::translate_virtual_fd(cage_id, virtual_fd as u64); From 27adcc3e2f7f8e501393480d66bee110af57307f Mon Sep 17 00:00:00 2001 From: Qianxi Chen Date: Mon, 30 Dec 2024 05:36:25 +0000 Subject: [PATCH 35/66] clean up --- src/RawPOSIX/src/interface/mem.rs | 121 ++++++++++++++++-- src/RawPOSIX/src/safeposix/dispatcher.rs | 31 +---- .../src/safeposix/syscalls/fs_calls.rs | 1 - src/RawPOSIX/src/safeposix/vmmap.rs | 4 - src/glibc/malloc/malloc.c | 4 +- src/glibc/misc/sbrk.c | 35 ----- src/glibc/nptl/allocatestack.c | 13 +- src/glibc/nptl/pthread_create.c | 1 - src/glibc/sysdeps/unix/sysv/linux/brk.c | 27 ---- .../crates/lind-multi-process/src/lib.rs | 16 --- src/wasmtime/crates/wasmtime/Cargo.toml | 1 + .../crates/wasmtime/src/runtime/instance.rs | 3 +- .../crates/wasmtime/src/runtime/vm/memory.rs | 6 +- .../src/runtime/vm/threads/shared_memory.rs | 7 +- 14 files changed, 124 insertions(+), 146 deletions(-) diff --git a/src/RawPOSIX/src/interface/mem.rs b/src/RawPOSIX/src/interface/mem.rs index b28e4f00e..44dd37530 100644 --- a/src/RawPOSIX/src/interface/mem.rs +++ b/src/RawPOSIX/src/interface/mem.rs @@ -12,6 +12,13 @@ use std::result::Result; // heap is placed at the very top of the memory pub const HEAP_ENTRY_INDEX: u32 = 0; +/// Round up the address length to be multiple of pages +/// +/// # Arguments +/// * `length` - length of the address +/// +/// # Returns +/// * `u64` - rounded up length pub fn round_up_page(length: u64) -> u64 { if length % PAGESIZE as u64 == 0 { length @@ -20,6 +27,24 @@ pub fn round_up_page(length: u64) -> u64 { } } +/// Copies the memory regions from parent to child based on the provided `vmmap` memory layout. +/// +/// This function is designed to replicate the parent's memory space into the child immediately after +/// a `fork_syscall` in Wasmtime. It assumes that the parent and child share the same `vmmap` structure, +/// a valid assumption in this context. +/// +/// The copying behavior varies based on the type of memory region: +/// 1. **PROT_NONE regions**: +/// - No action is taken, as memory regions are already configured with `PROT_NONE` by default. +/// 2. **Shared memory regions**: +/// - The function uses the `mremap` syscall to replicate shared memory efficiently. Refer to `man 2 mremap` for details. +/// 3. **Private memory regions**: +/// - The function uses `std::ptr::copy_nonoverlapping` to copy the memory contents directly. +/// - **TODO**: Investigate whether using `writev` could improve performance for this case. +/// +/// # Arguments +/// * `parent_vmmap` - vmmap struct of parent +/// * `child_vmmap` - vmmap struct of child pub fn fork_vmmap(parent_vmmap: &Vmmap, child_vmmap: &Vmmap) { let parent_base = parent_vmmap.base_address.unwrap(); let child_base = child_vmmap.base_address.unwrap(); @@ -56,6 +81,20 @@ pub fn fork_vmmap(parent_vmmap: &Vmmap, child_vmmap: &Vmmap) { } } +/// Handler of the `munmap_syscall`, interacting with the `vmmap` structure. +/// +/// This function processes the `munmap_syscall` by updating the `vmmap` entries and managing +/// the unmap operation. Instead of invoking the actual `munmap` syscall, the unmap operation +/// is simulated by setting the specified region to `PROT_NONE`. The memory remains valid but +/// becomes inaccessible due to the `PROT_NONE` setting. +/// +/// # Arguments +/// * `cageid` - Identifier of the cage that calls the `munmap` +/// * `addr` - Starting address of the region to unmap +/// * `length` - Length of the region to unmap +/// +/// # Returns +/// * `i32` - 0 for success and -1 for failure pub fn munmap_handler(cageid: u64, addr: *mut u8, len: usize) -> i32 { let cage = cagetable_getref(cageid); @@ -85,6 +124,28 @@ pub fn munmap_handler(cageid: u64, addr: *mut u8, len: usize) -> i32 { 0 } +/// Handles the `mmap_syscall`, interacting with the `vmmap` structure. +/// +/// This function processes the `mmap_syscall` by updating the `vmmap` entries and performing +/// the necessary mmap operations. The handling logic is as follows: +/// 1. Restrict allowed flags to `MAP_FIXED`, `MAP_SHARED`, `MAP_PRIVATE`, and `MAP_ANONYMOUS`. +/// 2. Disallow `PROT_EXEC`; return `EINVAL` if the `prot` argument includes `PROT_EXEC`. +/// 3. If `MAP_FIXED` is not specified, query the `vmmap` structure to locate an available memory region. +/// Otherwise, use the address provided by the user. +/// 4. Invoke the actual `mmap` syscall with the `MAP_FIXED` flag to configure the memory region's protections. +/// 5. Update the corresponding `vmmap` entry. +/// +/// # Arguments +/// * `cageid` - Identifier of the cage that initiated the `mmap` syscall. +/// * `addr` - Starting address of the memory region to mmap. +/// * `len` - Length of the memory region to mmap. +/// * `prot` - Memory protection flags (e.g., `PROT_READ`, `PROT_WRITE`). +/// * `flags` - Mapping flags (e.g., `MAP_SHARED`, `MAP_ANONYMOUS`). +/// * `fildes` - File descriptor associated with the mapping, if applicable. +/// * `off` - Offset within the file, if applicable. +/// +/// # Returns +/// * `u32` - Result of the `mmap` operation. See "man mmap" for details pub fn mmap_handler(cageid: u64, addr: *mut u8, len: usize, mut prot: i32, mut flags: i32, mut fildes: i32, off: i64) -> u32 { let cage = cagetable_getref(cageid); @@ -98,25 +159,21 @@ pub fn mmap_handler(cageid: u64, addr: *mut u8, len: usize, mut prot: i32, mut f } if prot & PROT_EXEC > 0 { - println!("mmap syscall error 1!"); return syscall_error(Errno::EINVAL, "mmap", "PROT_EXEC is not allowed") as u32; } // check if the provided address is multiple of pages let rounded_addr = round_up_page(addr as u64); if rounded_addr != addr as u64 { - println!("mmap syscall error 2!"); return syscall_error(Errno::EINVAL, "mmap", "address it not aligned") as u32; } // offset should be non-negative and multiple of pages if off < 0 { - println!("mmap syscall error 3!"); return syscall_error(Errno::EINVAL, "mmap", "offset cannot be negative") as u32; } let rounded_off = round_up_page(off as u64); if rounded_off != off as u64 { - println!("mmap syscall error 4!"); return syscall_error(Errno::EINVAL, "mmap", "offset it not aligned") as u32; } @@ -147,8 +204,6 @@ pub fn mmap_handler(cageid: u64, addr: *mut u8, len: usize, mut prot: i32, mut f useraddr = (space.start() << PAGESHIFT) as u32; } - // TODO: validate useraddr (like checking whether within the program break) - flags |= MAP_FIXED as i32; // either MAP_PRIVATE or MAP_SHARED should be set, but not both @@ -159,7 +214,6 @@ pub fn mmap_handler(cageid: u64, addr: *mut u8, len: usize, mut prot: i32, mut f let vmmap = cage.vmmap.read(); let sysaddr = vmmap.user_to_sys(useraddr); - println!("useraddr: {}, sysaddr: {}", useraddr, sysaddr); drop(vmmap); @@ -171,11 +225,10 @@ pub fn mmap_handler(cageid: u64, addr: *mut u8, len: usize, mut prot: i32, mut f let result = cage.mmap_syscall(sysaddr as *mut u8, rounded_length as usize, prot, flags, fildes, off); let vmmap = cage.vmmap.read(); - println!("sys addr: {}", result); let result = vmmap.sys_to_user(result); - println!("user addr: {}", result); drop(vmmap); + // if mmap addr is positive, that would mean the mapping is successful and we need to update the vmmap entry if result >= 0 { if result != useraddr { panic!("MAP_FIXED not fixed"); @@ -196,13 +249,34 @@ pub fn mmap_handler(cageid: u64, addr: *mut u8, len: usize, mut prot: i32, mut f } }; - vmmap.add_entry_with_overwrite(useraddr >> PAGESHIFT, (rounded_length >> PAGESHIFT) as u32, prot, maxprot, flags, backing, off, len as i64, cageid); + // update vmmap entry + vmmap.add_entry_with_overwrite(useraddr >> PAGESHIFT, + (rounded_length >> PAGESHIFT) as u32, + prot, + maxprot, + flags, + backing, + off, + len as i64, + cageid); } } useraddr as u32 } +/// Handles the `sbrk_syscall`, interacting with the `vmmap` structure. +/// +/// This function processes the `sbrk_syscall` by updating the `vmmap` entries and managing +/// the program break. It calculates the target program break after applying the specified +/// increment and delegates further processing to the `brk_handler`. +/// +/// # Arguments +/// * `cageid` - Identifier of the cage that initiated the `sbrk` syscall. +/// * `brk` - Increment to adjust the program break, which can be negative. +/// +/// # Returns +/// * `u32` - Result of the `sbrk` operation. Refer to `man sbrk` for details. pub fn sbrk_handler(cageid: u64, brk: i32) -> u32 { let cage = cagetable_getref(cageid); @@ -210,13 +284,16 @@ pub fn sbrk_handler(cageid: u64, brk: i32) -> u32 { let mut vmmap = cage.vmmap.read(); let heap = vmmap.find_page(HEAP_ENTRY_INDEX).unwrap().clone(); + // program break should always be the same as the heap entry end assert!(heap.npages == vmmap.program_break); + // pass 0 to sbrk will just return the current brk if brk == 0 { return (PAGESIZE * heap.npages) as u32; } // round up the break to multiple of pages + // brk increment could possibly be negative let brk_page; if brk < 0 { brk_page = -((round_up_page(-brk as u64) >> PAGESHIFT) as i32); @@ -224,15 +301,30 @@ pub fn sbrk_handler(cageid: u64, brk: i32) -> u32 { brk_page = (round_up_page(brk as u64) >> PAGESHIFT) as i32; } + // drop the vmmap so that brk_handler will not deadlock drop(vmmap); if brk_handler(cageid, ((heap.npages as i32 + brk_page) << PAGESHIFT) as u32) < 0 { return syscall_error(Errno::ENOMEM, "sbrk", "no memory") as u32; } + // sbrk syscall should return previous brk address before increment (PAGESIZE * heap.npages) as u32 } +/// Handles the `brk_syscall`, interacting with the `vmmap` structure. +/// +/// This function processes the `brk_syscall` by updating the `vmmap` entries and performing +/// the necessary operations to adjust the program break. Specifically, it updates the program +/// break by modifying the end of the heap entry (the first entry in `vmmap`) and invokes `mmap` +/// to adjust the memory protection as needed. +/// +/// # Arguments +/// * `cageid` - Identifier of the cage that initiated the `brk` syscall. +/// * `brk` - The new program break address. +/// +/// # Returns +/// * `u32` - Returns `0` on success or `-1` on failure. pub fn brk_handler(cageid: u64, brk: u32) -> i32 { let cage = cagetable_getref(cageid); @@ -247,6 +339,14 @@ pub fn brk_handler(cageid: u64, brk: u32) -> i32 { // TODO: check if brk has enough space + // if we are incrementing program break, we need to check if we have enough space + if brk_page > old_brk_page { + if vmmap.check_existing_mapping(old_brk_page, brk_page - old_brk_page, 0) { + return syscall_error(Errno::ENOMEM, "brk", "no memory"); + } + } + + // update vmmap entry vmmap.add_entry_with_overwrite(0, brk_page, heap.prot, heap.maxprot, heap.flags, heap.backing, heap.file_offset, heap.file_size, heap.cage_id); let old_heap_end_usr = (old_brk_page * PAGESIZE) as u32; @@ -330,7 +430,6 @@ pub fn check_and_convert_addr_ext(cage: &Cage, arg: u64, length: usize, prot: i3 // Validate memory mapping and permissions if vmmap.check_addr_mapping(page_num, npages, prot).is_none() { - println!("invalid address: {}", arg); return Err(Errno::EFAULT); // Return error if mapping invalid } diff --git a/src/RawPOSIX/src/safeposix/dispatcher.rs b/src/RawPOSIX/src/safeposix/dispatcher.rs index b84dcc8cc..8e650d29f 100644 --- a/src/RawPOSIX/src/safeposix/dispatcher.rs +++ b/src/RawPOSIX/src/safeposix/dispatcher.rs @@ -201,17 +201,6 @@ pub fn lind_syscall_api( ) -> i32 { let call_number = call_number as i32; - if call_number as i32 != WRITE_SYSCALL { - match call_name { - 0 => { - println!("\x1b[90mcage {} calls UNNAMED ({})\x1b[0m", cageid, call_number); - }, - _ => { - println!("\x1b[90mcage {} calls {} ({})\x1b[0m", cageid, interface::get_cstr(start_address + call_name).unwrap(), call_number); - } - } - } - let ret = match call_number { WRITE_SYSCALL => { let fd = arg1 as i32; @@ -1230,25 +1219,6 @@ pub fn lind_syscall_api( _ => -1, // Return -1 for unknown syscalls }; - if call_number as i32 != WRITE_SYSCALL { - match call_name { - 0 => { - if ret < 0 { - println!("\x1b[31mcage {} calls UNNAMED ({}) returns {}\x1b[0m", cageid, call_number, ret); - } else { - println!("\x1b[90mcage {} calls UNNAMED ({}) returns {}\x1b[0m", cageid, call_number, ret); - } - }, - _ => { - if ret < 0 { - println!("\x1b[31mcage {} calls {} ({}) returns {}\x1b[0m", cageid, interface::get_cstr(start_address + call_name).unwrap(), call_number, ret); - } else { - println!("\x1b[90mcage {} calls {} ({}) returns {}\x1b[0m", cageid, interface::get_cstr(start_address + call_name).unwrap(), call_number, ret); - } - } - } - } - ret } @@ -1271,6 +1241,7 @@ pub fn fork_vmmap_helper(parent_cageid: u64, child_cageid: u64) { interface::fork_vmmap(&parent_vmmap, &child_vmmap); + // update program break for child drop(child_vmmap); let mut child_vmmap = child_cage.vmmap.write(); child_vmmap.set_program_break(parent_vmmap.program_break); diff --git a/src/RawPOSIX/src/safeposix/syscalls/fs_calls.rs b/src/RawPOSIX/src/safeposix/syscalls/fs_calls.rs index d47ca4c26..f2689e0d9 100644 --- a/src/RawPOSIX/src/safeposix/syscalls/fs_calls.rs +++ b/src/RawPOSIX/src/safeposix/syscalls/fs_calls.rs @@ -780,7 +780,6 @@ impl Cage { virtual_fd: i32, off: i64 ) -> usize { - println!("mmap_syscall: addr: {:?}, len: {}, prot: {} flags: {}, fd: {}, off: {}", addr, len, prot, flags, virtual_fd, off); if virtual_fd != -1 { match fdtables::translate_virtual_fd(self.cageid, virtual_fd as u64) { Ok(kernel_fd) => { diff --git a/src/RawPOSIX/src/safeposix/vmmap.rs b/src/RawPOSIX/src/safeposix/vmmap.rs index 3747a4377..23efa2f5a 100644 --- a/src/RawPOSIX/src/safeposix/vmmap.rs +++ b/src/RawPOSIX/src/safeposix/vmmap.rs @@ -2,7 +2,6 @@ use crate::constants::{ MAP_ANONYMOUS, MAP_FAILED, MAP_FIXED, MAP_PRIVATE, MAP_SHARED, PAGESHIFT, PROT_EXEC, PROT_NONE, PROT_READ, PROT_WRITE }; use std::io; -use nodit::interval::ii; use nodit::NoditMap; use nodit::{interval::ie, Interval}; use crate::fdtables; @@ -896,19 +895,16 @@ impl VmmapOps for Vmmap { let rounded_num_pages = self.round_page_num_up_to_map_multiple(num_pages, pages_per_map); - println!("rounded_num_pages: {}", rounded_num_pages); for gap in self .entries .gaps_trimmed(ie(start, end)) { - println!("gap: {:?}", gap); let aligned_start_page = self.trunc_page_num_down_to_map_multiple(gap.start(), pages_per_map); let aligned_end_page = self.round_page_num_up_to_map_multiple(gap.end(), pages_per_map); - println!("aligned gap: {} {}", aligned_start_page, aligned_end_page); let gap_size = aligned_end_page - aligned_start_page; if gap_size >= rounded_num_pages { return Some(ie(aligned_end_page - rounded_num_pages, aligned_end_page)); diff --git a/src/glibc/malloc/malloc.c b/src/glibc/malloc/malloc.c index fab05ab51..b6ea1547f 100644 --- a/src/glibc/malloc/malloc.c +++ b/src/glibc/malloc/malloc.c @@ -4444,8 +4444,8 @@ _int_malloc (mstate av, size_t bytes) victim = av->top; size = chunksize (victim); - // if (__glibc_unlikely (size > av->system_mem)) - // malloc_printerr ("malloc(): corrupted top size"); + if (__glibc_unlikely (size > av->system_mem)) + malloc_printerr ("malloc(): corrupted top size"); if ((unsigned long) (size) >= (unsigned long) (nb + MINSIZE)) { diff --git a/src/glibc/misc/sbrk.c b/src/glibc/misc/sbrk.c index 8b4a340b7..a9d08a737 100644 --- a/src/glibc/misc/sbrk.c +++ b/src/glibc/misc/sbrk.c @@ -44,41 +44,6 @@ void * __sbrk (intptr_t increment) { return MAKE_SYSCALL(176, "syscall|sbrk", (uint64_t) increment, NOTUSED, NOTUSED, NOTUSED, NOTUSED, NOTUSED); - // __curbrk = __builtin_wasm_memory_size(0) * PAGESIZE; - - // // sbrk(0) returns the current memory size. - // if (increment == 0) { - // // The wasm spec doesn't guarantee that memory.grow of 0 always succeeds. - // return __curbrk; - // } - - // // FIXME: now two threads calling this sbrk simultaneously - // // will lead to the corruption of __curbrk, so we should move - // // this implementation into the runtime, and protect the __curbrk - // // with mutex (i.e. preventing two sbrk to be executed at the same time) - - // void * linear_mem_end = __builtin_wasm_memory_size(0) * PAGESIZE; - // void * old_break = __curbrk; - // void * new_break = old_break + increment; - - // if (new_break <= linear_mem_end) { - // // In this case, we don't need to grow linear mem - // __curbrk = new_break; - // return old_break; - // } - - // // Now we need to grow linear mem - // // int new_pages = (new_break - linear_mem_end) / PAGESIZE; - // int new_pages = (new_break - linear_mem_end + PAGESIZE - 1) / PAGESIZE; - - // MAKE_SYSCALL(176, "syscall|sbrk", (uint64_t) increment, NOTUSED, NOTUSED, NOTUSED, NOTUSED, NOTUSED); - // if (__builtin_wasm_memory_grow(0, new_pages) < 0) { - // errno = ENOMEM; - // return (void *)-1; - // } - - // __curbrk = new_break; - // return old_break; } // void * diff --git a/src/glibc/nptl/allocatestack.c b/src/glibc/nptl/allocatestack.c index ba6ee8d1c..061ae1296 100644 --- a/src/glibc/nptl/allocatestack.c +++ b/src/glibc/nptl/allocatestack.c @@ -324,6 +324,7 @@ allocate_stack (const struct pthread_attr *attr, struct pthread **pdp, size_t reported_guardsize; size_t reqsize; void *mem; + // lind-wasm: deleted PROT_EXEC since lind disallows PROT_EXEC mapping const int prot = (PROT_READ | PROT_WRITE); /* Adjust the stack size for alignment. */ @@ -362,19 +363,9 @@ allocate_stack (const struct pthread_attr *attr, struct pthread **pdp, /* If a guard page is required, avoid committing memory by first allocate with PROT_NONE and then reserve with required permission excluding the guard page. */ - printf("size: %d\n", size); mem = __mmap (NULL, size, (guardsize == 0) ? prot : PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); - // Replacement mmap with malloc - Dennis - // BUG: changed the malloc size to 16416 (1/4 of the original) - // since currently there is an issue on malloc that it cannot - // automatically grow the memory if memory is running out. - // Once the issue is fixed, we might be able to change the size - // back - Qianxi Chen - // size = 16416; - // void* mem = malloc(size); - if (mem == NULL) { // Handle memory allocation failure perror("malloc"); @@ -439,7 +430,7 @@ allocate_stack (const struct pthread_attr *attr, struct pthread **pdp, /* Don't allow setxid until cloned. */ pd->setxid_futex = -1; - // BUG: TLS related stuff is not working currently + // BUG: TLS related stuff is not working in lind-wasm currently /* Allocate the DTV for this thread. */ // if (_dl_allocate_tls (TLS_TPADJ (pd)) == NULL) // { diff --git a/src/glibc/nptl/pthread_create.c b/src/glibc/nptl/pthread_create.c index 8c3eea9cf..d94c0bb6c 100644 --- a/src/glibc/nptl/pthread_create.c +++ b/src/glibc/nptl/pthread_create.c @@ -342,7 +342,6 @@ static int create_thread (struct pthread *pd, const struct pthread_attr *attr, unsigned char *stack = 0; - printf("stacksize: %d\n", stacksize); struct clone_args *args = (void *)pd->stackblock + pd->stackblock_size - sizeof(struct clone_args) - TLS_TCB_SIZE; memset(args, 0, sizeof(struct clone_args)); args->flags = clone_flags; diff --git a/src/glibc/sysdeps/unix/sysv/linux/brk.c b/src/glibc/sysdeps/unix/sysv/linux/brk.c index f0e42f01f..b1665c48b 100644 --- a/src/glibc/sysdeps/unix/sysv/linux/brk.c +++ b/src/glibc/sysdeps/unix/sysv/linux/brk.c @@ -41,32 +41,5 @@ int __brk (void *addr) { return MAKE_SYSCALL(175, "syscall|brk", (uint64_t) addr, NOTUSED, NOTUSED, NOTUSED, NOTUSED, NOTUSED); -// __curbrk = __builtin_wasm_memory_size(0) * PAGESIZE; - -// // FIXME: now two threads calling this sbrk simultaneously -// // will lead to the corruption of __curbrk, so we should move -// // this implementation into the runtime, and protect the __curbrk -// // with mutex (i.e. preventing two brk/sbrk to be executed at the same time) - -// void * linear_mem_end = __builtin_wasm_memory_size(0) * PAGESIZE; -// void * old_break = __curbrk; -// void * new_break = addr; - -// if (new_break <= linear_mem_end) { -// // In this case, we don't need to grow linear mem -// __curbrk = new_break; -// return old_break; -// } - -// // Now we need to grow linear mem -// int new_pages = (new_break - linear_mem_end) / PAGESIZE; - -// if (__builtin_wasm_memory_grow(0, new_pages) < 0) { -// errno = ENOMEM; -// return (void *)-1; -// } - -// __curbrk = new_break; -// return old_break; } weak_alias (__brk, brk) diff --git a/src/wasmtime/crates/lind-multi-process/src/lib.rs b/src/wasmtime/crates/lind-multi-process/src/lib.rs index a3b101efe..28cf31fb1 100644 --- a/src/wasmtime/crates/lind-multi-process/src/lib.rs +++ b/src/wasmtime/crates/lind-multi-process/src/lib.rs @@ -329,20 +329,6 @@ impl, stack_addr: i32, stack_size: i32, child_tid: u64 ) -> Result { - println!("-----stack_addr: {}, stack_size: {}", stack_addr, stack_size); // get the base address of the memory let handle = caller.as_context().0.instance(InstanceId::from_index(0)); let defined_memory = handle.get_memory(MemoryIndex::from_u32(0)); @@ -1062,7 +1047,6 @@ impl, ) -> Result, Error> { - println!("memory grow: {}", delta_pages); let old_byte_size = self.byte_size(); // Wasm spec: when growing by 0 pages, always return the current size. @@ -222,8 +221,8 @@ impl MmapMemory { mut maximum: Option, memory_image: Option<&Arc>, ) -> Result { - println!("-----minimum: {}, maximum: {:?}", minimum, maximum); - maximum = Some(4294967296); + // lind-wasm: we enable maximum use of memory at start + maximum = Some(1 << 32); // It's a programmer error for these two configuration values to exceed // the host available address space, so panic if such a configuration is // found (mostly an issue for hypothetical 32-bit hosts). @@ -328,7 +327,6 @@ impl RuntimeLinearMemory for MmapMemory { } fn grow_to(&mut self, new_size: usize) -> Result<()> { - println!("-----grow to {}", new_size); assert!(usize_is_multiple_of_host_page_size(self.offset_guard_size)); assert!(usize_is_multiple_of_host_page_size(self.pre_guard_size)); assert!(usize_is_multiple_of_host_page_size(self.mmap.len())); diff --git a/src/wasmtime/crates/wasmtime/src/runtime/vm/threads/shared_memory.rs b/src/wasmtime/crates/wasmtime/src/runtime/vm/threads/shared_memory.rs index 774dffe07..9fe5f7901 100644 --- a/src/wasmtime/crates/wasmtime/src/runtime/vm/threads/shared_memory.rs +++ b/src/wasmtime/crates/wasmtime/src/runtime/vm/threads/shared_memory.rs @@ -31,11 +31,12 @@ struct SharedMemoryInner { impl SharedMemory { /// Construct a new [`SharedMemory`]. pub fn new(plan: MemoryPlan) -> Result { - println!("-----create new memory!"); let (minimum_bytes, maximum_bytes) = Memory::limit_new(&plan, None)?; let mut mmap_memory = MmapMemory::new(&plan, minimum_bytes, maximum_bytes, None)?; - if minimum_bytes < 4294967296 { - mmap_memory.grow_to(4294967296); + // lind-wasm: we enable maximum use of memory at start + let max_size = 1 << 32; + if minimum_bytes < max_size { + mmap_memory.grow_to(max_size); } Self::wrap(&plan, Box::new(mmap_memory), plan.memory) } From b9d60007b324e015543b89e7a9ef7883f9d75c30 Mon Sep 17 00:00:00 2001 From: Qianxi Chen Date: Mon, 30 Dec 2024 05:39:00 +0000 Subject: [PATCH 36/66] update comment --- src/RawPOSIX/src/interface/mem.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/RawPOSIX/src/interface/mem.rs b/src/RawPOSIX/src/interface/mem.rs index 44dd37530..f13ed29c7 100644 --- a/src/RawPOSIX/src/interface/mem.rs +++ b/src/RawPOSIX/src/interface/mem.rs @@ -337,8 +337,6 @@ pub fn brk_handler(cageid: u64, brk: u32) -> i32 { // round up the break to multiple of pages let brk_page = (round_up_page(brk as u64) >> PAGESHIFT) as u32; - // TODO: check if brk has enough space - // if we are incrementing program break, we need to check if we have enough space if brk_page > old_brk_page { if vmmap.check_existing_mapping(old_brk_page, brk_page - old_brk_page, 0) { From 9cdecd4e3f788a7122dbb208a3809bc6fb588f7b Mon Sep 17 00:00:00 2001 From: Qianxi Chen Date: Mon, 30 Dec 2024 05:40:55 +0000 Subject: [PATCH 37/66] added test file for mmap and sbrk --- .../memory_tests/deterministic/mmap_file.c | 53 +++++++++++++++++++ .../memory_tests/deterministic/mmap_shared.c | 43 +++++++++++++++ .../memory_tests/deterministic/sbrk.c | 33 ++++++++++++ 3 files changed, 129 insertions(+) create mode 100644 tests/unit-tests/memory_tests/deterministic/mmap_file.c create mode 100644 tests/unit-tests/memory_tests/deterministic/mmap_shared.c create mode 100644 tests/unit-tests/memory_tests/deterministic/sbrk.c diff --git a/tests/unit-tests/memory_tests/deterministic/mmap_file.c b/tests/unit-tests/memory_tests/deterministic/mmap_file.c new file mode 100644 index 000000000..8bab9e4e3 --- /dev/null +++ b/tests/unit-tests/memory_tests/deterministic/mmap_file.c @@ -0,0 +1,53 @@ +#include +#include +#include +#include +#include +#include + +#define FILE_PATH "example.txt" +#define FILE_SIZE 4096 + +int main() { + // Create or open a file + int fd = open(FILE_PATH, O_RDWR | O_CREAT, 0666); + if (fd == -1) { + perror("open"); + exit(EXIT_FAILURE); + } + + // Ensure the file has the desired size + if (ftruncate(fd, FILE_SIZE) == -1) { + perror("ftruncate"); + close(fd); + exit(EXIT_FAILURE); + } + + // Map the file into memory + void* addr = mmap(NULL, FILE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if (addr == MAP_FAILED) { + perror("mmap"); + close(fd); + exit(EXIT_FAILURE); + } + + // Close the file descriptor as it's no longer needed + close(fd); + + // Write data to the mapped memory + const char* message = "Hello, mmap!\0"; + memcpy(addr, message, strlen(message)); + + printf("Data written to memory-mapped file: %s\n", (char*)addr); + + // Read back the data from the mapped memory + printf("Data read back from memory-mapped file: %s\n", (char*)addr); + + // Unmap the memory + if (munmap(addr, FILE_SIZE) == -1) { + perror("munmap"); + exit(EXIT_FAILURE); + } + + return 0; +} diff --git a/tests/unit-tests/memory_tests/deterministic/mmap_shared.c b/tests/unit-tests/memory_tests/deterministic/mmap_shared.c new file mode 100644 index 000000000..c21c4e662 --- /dev/null +++ b/tests/unit-tests/memory_tests/deterministic/mmap_shared.c @@ -0,0 +1,43 @@ +#include +#include +#include +#include + +int main() { + int *addr1 = mmap(NULL, 10, PROT_READ | PROT_WRITE, + MAP_SHARED | MAP_ANONYMOUS, -1, 0); + int *addr2 = mmap(NULL, 10, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + + if(addr1 < 0) + { + perror("mmap"); + exit(1); + } + + if(addr2 < 0) + { + perror("mmap"); + exit(1); + } + + *addr1 = 1234; + *addr2 = 4321; + printf("parent value: %d, %d\n", *addr1, *addr2); + + if(fork()) { + // parent + printf("parent value after fork: %d, %d\n", *addr1, *addr2); + sleep(1); + *addr1 = 2333; + *addr2 = 3332; + printf("parent value after modification: %d, %d\n", *addr1, *addr2); + } else { + // child + printf("child value after fork: %d, %d\n", *addr1, *addr2); + sleep(2); + printf("child value after modification: %d, %d\n", *addr1, *addr2); + } + + return 0; +} diff --git a/tests/unit-tests/memory_tests/deterministic/sbrk.c b/tests/unit-tests/memory_tests/deterministic/sbrk.c new file mode 100644 index 000000000..de48a77c2 --- /dev/null +++ b/tests/unit-tests/memory_tests/deterministic/sbrk.c @@ -0,0 +1,33 @@ +#include +#include +#include + +int main() { + // Allocate memory using sbrk + size_t size = 1024; // Allocate 1024 bytes + void *initial_brk = sbrk(0); // Get the current program break + void *new_brk = sbrk(size); // Increment the program break + + if (new_brk == (void *)-1) { + perror("sbrk failed"); + return 1; + } + + printf("Initial program break: %p\n", initial_brk); + printf("New program break after allocation: %p\n", sbrk(0)); + + // Use the allocated memory + char *buffer = (char *)new_brk; + strcpy(buffer, "Hello, sbrk memory!"); + printf("Content in allocated memory: %s\n", buffer); + + // Deallocate memory by moving the program break back + if (sbrk(-size) == (void *)-1) { + perror("sbrk failed to deallocate"); + return 1; + } + + printf("Program break after deallocation: %p\n", sbrk(0)); + + return 0; +} From 851ce5f8e9ce1c0948d690795da7f07784b40ec4 Mon Sep 17 00:00:00 2001 From: Qianxi Chen Date: Fri, 3 Jan 2025 21:18:17 +0000 Subject: [PATCH 38/66] fixed incorrect handle of 32bit address --- src/RawPOSIX/src/interface/mem.rs | 1 - src/wasmtime/crates/lind-common/src/lib.rs | 8 +++---- .../crates/lind-multi-process/src/lib.rs | 24 +++++++++---------- .../crates/wasmtime/src/runtime/func.rs | 2 +- .../crates/wasmtime/src/runtime/instance.rs | 4 ++-- 5 files changed, 19 insertions(+), 20 deletions(-) diff --git a/src/RawPOSIX/src/interface/mem.rs b/src/RawPOSIX/src/interface/mem.rs index f13ed29c7..3e5876c53 100644 --- a/src/RawPOSIX/src/interface/mem.rs +++ b/src/RawPOSIX/src/interface/mem.rs @@ -189,7 +189,6 @@ pub fn mmap_handler(cageid: u64, addr: *mut u8, len: usize, mut prot: i32, mut f // pick an address of appropriate size, anywhere if useraddr == 0 { result = vmmap.find_map_space(rounded_length as u32 >> PAGESHIFT, 1); - println!("find map space result: {:?}", result); } else { // use address user provided as hint to find address result = vmmap.find_map_space_with_hint(rounded_length as u32 >> PAGESHIFT, 1, addr as u32); diff --git a/src/wasmtime/crates/lind-common/src/lib.rs b/src/wasmtime/crates/lind-common/src/lib.rs index f21beb2b1..30b7b0638 100644 --- a/src/wasmtime/crates/lind-common/src/lib.rs +++ b/src/wasmtime/crates/lind-common/src/lib.rs @@ -74,13 +74,13 @@ impl LindCommonCtx { // setjmp call. This function needs to be handled within wasmtime, but it is not an actual syscall so we use a different routine from lind_syscall pub fn lind_setjmp + Clone + Send + 'static + std::marker::Sync, U: Clone + Send + 'static + std::marker::Sync> - (&self, caller: &mut Caller<'_, T>, jmp_buf: i32) -> i32 { + (&self, caller: &mut Caller<'_, T>, jmp_buf: u32) -> i32 { wasmtime_lind_multi_process::setjmp_call(caller, jmp_buf) } // longjmp call. This function needs to be handled within wasmtime, but it is not an actual syscall so we use a different routine from lind_syscall pub fn lind_longjmp + Clone + Send + 'static + std::marker::Sync, U: Clone + Send + 'static + std::marker::Sync> - (&self, caller: &mut Caller<'_, T>, jmp_buf: i32, retval: i32) -> i32 { + (&self, caller: &mut Caller<'_, T>, jmp_buf: u32, retval: i32) -> i32 { wasmtime_lind_multi_process::longjmp_call(caller, jmp_buf, retval) } @@ -144,7 +144,7 @@ pub fn add_to_linker + Clone + Send + 'static + std::marker::S let host = caller.data().clone(); let ctx = get_cx(&host); - ctx.lind_setjmp(&mut caller, jmp_buf) + ctx.lind_setjmp(&mut caller, jmp_buf as u32) }, )?; @@ -156,7 +156,7 @@ pub fn add_to_linker + Clone + Send + 'static + std::marker::S let host = caller.data().clone(); let ctx = get_cx(&host); - ctx.lind_longjmp(&mut caller, jmp_buf, retval) + ctx.lind_longjmp(&mut caller, jmp_buf as u32, retval) }, )?; diff --git a/src/wasmtime/crates/lind-multi-process/src/lib.rs b/src/wasmtime/crates/lind-multi-process/src/lib.rs index 28cf31fb1..fdc8b6320 100644 --- a/src/wasmtime/crates/lind-multi-process/src/lib.rs +++ b/src/wasmtime/crates/lind-multi-process/src/lib.rs @@ -440,7 +440,7 @@ impl, - stack_addr: i32, stack_size: i32, child_tid: u64 + stack_addr: u32, stack_size: u32, child_tid: u64 ) -> Result { // get the base address of the memory let handle = caller.as_context().0.instance(InstanceId::from_index(0)); @@ -552,11 +552,11 @@ impl(&mut store, "set_stack_pointer") .unwrap(); - let _ = stack_pointer_setter.call(&mut store, stack_addr - offset); + let _ = stack_pointer_setter.call(&mut store, (stack_addr - offset) as i32); // get the asyncify_rewind_start and module start function let child_rewind_start; @@ -760,7 +760,7 @@ impl, jmp_buf: i32) -> Result { + pub fn setjmp_call(&self, mut caller: &mut Caller<'_, T>, jmp_buf: u32) -> Result { // get the base address of the memory let handle = caller.as_context().0.instance(InstanceId::from_index(0)); let defined_memory = handle.get_memory(MemoryIndex::from_u32(0)); @@ -877,7 +877,7 @@ impl, jmp_buf: i32, retval: i32) -> Result { + pub fn longjmp_call(&self, mut caller: &mut Caller<'_, T>, jmp_buf: u32, retval: i32) -> Result { // get the base address of the memory let handle = caller.as_context().0.instance(InstanceId::from_index(0)); let defined_memory = handle.get_memory(MemoryIndex::from_u32(0)); @@ -952,7 +952,7 @@ impl + Clone + Send + 'static + std::marker::Sync, // entry point of pthread_create syscall pub fn lind_pthread_create + Clone + Send + 'static + std::marker::Sync, U: Clone + Send + 'static + std::marker::Sync> (caller: &mut Caller<'_, T>, - stack_addr: i32, stack_size: i32, child_tid: u64) -> Result { + stack_addr: u32, stack_size: u32, child_tid: u64) -> Result { let host = caller.data().clone(); let ctx = host.get_ctx(); ctx.pthread_create_call(caller, stack_addr, stack_size, child_tid) @@ -1131,7 +1131,7 @@ pub fn clone_syscall + Clone + Send + 'static + std::marker::S } else { // pthread_create - match lind_pthread_create(caller, args.stack as i32, args.stack_size as i32, args.child_tid) { + match lind_pthread_create(caller, args.stack as u32, args.stack_size as u32, args.child_tid) { Ok(res) => res, Err(_e) => -1 } @@ -1167,7 +1167,7 @@ pub fn exit_syscall + Clone + Send + 'static + std::marker::Sy } pub fn setjmp_call + Clone + Send + 'static + std::marker::Sync, U: Clone + Send + 'static + std::marker::Sync> - (caller: &mut Caller<'_, T>, jmp_buf: i32) -> i32 { + (caller: &mut Caller<'_, T>, jmp_buf: u32) -> i32 { // first let's check if the process is currently in rewind state let rewind_res = catch_rewind(caller); if rewind_res.is_some() { @@ -1181,7 +1181,7 @@ pub fn setjmp_call + Clone + Send + 'static + std::marker::Syn } pub fn longjmp_call + Clone + Send + 'static + std::marker::Sync, U: Clone + Send + 'static + std::marker::Sync> - (caller: &mut Caller<'_, T>, jmp_buf: i32, retval: i32) -> i32 { + (caller: &mut Caller<'_, T>, jmp_buf: u32, retval: i32) -> i32 { let host = caller.data().clone(); let ctx = host.get_ctx(); diff --git a/src/wasmtime/crates/wasmtime/src/runtime/func.rs b/src/wasmtime/crates/wasmtime/src/runtime/func.rs index e0df91960..f049c06c2 100644 --- a/src/wasmtime/crates/wasmtime/src/runtime/func.rs +++ b/src/wasmtime/crates/wasmtime/src/runtime/func.rs @@ -2123,7 +2123,7 @@ impl Caller<'_, T> { .get_export(&mut self.store, name) } - pub fn get_stack_pointer(&mut self) -> Result { + pub fn get_stack_pointer(&mut self) -> Result { self.caller .host_state() .downcast_ref::().ok_or(()).unwrap() diff --git a/src/wasmtime/crates/wasmtime/src/runtime/instance.rs b/src/wasmtime/crates/wasmtime/src/runtime/instance.rs index 48f7746b9..24b9be5c7 100644 --- a/src/wasmtime/crates/wasmtime/src/runtime/instance.rs +++ b/src/wasmtime/crates/wasmtime/src/runtime/instance.rs @@ -525,13 +525,13 @@ impl Instance { self._get_export(store, entity, export_name_index) } - pub fn get_stack_pointer(&self, mut store: impl AsContextMut) -> Result { + pub fn get_stack_pointer(&self, mut store: impl AsContextMut) -> Result { if let Some(sp_extern) = self.get_export(store.as_context_mut(), "__stack_pointer") { match sp_extern { Extern::Global(sp) => { match sp.get(store.as_context_mut()) { Val::I32(val) => { - return Ok(val); + return Ok(val as u32); } _ => { // unexpected stack pointer type (not i32) From 1a23771006374ec89c31b5d2450976e37917687e Mon Sep 17 00:00:00 2001 From: Qianxi Chen Date: Fri, 3 Jan 2025 22:01:41 +0000 Subject: [PATCH 39/66] added some memory tests --- .../crates/wasmtime/src/runtime/vm/mmap.rs | 2 +- .../memory_tests/deterministic/malloc_large.c | 13 ++++ .../deterministic/mmap_complicated.c | 74 +++++++++++++++++++ 3 files changed, 88 insertions(+), 1 deletion(-) create mode 100644 tests/unit-tests/memory_tests/deterministic/malloc_large.c create mode 100644 tests/unit-tests/memory_tests/deterministic/mmap_complicated.c diff --git a/src/wasmtime/crates/wasmtime/src/runtime/vm/mmap.rs b/src/wasmtime/crates/wasmtime/src/runtime/vm/mmap.rs index 5e7ef93df..dd4e0f04b 100644 --- a/src/wasmtime/crates/wasmtime/src/runtime/vm/mmap.rs +++ b/src/wasmtime/crates/wasmtime/src/runtime/vm/mmap.rs @@ -100,7 +100,7 @@ impl Mmap { assert!(start <= self.len() - len); // lind-wasm: mmap prot is managed by rawposix - // self.sys.make_accessible(start, len) + // so we are skipping wasmtime's sys mmap here Ok(()) } diff --git a/tests/unit-tests/memory_tests/deterministic/malloc_large.c b/tests/unit-tests/memory_tests/deterministic/malloc_large.c new file mode 100644 index 000000000..ec738f183 --- /dev/null +++ b/tests/unit-tests/memory_tests/deterministic/malloc_large.c @@ -0,0 +1,13 @@ +#include +#include +#include + +int main() { + // try with extremely large malloc + char *buf = malloc(0x10000000); + + *buf = 42; + printf("%p: %d\n", buf, *buf); + + return 0; +} \ No newline at end of file diff --git a/tests/unit-tests/memory_tests/deterministic/mmap_complicated.c b/tests/unit-tests/memory_tests/deterministic/mmap_complicated.c new file mode 100644 index 000000000..d8d20bffd --- /dev/null +++ b/tests/unit-tests/memory_tests/deterministic/mmap_complicated.c @@ -0,0 +1,74 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +int main() { + // Define the size of the shared memory + size_t mem_size = 1024; + + // Create shared memory region using mmap + char *shared_mem = (char*)mmap(NULL, mem_size, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); + if (shared_mem == MAP_FAILED) { + perror("mmap"); + exit(EXIT_FAILURE); + } + + // Fork a child process + pid_t pid = fork(); + if (pid < 0) { + perror("fork"); + munmap(shared_mem, mem_size); + exit(EXIT_FAILURE); + } + + if (pid == 0) { + // Child process + printf("Child: Writing to shared memory.\n"); + const char *child_message = "Hello from the child process!"; + strncpy(shared_mem, child_message, mem_size); + + // Sleep to simulate some work + sleep(2); + + printf("Child: Reading from shared memory: '%s'\n", shared_mem); + + // Unmap shared memory in the child + if (munmap(shared_mem, mem_size) != 0) { + perror("munmap in child"); + exit(EXIT_FAILURE); + } + + printf("Child: Exiting.\n"); + } else { + // Parent process + printf("Parent: Waiting for child to write.\n"); + + // Sleep to simulate waiting for the child + sleep(1); + + printf("Parent: Reading from shared memory: '%s'\n", shared_mem); + + const char *parent_message = "Hello from the parent process!"; + strncpy(shared_mem, parent_message, mem_size); + + // Wait for the child to finish + wait(NULL); + + printf("Parent: Reading modified shared memory: '%s'\n", shared_mem); + + // Unmap shared memory in the parent + if (munmap(shared_mem, mem_size) != 0) { + perror("munmap in parent"); + exit(EXIT_FAILURE); + } + + printf("Parent: Exiting.\n"); + } + + return 0; +} From a180b42947cc324c8db9d880465a8030c6256437 Mon Sep 17 00:00:00 2001 From: Chinmay Shringi Date: Sun, 5 Jan 2025 16:09:25 -0500 Subject: [PATCH 40/66] revert: max bound check --- src/RawPOSIX/src/safeposix/dispatcher.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/RawPOSIX/src/safeposix/dispatcher.rs b/src/RawPOSIX/src/safeposix/dispatcher.rs index 482e1f079..f7e1fffd5 100644 --- a/src/RawPOSIX/src/safeposix/dispatcher.rs +++ b/src/RawPOSIX/src/safeposix/dispatcher.rs @@ -208,8 +208,7 @@ pub fn lind_syscall_api( // Get file descriptor let fd = arg1 as i32; - // Check bounds using MAX_IO_BUFFER_BYTES - let count = std::cmp::min(arg3 as usize, i32::MAX as usize); + let count = arg3 as usize; if count == 0 { return 0; // Early return for zero-length writes } From ac43ab30abef3d2c6449ae2974a67d442e8432ba Mon Sep 17 00:00:00 2001 From: Chinmay Shringi Date: Wed, 8 Jan 2025 22:00:28 +0000 Subject: [PATCH 41/66] fix: build errors return type --- src/RawPOSIX/src/safeposix/dispatcher.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/RawPOSIX/src/safeposix/dispatcher.rs b/src/RawPOSIX/src/safeposix/dispatcher.rs index 8c442cd7b..5401ddf72 100644 --- a/src/RawPOSIX/src/safeposix/dispatcher.rs +++ b/src/RawPOSIX/src/safeposix/dispatcher.rs @@ -309,7 +309,7 @@ pub fn lind_syscall_api( // Turn off PROT_EXEC for non-code pages let prot = prot & !PROT_EXEC; - interface::mmap_handler(cageid, addr, len, prot, flags, fd, off) + interface::mmap_handler(cageid, addr, len, prot, flags, fd, off) as i32 } PREAD_SYSCALL => { From 6b66c06f71a3e3e015291c68ac1e24c48bd96124 Mon Sep 17 00:00:00 2001 From: Chinmay Shringi Date: Wed, 8 Jan 2025 22:17:01 +0000 Subject: [PATCH 42/66] fix: resolved PR commets --- src/RawPOSIX/src/constants/fs_constants.rs | 4 ---- src/RawPOSIX/src/constants/net_constants.rs | 11 ----------- src/RawPOSIX/src/constants/sys_constants.rs | 2 -- src/RawPOSIX/src/interface/mem.rs | 1 - .../src/safeposix/syscalls/fs_calls.rs | 2 +- src/safeposix/shm.rs | 19 ------------------- 6 files changed, 1 insertion(+), 38 deletions(-) delete mode 100644 src/safeposix/shm.rs diff --git a/src/RawPOSIX/src/constants/fs_constants.rs b/src/RawPOSIX/src/constants/fs_constants.rs index e4d53d840..a5a6dac55 100644 --- a/src/RawPOSIX/src/constants/fs_constants.rs +++ b/src/RawPOSIX/src/constants/fs_constants.rs @@ -9,8 +9,6 @@ #![allow(dead_code)] #![allow(unused_variables)] -use crate::interface; - // ===== File Descriptor Constants ===== pub const DT_UNKNOWN: u8 = 0; @@ -46,9 +44,7 @@ pub const O_NOCTTY: i32 = 0o400; // Don't assign controlling terminal pub const O_TRUNC: i32 = 0o1000; // Truncate file to zero length pub const O_APPEND: i32 = 0o2000; // Append mode - writes always at end pub const O_NONBLOCK: i32 = 0o4000; // Non-blocking mode -// O_NDELAY=O_NONBLOCK pub const O_SYNC: i32 = 0o10000; // Synchronous writes -// O_FSYNC=O_SYNC pub const O_ASYNC: i32 = 0o20000; // Signal-driven I/O pub const O_CLOEXEC: i32 = 0o2000000; // Close on exec diff --git a/src/RawPOSIX/src/constants/net_constants.rs b/src/RawPOSIX/src/constants/net_constants.rs index 4290f9048..0a0f1d105 100644 --- a/src/RawPOSIX/src/constants/net_constants.rs +++ b/src/RawPOSIX/src/constants/net_constants.rs @@ -358,14 +358,3 @@ pub const EPOLL_CTL_MOD: i32 = 3; // Change event registration pub const FD_SET_MAX_FD: i32 = 1024; // Maximum file descriptor for fd_set -// ===== Connection States ===== -// Lind-specific enum for internal use -#[derive(Debug, PartialEq, Eq, Clone)] -pub enum ConnState { - NOTCONNECTED, - CONNECTED, - CONNRDONLY, - CONNWRONLY, - LISTEN, - INPROGRESS, -} diff --git a/src/RawPOSIX/src/constants/sys_constants.rs b/src/RawPOSIX/src/constants/sys_constants.rs index 34492abf4..d9c918999 100644 --- a/src/RawPOSIX/src/constants/sys_constants.rs +++ b/src/RawPOSIX/src/constants/sys_constants.rs @@ -9,8 +9,6 @@ #![allow(dead_code)] #![allow(unused_variables)] -use crate::interface; - // ===== User and Group ID Constants ===== // Lind-specific default values pub const DEFAULT_UID: u32 = 1000; // Default user ID diff --git a/src/RawPOSIX/src/interface/mem.rs b/src/RawPOSIX/src/interface/mem.rs index 3e5876c53..23a7c3a80 100644 --- a/src/RawPOSIX/src/interface/mem.rs +++ b/src/RawPOSIX/src/interface/mem.rs @@ -417,7 +417,6 @@ pub fn brk_handler(cageid: u64, brk: u32) -> i32 { /// - Preventing access outside of allocated memory regions pub fn check_and_convert_addr_ext(cage: &Cage, arg: u64, length: usize, prot: i32) -> Result { // Get read lock on virtual memory map - // TODO: need to add change here based on the protection, currently fixed for build error let mut vmmap = cage.vmmap.write(); // Calculate page numbers for start and end of region diff --git a/src/RawPOSIX/src/safeposix/syscalls/fs_calls.rs b/src/RawPOSIX/src/safeposix/syscalls/fs_calls.rs index f2689e0d9..bc26296ce 100644 --- a/src/RawPOSIX/src/safeposix/syscalls/fs_calls.rs +++ b/src/RawPOSIX/src/safeposix/syscalls/fs_calls.rs @@ -1196,7 +1196,7 @@ impl Cage { if 0 != (shmflg & SHM_RDONLY) { prot = PROT_READ; } else { - prot = libc::PROT_READ | libc::PROT_WRITE; + prot = PROT_READ | PROT_WRITE; } let mut rev_shm = self.rev_shm.lock(); rev_shm.push((shmaddr as u32, shmid)); diff --git a/src/safeposix/shm.rs b/src/safeposix/shm.rs deleted file mode 100644 index 565449424..000000000 --- a/src/safeposix/shm.rs +++ /dev/null @@ -1,19 +0,0 @@ -// In map_shm function -interface::libc_mmap( - shmaddr, - self.size as usize, - prot, - ((MAP_SHARED as i32) | (MAP_FIXED as i32)), // Cast each flag to i32 before combining - fobjfdno, - 0, -) - -// In unmap_shm function -interface::libc_mmap( - shmaddr, - self.size as usize, - PROT_NONE, - ((MAP_PRIVATE as i32) | (MAP_ANONYMOUS as i32) | (MAP_FIXED as i32)), // Cast each flag to i32 before combining - -1, - 0, -); \ No newline at end of file From 61d75eb65687524ec6a694304f157b134487883e Mon Sep 17 00:00:00 2001 From: Chinmay Shringi Date: Thu, 9 Jan 2025 03:34:54 +0000 Subject: [PATCH 43/66] fix: test case errors --- src/RawPOSIX/src/interface/mem.rs | 2 +- src/RawPOSIX/src/tests/fs_tests.rs | 15 ++++++++------- src/RawPOSIX/src/tests/sys_tests.rs | 2 +- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/RawPOSIX/src/interface/mem.rs b/src/RawPOSIX/src/interface/mem.rs index 23a7c3a80..12faee5db 100644 --- a/src/RawPOSIX/src/interface/mem.rs +++ b/src/RawPOSIX/src/interface/mem.rs @@ -249,7 +249,7 @@ pub fn mmap_handler(cageid: u64, addr: *mut u8, len: usize, mut prot: i32, mut f }; // update vmmap entry - vmmap.add_entry_with_overwrite(useraddr >> PAGESHIFT, + let _ = vmmap.add_entry_with_overwrite(useraddr >> PAGESHIFT, (rounded_length >> PAGESHIFT) as u32, prot, maxprot, diff --git a/src/RawPOSIX/src/tests/fs_tests.rs b/src/RawPOSIX/src/tests/fs_tests.rs index 89646be0e..69488c6f8 100644 --- a/src/RawPOSIX/src/tests/fs_tests.rs +++ b/src/RawPOSIX/src/tests/fs_tests.rs @@ -10,6 +10,7 @@ pub mod fs_tests { use libc::{c_void, O_DIRECTORY}; use std::fs::OpenOptions; use std::os::unix::fs::PermissionsExt; + use crate::constants::{S_IRWXA,SHMMAX,DEFAULT_UID,DEFAULT_GID}; use crate::interface::{StatData, FSData}; use libc::*; use crate::interface::{ShmidsStruct, get_errno}; @@ -421,7 +422,7 @@ pub mod fs_tests { //Checking if passing 0 as `len` to `mmap_syscall()` //correctly results in 'The value of len is 0` error. let mmap_result = cage.mmap_syscall(0 as *mut u8, 0, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); - assert_eq!(mmap_result, -1, "Expected mmap to fail with -1 due to zero length"); + assert_eq!(mmap_result as i32, -1, "Expected mmap to fail with -1 due to zero length"); // Fetch the errno and check that it is `EINVAL` (Invalid argument) let errno = get_errno(); assert_eq!(errno, libc::EINVAL, "Expected errno to be EINVAL for zero-length mmap"); @@ -448,7 +449,7 @@ pub mod fs_tests { assert_eq!(cage.write_syscall(fd, str2cbuf("Test text"), 9), 9); let mmap_result = cage.mmap_syscall(0 as *mut u8, 5, PROT_READ | PROT_WRITE, 0, fd, 0); - assert_eq!(mmap_result, -1, "mmap did not fail as expected"); + assert_eq!(mmap_result as i32, -1, "mmap did not fail as expected"); assert_eq!(cage.exit_syscall(libc::EXIT_SUCCESS), libc::EXIT_SUCCESS); lindrustfinalize(); } @@ -520,7 +521,7 @@ pub mod fs_tests { //allow reading correctly results in `File descriptor //is not open for reading` error. let mmap_result = cage.mmap_syscall(0 as *mut u8, 5, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); - assert_eq!(mmap_result, -1, "Expected mmap to fail"); + assert_eq!(mmap_result as i32, -1, "Expected mmap to fail"); // Fetch and print the errno for debugging let error = get_errno(); // Assert that the error is EACCES (Permission denied) @@ -569,7 +570,7 @@ pub mod fs_tests { 0, ); // Check if mmap_syscall returns -1 (failure) - assert_eq!(mmap_result, -1, "Expected mmap to fail due to lack of write permissions"); + assert_eq!(mmap_result as i32, -1, "Expected mmap to fail due to lack of write permissions"); // Fetch and check the errno for debugging let err = get_errno(); // Ensure the errno is EACCES (Permission denied) @@ -602,7 +603,7 @@ pub mod fs_tests { /* Native linux will return EINVAL - TESTED locally */ let result = cage.mmap_syscall(0 as *mut u8, 5, PROT_READ | PROT_WRITE, MAP_SHARED, fd, -10); - assert_eq!(result, -1, "Expected mmap to fail with -1 for negative offset"); + assert_eq!(result as i32, -1, "Expected mmap to fail with -1 for negative offset"); // Verify errno is set to EINVAL let errno = get_errno(); assert_eq!(errno, libc::EINVAL, "Expected errno to be EINVAL for negative offset"); @@ -613,7 +614,7 @@ pub mod fs_tests { /* Native linux will return EINVAL - TESTED locally */ let result_beyond_eof = cage.mmap_syscall(0 as *mut u8, 5, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 25); - assert_eq!(result_beyond_eof, -1, "Expected mmap to fail with -1 for offset beyond EOF"); + assert_eq!(result_beyond_eof as i32, -1, "Expected mmap to fail with -1 for offset beyond EOF"); // Verify errno is set to EINVAL let errno_beyond_eof = get_errno(); @@ -711,7 +712,7 @@ pub mod fs_tests { //Checking if passing the invalid file descriptor //correctly results in `Invalid file descriptor` error. assert_eq!( - cage.mmap_syscall(0 as *mut u8, 5, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0), + cage.mmap_syscall(0 as *mut u8, 5, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0) as i32, -(Errno::EBADF as i32) ); diff --git a/src/RawPOSIX/src/tests/sys_tests.rs b/src/RawPOSIX/src/tests/sys_tests.rs index 4414fe820..d45ecd8b3 100644 --- a/src/RawPOSIX/src/tests/sys_tests.rs +++ b/src/RawPOSIX/src/tests/sys_tests.rs @@ -6,7 +6,7 @@ pub mod sys_tests { use super::super::*; use crate::interface; - use crate::constants::DEFAULT_UID; + use crate::constants::{DEFAULT_UID, DEFAULT_GID, EXIT_SUCCESS}; use crate::safeposix::{cage::*, dispatcher::*, filesystem}; #[test] From 6ba266081098d31cae44d58cbc67f2a6a328e972 Mon Sep 17 00:00:00 2001 From: Chinmay Shringi Date: Thu, 9 Jan 2025 17:37:23 +0000 Subject: [PATCH 44/66] feat: rm UDSOCK_CAPACITY from const --- src/RawPOSIX/src/constants/net_constants.rs | 1 - src/RawPOSIX/src/tests/networking_tests.rs | 3 ++- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/RawPOSIX/src/constants/net_constants.rs b/src/RawPOSIX/src/constants/net_constants.rs index 0a0f1d105..55480d0ef 100644 --- a/src/RawPOSIX/src/constants/net_constants.rs +++ b/src/RawPOSIX/src/constants/net_constants.rs @@ -17,7 +17,6 @@ use crate::interface; // ===== Lind-specific Configuration ===== pub const DEFAULT_HOSTNAME: &str = "Lind"; pub const BLOCK_TIME: interface::RustDuration = interface::RustDuration::from_micros(100); -pub const UDSOCK_CAPACITY: usize = 212992; // Unix domain socket buffer size // ===== Socket Types ===== // Source: include/linux/net.h diff --git a/src/RawPOSIX/src/tests/networking_tests.rs b/src/RawPOSIX/src/tests/networking_tests.rs index cdcb9d5dd..41d697028 100644 --- a/src/RawPOSIX/src/tests/networking_tests.rs +++ b/src/RawPOSIX/src/tests/networking_tests.rs @@ -2406,7 +2406,8 @@ pub mod net_tests { // this test is used for testing select on AF_UNIX socket pipe writefds // currently would fail since select_syscall does not handle socket pipe // writefds correctly - let byte_chunk: usize = UDSOCK_CAPACITY; + // Unix domain socket buffer size + let byte_chunk: usize = 212992; //acquiring a lock on TESTMUTEX prevents other tests from running concurrently, // and also performs clean env setup From 05f9fc781efda7f267b6aa037b403d743245c627 Mon Sep 17 00:00:00 2001 From: Qianxi Chen Date: Fri, 10 Jan 2025 02:36:10 +0000 Subject: [PATCH 45/66] fixed initial memory size --- src/wasmtime/crates/wasmtime/src/runtime/instance.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/wasmtime/crates/wasmtime/src/runtime/instance.rs b/src/wasmtime/crates/wasmtime/src/runtime/instance.rs index 24b9be5c7..0100b2376 100644 --- a/src/wasmtime/crates/wasmtime/src/runtime/instance.rs +++ b/src/wasmtime/crates/wasmtime/src/runtime/instance.rs @@ -231,6 +231,11 @@ impl Instance { instantiate_type: InstantiateType, ) -> Result { let (instance, start) = Instance::new_raw(store.0, module, imports)?; + // retrieve the initial memory size + let plans = module.compiled_module().module().memory_plans.clone(); + let plan = plans.get(MemoryIndex::from_u32(0)).unwrap(); + // in wasmtime, one page is 65536 bytes, so we need to convert to pagesize in rawposix + let minimal_pages = plan.memory.minimum * 0x10; // initialize the memory // the memory initialization should happen inside microvisor, so we should discard the original @@ -244,7 +249,7 @@ impl Instance { let handle = store.0.instance(InstanceId::from_index(0)); let defined_memory = handle.get_memory(wasmtime_environ::MemoryIndex::from_u32(0)); let memory_base = defined_memory.base as usize; - rawposix::safeposix::dispatcher::init_vmmap_helper(pid, memory_base, Some(0x30)); + rawposix::safeposix::dispatcher::init_vmmap_helper(pid, memory_base, Some(minimal_pages as u32)); lind_syscall_api( pid, @@ -252,7 +257,7 @@ impl Instance { 0, memory_base as u64, 0, // the first memory region starts from 0 - 0x30 << PAGESHIFT, // we allocate 0x30 pages for the first memory region, which is the default value in wasmtime + minimal_pages << PAGESHIFT, // size of first memory region (PROT_READ | PROT_WRITE) as u64, (MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED) as u64, // we need to pass -1 here, but since lind_syscall_api only accepts u64 From 1b7a8115645e7d69c8125ba9a34b6a77e5f0879d Mon Sep 17 00:00:00 2001 From: ChinmayShringi Date: Tue, 14 Jan 2025 19:21:11 -0500 Subject: [PATCH 46/66] fix: fixed build errors --- src/RawPOSIX/src/constants/fs_constants.rs | 5 + .../src/safeposix/syscalls/fs_calls.rs | 8 +- .../src/safeposix/syscalls/fs_constants.rs | 203 ------------------ 3 files changed, 9 insertions(+), 207 deletions(-) delete mode 100644 src/RawPOSIX/src/safeposix/syscalls/fs_constants.rs diff --git a/src/RawPOSIX/src/constants/fs_constants.rs b/src/RawPOSIX/src/constants/fs_constants.rs index a5a6dac55..0d73c85f0 100644 --- a/src/RawPOSIX/src/constants/fs_constants.rs +++ b/src/RawPOSIX/src/constants/fs_constants.rs @@ -9,6 +9,11 @@ #![allow(dead_code)] #![allow(unused_variables)] +// ===== Standard File Descriptors ===== +pub const STDIN_FILENO: i32 = 0; // File descriptor for standard input +pub const STDOUT_FILENO: i32 = 1; // File descriptor for standard output +pub const STDERR_FILENO: i32 = 2; // File descriptor for standard error + // ===== File Descriptor Constants ===== pub const DT_UNKNOWN: u8 = 0; diff --git a/src/RawPOSIX/src/safeposix/syscalls/fs_calls.rs b/src/RawPOSIX/src/safeposix/syscalls/fs_calls.rs index 4e8f2898d..515f51c5b 100644 --- a/src/RawPOSIX/src/safeposix/syscalls/fs_calls.rs +++ b/src/RawPOSIX/src/safeposix/syscalls/fs_calls.rs @@ -11,7 +11,7 @@ use crate::constants::{ SEEK_SET, SEEK_CUR, SEEK_END, SHMMIN, SHMMAX, SHM_RDONLY, SHM_DEST, DEFAULT_UID, DEFAULT_GID, - SEM_VALUE_MAX, + SEM_VALUE_MAX, STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO }; use crate::interface; @@ -1927,9 +1927,9 @@ pub fn kernel_close(fdentry: fdtables::FDTableEntry, _count: u64) { // TODO: // Need to update once we merge with vmmap-alice - if kernel_fd == fs_constants::STDIN_FILENO - || kernel_fd == fs_constants::STDOUT_FILENO - || kernel_fd == fs_constants::STDERR_FILENO { + if kernel_fd == STDIN_FILENO + || kernel_fd == STDOUT_FILENO + || kernel_fd == STDERR_FILENO { return; } diff --git a/src/RawPOSIX/src/safeposix/syscalls/fs_constants.rs b/src/RawPOSIX/src/safeposix/syscalls/fs_constants.rs deleted file mode 100644 index 342ca101a..000000000 --- a/src/RawPOSIX/src/safeposix/syscalls/fs_constants.rs +++ /dev/null @@ -1,203 +0,0 @@ -// File system related constants -#![allow(dead_code)] -#![allow(unused_variables)] - -use crate::interface; - -/// TODO: -/// This is a temporary location for those three constants. Need to move after -/// merging with vmmap-alice -pub const STDIN_FILENO: i32 = 0; // File descriptor for standard input -pub const STDOUT_FILENO: i32 = 1; // File descriptor for standard output -pub const STDERR_FILENO: i32 = 2; // File descriptor for standard error - -// Define constants using static or const -// Imported into fs_calls file -// pub const DT_UNKNOWN: u8 = 0; - -// pub const STARTINGFD: i32 = 0; -// pub const MAXFD: i32 = 1024; -// pub const STARTINGPIPE: i32 = 0; -// pub const MAXPIPE: i32 = 1024; - -// pub const ROOTDIRECTORYINODE: usize = 1; -// pub const STREAMINODE: usize = 2; - -// pub const PIPE_CAPACITY: usize = 65536; - -// pub const F_OK: u32 = 0; -// pub const X_OK: u32 = 1; -// pub const W_OK: u32 = 2; -// pub const R_OK: u32 = 4; - -// pub const O_RDONLY: i32 = 0o0; -// pub const O_WRONLY: i32 = 0o1; -// pub const O_RDWR: i32 = 0o2; -// pub const O_RDWRFLAGS: i32 = 0o3; - -// pub const O_CREAT: i32 = 0o100; -// pub const O_EXCL: i32 = 0o200; -// pub const O_NOCTTY: i32 = 0o400; -// pub const O_TRUNC: i32 = 0o1000; -// pub const O_APPEND: i32 = 0o2000; -// pub const O_NONBLOCK: i32 = 0o4000; -// // O_NDELAY=O_NONBLOCK -// pub const O_SYNC: i32 = 0o10000; -// // O_FSYNC=O_SYNC -// pub const O_ASYNC: i32 = 0o20000; -// pub const O_CLOEXEC: i32 = 0o2000000; - -// pub const DEFAULTTIME: u64 = 1323630836; - -//Standard flag combinations -pub const S_IRWXA: u32 = 0o777; -pub const S_IRWXU: u32 = 0o700; -pub const S_IRUSR: u32 = 0o400; -pub const S_IWUSR: u32 = 0o200; -pub const S_IXUSR: u32 = 0o100; -pub const S_IRWXG: u32 = 0o070; -pub const S_IRGRP: u32 = 0o040; -pub const S_IWGRP: u32 = 0o020; -pub const S_IXGRP: u32 = 0o010; -pub const S_IRWXO: u32 = 0o007; -pub const S_IROTH: u32 = 0o004; -pub const S_IWOTH: u32 = 0o002; -pub const S_IXOTH: u32 = 0o001; - -// //Commands for FCNTL -// pub const F_DUPFD: i32 = 0; -// pub const F_GETFD: i32 = 1; -// pub const F_SETFD: i32 = 2; -// pub const F_GETFL: i32 = 3; -// pub const F_SETFL: i32 = 4; -// pub const F_GETLK: i32 = 5; -// pub const F_GETLK64: i32 = 5; -// pub const F_SETLK: i32 = 6; -// pub const F_SETLK64: i32 = 6; -// pub const F_SETLKW: i32 = 7; -// pub const F_SETLKW64: i32 = 7; -// pub const F_SETOWN: i32 = 8; -// pub const F_GETOWN: i32 = 9; -// pub const F_SETSIG: i32 = 10; -// pub const F_GETSIG: i32 = 11; -// pub const F_SETLEASE: i32 = 1024; -// pub const F_GETLEASE: i32 = 1025; -// pub const F_NOTIFY: i32 = 1026; - -// //Commands for IOCTL -// pub const FIONBIO: u32 = 21537; -// pub const FIOASYNC: u32 = 21586; - -// //File types for open/stat etc. -// pub const S_IFBLK: i32 = 0o60000; -// pub const S_IFCHR: i32 = 0o20000; -// pub const S_IFDIR: i32 = 0o40000; -// pub const S_IFIFO: i32 = 0o10000; -// pub const S_IFLNK: i32 = 0o120000; -// pub const S_IFREG: i32 = 0o100000; -// pub const S_IFSOCK: i32 = 0o140000; -// pub const S_FILETYPEFLAGS: i32 = 0o170000; - -// //for flock syscall -// pub const LOCK_SH: i32 = 1; -// pub const LOCK_EX: i32 = 2; -// pub const LOCK_UN: i32 = 8; -// pub const LOCK_NB: i32 = 4; -// //for mmap/munmap syscall -// pub const MAP_SHARED: i32 = 1; -// pub const MAP_PRIVATE: i32 = 2; -// pub const MAP_FIXED: i32 = 16; -// pub const MAP_ANONYMOUS: i32 = 32; -// pub const MAP_HUGE_SHIFT: i32 = 26; -// pub const MAP_HUGETLB: i32 = 262144; - -// pub const PROT_NONE: i32 = 0; -// pub const PROT_READ: i32 = 1; -// pub const PROT_WRITE: i32 = 2; -// pub const PROT_EXEC: i32 = 4; - -// pub const SEEK_SET: i32 = 0; -// pub const SEEK_CUR: i32 = 1; -// pub const SEEK_END: i32 = 2; - -// pub const IPC_PRIVATE: i32 = 0o0; -// pub const IPC_CREAT: i32 = 0o1000; -// pub const IPC_EXCL: i32 = 0o2000; - -// pub const IPC_RMID: i32 = 0; -// pub const IPC_SET: i32 = 1; -// pub const IPC_STAT: i32 = 2; - -pub const SHM_DEST: i32 = 0o1000; -pub const SHM_LOCKED: i32 = 0o2000; -pub const SHM_HUGETLB: i32 = 0o4000; - -pub const SHM_R: i32 = 0o400; -pub const SHM_W: i32 = 0o200; -pub const SHM_RDONLY: i32 = 0o10000; -pub const SHM_RND: i32 = 0o20000; -pub const SHM_REMAP: i32 = 0o40000; -pub const SHM_EXEC: i32 = 0o100000; - -pub const SHMMIN: u32 = 1; -pub const SHMMNI: u32 = 4096; -pub const SHMMAX: u32 = 4278190079; // (ULONG_MAX - (1UL << 24)) -pub const SHMALL: u32 = 4278190079; // (ULONG_MAX - (1UL << 24)); -pub const SHMSEG: u32 = SHMMNI; - -pub const SEM_VALUE_MAX: u32 = 2147483647; - -// //device info for char files -// #[derive(interface::SerdeSerialize, interface::SerdeDeserialize, PartialEq, Eq, Debug)] -// pub struct DevNo { -// pub major: u32, -// pub minor: u32, -// } -// pub const NULLDEVNO: DevNo = DevNo { major: 1, minor: 3 }; -// pub const ZERODEVNO: DevNo = DevNo { major: 1, minor: 5 }; -// pub const RANDOMDEVNO: DevNo = DevNo { major: 1, minor: 8 }; -// pub const URANDOMDEVNO: DevNo = DevNo { major: 1, minor: 9 }; - -// pub const FILEDATAPREFIX: &str = "linddata."; - -// pub fn is_reg(mode: u32) -> bool { -// (mode as i32 & S_FILETYPEFLAGS) == S_IFREG -// } - -// pub fn is_chr(mode: u32) -> bool { -// (mode as i32 & S_FILETYPEFLAGS) == S_IFCHR -// } - -// pub fn is_dir(mode: u32) -> bool { -// (mode as i32 & S_FILETYPEFLAGS) == S_IFDIR -// } - -// pub fn is_wronly(flags: i32) -> bool { -// (flags & O_RDWRFLAGS) == O_WRONLY -// } -// pub fn is_rdonly(flags: i32) -> bool { -// (flags & O_RDWRFLAGS) == O_RDONLY -// } - -// //the same as the glibc makedev -// pub fn makedev(dev: &DevNo) -> u64 { -// ((dev.major as u64 & 0x00000fff) << 8) -// | ((dev.major as u64 & 0xfffff000) << 32) -// | ((dev.minor as u64 & 0x000000ff) << 0) -// | ((dev.minor as u64 & 0xffffff00) << 12) -// } - -// //the same as the glibc major and minor functions -// pub fn major(devnum: u64) -> u32 { -// (((devnum & 0x00000000000fff00) >> 8) | ((devnum & 0xfffff00000000000) >> 32)) as u32 -// } -// pub fn minor(devnum: u64) -> u32 { -// (((devnum & 0x00000000000000ff) >> 0) | ((devnum & 0x00000ffffff00000) >> 12)) as u32 -// } - -// pub fn devtuple(devnum: u64) -> DevNo { -// DevNo { -// major: major(devnum), -// minor: minor(devnum), -// } -// } From 64eb5fb85291bb6ad0ad70d2ad312c695f7bcc6f Mon Sep 17 00:00:00 2001 From: ChinmayShringi Date: Thu, 23 Jan 2025 22:49:04 +0000 Subject: [PATCH 47/66] revert: removed check-and-convert-addr-ext function --- src/RawPOSIX/src/safeposix/dispatcher.rs | 996 ++++++----------------- 1 file changed, 247 insertions(+), 749 deletions(-) diff --git a/src/RawPOSIX/src/safeposix/dispatcher.rs b/src/RawPOSIX/src/safeposix/dispatcher.rs index bb3a86add..2e3e5f163 100644 --- a/src/RawPOSIX/src/safeposix/dispatcher.rs +++ b/src/RawPOSIX/src/safeposix/dispatcher.rs @@ -138,7 +138,6 @@ use crate::interface::{SigactionStruct, StatData}; use crate::{fdtables, interface}; use crate::interface::errnos::*; use crate::constants::*; -use crate::interface::check_and_convert_addr_ext; macro_rules! get_onearg { ($arg: expr) => { @@ -203,146 +202,59 @@ pub fn lind_syscall_api( let ret = match call_number { WRITE_SYSCALL => { - // Handles writing data from user buffer to file descriptor - - // Get file descriptor let fd = arg1 as i32; - + let buf = (start_address + arg2) as *const u8; let count = arg3 as usize; - if count == 0 { - return 0; // Early return for zero-length writes - } - - // Get cage reference for memory operations - let cage = interface::cagetable_getref(cageid); - - // Validate and convert user buffer address to system address - // PROT_READ is correct because write() reads FROM the buffer - let buf = match check_and_convert_addr_ext(&cage, arg2, count, PROT_READ) { - Ok(addr) => addr as *const u8, - Err(errno) => { - return syscall_error( - errno, - "write", - "buffer access violation or invalid address" - ); - } - }; - - // Perform write operation through cage abstraction - cage.write_syscall(fd, buf, count) + interface::cagetable_getref(cageid) + .write_syscall(fd, buf, count) } WRITEV_SYSCALL => { let fd = arg1 as i32; + let iovec = (start_address + arg2) as *const interface::IovecStruct; let iovcnt = arg3 as i32; - - // Validate count first - if iovcnt <= 0 { - return syscall_error( - Errno::EINVAL, - "writev", - "invalid iovec count" - ); - } - - let cage = interface::cagetable_getref(cageid); - - // Validate the iovec array address first - let iov_base = match check_and_convert_addr_ext( - &cage, - arg2, - (iovcnt as usize) * std::mem::size_of::(), - PROT_READ - ) { - Ok(addr) => addr as *const interface::IovecStruct, - Err(errno) => { - return syscall_error( - errno, - "writev", - "invalid iovec array address" - ); - } - }; - - // The actual write operation is delegated to the cage implementation - cage.writev_syscall(fd, iov_base, iovcnt) + + interface::cagetable_getref(cageid) + .writev_syscall(fd, iovec, iovcnt) } MUNMAP_SYSCALL => { - let addr = arg1 as *mut u8; - let length = arg2 as usize; - let cage = interface::cagetable_getref(cageid); - - if length == 0 { - return syscall_error( - Errno::EINVAL, - "munmap", - "length cannot be zero" - ); - } - - // Perform the unmapping operation - interface::munmap_handler(cageid, addr, length) + let addr = (start_address + arg1) as *mut u8; + let len = arg2 as usize; + + interface::cagetable_getref(cageid) + .munmap_syscall(addr, len) } MMAP_SYSCALL => { - let addr = arg1 as *mut u8; + let addr = (start_address + arg1) as *mut u8; let len = arg2 as usize; let prot = arg3 as i32; let flags = arg4 as i32; - let fd = arg5 as i32; + let fildes = arg5 as i32; let off = arg6 as i64; - - // Basic length validation - if len == 0 { - return syscall_error( - Errno::EINVAL, - "mmap", - "length cannot be zero" - ); - } - - // Force MAP_FIXED - let flags = flags | MAP_FIXED as i32; - - // Turn off PROT_EXEC for non-code pages - let prot = prot & !PROT_EXEC; - - interface::mmap_handler(cageid, addr, len, prot, flags, fd, off) as i32 + + interface::cagetable_getref(cageid) + .mmap_syscall(addr, len, prot, flags, fildes, off) } PREAD_SYSCALL => { let fd = arg1 as i32; + let buf = (start_address + arg2) as *mut u8; let count = arg3 as usize; let offset = arg4 as i64; - let cage = interface::cagetable_getref(cageid); - - // Validate and convert user buffer address - // Using PROT_WRITE since pread writes TO the buffer - let buf = match check_and_convert_addr_ext(&cage, arg2, count, PROT_WRITE) { - Ok(addr) => addr as *mut u8, - Err(errno) => return syscall_error(errno, "pread", "invalid buffer address"), - }; - - cage.pread_syscall(fd, buf, count, offset) + + interface::cagetable_getref(cageid) + .pread_syscall(fd, buf, count, offset) } READ_SYSCALL => { let fd = arg1 as i32; + let buf = (start_address + arg2) as *mut u8; let count = arg3 as usize; - let cage = interface::cagetable_getref(cageid); - - // Validate and convert user buffer address - // Using PROT_WRITE since read() writes TO the buffer - let buf = match check_and_convert_addr_ext(&cage, arg2, count, PROT_WRITE) { - Ok(addr) => addr as *mut u8, - Err(errno) => return syscall_error(errno, "read", "invalid buffer address"), - }; - // File descriptor validation and actual read operation - // handled by cage implementation - cage.read_syscall(fd, buf, count) + interface::cagetable_getref(cageid) + .read_syscall(fd, buf, count) } CLOSE_SYSCALL => { @@ -354,38 +266,26 @@ pub fn lind_syscall_api( } ACCESS_SYSCALL => { - let cage = interface::cagetable_getref(cageid); - - // Validate and convert path string from user space - let path = match check_and_convert_addr_ext(&cage, arg1, 1, PROT_READ) { - Ok(addr) => match interface::types::get_cstr(addr as u64) { - Ok(path_str) => path_str, - Err(_) => return -1, - }, - Err(errno) => return syscall_error(errno, "access", "invalid path address"), + let path = match interface::types::get_cstr(start_address + arg1) { + Ok(path_str) => path_str, + Err(_) => return -1, // Handle error appropriately, return an error code }; let amode = arg2 as i32; - // Perform access check through cage implementation - cage.access_syscall(path, amode) + interface::cagetable_getref(cageid) + .access_syscall(path, amode) } OPEN_SYSCALL => { - let cage = interface::cagetable_getref(cageid); - - // Validate and convert path string from user space - let path = match check_and_convert_addr_ext(&cage, arg1, 1, PROT_READ) { - Ok(addr) => match interface::types::get_cstr(addr as u64) { - Ok(path_str) => path_str, - Err(_) => return -1, - }, - Err(errno) => return syscall_error(errno, "open", "invalid path address"), + let path = match interface::types::get_cstr(start_address + arg1) { + Ok(path_str) => path_str, + Err(_) => return -1, // Handle error appropriately, return an error code }; let flags = arg2 as i32; let mode = arg3 as u32; - - // Perform open operation through cage implementation - cage.open_syscall(path, flags, mode) + + interface::cagetable_getref(cageid) + .open_syscall(path, flags, mode) } SOCKET_SYSCALL => { @@ -401,81 +301,45 @@ pub fn lind_syscall_api( CONNECT_SYSCALL => { let fd = arg1 as i32; - let cage = interface::cagetable_getref(cageid); - - // Validate and convert sockaddr from user space - let addr = match check_and_convert_addr_ext(&cage, arg2, arg3 as usize, PROT_READ) { - Ok(addr) => match interface::get_sockaddr(addr as u64, arg3 as u32) { - Ok(sockaddr) => sockaddr, - Err(_) => return syscall_error(Errno::EINVAL, "connect", "invalid sockaddr format"), - }, - Err(errno) => return syscall_error(errno, "connect", "invalid address"), - }; + let addrlen = arg3 as u32; + let addr = get_onearg!(interface::get_sockaddr(arg2, addrlen)); - // Convert to reference for connect operation let remoteaddr = match Ok::<&interface::GenSockaddr, i32>(&addr) { Ok(addr) => addr, Err(_) => panic!("Failed to get sockaddr"), // Handle error appropriately }; - - // Perform connect operation through cage implementation - // File descriptor validation handled by cage layer - cage.connect_syscall(fd, remoteaddr) + interface::cagetable_getref(cageid) + .connect_syscall(fd, remoteaddr) } BIND_SYSCALL => { let fd = arg1 as i32; - let cage = interface::cagetable_getref(cageid); - - // Validate and convert sockaddr from user space - let addr = match check_and_convert_addr_ext(&cage, arg2, arg3 as usize, PROT_READ) { - Ok(addr) => match interface::get_sockaddr(addr as u64, arg3 as u32) { - Ok(sockaddr) => sockaddr, - Err(_) => return syscall_error(Errno::EINVAL, "bind", "invalid sockaddr format"), - }, - Err(errno) => return syscall_error(errno, "bind", "invalid address"), - }; - - // Convert to reference for bind operation + let addrlen = arg3 as u32; + let addr = interface::get_sockaddr(start_address + arg2, addrlen).unwrap(); let localaddr = match Ok::<&interface::GenSockaddr, i32>(&addr) { Ok(addr) => addr, Err(_) => panic!("Failed to get sockaddr"), // Handle error appropriately }; - - // Perform bind operation through cage implementation - // File descriptor validation handled by cage layer - cage.bind_syscall(fd, localaddr) + interface::cagetable_getref(cageid) + .bind_syscall(fd, localaddr) } ACCEPT_SYSCALL => { - let mut addr = interface::GenSockaddr::V4(interface::SockaddrV4::default()); + let mut addr = interface::GenSockaddr::V4(interface::SockaddrV4::default()); //value doesn't matter let nullity1 = interface::arg_nullity(arg2); let nullity2 = interface::arg_nullity(arg3); - let cage = interface::cagetable_getref(cageid); - - // Handle NULL address case (both NULL) + if nullity1 && nullity2 { - cage.accept_syscall(arg1 as i32, &mut Some(&mut addr)) - } - // Handle non-NULL case (both non-NULL) - else if !(nullity1 || nullity2) { - // Perform accept operation first - let rv = cage.accept_syscall(arg1 as i32, &mut Some(&mut addr)); + interface::cagetable_getref(cageid) + .accept_syscall(arg1 as i32, &mut Some(&mut addr)) + } else if !(nullity1 || nullity2) { + let rv = interface::cagetable_getref(cageid) + .accept_syscall(arg1 as i32, &mut Some(&mut addr)); if rv >= 0 { - let addr2_addr = match check_and_convert_addr_ext(&cage, arg2, arg3 as usize, PROT_WRITE) { - Ok(addr) => addr, - Err(errno) => return syscall_error(errno, "accept", "invalid address buffer"), - }; - let len_addr = match check_and_convert_addr_ext(&cage, arg3, std::mem::size_of::(), PROT_WRITE) { - Ok(addr) => addr, - Err(errno) => return syscall_error(errno, "accept", "invalid length buffer"), - }; - interface::copy_out_sockaddr(addr2_addr as u64, len_addr as u64, addr); + interface::copy_out_sockaddr((start_address + arg2), (start_address + arg3), addr); } rv - } - // Handle invalid case (one NULL, one non-NULL) - else { + } else { syscall_error( Errno::EINVAL, "accept", @@ -505,152 +369,68 @@ pub fn lind_syscall_api( SELECT_SYSCALL => { // Get the number of file descriptors to check (highest fd + 1) let nfds = arg1 as i32; - // Get reference to the cage for memory operations - let cage = interface::cagetable_getref(cageid); - - // Validate and convert readfds buffer - // 1. check_and_convert_addr_ext validates memory access and converts user address to system address - // 2. PROT_READ | PROT_WRITE because select() both reads from and modifies the fd_sets - // 3. get_fdset converts the raw memory into an fd_set structure - let readfds = match check_and_convert_addr_ext(&cage, arg2, std::mem::size_of::(), PROT_READ | PROT_WRITE) { - Ok(addr) => match interface::get_fdset(addr) { - Ok(fds) => fds, - Err(_) => return syscall_error(Errno::EFAULT, "select", "failed to get readfds"), - }, - Err(errno) => return syscall_error(errno, "select", "invalid readfds address"), - }; - - // Validate and convert writefds buffer - // Similar to readfds, this fd_set indicates which descriptors to check for write-ready status - // The fd_set will be modified to show which descriptors are actually write-ready - let writefds = match check_and_convert_addr_ext(&cage, arg3, std::mem::size_of::(), PROT_READ | PROT_WRITE) { - Ok(addr) => match interface::get_fdset(addr) { - Ok(fds) => fds, - Err(_) => return syscall_error(Errno::EFAULT, "select", "failed to get writefds"), - }, - Err(errno) => return syscall_error(errno, "select", "invalid writefds address"), - }; - - // Validate and convert errorfds buffer (also called exceptfds in some implementations) - // This fd_set is used to monitor for exceptional conditions (like out-of-band data) - // Also requires both read and write access as select() modifies it - let errorfds = match check_and_convert_addr_ext(&cage, arg4, std::mem::size_of::(), PROT_READ | PROT_WRITE) { - Ok(addr) => match interface::get_fdset(addr) { - Ok(fds) => fds, - Err(_) => return syscall_error(Errno::EFAULT, "select", "failed to get errorfds"), - }, - Err(errno) => return syscall_error(errno, "select", "invalid errorfds address"), - }; - - // Validate and convert timeout buffer - // 1. Only needs PROT_READ as the timeout value is not modified by select() - // 2. duration_fromtimeval converts the timeval structure to a Duration - // 3. This specifies how long select() should block waiting for activity - let rposix_timeout = match check_and_convert_addr_ext(&cage, arg5, std::mem::size_of::(), PROT_READ) { - Ok(addr) => match interface::duration_fromtimeval(addr) { - Ok(timeout) => timeout, - Err(_) => return syscall_error(Errno::EFAULT, "select", "failed to get timeout"), - }, - Err(errno) => return syscall_error(errno, "select", "invalid timeout address"), - }; - - // Delegate to the cage's select implementation - // This will: - // 1. Monitor the specified file descriptors for activity - // 2. Modify the fd_sets to indicate which descriptors are ready - // 3. Return the number of ready descriptors or an error code - cage.select_syscall(nfds, readfds, writefds, errorfds, rposix_timeout) + let readfds = interface::get_fdset(arg2).unwrap(); + let writefds = interface::get_fdset(arg3).unwrap(); + let errorfds = interface::get_fdset(arg4).unwrap(); + let rposix_timeout = interface::duration_fromtimeval(arg5).unwrap(); + interface::cagetable_getref(cageid) + .select_syscall(nfds, readfds, writefds, errorfds, rposix_timeout) } RENAME_SYSCALL => { - let cage = interface::cagetable_getref(cageid); - - // Validate and convert old path from user space - let old_path = match check_and_convert_addr_ext(&cage, arg1, 1, PROT_READ) { - Ok(addr) => match interface::types::get_cstr(addr) { - Ok(path_str) => path_str, - Err(_) => return syscall_error(Errno::EFAULT, "rename", "invalid old path string"), - }, - Err(errno) => return syscall_error(errno, "rename", "invalid old path address"), + let old_ptr = (start_address + arg1) as *const u8; + let new_ptr = (start_address + arg2) as *const u8; + + // Convert the raw pointers to `&str` + let old = unsafe { + CStr::from_ptr(old_ptr as *const i8).to_str().unwrap() }; - - // Validate and convert new path from user space - let new_path = match check_and_convert_addr_ext(&cage, arg2, 1, PROT_READ) { - Ok(addr) => match interface::types::get_cstr(addr) { - Ok(path_str) => path_str, - Err(_) => return syscall_error(Errno::EFAULT, "rename", "invalid new path string"), - }, - Err(errno) => return syscall_error(errno, "rename", "invalid new path address"), + let new = unsafe { + CStr::from_ptr(new_ptr as *const i8).to_str().unwrap() }; - // Perform rename operation through cage implementation - cage.rename_syscall(old_path, new_path) + interface::cagetable_getref(cageid) + .rename_syscall(old, new) } XSTAT_SYSCALL => { - let cage = interface::cagetable_getref(cageid); - - // Validate and convert path string from user space - // Using PROT_READ because we need to read the path string FROM user space - // (stat takes the path as input, we don't write to it) - let path = match check_and_convert_addr_ext(&cage, arg1, 1, PROT_READ) { - Ok(addr) => match interface::types::get_cstr(addr) { - Ok(path_str) => path_str, - Err(_) => return syscall_error(Errno::EFAULT, "xstat", "invalid path string"), - }, - Err(errno) => return syscall_error(errno, "xstat", "invalid path address"), + let fd_ptr = (start_address + arg1) as *const u8; + let buf = match interface::get_statdatastruct(start_address + arg2) { + Ok(val) => val, + Err(errno) => { + return errno; + } }; - - // Validate stat buffer and prepare for writing - // Using PROT_WRITE because stat() writes the results TO this user space buffer - let buf = match check_and_convert_addr_ext(&cage, arg2, std::mem::size_of::(), PROT_WRITE) { - Ok(addr) => match interface::get_statdatastruct(addr) { - Ok(val) => val, - Err(errno) => return errno, - }, - Err(errno) => return syscall_error(errno, "xstat", "invalid stat buffer address"), + + let fd = unsafe { + CStr::from_ptr(fd_ptr as *const i8).to_str().unwrap() }; - - // Perform stat operation through cage implementation - // Results written directly to user buffer by cage layer - cage.stat_syscall(path, buf) + + interface::cagetable_getref(cageid) + .stat_syscall(fd, buf) } MKDIR_SYSCALL => { - let cage = interface::cagetable_getref(cageid); - - // Validate and convert path string from user space - // Using PROT_READ because we need to read the path string FROM user space - // (mkdir takes the path as input, we don't write to it) - let path = match check_and_convert_addr_ext(&cage, arg1, 1, PROT_READ) { - Ok(addr) => match interface::types::get_cstr(addr) { - Ok(path_str) => path_str, - Err(_) => return syscall_error(Errno::EFAULT, "mkdir", "invalid path string"), - }, - Err(errno) => return syscall_error(errno, "mkdir", "invalid path address"), - }; + let fd_ptr = (start_address + arg1) as *const u8; let mode = arg2 as u32; - - // Perform mkdir operation through cage implementation - cage.mkdir_syscall(path, mode) + + let fd= unsafe { + CStr::from_ptr(fd_ptr as *const i8).to_str().unwrap() + }; + + interface::cagetable_getref(cageid) + .mkdir_syscall(fd, mode) } RMDIR_SYSCALL => { - let cage = interface::cagetable_getref(cageid); - - // Validate and convert path string from user space - // Using PROT_READ because we need to read the path string FROM user space - // (rmdir takes the path as input, we don't write to it) - let path = match check_and_convert_addr_ext(&cage, arg1, 1, PROT_READ) { - Ok(addr) => match interface::types::get_cstr(addr) { - Ok(path_str) => path_str, - Err(_) => return syscall_error(Errno::EFAULT, "rmdir", "invalid path string"), - }, - Err(errno) => return syscall_error(errno, "rmdir", "invalid path address"), - }; + let fd_ptr = (start_address + arg1) as *const u8; + + let fd= unsafe { + CStr::from_ptr(fd_ptr as *const i8).to_str().unwrap() + }; - // Perform rmdir operation through cage implementation - cage.rmdir_syscall(path) + interface::cagetable_getref(cageid) + .rmdir_syscall(fd) } FCHDIR_SYSCALL => { @@ -663,78 +443,39 @@ pub fn lind_syscall_api( } CHDIR_SYSCALL => { - let cage = interface::cagetable_getref(cageid); - - // Validate and convert path string from user space - // Using PROT_READ because we need to read the path string FROM user space - // (chdir takes the path as input, we don't write to it) - let path = match check_and_convert_addr_ext(&cage, arg1, 1, PROT_READ) { - Ok(addr) => match interface::types::get_cstr(addr) { - Ok(path_str) => path_str, - Err(_) => return syscall_error(Errno::EFAULT, "chdir", "invalid path string"), - }, - Err(errno) => return syscall_error(errno, "chdir", "invalid path address"), - }; + let path = interface::types::get_cstr(start_address + arg1).unwrap(); - // Perform chdir operation through cage implementation - cage.chdir_syscall(path) + interface::cagetable_getref(cageid) + .chdir_syscall(path) } GETCWD_SYSCALL => { - let bufsize = arg2 as usize; - let cage = interface::cagetable_getref(cageid); - - // Validate buffer for writing - // Using PROT_WRITE because getcwd() writes the current working directory path - // TO this user space buffer - let buf = match check_and_convert_addr_ext(&cage, arg1, bufsize, PROT_WRITE) { - Ok(addr) => addr as *mut u8, - Err(errno) => return syscall_error(errno, "getcwd", "invalid buffer address"), - }; - - // Perform getcwd operation through cage implementation - // On success (ret == 0), return the buffer address - let ret = cage.getcwd_syscall(buf, bufsize as u32); + let buf = (start_address + arg1) as *mut u8; + let bufsize = arg2 as u32; + + let ret = interface::cagetable_getref(cageid) + .getcwd_syscall(buf, bufsize); if ret == 0 { return arg1 as i32; } ret } + FSTATFS_SYSCALL => { let fd = arg1 as i32; - let cage = interface::cagetable_getref(cageid); - - // Validate buffer for writing filesystem information - // Using PROT_WRITE because fstatfs() writes filesystem information - // TO this user space buffer - let buf = match check_and_convert_addr_ext(&cage, arg2, 1, PROT_WRITE) { - Ok(addr) => match interface::get_fsdatastruct(addr) { - Ok(val) => val, - Err(errno) => return errno, - }, - Err(errno) => return syscall_error(errno, "fstatfs", "invalid buffer address"), - }; + let buf = interface::get_fsdatastruct(start_address + arg2).unwrap(); - // Perform fstatfs operation through cage implementation - // File descriptor validation and actual operation handled by cage layer - cage.fstatfs_syscall(fd, buf) + interface::cagetable_getref(cageid) + .fstatfs_syscall(fd, buf) } CHMOD_SYSCALL => { - let cage = interface::cagetable_getref(cageid); - - // Validate and convert path string from user space - // Using PROT_READ because we need to read the path string FROM user space - // (chmod takes the path as input, we don't write to it) - let path = match check_and_convert_addr_ext(&cage, arg1, 1, PROT_READ) { - Ok(addr) => match interface::types::get_cstr(addr) { - Ok(path_str) => path_str, - Err(_) => return syscall_error(Errno::EFAULT, "chmod", "invalid path string"), - }, - Err(errno) => return syscall_error(errno, "chmod", "invalid path address"), + let fd_ptr = (start_address + arg1) as *const u8; + let fd= unsafe { + CStr::from_ptr(fd_ptr as *const i8).to_str().unwrap() }; let mode = arg2 as u32; - - // Perform chmod operation through cage implementation - cage.chmod_syscall(path, mode) + + interface::cagetable_getref(cageid) + .chmod_syscall(fd, mode) } DUP_SYSCALL => { @@ -775,63 +516,36 @@ pub fn lind_syscall_api( FXSTAT_SYSCALL => { let fd = arg1 as i32; - let cage = interface::cagetable_getref(cageid); - - // Validate stat buffer and prepare for writing - // Using PROT_WRITE because fstat() writes the results TO this user space buffer - let buf = match check_and_convert_addr_ext(&cage, arg2, std::mem::size_of::(), PROT_WRITE) { - Ok(addr) => interface::get_statdatastruct(addr).unwrap(), - Err(errno) => return syscall_error(errno, "fxstat", "invalid buffer address"), - }; + let buf = interface::get_statdatastruct(start_address + arg2).unwrap(); - // Perform fstat operation through cage implementation - // File descriptor validation and actual operation handled by cage layer - cage.fstat_syscall(fd, buf) + interface::cagetable_getref(cageid) + .fstat_syscall(fd, buf) } UNLINK_SYSCALL => { - let cage = interface::cagetable_getref(cageid); - - // Validate and convert path string from user space - // Using PROT_READ because we need to read the path string FROM user space - // (unlink takes the path as input, we don't write to it) - let path = match check_and_convert_addr_ext(&cage, arg1, 1, PROT_READ) { - Ok(addr) => match interface::types::get_cstr(addr) { - Ok(path_str) => path_str, - Err(_) => return syscall_error(Errno::EFAULT, "unlink", "invalid path string"), - }, - Err(errno) => return syscall_error(errno, "unlink", "invalid path address"), - }; + let fd_ptr = (start_address + arg1) as *const u8; - // Perform unlink operation through cage implementation - cage.unlink_syscall(path) + let fd = unsafe { + CStr::from_ptr(fd_ptr as *const i8).to_str().unwrap() + }; + + interface::cagetable_getref(cageid) + .unlink_syscall(fd) } LINK_SYSCALL => { - let cage = interface::cagetable_getref(cageid); - - // Validate and convert old path string from user space - // Using PROT_READ because we need to read the path string FROM user space - let old_path = match check_and_convert_addr_ext(&cage, arg1, 1, PROT_READ) { - Ok(addr) => match interface::types::get_cstr(addr) { - Ok(path_str) => path_str, - Err(_) => return syscall_error(Errno::EFAULT, "link", "invalid old path string"), - }, - Err(errno) => return syscall_error(errno, "link", "invalid old path address"), - }; + let old_ptr = (start_address + arg1) as *const u8; + let new_ptr = (start_address + arg1) as *const u8; - // Validate and convert new path string from user space - // Using PROT_READ because we need to read the path string FROM user space - let new_path = match check_and_convert_addr_ext(&cage, arg2, 1, PROT_READ) { - Ok(addr) => match interface::types::get_cstr(addr) { - Ok(path_str) => path_str, - Err(_) => return syscall_error(Errno::EFAULT, "link", "invalid new path string"), - }, - Err(errno) => return syscall_error(errno, "link", "invalid new path address"), - }; - - // Perform link operation through cage implementation - cage.link_syscall(old_path, new_path) + let old_fd= unsafe { + CStr::from_ptr(old_ptr as *const i8).to_str().unwrap() + }; + let new_fd = unsafe { + CStr::from_ptr(new_ptr as *const i8).to_str().unwrap() + }; + + interface::cagetable_getref(cageid) + .link_syscall(old_fd, new_fd) } LSEEK_SYSCALL => { @@ -857,21 +571,15 @@ pub fn lind_syscall_api( } TRUNCATE_SYSCALL => { - let cage = interface::cagetable_getref(cageid); - - // Validate and convert path string from user space - // Using PROT_READ because we need to read the path string FROM user space - let path = match check_and_convert_addr_ext(&cage, arg1, 1, PROT_READ) { - Ok(addr) => match interface::types::get_cstr(addr) { - Ok(path_str) => path_str, - Err(_) => return syscall_error(Errno::EFAULT, "truncate", "invalid path string"), - }, - Err(errno) => return syscall_error(errno, "truncate", "invalid path address"), - }; + let fd_ptr = (start_address + arg1) as *const u8; let length = arg2 as isize; - - // Perform truncate operation through cage implementation - cage.truncate_syscall(path, length) + + let fd = unsafe { + CStr::from_ptr(fd_ptr as *const i8).to_str().unwrap() + }; + + interface::cagetable_getref(cageid) + .truncate_syscall(fd, length) } FTRUNCATE_SYSCALL => { @@ -886,46 +594,23 @@ pub fn lind_syscall_api( GETDENTS_SYSCALL => { let virtual_fd = arg1 as i32; + let buf = (start_address + arg2) as *mut u8; let nbytes = arg3 as u32; - let cage = interface::cagetable_getref(cageid); - - // Validate buffer for writing directory entries - // Using PROT_WRITE because getdents() writes directory entries TO this user space buffer - let buf = match check_and_convert_addr_ext(&cage, arg2, nbytes as usize, PROT_WRITE) { - Ok(addr) => addr as *mut u8, - Err(errno) => return syscall_error(errno, "getdents", "invalid buffer address"), - }; - - // Perform getdents operation through cage implementation - // File descriptor validation handled by cage layer - cage.getdents_syscall(virtual_fd, buf, nbytes) + + interface::cagetable_getref(cageid) + .getdents_syscall(virtual_fd, buf, nbytes) } STATFS_SYSCALL => { - let cage = interface::cagetable_getref(cageid); - - // Validate and convert path string from user space - // Using PROT_READ because we need to read the path string FROM user space - let path = match check_and_convert_addr_ext(&cage, arg1, 1, PROT_READ) { - Ok(addr) => match interface::types::get_cstr(addr) { - Ok(path_str) => path_str, - Err(_) => return syscall_error(Errno::EFAULT, "statfs", "invalid path string"), - }, - Err(errno) => return syscall_error(errno, "statfs", "invalid path address"), - }; + let fd_ptr = (start_address + arg1) as *const u8; + let rposix_databuf = interface::get_fsdatastruct(start_address + arg2).unwrap(); - // Validate buffer for writing filesystem information - // Using PROT_WRITE because statfs() writes filesystem information TO this user space buffer - let rposix_databuf = match check_and_convert_addr_ext(&cage, arg2, 1, PROT_WRITE) { - Ok(addr) => match interface::get_fsdatastruct(addr) { - Ok(val) => val, - Err(errno) => return syscall_error(Errno::EFAULT, "statfs", "invalid stat buffer format"), - }, - Err(errno) => return syscall_error(errno, "statfs", "invalid stat buffer address"), - }; + let fd = unsafe { + CStr::from_ptr(fd_ptr as *const i8).to_str().unwrap() + }; - // Perform statfs operation through cage implementation - cage.statfs_syscall(&path, rposix_databuf) + interface::cagetable_getref(cageid) + .statfs_syscall(fd, rposix_databuf) } FCNTL_SYSCALL => { @@ -941,76 +626,46 @@ pub fn lind_syscall_api( RECV_SYSCALL => { let fd = arg1 as i32; - let count = arg3 as usize; - let cage = interface::cagetable_getref(cageid); - - // Validate buffer for writing received data - // Using PROT_WRITE because recv() writes received data TO this user space buffer - let buf = match check_and_convert_addr_ext(&cage, arg2, count, PROT_WRITE) { - Ok(addr) => addr as *mut u8, - Err(errno) => return syscall_error(errno, "recv", "invalid buffer address"), - }; + let buf = (start_address + arg2) as *mut u8; + let buflen = arg3 as usize; let flag = arg4 as i32; - - // Perform recv operation through cage implementation - // File descriptor validation handled by cage layer - cage.recv_syscall(fd, buf, count, flag) + + interface::cagetable_getref(cageid) + .recv_syscall(fd, buf, buflen, flag) } SENDTO_SYSCALL => { let fd = arg1 as i32; - let count = arg3 as usize; - let cage = interface::cagetable_getref(cageid); - - // Validate buffer for reading data to send - // Using PROT_READ because we need to read the data FROM user space - let buf = match check_and_convert_addr_ext(&cage, arg2, count, PROT_READ) { - Ok(addr) => addr as *const u8, - Err(errno) => return syscall_error(errno, "sendto", "invalid buffer address"), - }; + let buf = (start_address + arg2) as *const u8; + let buflen = arg3 as usize; let flag = arg4 as i32; // Get and validate socket address let addrlen = arg6 as u32; - let addr = match interface::get_sockaddr(start_address + arg5, addrlen) { - Ok(addr) => addr, - Err(_) => return syscall_error(Errno::EFAULT, "sendto", "invalid socket address"), - }; - - // Perform sendto operation through cage implementation - // File descriptor validation handled by cage layer - cage.sendto_syscall(fd, buf, count, flag, &addr) + let addr = interface::get_sockaddr(start_address + arg5, addrlen).unwrap(); + + interface::cagetable_getref(cageid) + .sendto_syscall(fd, buf, buflen, flag, &addr) } RECVFROM_SYSCALL => { let fd = arg1 as i32; - let count = arg3 as usize; - let cage = interface::cagetable_getref(cageid); - - // Validate buffer for writing received data - // Using PROT_WRITE because recvfrom() writes received data TO this user space buffer - let buf = match check_and_convert_addr_ext(&cage, arg2, count, PROT_WRITE) { - Ok(addr) => addr as *mut u8, - Err(errno) => return syscall_error(errno, "recvfrom", "invalid buffer address"), - }; + let buf = (start_address + arg2) as *mut u8; + let buflen = arg3 as usize; let flag = arg4 as i32; - - // Check if address and length arguments are provided let nullity1 = interface::arg_nullity(arg5); let nullity2 = interface::arg_nullity(arg6); // Handle different cases based on address arguments if nullity1 && nullity2 { - // Both address and length are NULL - simple receive - cage.recvfrom_syscall(fd, buf, count, flag, &mut None) - } + interface::cagetable_getref(cageid) + .recvfrom_syscall(fd, buf, buflen, flag, &mut None) + } else if !(nullity1 || nullity2) { - // Both address and length are provided - // Create a default sockaddr to store the sender's address - let mut newsockaddr = interface::GenSockaddr::V4(interface::SockaddrV4::default()); - - // Perform recvfrom operation - let rv = cage.recvfrom_syscall(fd, buf, count, flag, &mut Some(&mut newsockaddr)); + let mut newsockaddr = interface::GenSockaddr::V4(interface::SockaddrV4::default()); //dummy value, rust would complain if we used an uninitialized value here + + let rv = interface::cagetable_getref(cageid) + .recvfrom_syscall(fd, buf, buflen, flag, &mut Some(&mut newsockaddr)); if rv >= 0 { // Copy address information back to user space on success interface::copy_out_sockaddr(start_address + arg5, start_address + arg6, newsockaddr); @@ -1045,34 +700,21 @@ pub fn lind_syscall_api( interface::cagetable_getref(cageid) .shmget_syscall(key, size, shmfig) } + SHMAT_SYSCALL => { let shmid = arg1 as i32; - let cage = interface::cagetable_getref(cageid); - - // Validate shared memory address - // Using both PROT_READ and PROT_WRITE since shared memory needs both access types - let shmaddr = match check_and_convert_addr_ext(&cage, arg2, 1, PROT_READ | PROT_WRITE) { - Ok(addr) => addr as *mut u8, - Err(errno) => return syscall_error(errno, "shmat", "invalid shared memory address"), - }; + let shmaddr = (start_address + arg2) as *mut u8; let shmflg = arg3 as i32; - - // Perform shmat operation through cage implementation - cage.shmat_syscall(shmid, shmaddr, shmflg) + + interface::cagetable_getref(cageid) + .shmat_syscall(shmid, shmaddr, shmflg) } SHMDT_SYSCALL => { - let cage = interface::cagetable_getref(cageid); - - // Validate shared memory address - // Using both PROT_READ and PROT_WRITE since shared memory needs both access types - let shmaddr = match check_and_convert_addr_ext(&cage, arg1, 1, PROT_READ | PROT_WRITE) { - Ok(addr) => addr as *mut u8, - Err(errno) => return syscall_error(errno, "shmdt", "invalid shared memory address"), - }; + let shmaddr = (start_address + arg1) as *mut u8; - // Perform shmdt operation through cage implementation - cage.shmdt_syscall(shmaddr) + interface::cagetable_getref(cageid) + .shmdt_syscall(shmaddr) } MUTEX_DESTROY_SYSCALL => { @@ -1191,19 +833,13 @@ pub fn lind_syscall_api( } PWRITE_SYSCALL => { - let count = arg3 as usize; - let cage = interface::cagetable_getref(cageid); - - // Validate buffer for reading data to write - // Using PROT_READ because we need to read the data FROM user space - let buf = match check_and_convert_addr_ext(&cage, arg2, count, PROT_READ) { - Ok(addr) => addr as *const u8, - Err(errno) => return syscall_error(errno, "pwrite", "invalid buffer address"), - }; let virtual_fd = arg1 as i32; + let buf = (start_address + arg2) as *const u8; + let count = arg3 as usize; let offset = arg4 as i64; - - cage.pwrite_syscall(virtual_fd, buf, count, offset) + + interface::cagetable_getref(cageid) + .pwrite_syscall(virtual_fd, buf, count, offset) } GETUID_SYSCALL => { @@ -1261,18 +897,11 @@ pub fn lind_syscall_api( let virtual_fd = arg1 as i32; let level = arg2 as i32; let optname = arg3 as i32; - let optlen = arg5 as u32; - let cage = interface::cagetable_getref(cageid); - - // Validate buffer for reading socket option value - // Using PROT_READ because we need to read the option value FROM user space - let optval = match check_and_convert_addr_ext(&cage, arg4, optlen as usize, PROT_READ) { - Ok(addr) => addr as *mut u8, - Err(errno) => return syscall_error(errno, "setsockopt", "invalid optval address"), - }; + let optval = (start_address + arg4) as *mut u8; + let optlen = arg5 as u32; - // Perform setsockopt operation through cage implementation - cage.setsockopt_syscall(virtual_fd, level, optname, optval, optlen) + interface::cagetable_getref(cageid) + .setsockopt_syscall( virtual_fd, level, optname, optval, optlen) } SHUTDOWN_SYSCALL => { @@ -1290,19 +919,13 @@ pub fn lind_syscall_api( } SEND_SYSCALL => { - let fd = arg1 as i32; - let count = arg3 as usize; - let cage = interface::cagetable_getref(cageid); - - // Validate buffer for reading data to send - // Using PROT_READ because we need to read the data FROM user space - let buf = match check_and_convert_addr_ext(&cage, arg2, count, PROT_READ) { - Ok(addr) => addr as *const u8, - Err(errno) => return syscall_error(errno, "send", "invalid buffer address"), - }; + let virtual_fd = arg1 as i32; + let buf = (start_address + arg4) as *const u8; + let buflen = arg3 as usize; let flags = arg4 as i32; - - cage.send_syscall(fd, buf, count, flags) + + interface::cagetable_getref(cageid) + .send_syscall( virtual_fd, buf, buflen, flags) } LISTEN_SYSCALL => { @@ -1323,33 +946,18 @@ pub fn lind_syscall_api( } GETHOSTNAME_SYSCALL => { - let len = arg2 as usize; - let cage = interface::cagetable_getref(cageid); - - // Validate buffer for writing hostname - // Using PROT_WRITE because gethostname() writes hostname TO this user space buffer - let name = match check_and_convert_addr_ext(&cage, arg1, len, PROT_WRITE) { - Ok(addr) => addr as *mut u8, - Err(errno) => return syscall_error(errno, "gethostname", "invalid name address"), - }; - - // Perform gethostname operation through cage implementation - cage.gethostname_syscall(name, len as isize) - } + let name = (start_address + arg1) as *mut u8; + let len = arg2 as isize; + let ret = interface::cagetable_getref(cageid) + .gethostname_syscall(name, len); + ret + } GETIFADDRS_SYSCALL => { + let buf = (start_address + arg1) as *mut u8; let count = arg2 as usize; - let cage = interface::cagetable_getref(cageid); - - // Validate buffer for writing interface addresses - // Using PROT_WRITE because getifaddrs() writes interface data TO user space buffer - let buf = match check_and_convert_addr_ext(&cage, arg1, count, PROT_WRITE) { - Ok(addr) => addr as *mut u8, - Err(errno) => return syscall_error(errno, "getifaddrs", "invalid address"), - }; - - // Perform getifaddrs operation through cage implementation - cage.getifaddrs_syscall(buf, count) + interface::cagetable_getref(cageid) + .getifaddrs_syscall(buf, count) } KILL_SYSCALL => { @@ -1384,62 +992,25 @@ pub fn lind_syscall_api( } PIPE_SYSCALL => { - let cage = interface::cagetable_getref(cageid); - - // Validate buffer for writing pipe file descriptors - // Using PROT_WRITE because pipe() writes two fds TO this user space buffer - // Size is 8 bytes for two integers (file descriptors) - let pipe = match check_and_convert_addr_ext(&cage, arg1, 8, PROT_WRITE) { - Ok(addr) => match interface::get_pipearray(addr) { - Ok(pipe_array) => pipe_array, - Err(_) => return syscall_error(Errno::EFAULT, "pipe", "failed to get pipe array"), - }, - Err(errno) => return syscall_error(errno, "pipe", "invalid pipe address"), - }; - - cage.pipe_syscall(pipe) + let pipe = interface::get_pipearray(start_address + arg1).unwrap(); + + interface::cagetable_getref(cageid) + .pipe_syscall(pipe) } PIPE2_SYSCALL => { - let cage = interface::cagetable_getref(cageid); - - // Validate buffer for writing pipe file descriptors - // Using PROT_WRITE because pipe2() writes two fds TO this user space buffer - // Size is 8 bytes for two integers (file descriptors) - let pipe = match check_and_convert_addr_ext(&cage, arg1, 8, PROT_WRITE) { - Ok(addr) => match interface::get_pipearray(addr) { - Ok(pipe_array) => pipe_array, - Err(_) => return syscall_error(Errno::EFAULT, "pipe2", "failed to get pipe array"), - }, - Err(errno) => return syscall_error(errno, "pipe2", "invalid pipe address"), - }; + let pipe = interface::get_pipearray(start_address + arg1).unwrap(); let flag = arg2 as i32; - - cage.pipe2_syscall(pipe, flag) + + interface::cagetable_getref(cageid) + .pipe2_syscall(pipe, flag) } GETSOCKNAME_SYSCALL => { let fd = arg1 as i32; - let cage = interface::cagetable_getref(cageid); - - // Validate buffer for writing socket address - // Using PROT_WRITE because getsockname() writes address TO user space - let name_addr = match check_and_convert_addr_ext(&cage, arg2, 16, PROT_WRITE) { - Ok(addr) => addr, - Err(errno) => return syscall_error(errno, "getsockname", "invalid name address"), - }; - - // Validate buffer for writing address length - // Using PROT_WRITE because getsockname() writes length TO user space - let namelen_addr = match check_and_convert_addr_ext(&cage, arg3, 4, PROT_WRITE) { - Ok(addr) => addr, - Err(errno) => return syscall_error(errno, "getsockname", "invalid length address"), - }; - - // Initialize default socket address structure - let mut addr = interface::GenSockaddr::V4(interface::SockaddrV4::default()); - - // Check for null pointers + + let mut addr = interface::GenSockaddr::V4(interface::SockaddrV4::default()); //value doesn't matter + if interface::arg_nullity(arg2) || interface::arg_nullity(arg3) { return syscall_error( Errno::EINVAL, @@ -1447,12 +1018,12 @@ pub fn lind_syscall_api( "Either the address or the length were null", ); } - - let rv = cage.getsockname_syscall(fd, &mut Some(&mut addr)); - - // Copy out the address if operation was successful + + let rv = interface::cagetable_getref(cageid) + .getsockname_syscall(fd, &mut Some(&mut addr)); + if rv >= 0 { - interface::copy_out_sockaddr(name_addr, namelen_addr, addr); + interface::copy_out_sockaddr(start_address + arg2, start_address + arg3, addr); } rv } @@ -1461,59 +1032,31 @@ pub fn lind_syscall_api( let virtual_fd = arg1 as i32; let level = arg2 as i32; let optname = arg3 as i32; - let cage = interface::cagetable_getref(cageid); - - // Validate buffer for writing socket option value - // Using PROT_WRITE because getsockopt() writes option value TO user space - // Size is 4 bytes for an integer value - let optval_ptr = match check_and_convert_addr_ext(&cage, arg4, 4, PROT_WRITE) { - Ok(addr) => addr as *mut i32, - Err(errno) => return syscall_error(errno, "getsockopt", "invalid optval address"), - }; + + let optval_ptr = (start_address + arg4) as *mut i32; let optval = unsafe { &mut *optval_ptr }; - - cage.getsockopt_syscall(virtual_fd, level, optname, optval) + + interface::cagetable_getref(cageid) + .getsockopt_syscall(virtual_fd, level, optname, optval) } SOCKETPAIR_SYSCALL => { let domain = arg1 as i32; let _type = arg2 as i32; let protocol = arg3 as i32; - let cage = interface::cagetable_getref(cageid); - - // Validate buffer for writing socket pair file descriptors - // Using PROT_WRITE because socketpair() writes two fds TO this user space buffer - // Size is 8 bytes for two integers (file descriptors) - let virtual_socket_vector = match check_and_convert_addr_ext(&cage, arg4, 8, PROT_WRITE) { - Ok(addr) => match interface::get_sockpair(addr) { - Ok(sock_pair) => sock_pair, - Err(_) => return syscall_error(Errno::EFAULT, "socketpair", "failed to get socket pair array"), - }, - Err(errno) => return syscall_error(errno, "socketpair", "invalid socket vector address"), - }; - - cage.socketpair_syscall(domain, _type, protocol, virtual_socket_vector) + let virtual_socket_vector = interface::get_sockpair(start_address + arg4).unwrap(); + + interface::cagetable_getref(cageid) + .socketpair_syscall(domain, _type, protocol, virtual_socket_vector) } POLL_SYSCALL => { let nfds = arg2 as u64; - let cage = interface::cagetable_getref(cageid); - - // Validate buffer for reading and writing poll file descriptors - // Using PROT_READ | PROT_WRITE because: - // - READ: poll needs to read the fds and events to monitor - // - WRITE: poll needs to write back the returned events - // Size is nfds * 8 (size of pollfd struct) - let pollfds = match check_and_convert_addr_ext(&cage, arg1, (nfds * 8) as usize, PROT_READ | PROT_WRITE) { - Ok(addr) => match interface::get_pollstruct_slice(addr, nfds as usize) { - Ok(poll_array) => poll_array, - Err(_) => return syscall_error(Errno::EFAULT, "poll", "failed to get poll array"), - }, - Err(errno) => return syscall_error(errno, "poll", "invalid fds address"), - }; + let pollfds = interface::get_pollstruct_slice(start_address + arg1, nfds as usize).unwrap(); let timeout = arg3 as i32; - - cage.poll_syscall(pollfds, nfds, timeout) + + interface::cagetable_getref(cageid) + .poll_syscall(pollfds, nfds, timeout) } GETPID_SYSCALL => { @@ -1528,82 +1071,37 @@ pub fn lind_syscall_api( } FUTEX_SYSCALL => { - let cage = interface::cagetable_getref(cageid); - - // Validate buffer for futex operations - // Using PROT_READ | PROT_WRITE because: - // - READ: futex needs to read current value - // - WRITE: futex may modify the value depending on operation - let uaddr = match check_and_convert_addr_ext(&cage, arg1, 4, PROT_READ | PROT_WRITE) { - Ok(addr) => addr, - Err(errno) => return syscall_error(errno, "futex", "invalid uaddr address"), - }; - - // Convert remaining arguments + let uaddr = (start_address + arg1) as u64; let futex_op = arg2 as u32; let val = arg3 as u32; let timeout = arg4 as u32; let uaddr2 = arg5 as u32; let val3 = arg6 as u32; - - cage.futex_syscall(uaddr, futex_op, val, timeout, uaddr2, val3) + + interface::cagetable_getref(cageid) + .futex_syscall(uaddr, futex_op, val, timeout, uaddr2, val3) } NANOSLEEP_TIME64_SYSCALL => { let clockid = arg1 as u32; let flags = arg2 as i32; - let cage = interface::cagetable_getref(cageid); - - // Validate buffer for reading requested sleep time - // Using PROT_READ because we need to read the requested time FROM user space - // Size is 16 bytes for timespec64 structure - let req = match check_and_convert_addr_ext(&cage, arg3, 16, PROT_READ) { - Ok(addr) => addr as usize, - Err(errno) => return syscall_error(errno, "nanosleep", "invalid req address"), - }; - - // Validate buffer for writing remaining time - // Using PROT_WRITE because nanosleep writes remaining time TO user space - // Size is 16 bytes for timespec64 structure - let rem = match check_and_convert_addr_ext(&cage, arg4, 16, PROT_WRITE) { - Ok(addr) => addr as usize, - Err(errno) => return syscall_error(errno, "nanosleep", "invalid rem address"), - }; + let req = (start_address + arg3) as usize; + let rem = (start_address + arg4) as usize; - cage.nanosleep_time64_syscall(clockid, flags, req, rem) + interface::cagetable_getref(cageid) + .nanosleep_time64_syscall(clockid, flags, req, rem) } WAIT_SYSCALL => { - let cage = interface::cagetable_getref(cageid); - - // Validate buffer for writing process status - // Using PROT_WRITE because wait() writes status information TO user space - // Size is 4 bytes for status integer - let status = match check_and_convert_addr_ext(&cage, arg1, 4, PROT_WRITE) { - Ok(addr) => match interface::get_i32_ref(addr) { - Ok(status_ref) => status_ref, - Err(_) => return syscall_error(Errno::EFAULT, "wait", "failed to get status reference"), - }, - Err(errno) => return syscall_error(errno, "wait", "invalid status address"), - }; - - cage.wait_syscall(status) + let mut status = interface::get_i32_ref(start_address + arg1).unwrap(); + + interface::cagetable_getref(cageid) + .wait_syscall(&mut status) } WAITPID_SYSCALL => { let pid = arg1 as i32; - let cage = interface::cagetable_getref(cageid); - - // Validate buffer for writing process status - // Using PROT_WRITE because waitpid() writes status information TO user space - // Size is 4 bytes for status integer - let status = match check_and_convert_addr_ext(&cage, arg2, 4, PROT_WRITE) { - Ok(addr) => match interface::get_i32_ref(addr) { - Ok(status_ref) => status_ref, - Err(_) => return syscall_error(Errno::EFAULT, "waitpid", "failed to get status reference"), - }, - Err(errno) => return syscall_error(errno, "waitpid", "invalid status address"), - }; + let mut status = interface::get_i32_ref(start_address + arg2).unwrap(); let options = arg3 as i32; cage.waitpid_syscall(pid, status, options) From 606b1c96a4e8e7ab078415927f1e9b00175297b0 Mon Sep 17 00:00:00 2001 From: ChinmayShringi Date: Mon, 27 Jan 2025 20:13:10 +0000 Subject: [PATCH 48/66] feat: updated mmap test cases --- src/RawPOSIX/src/tests/fs_tests.rs | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/src/RawPOSIX/src/tests/fs_tests.rs b/src/RawPOSIX/src/tests/fs_tests.rs index 69488c6f8..453948d7d 100644 --- a/src/RawPOSIX/src/tests/fs_tests.rs +++ b/src/RawPOSIX/src/tests/fs_tests.rs @@ -422,7 +422,7 @@ pub mod fs_tests { //Checking if passing 0 as `len` to `mmap_syscall()` //correctly results in 'The value of len is 0` error. let mmap_result = cage.mmap_syscall(0 as *mut u8, 0, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); - assert_eq!(mmap_result as i32, -1, "Expected mmap to fail with -1 due to zero length"); + assert_eq!(mmap_result as i32, -EINVAL as i32, "Expected to fail with EINVAL due to zero length"); // Fetch the errno and check that it is `EINVAL` (Invalid argument) let errno = get_errno(); assert_eq!(errno, libc::EINVAL, "Expected errno to be EINVAL for zero-length mmap"); @@ -440,16 +440,18 @@ pub mod fs_tests { let cage = interface::cagetable_getref(1); - //Creating a regular file with `O_RDWR` flag - //making it valid for any mapping. + // Creating a regular file with `O_RDWR` flag + // making it valid for any mapping. let flags: i32 = O_TRUNC | O_CREAT | O_RDWR; let filepath = "/mmapTestFile1"; let fd = cage.open_syscall(filepath, flags, S_IRWXA); - //Writing into that file's first 9 bytes. + // Writing into that file's first 9 bytes. assert_eq!(cage.write_syscall(fd, str2cbuf("Test text"), 9), 9); + // When no flags are specified (flags = 0), mmap should fail with EINVAL let mmap_result = cage.mmap_syscall(0 as *mut u8, 5, PROT_READ | PROT_WRITE, 0, fd, 0); - assert_eq!(mmap_result as i32, -1, "mmap did not fail as expected"); + assert_eq!(mmap_result as i32, -EINVAL as i32, "mmap did not fail with EINVAL as expected"); + assert_eq!(cage.exit_syscall(libc::EXIT_SUCCESS), libc::EXIT_SUCCESS); lindrustfinalize(); } @@ -521,7 +523,8 @@ pub mod fs_tests { //allow reading correctly results in `File descriptor //is not open for reading` error. let mmap_result = cage.mmap_syscall(0 as *mut u8, 5, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); - assert_eq!(mmap_result as i32, -1, "Expected mmap to fail"); + assert_eq!(mmap_result as i32, -EINVAL as i32, "Expected to fail with EINVAL"); + // Fetch and print the errno for debugging let error = get_errno(); // Assert that the error is EACCES (Permission denied) @@ -570,7 +573,7 @@ pub mod fs_tests { 0, ); // Check if mmap_syscall returns -1 (failure) - assert_eq!(mmap_result as i32, -1, "Expected mmap to fail due to lack of write permissions"); + assert_eq!(mmap_result as i32, -EINVAL as i32, "Expected to fail with EINVAL due to no write permission"); // Fetch and check the errno for debugging let err = get_errno(); // Ensure the errno is EACCES (Permission denied) @@ -603,7 +606,8 @@ pub mod fs_tests { /* Native linux will return EINVAL - TESTED locally */ let result = cage.mmap_syscall(0 as *mut u8, 5, PROT_READ | PROT_WRITE, MAP_SHARED, fd, -10); - assert_eq!(result as i32, -1, "Expected mmap to fail with -1 for negative offset"); + assert_eq!(result as i32, -EINVAL as i32, "Expected mmap to fail with EINVAL for negative offset"); + // Verify errno is set to EINVAL let errno = get_errno(); assert_eq!(errno, libc::EINVAL, "Expected errno to be EINVAL for negative offset"); @@ -614,8 +618,8 @@ pub mod fs_tests { /* Native linux will return EINVAL - TESTED locally */ let result_beyond_eof = cage.mmap_syscall(0 as *mut u8, 5, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 25); - assert_eq!(result_beyond_eof as i32, -1, "Expected mmap to fail with -1 for offset beyond EOF"); - + assert_eq!(result_beyond_eof as i32, -EINVAL as i32, "Expected mmap to fail with EINVAL for offset beyond EOF"); + // Verify errno is set to EINVAL let errno_beyond_eof = get_errno(); assert_eq!(errno_beyond_eof, libc::EINVAL, "Expected errno to be EINVAL for offset beyond EOF"); From d32d07acdee5e659c00ea330400a12520adb5533 Mon Sep 17 00:00:00 2001 From: ChinmayShringi Date: Mon, 27 Jan 2025 20:23:24 +0000 Subject: [PATCH 49/66] feat: update dispatcher mmap syscall --- src/RawPOSIX/src/safeposix/dispatcher.rs | 40 +++++++++++++++++++----- 1 file changed, 32 insertions(+), 8 deletions(-) diff --git a/src/RawPOSIX/src/safeposix/dispatcher.rs b/src/RawPOSIX/src/safeposix/dispatcher.rs index 2e3e5f163..7b3f6b1f5 100644 --- a/src/RawPOSIX/src/safeposix/dispatcher.rs +++ b/src/RawPOSIX/src/safeposix/dispatcher.rs @@ -219,23 +219,46 @@ pub fn lind_syscall_api( } MUNMAP_SYSCALL => { - let addr = (start_address + arg1) as *mut u8; - let len = arg2 as usize; + let addr = arg1 as *mut u8; + let length = arg2 as usize; + let cage = interface::cagetable_getref(cageid); - interface::cagetable_getref(cageid) - .munmap_syscall(addr, len) + if length == 0 { + return syscall_error( + Errno::EINVAL, + "munmap", + "length cannot be zero" + ); + } + + // Perform the unmapping operation + interface::munmap_handler(cageid, addr, length) } MMAP_SYSCALL => { - let addr = (start_address + arg1) as *mut u8; + let addr = arg1 as *mut u8; let len = arg2 as usize; let prot = arg3 as i32; let flags = arg4 as i32; - let fildes = arg5 as i32; + let fd = arg5 as i32; let off = arg6 as i64; - interface::cagetable_getref(cageid) - .mmap_syscall(addr, len, prot, flags, fildes, off) + // Basic length validation + if len == 0 { + return syscall_error( + Errno::EINVAL, + "mmap", + "length cannot be zero" + ); + } + + // Force MAP_FIXED + let flags = flags | MAP_FIXED as i32; + + // Turn off PROT_EXEC for non-code pages + let prot = prot & !PROT_EXEC; + + interface::mmap_handler(cageid, addr, len, prot, flags, fd, off) as i32 } PREAD_SYSCALL => { @@ -1103,6 +1126,7 @@ pub fn lind_syscall_api( let pid = arg1 as i32; let mut status = interface::get_i32_ref(start_address + arg2).unwrap(); let options = arg3 as i32; + let cage = interface::cagetable_getref(cageid); cage.waitpid_syscall(pid, status, options) } From c91b4d52f0f8034b8cb432c31e5705768d714ee9 Mon Sep 17 00:00:00 2001 From: ChinmayShringi Date: Mon, 27 Jan 2025 20:30:10 +0000 Subject: [PATCH 50/66] feat: update dispatcher cage interface --- src/RawPOSIX/src/safeposix/dispatcher.rs | 42 +++++++++++++++--------- 1 file changed, 27 insertions(+), 15 deletions(-) diff --git a/src/RawPOSIX/src/safeposix/dispatcher.rs b/src/RawPOSIX/src/safeposix/dispatcher.rs index 7b3f6b1f5..2db5039b3 100644 --- a/src/RawPOSIX/src/safeposix/dispatcher.rs +++ b/src/RawPOSIX/src/safeposix/dispatcher.rs @@ -211,11 +211,21 @@ pub fn lind_syscall_api( WRITEV_SYSCALL => { let fd = arg1 as i32; - let iovec = (start_address + arg2) as *const interface::IovecStruct; let iovcnt = arg3 as i32; + let iovec = (start_address + arg2) as *const interface::IovecStruct; - interface::cagetable_getref(cageid) - .writev_syscall(fd, iovec, iovcnt) + // Validate count first + if iovcnt <= 0 { + return syscall_error( + Errno::EINVAL, + "writev", + "invalid iovec count" + ); + } + + let cage = interface::cagetable_getref(cageid); + // The actual write operation is delegated to the cage implementation + cage.writev_syscall(fd, iovec, iovcnt) } MUNMAP_SYSCALL => { @@ -262,22 +272,23 @@ pub fn lind_syscall_api( } PREAD_SYSCALL => { - let fd = arg1 as i32; let buf = (start_address + arg2) as *mut u8; + let fd = arg1 as i32; let count = arg3 as usize; let offset = arg4 as i64; - - interface::cagetable_getref(cageid) - .pread_syscall(fd, buf, count, offset) + let cage = interface::cagetable_getref(cageid); + cage.pread_syscall(fd, buf, count, offset) } READ_SYSCALL => { let fd = arg1 as i32; - let buf = (start_address + arg2) as *mut u8; let count = arg3 as usize; + let cage = interface::cagetable_getref(cageid); + let buf = (start_address + arg2) as *mut u8; - interface::cagetable_getref(cageid) - .read_syscall(fd, buf, count) + // File descriptor validation and actual read operation + // handled by cage implementation + cage.read_syscall(fd, buf, count) } CLOSE_SYSCALL => { @@ -289,26 +300,27 @@ pub fn lind_syscall_api( } ACCESS_SYSCALL => { + let cage = interface::cagetable_getref(cageid); let path = match interface::types::get_cstr(start_address + arg1) { Ok(path_str) => path_str, Err(_) => return -1, // Handle error appropriately, return an error code }; let amode = arg2 as i32; - interface::cagetable_getref(cageid) - .access_syscall(path, amode) + // Perform access check through cage implementation + cage.access_syscall(path, amode) } OPEN_SYSCALL => { + let cage = interface::cagetable_getref(cageid); let path = match interface::types::get_cstr(start_address + arg1) { Ok(path_str) => path_str, Err(_) => return -1, // Handle error appropriately, return an error code }; let flags = arg2 as i32; let mode = arg3 as u32; - - interface::cagetable_getref(cageid) - .open_syscall(path, flags, mode) + // Perform open operation through cage implementation + cage.open_syscall(path, flags, mode) } SOCKET_SYSCALL => { From 379d504f47b4bbd632eb42821aa2ac5c8cf6d374 Mon Sep 17 00:00:00 2001 From: ChinmayShringi Date: Mon, 27 Jan 2025 20:39:58 +0000 Subject: [PATCH 51/66] feat: removed explicit flags --- src/RawPOSIX/src/safeposix/dispatcher.rs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/RawPOSIX/src/safeposix/dispatcher.rs b/src/RawPOSIX/src/safeposix/dispatcher.rs index 2db5039b3..75ff94620 100644 --- a/src/RawPOSIX/src/safeposix/dispatcher.rs +++ b/src/RawPOSIX/src/safeposix/dispatcher.rs @@ -262,12 +262,6 @@ pub fn lind_syscall_api( ); } - // Force MAP_FIXED - let flags = flags | MAP_FIXED as i32; - - // Turn off PROT_EXEC for non-code pages - let prot = prot & !PROT_EXEC; - interface::mmap_handler(cageid, addr, len, prot, flags, fd, off) as i32 } From 32c2526cbf49e5da4c87e88878c23efd91b5afc2 Mon Sep 17 00:00:00 2001 From: ChinmayShringi Date: Wed, 29 Jan 2025 22:35:07 +0000 Subject: [PATCH 52/66] feat: removed start_address --- src/RawPOSIX/src/interface/mem.rs | 7 + src/RawPOSIX/src/safeposix/dispatcher.rs | 526 +++++++++++++---------- 2 files changed, 296 insertions(+), 237 deletions(-) diff --git a/src/RawPOSIX/src/interface/mem.rs b/src/RawPOSIX/src/interface/mem.rs index 12faee5db..4988e87a5 100644 --- a/src/RawPOSIX/src/interface/mem.rs +++ b/src/RawPOSIX/src/interface/mem.rs @@ -432,3 +432,10 @@ pub fn check_and_convert_addr_ext(cage: &Cage, arg: u64, length: usize, prot: i3 // Convert to physical address by adding base address Ok(vmmap.base_address.unwrap() as u64 + arg) } + +// Add the base address of the vmmap to the argument +pub fn translate_vmmap_addr(cage: &Cage, arg: u64) -> Result { + // Get read lock on virtual memory map + let vmmap = cage.vmmap.read(); + Ok(vmmap.base_address.unwrap() as u64 + arg) +} \ No newline at end of file diff --git a/src/RawPOSIX/src/safeposix/dispatcher.rs b/src/RawPOSIX/src/safeposix/dispatcher.rs index 75ff94620..01511e93c 100644 --- a/src/RawPOSIX/src/safeposix/dispatcher.rs +++ b/src/RawPOSIX/src/safeposix/dispatcher.rs @@ -138,6 +138,7 @@ use crate::interface::{SigactionStruct, StatData}; use crate::{fdtables, interface}; use crate::interface::errnos::*; use crate::constants::*; +use crate::interface::translate_vmmap_addr; macro_rules! get_onearg { ($arg: expr) => { @@ -202,18 +203,24 @@ pub fn lind_syscall_api( let ret = match call_number { WRITE_SYSCALL => { + // Handles writing data from user buffer to file descriptor + // Get file descriptor let fd = arg1 as i32; - let buf = (start_address + arg2) as *const u8; let count = arg3 as usize; - interface::cagetable_getref(cageid) - .write_syscall(fd, buf, count) + if count == 0 { + return 0; // Early return for zero-length writes + } + // Get cage reference for memory operations + let cage = interface::cagetable_getref(cageid); + // Convert user buffer address to system address + let buf = translate_vmmap_addr(&cage, arg2).unwrap() as *const u8; + // Perform write operation through cage abstraction + cage.write_syscall(fd, buf, count) } WRITEV_SYSCALL => { let fd = arg1 as i32; let iovcnt = arg3 as i32; - let iovec = (start_address + arg2) as *const interface::IovecStruct; - // Validate count first if iovcnt <= 0 { return syscall_error( @@ -222,10 +229,11 @@ pub fn lind_syscall_api( "invalid iovec count" ); } - let cage = interface::cagetable_getref(cageid); + // Convert iovec array address + let iov_base = translate_vmmap_addr(&cage, arg2).unwrap() as *const interface::IovecStruct; // The actual write operation is delegated to the cage implementation - cage.writev_syscall(fd, iovec, iovcnt) + cage.writev_syscall(fd, iov_base, iovcnt) } MUNMAP_SYSCALL => { @@ -266,11 +274,11 @@ pub fn lind_syscall_api( } PREAD_SYSCALL => { - let buf = (start_address + arg2) as *mut u8; let fd = arg1 as i32; let count = arg3 as usize; let offset = arg4 as i64; let cage = interface::cagetable_getref(cageid); + let buf = translate_vmmap_addr(&cage, arg2).unwrap() as *mut u8; cage.pread_syscall(fd, buf, count, offset) } @@ -278,7 +286,7 @@ pub fn lind_syscall_api( let fd = arg1 as i32; let count = arg3 as usize; let cage = interface::cagetable_getref(cageid); - let buf = (start_address + arg2) as *mut u8; + let buf = translate_vmmap_addr(&cage, arg2).unwrap() as *mut u8; // File descriptor validation and actual read operation // handled by cage implementation @@ -295,10 +303,8 @@ pub fn lind_syscall_api( ACCESS_SYSCALL => { let cage = interface::cagetable_getref(cageid); - let path = match interface::types::get_cstr(start_address + arg1) { - Ok(path_str) => path_str, - Err(_) => return -1, // Handle error appropriately, return an error code - }; + let addr = translate_vmmap_addr(&cage, arg1).unwrap(); + let path = interface::types::get_cstr(addr).unwrap(); let amode = arg2 as i32; // Perform access check through cage implementation @@ -307,10 +313,8 @@ pub fn lind_syscall_api( OPEN_SYSCALL => { let cage = interface::cagetable_getref(cageid); - let path = match interface::types::get_cstr(start_address + arg1) { - Ok(path_str) => path_str, - Err(_) => return -1, // Handle error appropriately, return an error code - }; + let addr = translate_vmmap_addr(&cage, arg1).unwrap(); + let path = interface::types::get_cstr(addr).unwrap(); let flags = arg2 as i32; let mode = arg3 as u32; // Perform open operation through cage implementation @@ -330,45 +334,50 @@ pub fn lind_syscall_api( CONNECT_SYSCALL => { let fd = arg1 as i32; - let addrlen = arg3 as u32; - let addr = get_onearg!(interface::get_sockaddr(arg2, addrlen)); - - let remoteaddr = match Ok::<&interface::GenSockaddr, i32>(&addr) { - Ok(addr) => addr, - Err(_) => panic!("Failed to get sockaddr"), // Handle error appropriately - }; - interface::cagetable_getref(cageid) - .connect_syscall(fd, remoteaddr) + let cage = interface::cagetable_getref(cageid); + let addr = translate_vmmap_addr(&cage, arg2).unwrap(); + let sockaddr = interface::get_sockaddr(addr as u64, arg3 as u32).unwrap(); + let remoteaddr = &sockaddr; + + // Perform connect operation through cage implementation + // File descriptor validation handled by cage layer + cage.connect_syscall(fd, remoteaddr) } BIND_SYSCALL => { let fd = arg1 as i32; - let addrlen = arg3 as u32; - let addr = interface::get_sockaddr(start_address + arg2, addrlen).unwrap(); - let localaddr = match Ok::<&interface::GenSockaddr, i32>(&addr) { - Ok(addr) => addr, - Err(_) => panic!("Failed to get sockaddr"), // Handle error appropriately - }; - interface::cagetable_getref(cageid) - .bind_syscall(fd, localaddr) + let cage = interface::cagetable_getref(cageid); + let addr = translate_vmmap_addr(&cage, arg2).unwrap(); + let sockaddr = interface::get_sockaddr(addr as u64, arg3 as u32).unwrap(); + let localaddr = &sockaddr; + + // Perform bind operation through cage implementation + // File descriptor validation handled by cage layer + cage.bind_syscall(fd, localaddr) } ACCEPT_SYSCALL => { - let mut addr = interface::GenSockaddr::V4(interface::SockaddrV4::default()); //value doesn't matter + let mut addr = interface::GenSockaddr::V4(interface::SockaddrV4::default()); let nullity1 = interface::arg_nullity(arg2); let nullity2 = interface::arg_nullity(arg3); - + let cage = interface::cagetable_getref(cageid); + // Handle NULL address case (both NULL) if nullity1 && nullity2 { - interface::cagetable_getref(cageid) - .accept_syscall(arg1 as i32, &mut Some(&mut addr)) - } else if !(nullity1 || nullity2) { - let rv = interface::cagetable_getref(cageid) - .accept_syscall(arg1 as i32, &mut Some(&mut addr)); + cage.accept_syscall(arg1 as i32, &mut Some(&mut addr)) + } + // Handle non-NULL case (both non-NULL) + else if !(nullity1 || nullity2) { + // Perform accept operation first + let rv = cage.accept_syscall(arg1 as i32, &mut Some(&mut addr)); if rv >= 0 { - interface::copy_out_sockaddr((start_address + arg2), (start_address + arg3), addr); + let addr2_addr = translate_vmmap_addr(&cage, arg2).unwrap(); + let len_addr = translate_vmmap_addr(&cage, arg3).unwrap(); + interface::copy_out_sockaddr(addr2_addr as u64, len_addr as u64, addr); } rv - } else { + } + // Handle invalid case (one NULL, one non-NULL) + else { syscall_error( Errno::EINVAL, "accept", @@ -398,18 +407,34 @@ pub fn lind_syscall_api( SELECT_SYSCALL => { // Get the number of file descriptors to check (highest fd + 1) let nfds = arg1 as i32; - let readfds = interface::get_fdset(arg2).unwrap(); - let writefds = interface::get_fdset(arg3).unwrap(); - let errorfds = interface::get_fdset(arg4).unwrap(); - let rposix_timeout = interface::duration_fromtimeval(arg5).unwrap(); - interface::cagetable_getref(cageid) - .select_syscall(nfds, readfds, writefds, errorfds, rposix_timeout) + // Get reference to the cage for memory operations + let cage = interface::cagetable_getref(cageid); + // Convert readfds buffer address + let readfds_addr = translate_vmmap_addr(&cage, arg2).unwrap(); + let readfds = interface::get_fdset(readfds_addr).unwrap(); + // Convert writefds buffer address + let writefds_addr = translate_vmmap_addr(&cage, arg3).unwrap(); + let writefds = interface::get_fdset(writefds_addr).unwrap(); + // Convert errorfds buffer address + let errorfds_addr = translate_vmmap_addr(&cage, arg4).unwrap(); + let errorfds = interface::get_fdset(errorfds_addr).unwrap(); + // Convert timeout buffer address + let timeout_addr = translate_vmmap_addr(&cage, arg5).unwrap(); + let rposix_timeout = interface::duration_fromtimeval(timeout_addr).unwrap(); + // Delegate to the cage's select implementation + // This will: + // 1. Monitor the specified file descriptors for activity + // 2. Modify the fd_sets to indicate which descriptors are ready + // 3. Return the number of ready descriptors or an error code + cage.select_syscall(nfds, readfds, writefds, errorfds, rposix_timeout) } RENAME_SYSCALL => { - let old_ptr = (start_address + arg1) as *const u8; - let new_ptr = (start_address + arg2) as *const u8; - + let cage = interface::cagetable_getref(cageid); + // Convert old path address + let old_ptr = translate_vmmap_addr(&cage, arg1).unwrap(); + // Convert new path address + let new_ptr = translate_vmmap_addr(&cage, arg2).unwrap(); // Convert the raw pointers to `&str` let old = unsafe { CStr::from_ptr(old_ptr as *const i8).to_str().unwrap() @@ -417,49 +442,39 @@ pub fn lind_syscall_api( let new = unsafe { CStr::from_ptr(new_ptr as *const i8).to_str().unwrap() }; - - interface::cagetable_getref(cageid) - .rename_syscall(old, new) + // Perform rename operation through cage implementation + cage.rename_syscall(old, new) } XSTAT_SYSCALL => { - let fd_ptr = (start_address + arg1) as *const u8; - let buf = match interface::get_statdatastruct(start_address + arg2) { - Ok(val) => val, - Err(errno) => { - return errno; - } - }; - - let fd = unsafe { - CStr::from_ptr(fd_ptr as *const i8).to_str().unwrap() - }; - - interface::cagetable_getref(cageid) - .stat_syscall(fd, buf) + let cage = interface::cagetable_getref(cageid); + // Convert path string address + let path_addr = translate_vmmap_addr(&cage, arg1).unwrap(); + let path = interface::types::get_cstr(path_addr).unwrap(); + // Convert stat buffer address + let buf_addr = translate_vmmap_addr(&cage, arg2).unwrap(); + let buf = interface::get_statdatastruct(buf_addr).unwrap(); + // Perform stat operation through cage implementation + // Results written directly to user buffer by cage layer + cage.stat_syscall(path, buf) } MKDIR_SYSCALL => { - let fd_ptr = (start_address + arg1) as *const u8; + let cage = interface::cagetable_getref(cageid); + // Convert path string address + let path_addr = translate_vmmap_addr(&cage, arg1).unwrap(); + let path = interface::types::get_cstr(path_addr).unwrap(); let mode = arg2 as u32; - - let fd= unsafe { - CStr::from_ptr(fd_ptr as *const i8).to_str().unwrap() - }; - - interface::cagetable_getref(cageid) - .mkdir_syscall(fd, mode) + // Perform mkdir operation through cage implementation + cage.mkdir_syscall(path, mode) } - RMDIR_SYSCALL => { - let fd_ptr = (start_address + arg1) as *const u8; - - let fd= unsafe { - CStr::from_ptr(fd_ptr as *const i8).to_str().unwrap() - }; - - interface::cagetable_getref(cageid) - .rmdir_syscall(fd) + let cage = interface::cagetable_getref(cageid); + // Convert path string address + let path_addr = translate_vmmap_addr(&cage, arg1).unwrap(); + let path = interface::types::get_cstr(path_addr).unwrap(); + // Perform rmdir operation through cage implementation + cage.rmdir_syscall(path) } FCHDIR_SYSCALL => { @@ -472,39 +487,47 @@ pub fn lind_syscall_api( } CHDIR_SYSCALL => { - let path = interface::types::get_cstr(start_address + arg1).unwrap(); + let cage = interface::cagetable_getref(cageid); + // Convert path string address + let path_addr = translate_vmmap_addr(&cage, arg1).unwrap(); + let path = interface::types::get_cstr(path_addr).unwrap(); - interface::cagetable_getref(cageid) - .chdir_syscall(path) + // Perform chdir operation through cage implementation + cage.chdir_syscall(path) } GETCWD_SYSCALL => { - let buf = (start_address + arg1) as *mut u8; - let bufsize = arg2 as u32; - - let ret = interface::cagetable_getref(cageid) - .getcwd_syscall(buf, bufsize); + let bufsize = arg2 as usize; + let cage = interface::cagetable_getref(cageid); + // Convert buffer address + let buf_addr = translate_vmmap_addr(&cage, arg1).unwrap(); + let buf = buf_addr as *mut u8; + // Perform getcwd operation through cage implementation + // On success (ret == 0), return the buffer address + let ret = cage.getcwd_syscall(buf, bufsize as u32); if ret == 0 { return arg1 as i32; } ret } FSTATFS_SYSCALL => { let fd = arg1 as i32; - let buf = interface::get_fsdatastruct(start_address + arg2).unwrap(); - - interface::cagetable_getref(cageid) - .fstatfs_syscall(fd, buf) + let cage = interface::cagetable_getref(cageid); + // Convert buffer address + let buf_addr = translate_vmmap_addr(&cage, arg2).unwrap(); + let buf = interface::get_fsdatastruct(buf_addr).unwrap(); + // Perform fstatfs operation through cage implementation + // File descriptor validation and actual operation handled by cage layer + cage.fstatfs_syscall(fd, buf) } CHMOD_SYSCALL => { - let fd_ptr = (start_address + arg1) as *const u8; - let fd= unsafe { - CStr::from_ptr(fd_ptr as *const i8).to_str().unwrap() - }; + let cage = interface::cagetable_getref(cageid); + // Convert path string address + let path_addr = translate_vmmap_addr(&cage, arg1).unwrap(); + let path = interface::types::get_cstr(path_addr).unwrap(); let mode = arg2 as u32; - - interface::cagetable_getref(cageid) - .chmod_syscall(fd, mode) + // Perform chmod operation through cage implementation + cage.chmod_syscall(path, mode) } DUP_SYSCALL => { @@ -545,27 +568,30 @@ pub fn lind_syscall_api( FXSTAT_SYSCALL => { let fd = arg1 as i32; - let buf = interface::get_statdatastruct(start_address + arg2).unwrap(); - - interface::cagetable_getref(cageid) - .fstat_syscall(fd, buf) + let cage = interface::cagetable_getref(cageid); + // Convert stat buffer address + let buf_addr = translate_vmmap_addr(&cage, arg2).unwrap(); + let buf = interface::get_statdatastruct(buf_addr).unwrap(); + // Perform fstat operation through cage implementation + // File descriptor validation and actual operation handled by cage layer + cage.fstat_syscall(fd, buf) } UNLINK_SYSCALL => { - let fd_ptr = (start_address + arg1) as *const u8; - - let fd = unsafe { - CStr::from_ptr(fd_ptr as *const i8).to_str().unwrap() - }; - - interface::cagetable_getref(cageid) - .unlink_syscall(fd) + let cage = interface::cagetable_getref(cageid); + // Convert path string address + let path_addr = translate_vmmap_addr(&cage, arg1).unwrap(); + let path = interface::types::get_cstr(path_addr).unwrap(); + // Perform unlink operation through cage implementation + cage.unlink_syscall(path) } LINK_SYSCALL => { - let old_ptr = (start_address + arg1) as *const u8; - let new_ptr = (start_address + arg1) as *const u8; - + let cage = interface::cagetable_getref(cageid); + // Convert old path string address + let old_ptr = translate_vmmap_addr(&cage, arg1).unwrap(); + // Convert new path string address + let new_ptr = translate_vmmap_addr(&cage, arg2).unwrap(); let old_fd= unsafe { CStr::from_ptr(old_ptr as *const i8).to_str().unwrap() }; @@ -573,8 +599,8 @@ pub fn lind_syscall_api( CStr::from_ptr(new_ptr as *const i8).to_str().unwrap() }; - interface::cagetable_getref(cageid) - .link_syscall(old_fd, new_fd) + // Perform link operation through cage implementation + cage.link_syscall(old_fd, new_fd) } LSEEK_SYSCALL => { @@ -600,15 +626,13 @@ pub fn lind_syscall_api( } TRUNCATE_SYSCALL => { - let fd_ptr = (start_address + arg1) as *const u8; + let cage = interface::cagetable_getref(cageid); + // Convert path string address + let path_addr = translate_vmmap_addr(&cage, arg1).unwrap(); + let path = interface::types::get_cstr(path_addr).unwrap(); let length = arg2 as isize; - - let fd = unsafe { - CStr::from_ptr(fd_ptr as *const i8).to_str().unwrap() - }; - - interface::cagetable_getref(cageid) - .truncate_syscall(fd, length) + // Perform truncate operation through cage implementation + cage.truncate_syscall(path, length) } FTRUNCATE_SYSCALL => { @@ -623,23 +647,27 @@ pub fn lind_syscall_api( GETDENTS_SYSCALL => { let virtual_fd = arg1 as i32; - let buf = (start_address + arg2) as *mut u8; let nbytes = arg3 as u32; - - interface::cagetable_getref(cageid) - .getdents_syscall(virtual_fd, buf, nbytes) + let cage = interface::cagetable_getref(cageid); + // Convert buffer address + let buf = translate_vmmap_addr(&cage, arg2).unwrap() as *mut u8; + // Perform getdents operation through cage implementation + // File descriptor validation handled by cage layer + cage.getdents_syscall(virtual_fd, buf, nbytes) } STATFS_SYSCALL => { - let fd_ptr = (start_address + arg1) as *const u8; - let rposix_databuf = interface::get_fsdatastruct(start_address + arg2).unwrap(); + let cage = interface::cagetable_getref(cageid); + // Convert path string address + let path_addr = translate_vmmap_addr(&cage, arg1).unwrap(); + let path = interface::types::get_cstr(path_addr).unwrap(); - let fd = unsafe { - CStr::from_ptr(fd_ptr as *const i8).to_str().unwrap() - }; + // Convert buffer address + let buf_addr = translate_vmmap_addr(&cage, arg2).unwrap(); + let rposix_databuf = interface::get_fsdatastruct(buf_addr).unwrap(); - interface::cagetable_getref(cageid) - .statfs_syscall(fd, rposix_databuf) + // Perform statfs operation through cage implementation + cage.statfs_syscall(&path, rposix_databuf) } FCNTL_SYSCALL => { @@ -655,46 +683,57 @@ pub fn lind_syscall_api( RECV_SYSCALL => { let fd = arg1 as i32; - let buf = (start_address + arg2) as *mut u8; - let buflen = arg3 as usize; + let count = arg3 as usize; + let cage = interface::cagetable_getref(cageid); + // Convert buffer address for writing received data + let buf = translate_vmmap_addr(&cage, arg2).unwrap() as *mut u8; let flag = arg4 as i32; - - interface::cagetable_getref(cageid) - .recv_syscall(fd, buf, buflen, flag) + // Perform recv operation through cage implementation + // File descriptor validation handled by cage layer + cage.recv_syscall(fd, buf, count, flag) } SENDTO_SYSCALL => { let fd = arg1 as i32; - let buf = (start_address + arg2) as *const u8; - let buflen = arg3 as usize; + let count = arg3 as usize; + let cage = interface::cagetable_getref(cageid); + // Convert buffer address for reading data to send + let buf = translate_vmmap_addr(&cage, arg2).unwrap() as *const u8; let flag = arg4 as i32; // Get and validate socket address let addrlen = arg6 as u32; - let addr = interface::get_sockaddr(start_address + arg5, addrlen).unwrap(); - - interface::cagetable_getref(cageid) - .sendto_syscall(fd, buf, buflen, flag, &addr) + let addr = match interface::get_sockaddr(start_address + arg5, addrlen) { + Ok(addr) => addr, + Err(_) => return syscall_error(Errno::EFAULT, "sendto", "invalid socket address"), + }; + // Perform sendto operation through cage implementation + // File descriptor validation handled by cage layer + cage.sendto_syscall(fd, buf, count, flag, &addr) } RECVFROM_SYSCALL => { let fd = arg1 as i32; - let buf = (start_address + arg2) as *mut u8; - let buflen = arg3 as usize; + let count = arg3 as usize; + let cage = interface::cagetable_getref(cageid); + // Convert buffer address for writing received data + let buf = translate_vmmap_addr(&cage, arg2).unwrap() as *mut u8; let flag = arg4 as i32; + // Check if address and length arguments are provided let nullity1 = interface::arg_nullity(arg5); let nullity2 = interface::arg_nullity(arg6); // Handle different cases based on address arguments if nullity1 && nullity2 { - interface::cagetable_getref(cageid) - .recvfrom_syscall(fd, buf, buflen, flag, &mut None) - } + // Both address and length are NULL - simple receive + cage.recvfrom_syscall(fd, buf, count, flag, &mut None) + } else if !(nullity1 || nullity2) { - let mut newsockaddr = interface::GenSockaddr::V4(interface::SockaddrV4::default()); //dummy value, rust would complain if we used an uninitialized value here - - let rv = interface::cagetable_getref(cageid) - .recvfrom_syscall(fd, buf, buflen, flag, &mut Some(&mut newsockaddr)); + // Both address and length are provided + // Create a default sockaddr to store the sender's address + let mut newsockaddr = interface::GenSockaddr::V4(interface::SockaddrV4::default()); + // Perform recvfrom operation + let rv = cage.recvfrom_syscall(fd, buf, count, flag, &mut Some(&mut newsockaddr)); if rv >= 0 { // Copy address information back to user space on success interface::copy_out_sockaddr(start_address + arg5, start_address + arg6, newsockaddr); @@ -732,18 +771,21 @@ pub fn lind_syscall_api( SHMAT_SYSCALL => { let shmid = arg1 as i32; - let shmaddr = (start_address + arg2) as *mut u8; + let cage = interface::cagetable_getref(cageid); + // Convert virtual address to physical address + let shmaddr = translate_vmmap_addr(&cage, arg2).unwrap() as *mut u8; let shmflg = arg3 as i32; - - interface::cagetable_getref(cageid) - .shmat_syscall(shmid, shmaddr, shmflg) + // Perform shmat operation through cage implementation + cage.shmat_syscall(shmid, shmaddr, shmflg) } SHMDT_SYSCALL => { - let shmaddr = (start_address + arg1) as *mut u8; + let cage = interface::cagetable_getref(cageid); + // Convert virtual address to physical address + let shmaddr = translate_vmmap_addr(&cage, arg1).unwrap() as *mut u8; - interface::cagetable_getref(cageid) - .shmdt_syscall(shmaddr) + // Perform shmdt operation through cage implementation + cage.shmdt_syscall(shmaddr) } MUTEX_DESTROY_SYSCALL => { @@ -862,13 +904,13 @@ pub fn lind_syscall_api( } PWRITE_SYSCALL => { - let virtual_fd = arg1 as i32; - let buf = (start_address + arg2) as *const u8; let count = arg3 as usize; + let cage = interface::cagetable_getref(cageid); + // Convert buffer address to physical address + let buf = translate_vmmap_addr(&cage, arg2).unwrap() as *const u8; + let virtual_fd = arg1 as i32; let offset = arg4 as i64; - - interface::cagetable_getref(cageid) - .pwrite_syscall(virtual_fd, buf, count, offset) + cage.pwrite_syscall(virtual_fd, buf, count, offset) } GETUID_SYSCALL => { @@ -926,11 +968,12 @@ pub fn lind_syscall_api( let virtual_fd = arg1 as i32; let level = arg2 as i32; let optname = arg3 as i32; - let optval = (start_address + arg4) as *mut u8; - let optlen = arg5 as u32; - - interface::cagetable_getref(cageid) - .setsockopt_syscall( virtual_fd, level, optname, optval, optlen) + let optlen = arg5 as u32; + let cage = interface::cagetable_getref(cageid); + // Convert user space address to physical address + let optval = translate_vmmap_addr(&cage, arg4).unwrap() as *mut u8; + // Perform setsockopt operation through cage implementation + cage.setsockopt_syscall(virtual_fd, level, optname, optval, optlen) } SHUTDOWN_SYSCALL => { @@ -948,13 +991,13 @@ pub fn lind_syscall_api( } SEND_SYSCALL => { - let virtual_fd = arg1 as i32; - let buf = (start_address + arg4) as *const u8; - let buflen = arg3 as usize; + let fd = arg1 as i32; + let count = arg3 as usize; + let cage = interface::cagetable_getref(cageid); + // Convert user space buffer address to physical address + let buf = translate_vmmap_addr(&cage, arg2).unwrap() as *const u8; let flags = arg4 as i32; - - interface::cagetable_getref(cageid) - .send_syscall( virtual_fd, buf, buflen, flags) + cage.send_syscall(fd, buf, count, flags) } LISTEN_SYSCALL => { @@ -975,18 +1018,21 @@ pub fn lind_syscall_api( } GETHOSTNAME_SYSCALL => { - let name = (start_address + arg1) as *mut u8; - let len = arg2 as isize; - let ret = interface::cagetable_getref(cageid) - .gethostname_syscall(name, len); - ret - } + let len = arg2 as usize; + let cage = interface::cagetable_getref(cageid); + // Convert user space buffer address to physical address + let name = translate_vmmap_addr(&cage, arg1).unwrap() as *mut u8; + // Perform gethostname operation through cage implementation + cage.gethostname_syscall(name, len as isize) + } GETIFADDRS_SYSCALL => { - let buf = (start_address + arg1) as *mut u8; let count = arg2 as usize; - interface::cagetable_getref(cageid) - .getifaddrs_syscall(buf, count) + let cage = interface::cagetable_getref(cageid); + // Convert user space buffer address to physical address + let buf = translate_vmmap_addr(&cage, arg1).unwrap() as *mut u8; + // Perform getifaddrs operation through cage implementation + cage.getifaddrs_syscall(buf, count) } KILL_SYSCALL => { @@ -1021,25 +1067,29 @@ pub fn lind_syscall_api( } PIPE_SYSCALL => { - let pipe = interface::get_pipearray(start_address + arg1).unwrap(); - - interface::cagetable_getref(cageid) - .pipe_syscall(pipe) + let cage = interface::cagetable_getref(cageid); + // Convert user space buffer address to physical address + let pipe = interface::get_pipearray(translate_vmmap_addr(&cage, arg1).unwrap() as u64).unwrap(); + cage.pipe_syscall(pipe) } PIPE2_SYSCALL => { - let pipe = interface::get_pipearray(start_address + arg1).unwrap(); + let cage = interface::cagetable_getref(cageid); + // Convert user space buffer address to physical address + let pipe = interface::get_pipearray(translate_vmmap_addr(&cage, arg1).unwrap() as u64).unwrap(); let flag = arg2 as i32; - - interface::cagetable_getref(cageid) - .pipe2_syscall(pipe, flag) + cage.pipe2_syscall(pipe, flag) } GETSOCKNAME_SYSCALL => { let fd = arg1 as i32; - - let mut addr = interface::GenSockaddr::V4(interface::SockaddrV4::default()); //value doesn't matter - + let cage = interface::cagetable_getref(cageid); + // Convert user space buffer addresses to physical addresses + let name_addr = translate_vmmap_addr(&cage, arg2).unwrap(); + let namelen_addr = translate_vmmap_addr(&cage, arg3).unwrap(); + // Initialize default socket address structure + let mut addr = interface::GenSockaddr::V4(interface::SockaddrV4::default()); + // Check for null pointers if interface::arg_nullity(arg2) || interface::arg_nullity(arg3) { return syscall_error( Errno::EINVAL, @@ -1047,12 +1097,10 @@ pub fn lind_syscall_api( "Either the address or the length were null", ); } - - let rv = interface::cagetable_getref(cageid) - .getsockname_syscall(fd, &mut Some(&mut addr)); - + let rv = cage.getsockname_syscall(fd, &mut Some(&mut addr)); + // Copy out the address if operation was successful if rv >= 0 { - interface::copy_out_sockaddr(start_address + arg2, start_address + arg3, addr); + interface::copy_out_sockaddr(name_addr, namelen_addr, addr); } rv } @@ -1061,31 +1109,31 @@ pub fn lind_syscall_api( let virtual_fd = arg1 as i32; let level = arg2 as i32; let optname = arg3 as i32; - - let optval_ptr = (start_address + arg4) as *mut i32; + let cage = interface::cagetable_getref(cageid); + // Convert user space buffer address to physical address + let optval_ptr = translate_vmmap_addr(&cage, arg4).unwrap() as *mut i32; let optval = unsafe { &mut *optval_ptr }; - - interface::cagetable_getref(cageid) - .getsockopt_syscall(virtual_fd, level, optname, optval) + cage.getsockopt_syscall(virtual_fd, level, optname, optval) } SOCKETPAIR_SYSCALL => { let domain = arg1 as i32; let _type = arg2 as i32; let protocol = arg3 as i32; - let virtual_socket_vector = interface::get_sockpair(start_address + arg4).unwrap(); - - interface::cagetable_getref(cageid) - .socketpair_syscall(domain, _type, protocol, virtual_socket_vector) + let cage = interface::cagetable_getref(cageid); + // Convert user space buffer address to physical address + let virtual_socket_vector = interface::get_sockpair(translate_vmmap_addr(&cage, arg4).unwrap() as u64).unwrap(); + cage.socketpair_syscall(domain, _type, protocol, virtual_socket_vector) } POLL_SYSCALL => { let nfds = arg2 as u64; - let pollfds = interface::get_pollstruct_slice(start_address + arg1, nfds as usize).unwrap(); + let cage = interface::cagetable_getref(cageid); + // Convert user space buffer address to physical address + let addr = translate_vmmap_addr(&cage, arg1).unwrap(); + let pollfds = interface::get_pollstruct_slice(addr, nfds as usize).unwrap(); let timeout = arg3 as i32; - - interface::cagetable_getref(cageid) - .poll_syscall(pollfds, nfds, timeout) + cage.poll_syscall(pollfds, nfds, timeout) } GETPID_SYSCALL => { @@ -1100,39 +1148,43 @@ pub fn lind_syscall_api( } FUTEX_SYSCALL => { - let uaddr = (start_address + arg1) as u64; + let cage = interface::cagetable_getref(cageid); + // Convert user space buffer address to physical address + let uaddr = translate_vmmap_addr(&cage, arg1).unwrap(); + // Convert remaining arguments let futex_op = arg2 as u32; let val = arg3 as u32; let timeout = arg4 as u32; let uaddr2 = arg5 as u32; let val3 = arg6 as u32; - - interface::cagetable_getref(cageid) - .futex_syscall(uaddr, futex_op, val, timeout, uaddr2, val3) + cage.futex_syscall(uaddr, futex_op, val, timeout, uaddr2, val3) } NANOSLEEP_TIME64_SYSCALL => { let clockid = arg1 as u32; let flags = arg2 as i32; - let req = (start_address + arg3) as usize; - let rem = (start_address + arg4) as usize; - - interface::cagetable_getref(cageid) - .nanosleep_time64_syscall(clockid, flags, req, rem) + let cage = interface::cagetable_getref(cageid); + // Convert user space buffer address to physical address + let req = translate_vmmap_addr(&cage, arg3).unwrap() as usize; + let rem = translate_vmmap_addr(&cage, arg4).unwrap() as usize; + cage.nanosleep_time64_syscall(clockid, flags, req, rem) } WAIT_SYSCALL => { - let mut status = interface::get_i32_ref(start_address + arg1).unwrap(); - - interface::cagetable_getref(cageid) - .wait_syscall(&mut status) + let cage = interface::cagetable_getref(cageid); + // Convert user space buffer address to physical address + let status_addr = translate_vmmap_addr(&cage, arg1).unwrap() as u64; + let status = interface::get_i32_ref(status_addr).unwrap(); + cage.wait_syscall(status) } WAITPID_SYSCALL => { let pid = arg1 as i32; - let mut status = interface::get_i32_ref(start_address + arg2).unwrap(); - let options = arg3 as i32; let cage = interface::cagetable_getref(cageid); + // Convert user space buffer address to physical address + let status_addr = translate_vmmap_addr(&cage, arg2).unwrap(); + let status = interface::get_i32_ref(status_addr).unwrap(); + let options = arg3 as i32; cage.waitpid_syscall(pid, status, options) } From b80444282c103a978f6708d31159cef74bb63d30 Mon Sep 17 00:00:00 2001 From: ChinmayShringi Date: Tue, 4 Feb 2025 21:33:29 +0000 Subject: [PATCH 53/66] feat: added new line --- src/RawPOSIX/src/interface/mem.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/RawPOSIX/src/interface/mem.rs b/src/RawPOSIX/src/interface/mem.rs index 4988e87a5..ccdfdd379 100644 --- a/src/RawPOSIX/src/interface/mem.rs +++ b/src/RawPOSIX/src/interface/mem.rs @@ -438,4 +438,4 @@ pub fn translate_vmmap_addr(cage: &Cage, arg: u64) -> Result { // Get read lock on virtual memory map let vmmap = cage.vmmap.read(); Ok(vmmap.base_address.unwrap() as u64 + arg) -} \ No newline at end of file +} From 816be2d148adba6fdf9aa295d8c6bad10fd821f7 Mon Sep 17 00:00:00 2001 From: ChinmayShringi Date: Tue, 4 Feb 2025 21:38:52 +0000 Subject: [PATCH 54/66] feat: added comment formatting --- src/RawPOSIX/src/interface/mem.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/RawPOSIX/src/interface/mem.rs b/src/RawPOSIX/src/interface/mem.rs index ccdfdd379..74afb54aa 100644 --- a/src/RawPOSIX/src/interface/mem.rs +++ b/src/RawPOSIX/src/interface/mem.rs @@ -433,7 +433,14 @@ pub fn check_and_convert_addr_ext(cage: &Cage, arg: u64, length: usize, prot: i3 Ok(vmmap.base_address.unwrap() as u64 + arg) } -// Add the base address of the vmmap to the argument +/// This function translates a virtual memory address to a physical address by adding the base address of the vmmap to the argument. +/// +/// # Arguments +/// * `cage` - Reference to the memory cage containing the virtual memory map +/// * `arg` - Virtual memory address to translate +/// +/// # Returns +/// * `Ok(u64)` - Translated physical memory address pub fn translate_vmmap_addr(cage: &Cage, arg: u64) -> Result { // Get read lock on virtual memory map let vmmap = cage.vmmap.read(); From 03e88682c8b8d1be68f336ddc0a61d3151f42020 Mon Sep 17 00:00:00 2001 From: Qianxi Chen Date: Tue, 4 Feb 2025 22:07:59 +0000 Subject: [PATCH 55/66] clean up start address --- src/RawPOSIX/src/interface/mem.rs | 25 ++++++++++++ src/RawPOSIX/src/safeposix/dispatcher.rs | 38 ++++--------------- src/wasmtime/crates/lind-common/src/lib.rs | 1 - .../crates/lind-multi-process/src/lib.rs | 2 - .../crates/wasmtime/src/runtime/instance.rs | 7 ++-- .../crates/wasmtime/src/runtime/vm/memory.rs | 4 +- .../src/runtime/vm/threads/shared_memory.rs | 3 +- src/wasmtime/src/commands/run.rs | 1 - 8 files changed, 40 insertions(+), 41 deletions(-) diff --git a/src/RawPOSIX/src/interface/mem.rs b/src/RawPOSIX/src/interface/mem.rs index 74afb54aa..49a4cf626 100644 --- a/src/RawPOSIX/src/interface/mem.rs +++ b/src/RawPOSIX/src/interface/mem.rs @@ -393,6 +393,31 @@ pub fn brk_handler(cageid: u64, brk: u32) -> i32 { 0 } +// set the wasm linear memory base address to vmmap +pub fn init_vmmap_helper(cageid: u64, base_address: usize, program_break: Option) { + let cage = cagetable_getref(cageid); + let mut vmmap = cage.vmmap.write(); + vmmap.set_base_address(base_address); + if program_break.is_some() { + vmmap.set_program_break(program_break.unwrap()); + } +} + +// clone the cage memory. Invoked by wasmtime after cage is forked +pub fn fork_vmmap_helper(parent_cageid: u64, child_cageid: u64) { + let parent_cage = cagetable_getref(parent_cageid); + let child_cage = cagetable_getref(child_cageid); + let parent_vmmap = parent_cage.vmmap.read(); + let child_vmmap = child_cage.vmmap.read(); + + fork_vmmap(&parent_vmmap, &child_vmmap); + + // update program break for child + drop(child_vmmap); + let mut child_vmmap = child_cage.vmmap.write(); + child_vmmap.set_program_break(parent_vmmap.program_break); +} + /// Validates and converts a virtual memory address to a physical address with protection checks /// /// This function performs several critical memory management operations: diff --git a/src/RawPOSIX/src/safeposix/dispatcher.rs b/src/RawPOSIX/src/safeposix/dispatcher.rs index 01511e93c..824bb970d 100644 --- a/src/RawPOSIX/src/safeposix/dispatcher.rs +++ b/src/RawPOSIX/src/safeposix/dispatcher.rs @@ -177,8 +177,6 @@ pub extern "C" fn rustposix_thread_init(cageid: u64, signalflag: u64) { /// * `call_number` - Unique number for each system call, used to identify which syscall to invoke. /// * `call_name` - A legacy argument from the initial 3i proposal, currently unused and subject to /// change with future 3i integration. -/// * `start_address` - Base address of WebAssembly linear memory, used for address translation -/// between virtual and system memory address. /// * `arg1 - arg6` - Syscall-specific arguments. Any unused argument is set to `0xdeadbeefdeadbeef`. /// /// ### Returns: @@ -191,7 +189,6 @@ pub fn lind_syscall_api( cageid: u64, call_number: u32, call_name: u64, - start_address: u64, arg1: u64, arg2: u64, arg3: u64, @@ -615,9 +612,10 @@ pub fn lind_syscall_api( } IOCTL_SYSCALL => { + let cage = interface::cagetable_getref(cageid); let virtual_fd = arg1 as i32; let request = arg2 as u64; - let ptrunion = (start_address + arg3) as *mut u8; + let ptrunion = translate_vmmap_addr(&cage, arg3).unwrap() as *mut u8; // Perform ioctl operation through cage implementation // Note: We restrict ioctl operations for security @@ -699,11 +697,12 @@ pub fn lind_syscall_api( let cage = interface::cagetable_getref(cageid); // Convert buffer address for reading data to send let buf = translate_vmmap_addr(&cage, arg2).unwrap() as *const u8; + let sockaddr = translate_vmmap_addr(&cage, arg5).unwrap(); let flag = arg4 as i32; // Get and validate socket address let addrlen = arg6 as u32; - let addr = match interface::get_sockaddr(start_address + arg5, addrlen) { + let addr = match interface::get_sockaddr(sockaddr, addrlen) { Ok(addr) => addr, Err(_) => return syscall_error(Errno::EFAULT, "sendto", "invalid socket address"), }; @@ -736,7 +735,9 @@ pub fn lind_syscall_api( let rv = cage.recvfrom_syscall(fd, buf, count, flag, &mut Some(&mut newsockaddr)); if rv >= 0 { // Copy address information back to user space on success - interface::copy_out_sockaddr(start_address + arg5, start_address + arg6, newsockaddr); + interface::copy_out_sockaddr(translate_vmmap_addr(&cage, arg5).unwrap(), + translate_vmmap_addr(&cage, arg6).unwrap(), + newsockaddr); } rv } else { @@ -1207,31 +1208,6 @@ pub fn lind_syscall_api( ret } -// set the wasm linear memory base address to vmmap -pub fn init_vmmap_helper(cageid: u64, base_address: usize, program_break: Option) { - let cage = interface::cagetable_getref(cageid); - let mut vmmap = cage.vmmap.write(); - vmmap.set_base_address(base_address); - if program_break.is_some() { - vmmap.set_program_break(program_break.unwrap()); - } -} - -// clone the cage memory. Invoked by wasmtime after cage is forked -pub fn fork_vmmap_helper(parent_cageid: u64, child_cageid: u64) { - let parent_cage = interface::cagetable_getref(parent_cageid); - let child_cage = interface::cagetable_getref(child_cageid); - let parent_vmmap = parent_cage.vmmap.read(); - let child_vmmap = child_cage.vmmap.read(); - - interface::fork_vmmap(&parent_vmmap, &child_vmmap); - - // update program break for child - drop(child_vmmap); - let mut child_vmmap = child_cage.vmmap.write(); - child_vmmap.set_program_break(parent_vmmap.program_break); -} - #[no_mangle] pub fn lindcancelinit(cageid: u64) { let cage = interface::cagetable_getref(cageid); diff --git a/src/wasmtime/crates/lind-common/src/lib.rs b/src/wasmtime/crates/lind-common/src/lib.rs index 30b7b0638..6e6d58ebe 100644 --- a/src/wasmtime/crates/lind-common/src/lib.rs +++ b/src/wasmtime/crates/lind-common/src/lib.rs @@ -60,7 +60,6 @@ impl LindCommonCtx { self.pid as u64, call_number, call_name, - start_address, arg1, arg2, arg3, diff --git a/src/wasmtime/crates/lind-multi-process/src/lib.rs b/src/wasmtime/crates/lind-multi-process/src/lib.rs index fdc8b6320..00e00cfc2 100644 --- a/src/wasmtime/crates/lind-multi-process/src/lib.rs +++ b/src/wasmtime/crates/lind-multi-process/src/lib.rs @@ -276,7 +276,6 @@ impl>, ) -> Result { // lind-wasm: we enable maximum use of memory at start - maximum = Some(1 << 32); + maximum = Some(MAX_MEMORY_SIZE); // It's a programmer error for these two configuration values to exceed // the host available address space, so panic if such a configuration is // found (mostly an issue for hypothetical 32-bit hosts). diff --git a/src/wasmtime/crates/wasmtime/src/runtime/vm/threads/shared_memory.rs b/src/wasmtime/crates/wasmtime/src/runtime/vm/threads/shared_memory.rs index 9fe5f7901..db19db380 100644 --- a/src/wasmtime/crates/wasmtime/src/runtime/vm/threads/shared_memory.rs +++ b/src/wasmtime/crates/wasmtime/src/runtime/vm/threads/shared_memory.rs @@ -3,6 +3,7 @@ use crate::runtime::vm::memory::{validate_atomic_addr, MmapMemory}; use crate::runtime::vm::threads::parking_spot::{ParkingSpot, Waiter}; use crate::runtime::vm::vmcontext::VMMemoryDefinition; use crate::runtime::vm::{Memory, RuntimeLinearMemory, Store, WaitResult}; +use crate::vm::memory::MAX_MEMORY_SIZE; use std::cell::RefCell; use std::ops::Range; use std::sync::atomic::{AtomicU32, AtomicU64, Ordering}; @@ -34,7 +35,7 @@ impl SharedMemory { let (minimum_bytes, maximum_bytes) = Memory::limit_new(&plan, None)?; let mut mmap_memory = MmapMemory::new(&plan, minimum_bytes, maximum_bytes, None)?; // lind-wasm: we enable maximum use of memory at start - let max_size = 1 << 32; + let max_size = MAX_MEMORY_SIZE; if minimum_bytes < max_size { mmap_memory.grow_to(max_size); } diff --git a/src/wasmtime/src/commands/run.rs b/src/wasmtime/src/commands/run.rs index e4e979f67..266d5e5c7 100644 --- a/src/wasmtime/src/commands/run.rs +++ b/src/wasmtime/src/commands/run.rs @@ -216,7 +216,6 @@ impl RunCommand { 1, EXIT_SYSCALL as u32, 0, - 0, code as u64, 0, 0, From 2739ee5848aa669007e09eeeba316fdb826db727 Mon Sep 17 00:00:00 2001 From: ChinmayShringi Date: Tue, 4 Feb 2025 22:49:11 +0000 Subject: [PATCH 56/66] fix: remove comment headers --- src/RawPOSIX/src/constants/fs_constants.rs | 9 --------- src/RawPOSIX/src/constants/net_constants.rs | 11 ----------- src/RawPOSIX/src/constants/sys_constants.rs | 8 -------- 3 files changed, 28 deletions(-) diff --git a/src/RawPOSIX/src/constants/fs_constants.rs b/src/RawPOSIX/src/constants/fs_constants.rs index 0d73c85f0..40b272d3c 100644 --- a/src/RawPOSIX/src/constants/fs_constants.rs +++ b/src/RawPOSIX/src/constants/fs_constants.rs @@ -1,11 +1,3 @@ -//! File System Constants Module -//! These constants define file system-related flags and parameters -//! -//! Primary Source References: -//! - Linux kernel v6.5: include/uapi/asm-generic/fcntl.h -//! - Linux kernel v6.5: include/uapi/linux/stat.h -//! - POSIX.1-2017 (IEEE Std 1003.1-2017) - #![allow(dead_code)] #![allow(unused_variables)] @@ -188,5 +180,4 @@ pub const MREMAP_FIXED: u32 = 0x02; // New address is specified exactly // ===== File Access Modes ===== // Source: include/uapi/asm-generic/fcntl.h -// NOTE: These should probably be moved to fs_constants.rs pub const O_ACCMODE: i32 = 0o003; // Mask for file access modes diff --git a/src/RawPOSIX/src/constants/net_constants.rs b/src/RawPOSIX/src/constants/net_constants.rs index 55480d0ef..9cfd9213e 100644 --- a/src/RawPOSIX/src/constants/net_constants.rs +++ b/src/RawPOSIX/src/constants/net_constants.rs @@ -1,14 +1,3 @@ -//! Network Constants Module -//! These constants define network-related flags and parameters -//! -//! Primary Source References: -//! - Linux kernel v6.5: include/uapi/linux/socket.h -//! - Linux kernel v6.5: include/uapi/linux/in.h -//! - Linux kernel v6.5: include/uapi/linux/tcp.h -//! - Linux kernel v6.5: include/uapi/linux/poll.h -//! - Linux kernel v6.5: include/uapi/linux/eventpoll.h -//! - POSIX.1-2017 (IEEE Std 1003.1-2017) - #![allow(dead_code)] #![allow(non_upper_case_globals)] diff --git a/src/RawPOSIX/src/constants/sys_constants.rs b/src/RawPOSIX/src/constants/sys_constants.rs index d9c918999..dac7003c7 100644 --- a/src/RawPOSIX/src/constants/sys_constants.rs +++ b/src/RawPOSIX/src/constants/sys_constants.rs @@ -1,11 +1,3 @@ -//! System Constants Module -//! -//! Primary Source References: -//! - Linux kernel v6.5: include/uapi/asm-generic/signal.h -//! - Linux kernel v6.5: include/uapi/asm-generic/resource.h -//! - POSIX.1-2017 (IEEE Std 1003.1-2017) -//! - Linux man-pages project: signal(7) - #![allow(dead_code)] #![allow(unused_variables)] From 1fda11fba0bc0da400aef0ee76a70c9dfbb4040e Mon Sep 17 00:00:00 2001 From: Qianxi Chen Date: Thu, 6 Feb 2025 22:34:04 +0000 Subject: [PATCH 57/66] updated address checking for new syscalls (readlink/readlinkat/clock_gettime) --- src/RawPOSIX/src/interface/mem.rs | 2 -- src/RawPOSIX/src/safeposix/dispatcher.rs | 21 ++++++++++----------- 2 files changed, 10 insertions(+), 13 deletions(-) diff --git a/src/RawPOSIX/src/interface/mem.rs b/src/RawPOSIX/src/interface/mem.rs index 49a4cf626..236797ccf 100644 --- a/src/RawPOSIX/src/interface/mem.rs +++ b/src/RawPOSIX/src/interface/mem.rs @@ -51,8 +51,6 @@ pub fn fork_vmmap(parent_vmmap: &Vmmap, child_vmmap: &Vmmap) { // iterate through each vmmap entry for (_interval, entry) in parent_vmmap.entries.iter() { - // if the entry has PROT_NONE, that means the entry is currently not used - if entry.prot == PROT_NONE { continue; } // translate page number to user address let addr_st = (entry.page_num << PAGESHIFT) as u32; let addr_len = (entry.npages << PAGESHIFT) as usize; diff --git a/src/RawPOSIX/src/safeposix/dispatcher.rs b/src/RawPOSIX/src/safeposix/dispatcher.rs index 08dd9ffe8..1d171fe10 100644 --- a/src/RawPOSIX/src/safeposix/dispatcher.rs +++ b/src/RawPOSIX/src/safeposix/dispatcher.rs @@ -1178,7 +1178,8 @@ pub fn lind_syscall_api( CLOCK_GETTIME_SYSCALL => { let clockid = arg1 as u32; - let tp = (start_address + arg2) as usize; + let cage = interface::cagetable_getref(cageid); + let tp = translate_vmmap_addr(&cage, arg2).unwrap() as usize; interface::cagetable_getref(cageid) .clock_gettime_syscall(clockid, tp) @@ -1216,12 +1217,11 @@ pub fn lind_syscall_api( } READLINK_SYSCALL => { - let path_ptr = (start_address + arg1) as *const u8; - let path = unsafe { - CStr::from_ptr(path_ptr as *const i8).to_str().unwrap() - }; + let cage = interface::cagetable_getref(cageid); + let addr = translate_vmmap_addr(&cage, arg1).unwrap(); + let path = interface::types::get_cstr(addr).unwrap(); - let buf = (start_address + arg2) as *mut u8; + let buf = translate_vmmap_addr(&cage, arg2).unwrap() as *mut u8; let buflen = arg3 as usize; @@ -1232,12 +1232,11 @@ pub fn lind_syscall_api( READLINKAT_SYSCALL => { let fd = arg1 as i32; - let path_ptr = (start_address + arg2) as *const u8; - let path = unsafe { - CStr::from_ptr(path_ptr as *const i8).to_str().unwrap() - }; + let cage = interface::cagetable_getref(cageid); + let addr = translate_vmmap_addr(&cage, arg2).unwrap(); + let path = interface::types::get_cstr(addr).unwrap(); - let buf = (start_address + arg3) as *mut u8; + let buf = translate_vmmap_addr(&cage, arg3).unwrap() as *mut u8; let buflen = arg4 as usize; From 51d7f24a8af515541cb2cfbc8ca3d9a6460ebb5d Mon Sep 17 00:00:00 2001 From: ChinmayShringi Date: Mon, 10 Feb 2025 07:09:21 +0000 Subject: [PATCH 58/66] fix: remove unused constants --- src/RawPOSIX/src/constants/fs_constants.rs | 4 ---- src/RawPOSIX/src/constants/net_constants.rs | 4 +--- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/src/RawPOSIX/src/constants/fs_constants.rs b/src/RawPOSIX/src/constants/fs_constants.rs index 40b272d3c..bd33df19d 100644 --- a/src/RawPOSIX/src/constants/fs_constants.rs +++ b/src/RawPOSIX/src/constants/fs_constants.rs @@ -165,10 +165,6 @@ pub const MAP_ANON: u32 = 0x20; // Don't use a file descriptor pub const PAGESHIFT: u32 = 12; // 4KB pages (1 << 12 = 4096) pub const PAGESIZE: u32 = 1 << PAGESHIFT; -// Lind-specific page size constants -pub const MAP_PAGESHIFT: u32 = 16; // Custom value for Lind -pub const MAP_PAGESIZE: u32 = 1 << MAP_PAGESHIFT; - // ===== Memory Mapping Error Value ===== // Source: include/uapi/asm-generic/mman-common.h pub const MAP_FAILED: *mut std::ffi::c_void = (-1isize) as *mut std::ffi::c_void; diff --git a/src/RawPOSIX/src/constants/net_constants.rs b/src/RawPOSIX/src/constants/net_constants.rs index 9cfd9213e..04e0efcf2 100644 --- a/src/RawPOSIX/src/constants/net_constants.rs +++ b/src/RawPOSIX/src/constants/net_constants.rs @@ -3,7 +3,6 @@ use crate::interface; -// ===== Lind-specific Configuration ===== pub const DEFAULT_HOSTNAME: &str = "Lind"; pub const BLOCK_TIME: interface::RustDuration = interface::RustDuration::from_micros(100); @@ -85,7 +84,6 @@ pub const PF_ATMPVC: i32 = AF_ATMPVC; pub const PF_X25: i32 = AF_X25; pub const PF_INET6: i32 = AF_INET6; pub const PF_ROSE: i32 = AF_ROSE; -pub const PF_DECnet: i32 = AF_DECnet; pub const PF_NETBEUI: i32 = AF_NETBEUI; pub const PF_SECURITY: i32 = AF_SECURITY; pub const PF_KEY: i32 = AF_KEY; @@ -312,7 +310,7 @@ pub const TCP_RXT_FINDROP: i32 = 0x100; // Drop after 3 FIN retransmissions // ===== Socket Object ID Range ===== // Lind-specific constants pub const MINSOCKOBJID: i32 = 0; -pub const MAXSOCKOBJID: i32 = 1024; + // ===== Poll Constants ===== // Source: include/uapi/asm-generic/poll.h From 788dd5484d146f5e4446303cfafbe31858425235 Mon Sep 17 00:00:00 2001 From: ChinmayShringi Date: Mon, 10 Feb 2025 22:05:09 +0000 Subject: [PATCH 59/66] rm: fs constatns --- src/RawPOSIX/src/constants/fs_constants.rs | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/src/RawPOSIX/src/constants/fs_constants.rs b/src/RawPOSIX/src/constants/fs_constants.rs index bd33df19d..2b90de212 100644 --- a/src/RawPOSIX/src/constants/fs_constants.rs +++ b/src/RawPOSIX/src/constants/fs_constants.rs @@ -7,19 +7,7 @@ pub const STDOUT_FILENO: i32 = 1; // File descriptor for standard output pub const STDERR_FILENO: i32 = 2; // File descriptor for standard error // ===== File Descriptor Constants ===== -pub const DT_UNKNOWN: u8 = 0; - -pub const STARTINGFD: i32 = 0; // Starting file descriptor number -pub const MAXFD: i32 = 1024; // Maximum number of file descriptors -pub const STARTINGPIPE: i32 = 0; // Starting pipe descriptor number -pub const MAXPIPE: i32 = 1024; // Maximum number of pipes - -// ===== Inode Constants ===== -pub const ROOTDIRECTORYINODE: usize = 1; // Root directory inode number -pub const STREAMINODE: usize = 2; // Stream inode number - -// ===== Pipe Constants ===== -pub const PIPE_CAPACITY: usize = 65536; // Maximum pipe buffer size +pub const DT_UNKNOWN: u8 = 0; //source: include/dirent.h // ===== File Access Permission Flags ===== pub const F_OK: u32 = 0; // Test for existence @@ -45,8 +33,6 @@ pub const O_SYNC: i32 = 0o10000; // Synchronous writes pub const O_ASYNC: i32 = 0o20000; // Signal-driven I/O pub const O_CLOEXEC: i32 = 0o2000000; // Close on exec -pub const DEFAULTTIME: u64 = 1323630836; // Default timestamp value - // ===== File Permissions ===== // Source: include/uapi/linux/stat.h pub const S_IRWXA: u32 = 0o777; // All permissions for all users From 194743a7d246b89484027580e53ec15c5256fd78 Mon Sep 17 00:00:00 2001 From: ChinmayShringi Date: Mon, 10 Feb 2025 22:10:40 +0000 Subject: [PATCH 60/66] feat: add root --- src/RawPOSIX/src/constants/fs_constants.rs | 3 +++ src/RawPOSIX/src/safeposix/syscalls/fs_calls.rs | 5 ++--- src/RawPOSIX/src/safeposix/syscalls/net_calls.rs | 3 +-- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/RawPOSIX/src/constants/fs_constants.rs b/src/RawPOSIX/src/constants/fs_constants.rs index 2b90de212..95e69f7ba 100644 --- a/src/RawPOSIX/src/constants/fs_constants.rs +++ b/src/RawPOSIX/src/constants/fs_constants.rs @@ -1,6 +1,9 @@ #![allow(dead_code)] #![allow(unused_variables)] +// Root directory for Lind filesystem +pub const LIND_ROOT: &str = "/home/lind/lind-wasm/src/RawPOSIX/tmp"; + // ===== Standard File Descriptors ===== pub const STDIN_FILENO: i32 = 0; // File descriptor for standard input pub const STDOUT_FILENO: i32 = 1; // File descriptor for standard output diff --git a/src/RawPOSIX/src/safeposix/syscalls/fs_calls.rs b/src/RawPOSIX/src/safeposix/syscalls/fs_calls.rs index 6169915fd..2c93e30e1 100644 --- a/src/RawPOSIX/src/safeposix/syscalls/fs_calls.rs +++ b/src/RawPOSIX/src/safeposix/syscalls/fs_calls.rs @@ -11,7 +11,8 @@ use crate::constants::{ SEEK_SET, SEEK_CUR, SEEK_END, SHMMIN, SHMMAX, SHM_RDONLY, SHM_DEST, DEFAULT_UID, DEFAULT_GID, - SEM_VALUE_MAX, STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO + SEM_VALUE_MAX, STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO, + LIND_ROOT }; use crate::interface; @@ -38,8 +39,6 @@ use std::mem; use crate::fdtables; use crate::safeposix::cage::Cage; -static LIND_ROOT: &str = "/home/lind-wasm/src/RawPOSIX/tmp"; - const FDKIND_KERNEL: u32 = 0; const FDKIND_IMPIPE: u32 = 1; diff --git a/src/RawPOSIX/src/safeposix/syscalls/net_calls.rs b/src/RawPOSIX/src/safeposix/syscalls/net_calls.rs index e0f1dd4d8..2ec479dd9 100644 --- a/src/RawPOSIX/src/safeposix/syscalls/net_calls.rs +++ b/src/RawPOSIX/src/safeposix/syscalls/net_calls.rs @@ -3,7 +3,7 @@ use crate::constants::net_constants; use crate::{interface::FdSet, safeposix::cage::*}; use crate::interface::*; use crate::interface; -use crate::constants::sys_constants; +use crate::constants::{sys_constants,LIND_ROOT}; use crate::fdtables::{self, FDTableEntry}; @@ -27,7 +27,6 @@ use libc::*; use std::{os::fd::RawFd, ptr}; use bit_set::BitSet; -static LIND_ROOT: &str = "/home/lind-wasm/src/RawPOSIX/tmp"; const FDKIND_KERNEL: u32 = 0; const FDKIND_IMPIPE: u32 = 1; const FDKIND_IMSOCK: u32 = 2; From b3fa91a80095a79c8b91680cea9c2a2bf52af37a Mon Sep 17 00:00:00 2001 From: ChinmayShringi Date: Mon, 10 Feb 2025 22:13:41 +0000 Subject: [PATCH 61/66] rm: socket obj --- src/RawPOSIX/src/constants/net_constants.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/RawPOSIX/src/constants/net_constants.rs b/src/RawPOSIX/src/constants/net_constants.rs index 04e0efcf2..1b514ca85 100644 --- a/src/RawPOSIX/src/constants/net_constants.rs +++ b/src/RawPOSIX/src/constants/net_constants.rs @@ -307,10 +307,6 @@ pub const PERSIST_TIMEOUT: i32 = 0x40; // Persist timeout pub const TCP_RXT_CONNDROPTIME: i32 = 0x80; // Retransmission timeout before drop pub const TCP_RXT_FINDROP: i32 = 0x100; // Drop after 3 FIN retransmissions -// ===== Socket Object ID Range ===== -// Lind-specific constants -pub const MINSOCKOBJID: i32 = 0; - // ===== Poll Constants ===== // Source: include/uapi/asm-generic/poll.h From 8d1e3e2856d57755ee5807e8fa21ee302e5d4bb7 Mon Sep 17 00:00:00 2001 From: ChinmayShringi Date: Tue, 11 Feb 2025 01:59:21 +0000 Subject: [PATCH 62/66] feat: updated constant --- src/RawPOSIX/src/constants/fs_constants.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/RawPOSIX/src/constants/fs_constants.rs b/src/RawPOSIX/src/constants/fs_constants.rs index 95e69f7ba..abedd1d2b 100644 --- a/src/RawPOSIX/src/constants/fs_constants.rs +++ b/src/RawPOSIX/src/constants/fs_constants.rs @@ -9,7 +9,7 @@ pub const STDIN_FILENO: i32 = 0; // File descriptor for standard input pub const STDOUT_FILENO: i32 = 1; // File descriptor for standard output pub const STDERR_FILENO: i32 = 2; // File descriptor for standard error -// ===== File Descriptor Constants ===== +// ===== Directory Entry Constant ===== pub const DT_UNKNOWN: u8 = 0; //source: include/dirent.h // ===== File Access Permission Flags ===== From ef31fb91485a1021a84bdac538f08568b5fb2008 Mon Sep 17 00:00:00 2001 From: ChinmayShringi Date: Tue, 11 Feb 2025 02:25:50 +0000 Subject: [PATCH 63/66] feat: added source before constants --- src/RawPOSIX/src/constants/fs_constants.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/RawPOSIX/src/constants/fs_constants.rs b/src/RawPOSIX/src/constants/fs_constants.rs index abedd1d2b..e2e561ef9 100644 --- a/src/RawPOSIX/src/constants/fs_constants.rs +++ b/src/RawPOSIX/src/constants/fs_constants.rs @@ -10,7 +10,8 @@ pub const STDOUT_FILENO: i32 = 1; // File descriptor for standard output pub const STDERR_FILENO: i32 = 2; // File descriptor for standard error // ===== Directory Entry Constant ===== -pub const DT_UNKNOWN: u8 = 0; //source: include/dirent.h +// Source: include/dirent.h +pub const DT_UNKNOWN: u8 = 0; // ===== File Access Permission Flags ===== pub const F_OK: u32 = 0; // Test for existence @@ -26,6 +27,7 @@ pub const O_RDWR: i32 = 0o2; // Open read-write pub const O_RDWRFLAGS: i32 = 0o3; // Mask for access modes // ===== File Creation and Status Flags ===== +// Source: include/linux/coda.h pub const O_CREAT: i32 = 0o100; // Create file if it doesn't exist pub const O_EXCL: i32 = 0o200; // Error if O_CREAT and file exists pub const O_NOCTTY: i32 = 0o400; // Don't assign controlling terminal @@ -53,6 +55,7 @@ pub const S_IWOTH: u32 = 0o002; // Others write pub const S_IXOTH: u32 = 0o001; // Others execute //Commands for FCNTL +// Source: include/linux/fcntl.h pub const F_DUPFD: i32 = 0; pub const F_GETFD: i32 = 1; pub const F_SETFD: i32 = 2; @@ -77,6 +80,7 @@ pub const FIONBIO: u32 = 21537; pub const FIOASYNC: u32 = 21586; //File types for open/stat etc. +// Source: include/linux/stat.h pub const S_IFBLK: i32 = 0o60000; pub const S_IFCHR: i32 = 0o20000; pub const S_IFDIR: i32 = 0o40000; @@ -97,11 +101,12 @@ pub const MAP_ANONYMOUS: u32 = 32; pub const MAP_HUGE_SHIFT: i32 = 26; pub const MAP_HUGETLB: i32 = 262144; - +// Source: include/linux/fs.h pub const SEEK_SET: i32 = 0; // Seek from beginning of file pub const SEEK_CUR: i32 = 1; // Seek from current position pub const SEEK_END: i32 = 2; // Seek from end of file +// Source: include/linux/ipc.h pub const IPC_PRIVATE: i32 = 0o0; pub const IPC_CREAT: i32 = 0o1000; pub const IPC_EXCL: i32 = 0o2000; @@ -110,6 +115,7 @@ pub const IPC_RMID: i32 = 0; pub const IPC_SET: i32 = 1; pub const IPC_STAT: i32 = 2; +// Source: linux/bits/shm.h pub const SHM_DEST: i32 = 0o1000; // Destroy segment when last process detaches pub const SHM_LOCKED: i32 = 0o2000; // Lock segment in memory pub const SHM_HUGETLB: i32 = 0o4000; // Use huge TLB pages From 3746f49890542fd26c52594d009041ee9bb3780e Mon Sep 17 00:00:00 2001 From: ChinmayShringi Date: Tue, 11 Feb 2025 04:39:37 +0000 Subject: [PATCH 64/66] fix: removed hostname and blocktime --- src/RawPOSIX/src/constants/net_constants.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/RawPOSIX/src/constants/net_constants.rs b/src/RawPOSIX/src/constants/net_constants.rs index 1b514ca85..4f0701e28 100644 --- a/src/RawPOSIX/src/constants/net_constants.rs +++ b/src/RawPOSIX/src/constants/net_constants.rs @@ -3,9 +3,6 @@ use crate::interface; -pub const DEFAULT_HOSTNAME: &str = "Lind"; -pub const BLOCK_TIME: interface::RustDuration = interface::RustDuration::from_micros(100); - // ===== Socket Types ===== // Source: include/linux/net.h pub const SOCK_STREAM: i32 = 1; // Stream (connection) socket From 1f22d50ee19266c6e90d6dfbd87e4baf8feed6bb Mon Sep 17 00:00:00 2001 From: Qianxi Chen Date: Wed, 12 Feb 2025 17:02:51 +0000 Subject: [PATCH 65/66] delete getifaddrs --- src/RawPOSIX/src/safeposix/dispatcher.rs | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/RawPOSIX/src/safeposix/dispatcher.rs b/src/RawPOSIX/src/safeposix/dispatcher.rs index e74145944..b72104119 100644 --- a/src/RawPOSIX/src/safeposix/dispatcher.rs +++ b/src/RawPOSIX/src/safeposix/dispatcher.rs @@ -1031,15 +1031,6 @@ pub fn lind_syscall_api( cage.gethostname_syscall(name, len as isize) } - GETIFADDRS_SYSCALL => { - let count = arg2 as usize; - let cage = interface::cagetable_getref(cageid); - // Convert user space buffer address to physical address - let buf = translate_vmmap_addr(&cage, arg1).unwrap() as *mut u8; - // Perform getifaddrs operation through cage implementation - cage.getifaddrs_syscall(buf, count) - } - KILL_SYSCALL => { let cage_id = arg1 as i32; let sig = arg2 as i32; From 9fdc5822864968eca5df2cdc74f778718ba28657 Mon Sep 17 00:00:00 2001 From: Qianxi Chen Date: Wed, 12 Feb 2025 19:41:26 +0000 Subject: [PATCH 66/66] updated some comments --- src/RawPOSIX/src/safeposix/syscalls/sys_calls.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/RawPOSIX/src/safeposix/syscalls/sys_calls.rs b/src/RawPOSIX/src/safeposix/syscalls/sys_calls.rs index 0a43f6485..61ee4fdd6 100644 --- a/src/RawPOSIX/src/safeposix/syscalls/sys_calls.rs +++ b/src/RawPOSIX/src/safeposix/syscalls/sys_calls.rs @@ -179,7 +179,7 @@ impl Cage { sigset: newsigset, main_threadid: interface::RustAtomicU64::new(0), interval_timer: interface::IntervalTimer::new(child_cageid), - vmmap: interface::RustLock::new(new_vmmap), // Initialize empty virtual memory map for new process + vmmap: interface::RustLock::new(new_vmmap), // clone the vmmap for the child zombies: interface::RustLock::new(vec![]), child_num: interface::RustAtomicU64::new(0), }; @@ -262,9 +262,8 @@ impl Cage { sigset: newsigset, main_threadid: interface::RustAtomicU64::new(0), interval_timer: self.interval_timer.clone_with_new_cageid(child_cageid), - vmmap: interface::RustLock::new(Vmmap::new()), // Fresh clean vmmap - // when a process exec-ed, its child relationship should be perserved - zombies: interface::RustLock::new(cloned_zombies), + vmmap: interface::RustLock::new(Vmmap::new()), // memory is cleared after exec + zombies: interface::RustLock::new(cloned_zombies), // when a process exec-ed, its child relationship should be perserved child_num: interface::RustAtomicU64::new(child_num), }; //wasteful clone of fdtable, but mutability constraints exist