diff --git a/api/src/mm.rs b/api/src/mm.rs index a6c8c695..b1092f6c 100644 --- a/api/src/mm.rs +++ b/api/src/mm.rs @@ -1,10 +1,8 @@ use alloc::string::String; use core::{ - alloc::Layout, ffi::c_char, hint::unlikely, mem::{MaybeUninit, transmute}, - ptr, slice, str, }; use axerrno::{AxError, AxResult}; @@ -14,226 +12,10 @@ use axhal::{ }; use axio::prelude::*; use axtask::current; -use memory_addr::{MemoryAddr, PAGE_SIZE_4K, VirtAddr}; -use starry_core::{mm::access_user_memory, task::AsThread}; +use memory_addr::VirtAddr; +use starry_core::task::AsThread; use starry_vm::{vm_load_until_nul, vm_read_slice, vm_write_slice}; -fn check_region(start: VirtAddr, layout: Layout, access_flags: MappingFlags) -> AxResult<()> { - let align = layout.align(); - if start.as_usize() & (align - 1) != 0 { - return Err(AxError::BadAddress); - } - - let curr = current(); - let mut aspace = curr.as_thread().proc_data.aspace.lock(); - - if !aspace.can_access_range(start, layout.size(), access_flags) { - return Err(AxError::BadAddress); - } - - let page_start = start.align_down_4k(); - let page_end = (start + layout.size()).align_up_4k(); - aspace.populate_area(page_start, page_end - page_start, access_flags)?; - - Ok(()) -} - -fn check_null_terminated( - start: VirtAddr, - access_flags: MappingFlags, -) -> AxResult { - let align = Layout::new::().align(); - if start.as_usize() & (align - 1) != 0 { - return Err(AxError::BadAddress); - } - - let zero = T::default(); - - let mut page = start.align_down_4k(); - - let start = start.as_ptr_of::(); - let mut len = 0; - - access_user_memory(|| { - loop { - // SAFETY: This won't overflow the address space since we'll check - // it below. - let ptr = unsafe { start.add(len) }; - while ptr as usize >= page.as_ptr() as usize { - // We cannot prepare `aspace` outside of the loop, since holding - // aspace requires a mutex which would be required on page - // fault, and page faults can trigger inside the loop. - - // TODO: this is inefficient, but we have to do this instead of - // querying the page table since the page might has not been - // allocated yet. - let curr = current(); - let aspace = curr.as_thread().proc_data.aspace.lock(); - if !aspace.can_access_range(page, PAGE_SIZE_4K, access_flags) { - return Err(AxError::BadAddress); - } - - page += PAGE_SIZE_4K; - } - - // This might trigger a page fault - // SAFETY: The pointer is valid and points to a valid memory region. - if unsafe { ptr.read_volatile() } == zero { - break; - } - len += 1; - } - Ok(()) - })?; - - Ok(len) -} - -/// A pointer to user space memory. -#[repr(transparent)] -#[derive(PartialEq, Clone, Copy)] -pub struct UserPtr(*mut T); - -impl From for UserPtr { - fn from(value: usize) -> Self { - UserPtr(value as *mut _) - } -} - -impl From<*mut T> for UserPtr { - fn from(value: *mut T) -> Self { - UserPtr(value) - } -} - -impl Default for UserPtr { - fn default() -> Self { - Self(ptr::null_mut()) - } -} - -impl UserPtr { - const ACCESS_FLAGS: MappingFlags = MappingFlags::READ.union(MappingFlags::WRITE); - - pub fn address(&self) -> VirtAddr { - VirtAddr::from_ptr_of(self.0) - } - - pub fn cast(self) -> UserPtr { - UserPtr(self.0 as *mut U) - } - - pub fn is_null(&self) -> bool { - self.0.is_null() - } - - pub fn get_as_mut(self) -> AxResult<&'static mut T> { - check_region(self.address(), Layout::new::(), Self::ACCESS_FLAGS)?; - Ok(unsafe { &mut *self.0 }) - } - - pub fn get_as_mut_slice(self, len: usize) -> AxResult<&'static mut [T]> { - check_region( - self.address(), - Layout::array::(len).unwrap(), - Self::ACCESS_FLAGS, - )?; - Ok(unsafe { slice::from_raw_parts_mut(self.0, len) }) - } - - pub fn get_as_mut_null_terminated(self) -> AxResult<&'static mut [T]> - where - T: PartialEq + Default, - { - let len = check_null_terminated::(self.address(), Self::ACCESS_FLAGS)?; - Ok(unsafe { slice::from_raw_parts_mut(self.0, len) }) - } -} - -/// An immutable pointer to user space memory. -#[repr(transparent)] -#[derive(PartialEq, Clone, Copy)] -pub struct UserConstPtr(*const T); - -impl From for UserConstPtr { - fn from(value: usize) -> Self { - UserConstPtr(value as *const _) - } -} - -impl From<*const T> for UserConstPtr { - fn from(value: *const T) -> Self { - UserConstPtr(value) - } -} - -impl Default for UserConstPtr { - fn default() -> Self { - Self(ptr::null()) - } -} - -impl UserConstPtr { - const ACCESS_FLAGS: MappingFlags = MappingFlags::READ; - - pub fn address(&self) -> VirtAddr { - VirtAddr::from_ptr_of(self.0) - } - - pub fn cast(self) -> UserConstPtr { - UserConstPtr(self.0 as *const U) - } - - pub fn is_null(&self) -> bool { - self.0.is_null() - } - - pub fn get_as_ref(self) -> AxResult<&'static T> { - check_region(self.address(), Layout::new::(), Self::ACCESS_FLAGS)?; - Ok(unsafe { &*self.0 }) - } - - pub fn get_as_slice(self, len: usize) -> AxResult<&'static [T]> { - check_region( - self.address(), - Layout::array::(len).unwrap(), - Self::ACCESS_FLAGS, - )?; - Ok(unsafe { slice::from_raw_parts(self.0, len) }) - } - - pub fn get_as_null_terminated(self) -> AxResult<&'static [T]> - where - T: PartialEq + Default, - { - let len = check_null_terminated::(self.address(), Self::ACCESS_FLAGS)?; - Ok(unsafe { slice::from_raw_parts(self.0, len) }) - } -} - -impl UserConstPtr { - /// Get the pointer as `&str`, validating the memory region. - pub fn get_as_str(self) -> AxResult<&'static str> { - let slice = self.get_as_null_terminated()?; - // SAFETY: c_char is u8 - let slice = unsafe { transmute::<&[c_char], &[u8]>(slice) }; - - str::from_utf8(slice).map_err(|_| AxError::IllegalBytes) - } -} - -macro_rules! nullable { - ($ptr:ident.$func:ident($($arg:expr),*)) => { - if $ptr.is_null() { - Ok(None) - } else { - Some($ptr.$func($($arg),*)).transpose() - } - }; -} - -pub(crate) use nullable; - #[register_trap_handler(PAGE_FAULT)] fn handle_page_fault(vaddr: VirtAddr, access_flags: MappingFlags) -> bool { debug!("Page fault at {vaddr:#x}, access_flags: {access_flags:#x?}"); diff --git a/api/src/socket.rs b/api/src/socket.rs index 6c502fa7..1dcb3607 100644 --- a/api/src/socket.rs +++ b/api/src/socket.rs @@ -12,45 +12,44 @@ use axerrno::{AxError, AxResult, LinuxError}; use axnet::vsock::VsockAddr; use axnet::{SocketAddrEx, unix::UnixSocketAddr}; use linux_raw_sys::net::*; - -use crate::mm::{UserConstPtr, UserPtr}; +use starry_vm::{VmMutPtr, VmPtr, vm_load, vm_write_slice}; /// Trait to extend [`SocketAddr`] and its variants with methods for reading /// from and writing to user space. pub trait SocketAddrExt: Sized { /// This method attempts to interpret the data pointed to by `addr` with the /// given `addrlen` as a valid socket address of the implementing type. - fn read_from_user(addr: UserConstPtr, addrlen: socklen_t) -> AxResult; + fn read_from_user(addr: *const sockaddr, addrlen: socklen_t) -> AxResult; /// This method serializes the current socket address instance into the /// [`sockaddr`] structure pointed to by `addr` in user space. - fn write_to_user(&self, addr: UserPtr, addrlen: &mut socklen_t) -> AxResult<()>; + fn write_to_user(&self, addr: *mut sockaddr, addrlen: *mut socklen_t) -> AxResult<()>; /// Gets the address family of the socket address. fn family(&self) -> u16; } -fn read_family(addr: UserConstPtr, addrlen: socklen_t) -> AxResult { +fn read_family(addr: *const sockaddr, addrlen: socklen_t) -> AxResult { if size_of::<__kernel_sa_family_t>() > addrlen as usize { return Err(AxError::InvalidInput); } - let family = *addr.cast::<__kernel_sa_family_t>().get_as_ref()?; + let family = addr.cast::<__kernel_sa_family_t>().vm_read()?; Ok(family) } + unsafe fn cast_to_slice(value: &T) -> &[u8] { unsafe { core::slice::from_raw_parts(value as *const T as *const u8, size_of::()) } } -fn fill_addr(addr: UserPtr, addrlen: &mut socklen_t, data: &[u8]) -> AxResult<()> { - let len = (*addrlen as usize).min(data.len()); - addr.cast::() - .get_as_mut_slice(len)? - .copy_from_slice(&data[..len]); - *addrlen = data.len() as _; + +fn fill_addr(addr: *mut sockaddr, addrlen: *mut socklen_t, data: &[u8]) -> AxResult<()> { + let len = (addrlen.vm_read()? as usize).min(data.len()); + vm_write_slice(addr.cast::(), &data[..len])?; + addrlen.vm_write(data.len() as _)?; Ok(()) } impl SocketAddrExt for SocketAddr { - fn read_from_user(addr: UserConstPtr, addrlen: socklen_t) -> AxResult { + fn read_from_user(addr: *const sockaddr, addrlen: socklen_t) -> AxResult { match read_family(addr, addrlen)? as u32 { AF_INET => SocketAddrV4::read_from_user(addr, addrlen).map(Self::V4), AF_INET6 => SocketAddrV6::read_from_user(addr, addrlen).map(Self::V6), @@ -58,7 +57,7 @@ impl SocketAddrExt for SocketAddr { } } - fn write_to_user(&self, addr: UserPtr, addrlen: &mut socklen_t) -> AxResult<()> { + fn write_to_user(&self, addr: *mut sockaddr, addrlen: *mut socklen_t) -> AxResult<()> { match self { SocketAddr::V4(v4) => v4.write_to_user(addr, addrlen), SocketAddr::V6(v6) => v6.write_to_user(addr, addrlen), @@ -74,11 +73,11 @@ impl SocketAddrExt for SocketAddr { } impl SocketAddrExt for SocketAddrV4 { - fn read_from_user(addr: UserConstPtr, addrlen: socklen_t) -> AxResult { + fn read_from_user(addr: *const sockaddr, addrlen: socklen_t) -> AxResult { if addrlen != size_of::() as socklen_t { return Err(AxError::InvalidInput); } - let addr_in = addr.cast::().get_as_ref()?; + let addr_in = unsafe { addr.cast::().vm_read_uninit()?.assume_init() }; if addr_in.sin_family as u32 != AF_INET { return Err(AxError::from(LinuxError::EAFNOSUPPORT)); } @@ -89,7 +88,7 @@ impl SocketAddrExt for SocketAddrV4 { )) } - fn write_to_user(&self, addr: UserPtr, addrlen: &mut socklen_t) -> AxResult<()> { + fn write_to_user(&self, addr: *mut sockaddr, addrlen: *mut socklen_t) -> AxResult<()> { let sockin_addr = sockaddr_in { sin_family: AF_INET as _, sin_port: self.port().to_be(), @@ -107,11 +106,11 @@ impl SocketAddrExt for SocketAddrV4 { } impl SocketAddrExt for SocketAddrV6 { - fn read_from_user(addr: UserConstPtr, addrlen: socklen_t) -> AxResult { + fn read_from_user(addr: *const sockaddr, addrlen: socklen_t) -> AxResult { if addrlen != size_of::() as socklen_t { return Err(AxError::InvalidInput); } - let addr_in6 = addr.cast::().get_as_ref()?; + let addr_in6 = unsafe { addr.cast::().vm_read_uninit()?.assume_init() }; if addr_in6.sin6_family as u32 != AF_INET6 { return Err(AxError::from(LinuxError::EAFNOSUPPORT)); } @@ -124,7 +123,7 @@ impl SocketAddrExt for SocketAddrV6 { )) } - fn write_to_user(&self, addr: UserPtr, addrlen: &mut socklen_t) -> AxResult<()> { + fn write_to_user(&self, addr: *mut sockaddr, addrlen: *mut socklen_t) -> AxResult<()> { let sockin_addr = sockaddr_in6 { sin6_family: AF_INET6 as _, sin6_port: self.port().to_be(), @@ -145,13 +144,15 @@ impl SocketAddrExt for SocketAddrV6 { } impl SocketAddrExt for UnixSocketAddr { - fn read_from_user(addr: UserConstPtr, addrlen: socklen_t) -> AxResult { + fn read_from_user(addr: *const sockaddr, addrlen: socklen_t) -> AxResult { if read_family(addr, addrlen)? as u32 != AF_UNIX { return Err(AxError::from(LinuxError::EAFNOSUPPORT)); } let offset = size_of::<__kernel_sa_family_t>(); - let ptr = UserConstPtr::::from(addr.address().as_usize() + offset); - let data = ptr.get_as_slice(addrlen as usize - offset)?; + let base = addr.cast::().wrapping_add(offset); + let len = addrlen as usize - offset; + let data = vm_load(base, len)?; + Ok(if data.is_empty() { Self::Unnamed } else if data[0] == 0 { @@ -166,7 +167,7 @@ impl SocketAddrExt for UnixSocketAddr { }) } - fn write_to_user(&self, addr: UserPtr, addrlen: &mut socklen_t) -> AxResult<()> { + fn write_to_user(&self, addr: *mut sockaddr, addrlen: *mut socklen_t) -> AxResult<()> { let data_len = match self { UnixSocketAddr::Unnamed => 0, UnixSocketAddr::Abstract(name) => name.len() + 1, @@ -210,12 +211,12 @@ pub struct sockaddr_vm { #[cfg(feature = "vsock")] impl SocketAddrExt for VsockAddr { - fn read_from_user(addr: UserConstPtr, addrlen: socklen_t) -> AxResult { + fn read_from_user(addr: *const sockaddr, addrlen: socklen_t) -> AxResult { if addrlen != size_of::() as socklen_t { return Err(AxError::InvalidInput); } - let addr_vsock = addr.cast::().get_as_ref()?; + let addr_vsock = unsafe { addr.cast::().vm_read_uninit()?.assume_init() }; if addr_vsock.svm_family as u32 != AF_VSOCK { return Err(AxError::from(LinuxError::EAFNOSUPPORT)); } @@ -225,7 +226,7 @@ impl SocketAddrExt for VsockAddr { }) } - fn write_to_user(&self, addr: UserPtr, addrlen: &mut socklen_t) -> AxResult<()> { + fn write_to_user(&self, addr: *mut sockaddr, addrlen: *mut socklen_t) -> AxResult<()> { let sockvm_addr = sockaddr_vm { svm_family: AF_VSOCK as _, svm_reserved1: 0, @@ -242,7 +243,7 @@ impl SocketAddrExt for VsockAddr { } impl SocketAddrExt for SocketAddrEx { - fn read_from_user(addr: UserConstPtr, addrlen: socklen_t) -> AxResult { + fn read_from_user(addr: *const sockaddr, addrlen: socklen_t) -> AxResult { match read_family(addr, addrlen)? as u32 { AF_INET | AF_INET6 => SocketAddr::read_from_user(addr, addrlen).map(Self::Ip), AF_UNIX => UnixSocketAddr::read_from_user(addr, addrlen).map(Self::Unix), @@ -252,7 +253,7 @@ impl SocketAddrExt for SocketAddrEx { } } - fn write_to_user(&self, addr: UserPtr, addrlen: &mut socklen_t) -> AxResult<()> { + fn write_to_user(&self, addr: *mut sockaddr, addrlen: *mut socklen_t) -> AxResult<()> { match self { SocketAddrEx::Ip(ip_addr) => ip_addr.write_to_user(addr, addrlen), SocketAddrEx::Unix(unix_addr) => unix_addr.write_to_user(addr, addrlen), diff --git a/api/src/syscall/fs/fd_ops.rs b/api/src/syscall/fs/fd_ops.rs index 825ee48b..e67648d7 100644 --- a/api/src/syscall/fs/fd_ops.rs +++ b/api/src/syscall/fs/fd_ops.rs @@ -12,13 +12,14 @@ use axtask::current; use bitflags::bitflags; use linux_raw_sys::general::*; use starry_core::{task::AsThread, vfs::Device}; +use starry_vm::{VmMutPtr, VmPtr}; use crate::{ file::{ Directory, FD_TABLE, File, FileLike, Pipe, add_file_like, close_file_like, get_file_like, with_fs, }, - mm::{UserPtr, vm_load_string}, + mm::vm_load_string, syscall::sys::{sys_getegid, sys_geteuid}, vfs::dev::tty, }; @@ -245,8 +246,10 @@ pub fn sys_fcntl(fd: c_int, cmd: c_int, arg: usize) -> AxResult { F_SETLK | F_SETLKW => Ok(0), F_OFD_SETLK | F_OFD_SETLKW => Ok(0), F_GETLK | F_OFD_GETLK => { - let arg = UserPtr::::from(arg); - arg.get_as_mut()?.l_type = F_UNLCK as _; + let ptr = arg as *mut flock64; + let mut lock = unsafe { ptr.vm_read_uninit()?.assume_init() }; + lock.l_type = F_UNLCK as _; + ptr.vm_write(lock)?; Ok(0) } F_SETFL => { diff --git a/api/src/syscall/fs/io.rs b/api/src/syscall/fs/io.rs index a3be9d4a..e24f5fe6 100644 --- a/api/src/syscall/fs/io.rs +++ b/api/src/syscall/fs/io.rs @@ -16,7 +16,7 @@ use syscalls::Sysno; use crate::{ file::{File, FileLike, Pipe, get_file_like}, io::{IoVec, IoVectorBuf}, - mm::{UserConstPtr, VmBytes, VmBytesMut}, + mm::{VmBytes, VmBytesMut, vm_load_string}, }; struct DummyFd; @@ -85,8 +85,8 @@ pub fn sys_lseek(fd: c_int, offset: __kernel_off_t, whence: c_int) -> AxResult, length: __kernel_off_t) -> AxResult { - let path = path.get_as_str()?; +pub fn sys_truncate(path: *const c_char, length: __kernel_off_t) -> AxResult { + let path = vm_load_string(path)?; debug!("sys_truncate <= {path:?} {length}"); if length < 0 { return Err(AxError::InvalidInput); diff --git a/api/src/syscall/fs/memfd.rs b/api/src/syscall/fs/memfd.rs index 147a94e2..0b861421 100644 --- a/api/src/syscall/fs/memfd.rs +++ b/api/src/syscall/fs/memfd.rs @@ -5,14 +5,11 @@ use axerrno::{AxError, AxResult}; use axfs::{FS_CONTEXT, OpenOptions}; use linux_raw_sys::general::MFD_CLOEXEC; -use crate::{ - file::{File, FileLike}, - mm::UserConstPtr, -}; +use crate::file::{File, FileLike}; // TODO: correct memfd implementation -pub fn sys_memfd_create(_name: UserConstPtr, flags: u32) -> AxResult { +pub fn sys_memfd_create(_name: *const c_char, flags: u32) -> AxResult { // This is cursed for id in 0..0xffff { let name = format!("/tmp/memfd-{id:04x}"); diff --git a/api/src/syscall/io_mpx/epoll.rs b/api/src/syscall/io_mpx/epoll.rs index 05b76286..1cb9ae2f 100644 --- a/api/src/syscall/io_mpx/epoll.rs +++ b/api/src/syscall/io_mpx/epoll.rs @@ -1,3 +1,4 @@ +use alloc::vec; use core::time::Duration; use axerrno::{AxError, AxResult}; @@ -8,13 +9,13 @@ use linux_raw_sys::general::{ EPOLL_CLOEXEC, EPOLL_CTL_ADD, EPOLL_CTL_DEL, EPOLL_CTL_MOD, epoll_event, timespec, }; use starry_signal::SignalSet; +use starry_vm::{VmMutPtr, VmPtr}; use crate::{ file::{ FileLike, epoll::{Epoll, EpollEvent, EpollFlags}, }, - mm::{UserConstPtr, UserPtr, nullable}, signal::with_replacen_blocked, syscall::signal::check_sigset_size, time::TimeValueLike, @@ -36,17 +37,12 @@ pub fn sys_epoll_create1(flags: u32) -> AxResult { .map(|fd| fd as isize) } -pub fn sys_epoll_ctl( - epfd: i32, - op: u32, - fd: i32, - event: UserConstPtr, -) -> AxResult { +pub fn sys_epoll_ctl(epfd: i32, op: u32, fd: i32, event: *const epoll_event) -> AxResult { let epoll = Epoll::from_fd(epfd)?; debug!("sys_epoll_ctl <= epfd: {epfd}, op: {op}, fd: {fd}"); let parse_event = || -> AxResult<(EpollEvent, EpollFlags)> { - let event = event.get_as_ref()?; + let event = unsafe { event.vm_read_uninit()?.assume_init() }; let events = IoEvents::from_bits_truncate(event.events); let flags = EpollFlags::from_bits(event.events & !events.bits()).ok_or(AxError::InvalidInput)?; @@ -77,10 +73,10 @@ pub fn sys_epoll_ctl( fn do_epoll_wait( epfd: i32, - events: UserPtr, + events: *mut epoll_event, maxevents: i32, timeout: Option, - sigmask: UserConstPtr, + sigmask: *const SignalSet, sigsetsize: usize, ) -> AxResult { check_sigset_size(sigsetsize)?; @@ -91,28 +87,34 @@ fn do_epoll_wait( if maxevents <= 0 { return Err(AxError::InvalidInput); } - let events = events.get_as_mut_slice(maxevents as usize)?; - - with_replacen_blocked( - nullable!(sigmask.get_as_ref())?.copied(), - || match block_on(future::timeout( + let mut buf = vec![epoll_event { events: 0, data: 0 }; maxevents as usize]; + let sig = match sigmask.nullable() { + Some(p) => Some(unsafe { p.vm_read_uninit()?.assume_init() }), + None => None, + }; + let n = with_replacen_blocked(sig, || { + match block_on(future::timeout( timeout, poll_io(epoll.as_ref(), IoEvents::IN, false, || { - epoll.poll_events(events) + epoll.poll_events(&mut buf) }), )) { Ok(r) => r.map(|n| n as _), Err(_) => Ok(0), - }, - ) + } + })?; + for (i, ev) in buf.iter().take(n as usize).enumerate() { + unsafe { events.add(i).vm_write(*ev)? }; + } + Ok(n) } pub fn sys_epoll_pwait( epfd: i32, - events: UserPtr, + events: *mut epoll_event, maxevents: i32, timeout: i32, - sigmask: UserConstPtr, + sigmask: *const SignalSet, sigsetsize: usize, ) -> AxResult { let timeout = match timeout { @@ -125,14 +127,15 @@ pub fn sys_epoll_pwait( pub fn sys_epoll_pwait2( epfd: i32, - events: UserPtr, + events: *mut epoll_event, maxevents: i32, - timeout: UserConstPtr, - sigmask: UserConstPtr, + timeout: *const timespec, + sigmask: *const SignalSet, sigsetsize: usize, ) -> AxResult { - let timeout = nullable!(timeout.get_as_ref())? - .map(|ts| ts.try_into_time_value()) + let timeout = timeout + .nullable() + .map(|ts| unsafe { ts.vm_read_uninit()?.assume_init().try_into_time_value() }) .transpose()?; do_epoll_wait(epfd, events, maxevents, timeout, sigmask, sigsetsize) } diff --git a/api/src/syscall/io_mpx/poll.rs b/api/src/syscall/io_mpx/poll.rs index 30fae238..6d02739c 100644 --- a/api/src/syscall/io_mpx/poll.rs +++ b/api/src/syscall/io_mpx/poll.rs @@ -6,13 +6,11 @@ use axpoll::IoEvents; use axtask::future::{self, block_on, poll_io}; use linux_raw_sys::general::{POLLNVAL, pollfd, timespec}; use starry_signal::SignalSet; +use starry_vm::{VmMutPtr, VmPtr}; use super::FdPollSet; use crate::{ - file::get_file_like, - mm::{UserConstPtr, UserPtr, nullable}, - signal::with_replacen_blocked, - syscall::signal::check_sigset_size, + file::get_file_like, signal::with_replacen_blocked, syscall::signal::check_sigset_size, time::TimeValueLike, }; @@ -86,28 +84,49 @@ fn do_poll( } #[cfg(target_arch = "x86_64")] -pub fn sys_poll(fds: UserPtr, nfds: u32, timeout: i32) -> AxResult { - let fds = fds.get_as_mut_slice(nfds as usize)?; +pub fn sys_poll(fds: *mut pollfd, nfds: u32, timeout: i32) -> AxResult { + let n = nfds as usize; + let mut local: Vec = Vec::with_capacity(n); + for i in 0..n { + local.push(unsafe { fds.add(i).vm_read_uninit()?.assume_init() }); + } let timeout = if timeout < 0 { None } else { Some(TimeValue::from_millis(timeout as u64)) }; - do_poll(fds, timeout, None) + let ret = do_poll(&mut local, timeout, None)?; + for (i, it) in local.iter().enumerate() { + unsafe { fds.add(i).vm_write(*it)? }; + } + Ok(ret) } pub fn sys_ppoll( - fds: UserPtr, + fds: *mut pollfd, nfds: i32, - timeout: UserConstPtr, - sigmask: UserConstPtr, + timeout: *const timespec, + sigmask: *const SignalSet, sigsetsize: usize, ) -> AxResult { check_sigset_size(sigsetsize)?; - let fds = fds.get_as_mut_slice(nfds.try_into().map_err(|_| AxError::InvalidInput)?)?; - let timeout = nullable!(timeout.get_as_ref())? - .map(|ts| ts.try_into_time_value()) + let n: usize = nfds.try_into().map_err(|_| AxError::InvalidInput)?; + let mut local: Vec = Vec::with_capacity(n); + for i in 0..n { + local.push(unsafe { fds.add(i).vm_read_uninit()?.assume_init() }); + } + let timeout = timeout + .nullable() + .map(|ts| unsafe { ts.vm_read_uninit()?.assume_init().try_into_time_value() }) .transpose()?; + let sig = match sigmask.nullable() { + Some(p) => Some(unsafe { p.vm_read_uninit()?.assume_init() }), + None => None, + }; // TODO: handle signal - do_poll(fds, timeout, nullable!(sigmask.get_as_ref())?.copied()) + let ret = do_poll(&mut local, timeout, sig)?; + for (i, it) in local.iter().enumerate() { + unsafe { fds.add(i).vm_write(*it)? }; + } + Ok(ret) } diff --git a/api/src/syscall/io_mpx/select.rs b/api/src/syscall/io_mpx/select.rs index 3ff65f99..295ca612 100644 --- a/api/src/syscall/io_mpx/select.rs +++ b/api/src/syscall/io_mpx/select.rs @@ -10,13 +10,11 @@ use linux_raw_sys::{ select_macros::{FD_ISSET, FD_SET, FD_ZERO}, }; use starry_signal::SignalSet; +use starry_vm::{VmMutPtr, VmPtr}; use super::FdPollSet; use crate::{ - file::FD_TABLE, - mm::{UserConstPtr, UserPtr, nullable}, - signal::with_replacen_blocked, - syscall::signal::check_sigset_size, + file::FD_TABLE, signal::with_replacen_blocked, syscall::signal::check_sigset_size, time::TimeValueLike, }; @@ -44,30 +42,44 @@ impl fmt::Debug for FdSet { fn do_select( nfds: u32, - readfds: UserPtr<__kernel_fd_set>, - writefds: UserPtr<__kernel_fd_set>, - exceptfds: UserPtr<__kernel_fd_set>, + readfds: *mut __kernel_fd_set, + writefds: *mut __kernel_fd_set, + exceptfds: *mut __kernel_fd_set, timeout: Option, - sigmask: UserConstPtr, + sigmask: *const SignalSetWithSize, ) -> AxResult { if nfds > __FD_SETSIZE { return Err(AxError::InvalidInput); } - let sigmask = if let Some(sigmask) = nullable!(sigmask.get_as_ref())? { - check_sigset_size(sigmask.sigsetsize)?; - let set = sigmask.set; - nullable!(set.get_as_ref())? - } else { - None + let sigmask = match sigmask.nullable() { + Some(p) => { + let sig = unsafe { p.vm_read_uninit()?.assume_init() }; + check_sigset_size(sig.sigsetsize)?; + match sig.set.nullable() { + Some(sp) => Some(unsafe { sp.vm_read_uninit()?.assume_init() }), + None => None, + } + } + None => None, }; - let mut readfds = nullable!(readfds.get_as_mut())?; - let mut writefds = nullable!(writefds.get_as_mut())?; - let mut exceptfds = nullable!(exceptfds.get_as_mut())?; + let mut read_local = match readfds.nullable() { + Some(p) => Some(unsafe { p.vm_read_uninit()?.assume_init() }), + None => None, + }; + + let mut write_local = match writefds.nullable() { + Some(p) => Some(unsafe { p.vm_read_uninit()?.assume_init() }), + None => None, + }; + let mut except_local = match exceptfds.nullable() { + Some(p) => Some(unsafe { p.vm_read_uninit()?.assume_init() }), + None => None, + }; - let read_set = FdSet::new(nfds as _, readfds.as_deref()); - let write_set = FdSet::new(nfds as _, writefds.as_deref()); - let except_set = FdSet::new(nfds as _, exceptfds.as_deref()); + let read_set = FdSet::new(nfds as _, read_local.as_ref()); + let write_set = FdSet::new(nfds as _, write_local.as_ref()); + let except_set = FdSet::new(nfds as _, except_local.as_ref()); debug!( "sys_select <= nfds: {nfds} sets: [read: {read_set:?}, write: {write_set:?}, except: \ @@ -98,16 +110,16 @@ fn do_select( drop(fd_table); let fds = FdPollSet(fds); - if let Some(readfds) = readfds.as_deref_mut() { - unsafe { FD_ZERO(readfds) }; + if let Some(read_local) = read_local.as_mut() { + unsafe { FD_ZERO(read_local) }; } - if let Some(writefds) = writefds.as_deref_mut() { - unsafe { FD_ZERO(writefds) }; + if let Some(write_local) = write_local.as_mut() { + unsafe { FD_ZERO(write_local) }; } - if let Some(exceptfds) = exceptfds.as_deref_mut() { - unsafe { FD_ZERO(exceptfds) }; + if let Some(except_local) = except_local.as_mut() { + unsafe { FD_ZERO(except_local) }; } - with_replacen_blocked(sigmask.copied(), || { + with_replacen_blocked(sigmask, || { match block_on(future::timeout( timeout, poll_io(&fds, IoEvents::empty(), false, || { @@ -115,19 +127,19 @@ fn do_select( for ((fd, interested), index) in fds.0.iter().zip(fd_indices.iter().copied()) { let events = fd.poll() & *interested; if events.contains(IoEvents::IN) - && let Some(set) = readfds.as_deref_mut() + && let Some(set) = read_local.as_mut() { res += 1; unsafe { FD_SET(index as _, set) }; } if events.contains(IoEvents::OUT) - && let Some(set) = writefds.as_deref_mut() + && let Some(set) = write_local.as_mut() { res += 1; unsafe { FD_SET(index as _, set) }; } if events.contains(IoEvents::ERR) - && let Some(set) = exceptfds.as_deref_mut() + && let Some(set) = except_local.as_mut() { res += 1; unsafe { FD_SET(index as _, set) }; @@ -144,50 +156,64 @@ fn do_select( Err(_) => Ok(0), } }) + .and_then(|ret| { + if let Some((p, set)) = readfds.nullable().zip(read_local) { + p.vm_write(set)?; + } + if let Some((p, set)) = writefds.nullable().zip(write_local) { + p.vm_write(set)?; + } + if let Some((p, set)) = exceptfds.nullable().zip(except_local) { + p.vm_write(set)?; + } + Ok(ret) + }) } #[cfg(target_arch = "x86_64")] pub fn sys_select( nfds: u32, - readfds: UserPtr<__kernel_fd_set>, - writefds: UserPtr<__kernel_fd_set>, - exceptfds: UserPtr<__kernel_fd_set>, - timeout: UserConstPtr, + readfds: *mut __kernel_fd_set, + writefds: *mut __kernel_fd_set, + exceptfds: *mut __kernel_fd_set, + timeout: *const timeval, ) -> AxResult { do_select( nfds, readfds, writefds, exceptfds, - nullable!(timeout.get_as_ref())? - .map(|it| it.try_into_time_value()) + timeout + .nullable() + .map(|p| unsafe { p.vm_read_uninit()?.assume_init().try_into_time_value() }) .transpose()?, - 0.into(), + core::ptr::null(), ) } #[repr(C)] #[derive(Clone, Copy)] pub struct SignalSetWithSize { - set: UserConstPtr, + set: *const SignalSet, sigsetsize: usize, } pub fn sys_pselect6( nfds: u32, - readfds: UserPtr<__kernel_fd_set>, - writefds: UserPtr<__kernel_fd_set>, - exceptfds: UserPtr<__kernel_fd_set>, - timeout: UserConstPtr, - sigmask: UserConstPtr, + readfds: *mut __kernel_fd_set, + writefds: *mut __kernel_fd_set, + exceptfds: *mut __kernel_fd_set, + timeout: *const timespec, + sigmask: *const SignalSetWithSize, ) -> AxResult { do_select( nfds, readfds, writefds, exceptfds, - nullable!(timeout.get_as_ref())? - .map(|ts| ts.try_into_time_value()) + timeout + .nullable() + .map(|p| unsafe { p.vm_read_uninit()?.assume_init().try_into_time_value() }) .transpose()?, sigmask, ) diff --git a/api/src/syscall/ipc/shm.rs b/api/src/syscall/ipc/shm.rs index 936d6880..65f04669 100644 --- a/api/src/syscall/ipc/shm.rs +++ b/api/src/syscall/ipc/shm.rs @@ -14,9 +14,9 @@ use starry_core::{ shm::{SHM_MANAGER, ShmInner, ShmidDs}, task::AsThread, }; +use starry_vm::{VmMutPtr, VmPtr}; use super::{IPC_PRIVATE, IPC_RMID, IPC_SET, IPC_STAT, next_ipc_id}; -use crate::mm::{UserPtr, nullable}; bitflags::bitflags! { /// flags for sys_shmat @@ -150,7 +150,7 @@ pub fn sys_shmat(shmid: i32, addr: usize, shmflg: u32) -> AxResult { Ok(start_addr.as_usize() as isize) } -pub fn sys_shmctl(shmid: i32, cmd: u32, buf: UserPtr) -> AxResult { +pub fn sys_shmctl(shmid: i32, cmd: u32, buf: *mut ShmidDs) -> AxResult { let shm_inner = { let shm_manager = SHM_MANAGER.lock(); shm_manager @@ -161,10 +161,10 @@ pub fn sys_shmctl(shmid: i32, cmd: u32, buf: UserPtr) -> AxResult sys_write(uctx.arg0() as _, uctx.arg1() as _, uctx.arg2() as _), Sysno::writev => sys_writev(uctx.arg0() as _, uctx.arg1() as _, uctx.arg2() as _), Sysno::lseek => sys_lseek(uctx.arg0() as _, uctx.arg1() as _, uctx.arg2() as _), - Sysno::truncate => sys_truncate(uctx.arg0().into(), uctx.arg1() as _), + Sysno::truncate => sys_truncate(uctx.arg0() as _, uctx.arg1() as _), Sysno::ftruncate => sys_ftruncate(uctx.arg0() as _, uctx.arg1() as _), Sysno::fallocate => sys_fallocate( uctx.arg0() as _, @@ -218,51 +218,51 @@ pub fn handle_syscall(uctx: &mut UserContext) { // io mpx #[cfg(target_arch = "x86_64")] - Sysno::poll => sys_poll(uctx.arg0().into(), uctx.arg1() as _, uctx.arg2() as _), + Sysno::poll => sys_poll(uctx.arg0() as _, uctx.arg1() as _, uctx.arg2() as _), Sysno::ppoll => sys_ppoll( - uctx.arg0().into(), + uctx.arg0() as _, uctx.arg1() as _, - uctx.arg2().into(), - uctx.arg3().into(), + uctx.arg2() as _, + uctx.arg3() as _, uctx.arg4() as _, ), #[cfg(target_arch = "x86_64")] Sysno::select => sys_select( uctx.arg0() as _, - uctx.arg1().into(), - uctx.arg2().into(), - uctx.arg3().into(), - uctx.arg4().into(), + uctx.arg1() as _, + uctx.arg2() as _, + uctx.arg3() as _, + uctx.arg4() as _, ), Sysno::pselect6 => sys_pselect6( uctx.arg0() as _, - uctx.arg1().into(), - uctx.arg2().into(), - uctx.arg3().into(), - uctx.arg4().into(), - uctx.arg5().into(), + uctx.arg1() as _, + uctx.arg2() as _, + uctx.arg3() as _, + uctx.arg4() as _, + uctx.arg5() as _, ), Sysno::epoll_create1 => sys_epoll_create1(uctx.arg0() as _), Sysno::epoll_ctl => sys_epoll_ctl( uctx.arg0() as _, uctx.arg1() as _, uctx.arg2() as _, - uctx.arg3().into(), + uctx.arg3() as _, ), Sysno::epoll_pwait => sys_epoll_pwait( uctx.arg0() as _, - uctx.arg1().into(), + uctx.arg1() as _, uctx.arg2() as _, uctx.arg3() as _, - uctx.arg4().into(), + uctx.arg4() as _, uctx.arg5() as _, ), Sysno::epoll_pwait2 => sys_epoll_pwait2( uctx.arg0() as _, - uctx.arg1().into(), + uctx.arg1() as _, uctx.arg2() as _, - uctx.arg3().into(), - uctx.arg4().into(), + uctx.arg3() as _, + uctx.arg4() as _, uctx.arg5() as _, ), @@ -295,7 +295,7 @@ pub fn handle_syscall(uctx: &mut UserContext) { ), // memfd - Sysno::memfd_create => sys_memfd_create(uctx.arg0().into(), uctx.arg1() as _), + Sysno::memfd_create => sys_memfd_create(uctx.arg0() as _, uctx.arg1() as _), // fs stat #[cfg(target_arch = "x86_64")] @@ -539,7 +539,7 @@ pub fn handle_syscall(uctx: &mut UserContext) { // shm Sysno::shmget => sys_shmget(uctx.arg0() as _, uctx.arg1() as _, uctx.arg2() as _), Sysno::shmat => sys_shmat(uctx.arg0() as _, uctx.arg1() as _, uctx.arg2() as _), - Sysno::shmctl => sys_shmctl(uctx.arg0() as _, uctx.arg1() as _, uctx.arg2().into()), + Sysno::shmctl => sys_shmctl(uctx.arg0() as _, uctx.arg1() as _, uctx.arg2() as _), Sysno::shmdt => sys_shmdt(uctx.arg0() as _), // net @@ -548,22 +548,18 @@ pub fn handle_syscall(uctx: &mut UserContext) { uctx.arg0() as _, uctx.arg1() as _, uctx.arg2() as _, - uctx.arg3().into(), + uctx.arg3() as _, ), - Sysno::bind => sys_bind(uctx.arg0() as _, uctx.arg1().into(), uctx.arg2() as _), - Sysno::connect => sys_connect(uctx.arg0() as _, uctx.arg1().into(), uctx.arg2() as _), - Sysno::getsockname => { - sys_getsockname(uctx.arg0() as _, uctx.arg1().into(), uctx.arg2().into()) - } - Sysno::getpeername => { - sys_getpeername(uctx.arg0() as _, uctx.arg1().into(), uctx.arg2().into()) - } + Sysno::bind => sys_bind(uctx.arg0() as _, uctx.arg1() as _, uctx.arg2() as _), + Sysno::connect => sys_connect(uctx.arg0() as _, uctx.arg1() as _, uctx.arg2() as _), + Sysno::getsockname => sys_getsockname(uctx.arg0() as _, uctx.arg1() as _, uctx.arg2() as _), + Sysno::getpeername => sys_getpeername(uctx.arg0() as _, uctx.arg1() as _, uctx.arg2() as _), Sysno::listen => sys_listen(uctx.arg0() as _, uctx.arg1() as _), - Sysno::accept => sys_accept(uctx.arg0() as _, uctx.arg1().into(), uctx.arg2().into()), + Sysno::accept => sys_accept(uctx.arg0() as _, uctx.arg1() as _, uctx.arg2() as _), Sysno::accept4 => sys_accept4( uctx.arg0() as _, - uctx.arg1().into(), - uctx.arg2().into(), + uctx.arg1() as _, + uctx.arg2() as _, uctx.arg3() as _, ), Sysno::shutdown => sys_shutdown(uctx.arg0() as _, uctx.arg1() as _), @@ -572,7 +568,7 @@ pub fn handle_syscall(uctx: &mut UserContext) { uctx.arg1() as _, uctx.arg2() as _, uctx.arg3() as _, - uctx.arg4().into(), + uctx.arg4() as _, uctx.arg5() as _, ), Sysno::recvfrom => sys_recvfrom( @@ -580,23 +576,23 @@ pub fn handle_syscall(uctx: &mut UserContext) { uctx.arg1() as _, uctx.arg2() as _, uctx.arg3() as _, - uctx.arg4().into(), - uctx.arg5().into(), + uctx.arg4() as _, + uctx.arg5() as _, ), - Sysno::sendmsg => sys_sendmsg(uctx.arg0() as _, uctx.arg1().into(), uctx.arg2() as _), - Sysno::recvmsg => sys_recvmsg(uctx.arg0() as _, uctx.arg1().into(), uctx.arg2() as _), + Sysno::sendmsg => sys_sendmsg(uctx.arg0() as _, uctx.arg1() as _, uctx.arg2() as _), + Sysno::recvmsg => sys_recvmsg(uctx.arg0() as _, uctx.arg1() as _, uctx.arg2() as _), Sysno::getsockopt => sys_getsockopt( uctx.arg0() as _, uctx.arg1() as _, uctx.arg2() as _, - uctx.arg3().into(), - uctx.arg4().into(), + uctx.arg3() as _, + uctx.arg4() as _, ), Sysno::setsockopt => sys_setsockopt( uctx.arg0() as _, uctx.arg1() as _, uctx.arg2() as _, - uctx.arg3().into(), + uctx.arg3() as _, uctx.arg4() as _, ), diff --git a/api/src/syscall/net/cmsg.rs b/api/src/syscall/net/cmsg.rs index f60d9cb4..67529921 100644 --- a/api/src/syscall/net/cmsg.rs +++ b/api/src/syscall/net/cmsg.rs @@ -1,12 +1,10 @@ use alloc::{sync::Arc, vec::Vec}; use axerrno::{AxError, AxResult}; -use linux_raw_sys::net::{SCM_RIGHTS, SOL_SOCKET, cmsghdr}; +use linux_raw_sys::net::{SCM_RIGHTS, SOL_SOCKET, cmsghdr, socklen_t}; +use starry_vm::{VmMutPtr, VmPtr, vm_load}; -use crate::{ - file::{FileLike, get_file_like}, - mm::{UserConstPtr, UserPtr}, -}; +use crate::file::{FileLike, get_file_like}; pub enum CMsg { Rights { fds: Vec> }, @@ -17,12 +15,13 @@ impl CMsg { return Err(AxError::InvalidInput); } - let data = - UserConstPtr::::from((hdr as *const cmsghdr as usize) + size_of::()) - .get_as_slice(hdr.cmsg_len - size_of::())?; + let data_len = hdr.cmsg_len - size_of::(); + let data_ptr = (hdr as *const cmsghdr as usize + size_of::()) as *const u8; + let data = vm_load(data_ptr, data_len)?; + Ok(match (hdr.cmsg_level as u32, hdr.cmsg_type as u32) { (SOL_SOCKET, SCM_RIGHTS) => { - if data.len() % size_of::() != 0 { + if !data.len().is_multiple_of(size_of::()) { return Err(AxError::InvalidInput); } let mut fds = Vec::new(); @@ -43,45 +42,49 @@ impl CMsg { } } -pub struct CMsgBuilder<'a> { - hdr: UserPtr, - len: &'a mut usize, +pub struct CMsgBuilder { + hdr: *mut cmsghdr, + len: *mut socklen_t, capacity: usize, + written: usize, } -impl<'a> CMsgBuilder<'a> { - pub fn new(msg: UserPtr, len: &'a mut usize) -> Self { - let capacity = *len; - *len = 0; - Self { +impl CMsgBuilder { + pub fn new(msg: *mut cmsghdr, len: *mut socklen_t) -> AxResult { + let capacity = len.vm_read()? as usize; + len.vm_write(0)?; + Ok(Self { hdr: msg, len, capacity, - } + written: 0, + }) } pub fn push( &mut self, level: u32, ty: u32, - body: impl FnOnce(&mut [u8]) -> AxResult, + body: impl FnOnce(*mut u8, usize) -> AxResult, ) -> AxResult { - let Some(body_capacity) = (self.capacity - *self.len).checked_sub(size_of::()) + let Some(body_capacity) = (self.capacity - self.written).checked_sub(size_of::()) else { return Ok(false); }; - let hdr = self.hdr.get_as_mut()?; - hdr.cmsg_level = level as _; - hdr.cmsg_type = ty as _; - - let data = UserPtr::::from(self.hdr.address().as_usize() + size_of::()) - .get_as_mut_slice(body_capacity)?; - let body_len = body(data)?; + let data_ptr = ((self.hdr as usize) + size_of::()) as *mut u8; + let body_len = body(data_ptr, body_capacity)?; let cmsg_len = size_of::() + body_len; - hdr.cmsg_len = cmsg_len; - self.hdr = UserPtr::from(hdr as *const _ as usize + cmsg_len); - *self.len += cmsg_len; + let hdr = cmsghdr { + cmsg_len, + cmsg_level: level as _, + cmsg_type: ty as _, + }; + self.hdr.vm_write(hdr)?; + + self.hdr = (self.hdr as usize + cmsg_len) as *mut cmsghdr; + self.written += cmsg_len; + self.len.vm_write(self.written as socklen_t)?; Ok(true) } } diff --git a/api/src/syscall/net/io.rs b/api/src/syscall/net/io.rs index 8ab55e45..570915d0 100644 --- a/api/src/syscall/net/io.rs +++ b/api/src/syscall/net/io.rs @@ -1,5 +1,5 @@ use alloc::{boxed::Box, vec::Vec}; -use core::net::Ipv4Addr; +use core::{net::Ipv4Addr, ptr::addr_of_mut}; use axerrno::{AxError, AxResult}; use axio::prelude::*; @@ -7,11 +7,12 @@ use axnet::{CMsgData, RecvFlags, RecvOptions, SendFlags, SendOptions, SocketAddr use linux_raw_sys::net::{ MSG_PEEK, MSG_TRUNC, SCM_RIGHTS, SOL_SOCKET, cmsghdr, msghdr, sockaddr, socklen_t, }; +use starry_vm::{VmMutPtr, VmPtr}; use crate::{ file::{FileLike, Socket, add_file_like}, io::{IoVec, IoVectorBuf}, - mm::{UserConstPtr, UserPtr, VmBytes, VmBytesMut}, + mm::{VmBytes, VmBytesMut}, socket::SocketAddrExt, syscall::net::{CMsg, CMsgBuilder}, }; @@ -20,7 +21,7 @@ fn send_impl( fd: i32, mut src: impl Read + IoBuf, flags: u32, - addr: UserConstPtr, + addr: *const sockaddr, addrlen: socklen_t, cmsg: Vec, ) -> AxResult { @@ -50,24 +51,24 @@ pub fn sys_sendto( buf: *const u8, len: usize, flags: u32, - addr: UserConstPtr, + addr: *const sockaddr, addrlen: socklen_t, ) -> AxResult { send_impl(fd, VmBytes::new(buf, len), flags, addr, addrlen, Vec::new()) } -pub fn sys_sendmsg(fd: i32, msg: UserConstPtr, flags: u32) -> AxResult { - let msg = msg.get_as_ref()?; +pub fn sys_sendmsg(fd: i32, msg: *const msghdr, flags: u32) -> AxResult { + let msg = unsafe { msg.vm_read_uninit()?.assume_init() }; let mut cmsg = Vec::new(); if !msg.msg_control.is_null() { let mut ptr = msg.msg_control as usize; let ptr_end = ptr + msg.msg_controllen; while ptr + size_of::() <= ptr_end { - let hdr = UserConstPtr::::from(ptr).get_as_ref()?; + let hdr = unsafe { (ptr as *const cmsghdr).vm_read_uninit()?.assume_init() }; if ptr_end - ptr < hdr.cmsg_len { return Err(AxError::InvalidInput); } - cmsg.push(Box::new(CMsg::parse(hdr)?) as CMsgData); + cmsg.push(Box::new(CMsg::parse(&hdr)?) as CMsgData); ptr += hdr.cmsg_len; } } @@ -75,7 +76,7 @@ pub fn sys_sendmsg(fd: i32, msg: UserConstPtr, flags: u32) -> AxResult, - addrlen: UserPtr, + addr: *mut sockaddr, + addrlen: *mut socklen_t, cmsg_builder: Option, ) -> AxResult { debug!("sys_recv <= fd: {fd}, flags: {flags}"); @@ -114,7 +115,7 @@ fn recv_impl( )?; if let Some(remote_addr) = remote_addr { - remote_addr.write_to_user(addr, addrlen.get_as_mut()?)?; + remote_addr.write_to_user(addr, addrlen)?; } if let Some(mut builder) = cmsg_builder { @@ -125,15 +126,21 @@ fn recv_impl( }; let pushed = match *cmsg { - CMsg::Rights { fds } => builder.push(SOL_SOCKET, SCM_RIGHTS, |data| { - let mut written = 0; - for (f, chunk) in fds.into_iter().zip(data.chunks_exact_mut(size_of::())) { - let fd = add_file_like(f, false)?; - chunk.copy_from_slice(&fd.to_ne_bytes()); - written += size_of::(); - } - Ok(written) - })?, + CMsg::Rights { fds } => { + builder.push(SOL_SOCKET, SCM_RIGHTS, |data_ptr, capacity| { + let mut written = 0; + for f in fds.into_iter() { + if written + size_of::() > capacity { + break; + } + let fd = add_file_like(f, false)?; + let ptr = ((data_ptr as usize) + written) as *mut i32; + ptr.vm_write(fd)?; + written += size_of::(); + } + Ok(written) + })? + } }; if !pushed { break; @@ -150,25 +157,26 @@ pub fn sys_recvfrom( buf: *mut u8, len: usize, flags: u32, - addr: UserPtr, - addrlen: UserPtr, + addr: *mut sockaddr, + addrlen: *mut socklen_t, ) -> AxResult { recv_impl(fd, VmBytesMut::new(buf, len), flags, addr, addrlen, None) } -pub fn sys_recvmsg(fd: i32, msg: UserPtr, flags: u32) -> AxResult { - let msg = msg.get_as_mut()?; +pub fn sys_recvmsg(fd: i32, msg: *mut msghdr, flags: u32) -> AxResult { + let msg_val = unsafe { msg.vm_read_uninit()?.assume_init() }; + recv_impl( fd, - IoVectorBuf::new(msg.msg_iov as *mut IoVec, msg.msg_iovlen)?.into_io(), + IoVectorBuf::new(msg_val.msg_iov as *mut IoVec, msg_val.msg_iovlen)?.into_io(), flags, - UserPtr::from(msg.msg_name as usize), - UserPtr::from(&mut msg.msg_namelen as *mut _ as *mut socklen_t), - (!msg.msg_control.is_null()).then(|| { - CMsgBuilder::new( - UserPtr::from(msg.msg_control as *mut cmsghdr), - &mut msg.msg_controllen, - ) - }), + msg_val.msg_name as *mut sockaddr, + unsafe { addr_of_mut!((*msg).msg_namelen) } as *mut socklen_t, + Option::from(msg_val.msg_control as *mut cmsghdr) + .map(|control| { + CMsgBuilder::new(control, unsafe { addr_of_mut!((*msg).msg_controllen) } + as *mut socklen_t) + }) + .transpose()?, ) } diff --git a/api/src/syscall/net/name.rs b/api/src/syscall/net/name.rs index 411b14cd..990033d7 100644 --- a/api/src/syscall/net/name.rs +++ b/api/src/syscall/net/name.rs @@ -4,32 +4,23 @@ use linux_raw_sys::net::{sockaddr, socklen_t}; use crate::{ file::{FileLike, Socket}, - mm::UserPtr, socket::SocketAddrExt, }; -pub fn sys_getsockname( - fd: i32, - addr: UserPtr, - addrlen: UserPtr, -) -> AxResult { +pub fn sys_getsockname(fd: i32, addr: *mut sockaddr, addrlen: *mut socklen_t) -> AxResult { let socket = Socket::from_fd(fd)?; let local_addr = socket.local_addr()?; debug!("sys_getsockname <= fd: {fd}, addr: {local_addr:?}"); - local_addr.write_to_user(addr, addrlen.get_as_mut()?)?; + local_addr.write_to_user(addr, addrlen)?; Ok(0) } -pub fn sys_getpeername( - fd: i32, - addr: UserPtr, - addrlen: UserPtr, -) -> AxResult { +pub fn sys_getpeername(fd: i32, addr: *mut sockaddr, addrlen: *mut socklen_t) -> AxResult { let socket = Socket::from_fd(fd)?; let peer_addr = socket.peer_addr()?; debug!("sys_getpeername <= fd: {fd}, addr: {peer_addr:?}"); - peer_addr.write_to_user(addr, addrlen.get_as_mut()?)?; + peer_addr.write_to_user(addr, addrlen)?; Ok(0) } diff --git a/api/src/syscall/net/opt.rs b/api/src/syscall/net/opt.rs index d11c0977..ae1be4af 100644 --- a/api/src/syscall/net/opt.rs +++ b/api/src/syscall/net/opt.rs @@ -1,11 +1,9 @@ use axerrno::{AxError, AxResult, LinuxError}; use axnet::options::{Configurable, GetSocketOption, SetSocketOption}; use linux_raw_sys::net::socklen_t; +use starry_vm::{VmMutPtr, VmPtr}; -use crate::{ - file::{FileLike, Socket}, - mm::{UserConstPtr, UserPtr}, -}; +use crate::file::{FileLike, Socket}; const PROTO_TCP: u32 = linux_raw_sys::net::IPPROTO_TCP as u32; @@ -116,39 +114,43 @@ pub fn sys_getsockopt( fd: i32, level: u32, optname: u32, - optval: UserPtr, - optlen: UserPtr, + optval: *mut u8, + optlen: *mut socklen_t, ) -> AxResult { - let optlen = optlen.get_as_mut()?; + let mut len = optlen.vm_read()?; debug!( "sys_getsockopt <= fd: {}, level: {}, optname: {}, optval: {:?}, optlen: {}", - fd, - level, - optname, - optval.address(), - optlen, + fd, level, optname, optval, len, ); - fn get<'a, T: 'static>(val: UserPtr, len: &mut socklen_t) -> AxResult<&'a mut T> { + fn write_out(dst: *mut u8, len: &mut socklen_t, val: T) -> AxResult<()> + where + T: 'static, + { if (*len as usize) < size_of::() { return Err(AxError::InvalidInput); } *len = size_of::() as socklen_t; - val.cast().get_as_mut() + (dst as *mut T).vm_write(val)?; + Ok(()) } let socket = Socket::from_fd(fd)?; macro_rules! dispatch { ($which:ident) => { - socket.get_option(GetSocketOption::$which(get(optval, optlen)?))?; + let mut out = Default::default(); + socket.get_option(GetSocketOption::$which(&mut out))?; + write_out(optval, &mut len, out)?; }; ($which:ident as $conv:ty) => { let mut val = Default::default(); socket.get_option(GetSocketOption::$which(&mut val))?; - *get(optval, optlen)? = <$conv>::rust_to_sys(val)?; + let val_sys = <$conv>::rust_to_sys(val)?; + write_out(optval, &mut len, val_sys)?; }; } call_dispatch!(dispatch, (level, optname)); + optlen.vm_write(len)?; Ok(0) } @@ -157,32 +159,28 @@ pub fn sys_setsockopt( fd: i32, level: u32, optname: u32, - optval: UserConstPtr, + optval: *const u8, optlen: socklen_t, ) -> AxResult { debug!( "sys_setsockopt <= fd: {}, level: {}, optname: {}, optval: {:?}, optlen: {}", - fd, - level, - optname, - optval.address(), - optlen + fd, level, optname, optval, optlen ); - fn get<'a, T: 'static>(val: UserConstPtr, len: socklen_t) -> AxResult<&'a T> { + fn get(val: *const u8, len: socklen_t) -> AxResult { if len as usize != size_of::() { return Err(AxError::InvalidInput); } - val.cast().get_as_ref() + Ok(unsafe { (val as *const T).vm_read_uninit()?.assume_init() }) } let socket = Socket::from_fd(fd)?; macro_rules! dispatch { ($which:ident) => { - socket.set_option(SetSocketOption::$which(get(optval, optlen)?))?; + socket.set_option(SetSocketOption::$which(&(get(optval, optlen)?)))?; }; ($which:ident as $conv:ty) => { - let mut val = <$conv>::sys_to_rust(*get(optval, optlen)?)?; + let mut val = <$conv>::sys_to_rust(get(optval, optlen)?)?; socket.set_option(SetSocketOption::$which(&mut val))?; }; } diff --git a/api/src/syscall/net/socket.rs b/api/src/syscall/net/socket.rs index b8ebc904..dfaec4c9 100644 --- a/api/src/syscall/net/socket.rs +++ b/api/src/syscall/net/socket.rs @@ -16,10 +16,10 @@ use linux_raw_sys::{ }, }; use starry_core::task::AsThread; +use starry_vm::VmMutPtr; use crate::{ file::{FileLike, Socket}, - mm::{UserConstPtr, UserPtr}, socket::SocketAddrExt, }; @@ -65,7 +65,7 @@ pub fn sys_socket(domain: u32, raw_ty: u32, proto: u32) -> AxResult { socket.add_to_fd_table(cloexec).map(|fd| fd as isize) } -pub fn sys_bind(fd: i32, addr: UserConstPtr, addrlen: u32) -> AxResult { +pub fn sys_bind(fd: i32, addr: *const sockaddr, addrlen: u32) -> AxResult { let addr = SocketAddrEx::read_from_user(addr, addrlen)?; debug!("sys_bind <= fd: {fd}, addr: {addr:?}"); @@ -74,7 +74,7 @@ pub fn sys_bind(fd: i32, addr: UserConstPtr, addrlen: u32) -> AxResult Ok(0) } -pub fn sys_connect(fd: i32, addr: UserConstPtr, addrlen: u32) -> AxResult { +pub fn sys_connect(fd: i32, addr: *const sockaddr, addrlen: u32) -> AxResult { let addr = SocketAddrEx::read_from_user(addr, addrlen)?; debug!("sys_connect <= fd: {fd}, addr: {addr:?}"); @@ -101,18 +101,14 @@ pub fn sys_listen(fd: i32, backlog: i32) -> AxResult { Ok(0) } -pub fn sys_accept( - fd: i32, - addr: UserPtr, - addrlen: UserPtr, -) -> AxResult { +pub fn sys_accept(fd: i32, addr: *mut sockaddr, addrlen: *mut socklen_t) -> AxResult { sys_accept4(fd, addr, addrlen, 0) } pub fn sys_accept4( fd: i32, - addr: UserPtr, - addrlen: UserPtr, + addr: *mut sockaddr, + addrlen: *mut socklen_t, flags: u32, ) -> AxResult { debug!("sys_accept <= fd: {fd}, flags: {flags}"); @@ -130,7 +126,7 @@ pub fn sys_accept4( debug!("sys_accept => fd: {fd}, addr: {remote_addr:?}"); if !addr.is_null() { - remote_addr.write_to_user(addr, addrlen.get_as_mut()?)?; + remote_addr.write_to_user(addr, addrlen)?; } Ok(fd) @@ -149,12 +145,7 @@ pub fn sys_shutdown(fd: i32, how: u32) -> AxResult { socket.shutdown(how).map(|_| 0) } -pub fn sys_socketpair( - domain: u32, - raw_ty: u32, - proto: u32, - fds: UserPtr<[i32; 2]>, -) -> AxResult { +pub fn sys_socketpair(domain: u32, raw_ty: u32, proto: u32, fds: *mut [i32; 2]) -> AxResult { debug!("sys_socketpair <= domain: {domain}, ty: {raw_ty}, proto: {proto}"); let ty = raw_ty & 0xFF; @@ -186,9 +177,9 @@ pub fn sys_socketpair( } let cloexec = raw_ty & O_CLOEXEC != 0; - *fds.get_as_mut()? = [ + fds.vm_write([ sock1.add_to_fd_table(cloexec)?, sock2.add_to_fd_table(cloexec)?, - ]; + ])?; Ok(0) } diff --git a/api/src/vfs/dev/event.rs b/api/src/vfs/dev/event.rs index 389ede1e..75021c24 100644 --- a/api/src/vfs/dev/event.rs +++ b/api/src/vfs/dev/event.rs @@ -1,4 +1,4 @@ -use alloc::{format, sync::Arc}; +use alloc::{format, sync::Arc, vec}; use core::{any::Any, task::Context, time::Duration}; #[allow(unused_imports)] @@ -16,9 +16,9 @@ use linux_raw_sys::{ ioctl::{EVIOCGID, EVIOCGRAB, EVIOCGVERSION}, }; use starry_core::vfs::{Device, DeviceOps, DirMapping, SimpleFs}; +use starry_vm::{VmMutPtr, vm_write_slice}; use zerocopy::{FromBytes, Immutable, IntoBytes}; -use crate::mm::UserPtr; const KEY_CNT: usize = EventType::Key.bits_count(); struct Inner { @@ -93,12 +93,14 @@ impl EventDev { } fn get_event_bits(&self, arg: usize, size: usize, ty: u8) -> AxResult { - let bits = UserPtr::::from(arg).get_as_mut_slice(size)?; + let mut bits = vec![0u8; size]; if ty == 0 { - Ok(copy_bytes(self.ev_bits.as_bytes(), bits)) + let written = copy_bytes(self.ev_bits.as_bytes(), &mut bits); + vm_write_slice(arg as *mut u8, &bits[..written])?; + Ok(written) } else { let ty = EventType::from_repr(ty).ok_or(AxError::InvalidInput)?; - match self.inner.lock().device.get_event_bits(ty, bits) { + match self.inner.lock().device.get_event_bits(ty, &mut bits) { Ok(true) => {} Ok(false) => { debug!("No events for {ty:?}"); @@ -107,7 +109,9 @@ impl EventDev { warn!("Failed to get event bits: {err:?}"); } } - Ok(bits.len().min(ty.bits_count().div_ceil(8))) + let written = bits.len().min(ty.bits_count().div_ceil(8)); + vm_write_slice(arg as *mut u8, &bits[..written])?; + Ok(written) } } } @@ -119,13 +123,14 @@ fn copy_bytes(src: &[u8], dst: &mut [u8]) -> usize { } fn return_str(arg: usize, size: usize, s: &str) -> AxResult { - let slice = UserPtr::::from(arg).get_as_mut_slice(size)?; - Ok(copy_bytes(s.as_bytes(), slice)) + let len = s.len().min(size); + vm_write_slice(arg as *mut u8, &s.as_bytes()[..len])?; + Ok(len) } fn return_zero_bits(arg: usize, size: usize, bits: usize) -> AxResult { - let slice = UserPtr::::from(arg).get_as_mut_slice(size)?; - let len = bits.div_ceil(8).min(slice.len()); - slice[..len].fill(0); + let len = bits.div_ceil(8).min(size); + let slice = vec![0u8; len]; + vm_write_slice(arg as *mut u8, &slice)?; Ok(len) } @@ -206,12 +211,11 @@ impl DeviceOps for EventDev { fn ioctl(&self, cmd: u32, arg: usize) -> VfsResult { match cmd { EVIOCGVERSION => { - *UserPtr::::from(arg).get_as_mut()? = 0x10001; + (arg as *mut u32).vm_write(0x10001)?; Ok(0) } EVIOCGID => { - *UserPtr::::from(arg).get_as_mut()? = - self.inner.lock().device.device_id(); + (arg as *mut InputDeviceId).vm_write(self.inner.lock().device.device_id())?; Ok(0) } EVIOCGRAB => Ok(0), @@ -266,11 +270,11 @@ impl DeviceOps for EventDev { } // EVIOCGKEY 0x18 => { - let bits = UserPtr::::from(arg).get_as_mut_slice(size)?; - return Ok(copy_bytes( - self.inner.lock().key_state.as_bytes(), - bits, - )); + let mut bits = vec![0u8; size]; + let n = + copy_bytes(self.inner.lock().key_state.as_bytes(), &mut bits); + vm_write_slice(arg as *mut u8, &bits[..n])?; + return Ok(n); } // EVIOCGLED 0x19 => {