From aab61578715d153a1fcd765230b61f92b5831568 Mon Sep 17 00:00:00 2001 From: Wildan M Date: Tue, 21 Oct 2025 23:18:40 +0700 Subject: [PATCH] Further fixes of shm read/write handling --- ipcd/src/shm.rs | 63 +++++++++++++++++++++++++++++-------------------- 1 file changed, 38 insertions(+), 25 deletions(-) diff --git a/ipcd/src/shm.rs b/ipcd/src/shm.rs index 340663e492..84689cd95b 100644 --- a/ipcd/src/shm.rs +++ b/ipcd/src/shm.rs @@ -35,7 +35,7 @@ impl SchemeSync for ShmScheme { fn open(&mut self, path: &str, flags: usize, _ctx: &CallerCtx) -> Result { let path = Rc::from(path); let entry = match self.maps.entry(Rc::clone(&path)) { - Entry::Occupied(mut e) => { + Entry::Occupied(e) => { if flags & syscall::O_EXCL != 0 && flags & syscall::O_CREAT != 0 { return Err(Error::new(EEXIST)); } @@ -102,11 +102,22 @@ impl SchemeSync for ShmScheme { } fn ftruncate(&mut self, id: usize, len: u64, _ctx: &CallerCtx) -> Result<()> { let path = self.handles.get(&id).ok_or(Error::new(EBADF))?; - self.maps + match self + .maps .get_mut(path) .expect("handle pointing to nothing") - .buffer = Some(MmapGuard::alloc((len as usize).div_ceil(PAGE_SIZE))?); - Ok(()) + .buffer + { + Some(_) => { + //TODO: Reallocating is unsafe here as we are mixing ftruncate with mmap + // which requires the memory to be contiguous. + Err(Error::new(EIO)) + } + ref mut buf @ None => { + *buf = Some(MmapGuard::alloc((len as usize))?); + Ok(()) + } + } } fn mmap_prep( &mut self, @@ -132,7 +143,7 @@ impl SchemeSync for ShmScheme { } //TODO: this should be only handled by ftruncate ref mut buf @ None => { - *buf = Some(MmapGuard::alloc(size.div_ceil(PAGE_SIZE))?); + *buf = Some(MmapGuard::alloc(size)?); Ok(buf.as_mut().unwrap().as_ptr() + offset as usize) } } @@ -180,9 +191,12 @@ impl SchemeSync for ShmScheme { pub struct MmapGuard { base: usize, size: usize, + // user specified, non-aligned size + len: usize, } impl MmapGuard { - pub fn alloc(page_count: usize) -> Result { + pub fn alloc(len: usize) -> Result { + let page_count = len.div_ceil(PAGE_SIZE); let size = page_count * PAGE_SIZE; let base = unsafe { syscall::fmap( @@ -196,7 +210,7 @@ impl MmapGuard { ) }?; - Ok(Self { base, size }) + Ok(Self { base, size, len }) } pub fn len(&self) -> usize { self.size @@ -204,27 +218,24 @@ impl MmapGuard { pub fn as_ptr(&self) -> usize { self.base } - pub fn as_slice(&self) -> &[u8] { - unsafe { core::slice::from_raw_parts(self.base as *const u8, self.size) } - } - pub fn as_slice_mut(&mut self) -> &mut [u8] { - unsafe { core::slice::from_raw_parts_mut(self.base as *mut u8, self.size) } - } pub fn read(&self, offset: usize, buf: &mut [u8]) -> Result { let read_len = buf.len(); let end = offset .checked_add(read_len) - .ok_or_else(|| Error::new(ERANGE))?; + .ok_or_else(|| Error::new(ERANGE)) + .map(|f| cmp::min(f, self.len))?; - if end > self.size { - return Err(Error::new(ERANGE)); + if offset > self.len { + return Err(Error::new(EINVAL)); } - let mmap_slice = Self::as_slice(self); - let source_slice = &mmap_slice[offset..end]; - buf.copy_from_slice(source_slice); + unsafe { + let src_ptr = (self.base as *const u8).add(offset); + let dst_ptr = buf.as_mut_ptr(); + core::ptr::copy_nonoverlapping(src_ptr, dst_ptr, end - offset); + } - Ok(read_len) + Ok(end - offset) } pub fn write(&mut self, offset: usize, buf: &[u8]) -> Result { let write_len = buf.len(); @@ -232,13 +243,15 @@ impl MmapGuard { .checked_add(write_len) .ok_or_else(|| Error::new(ERANGE))?; - if end > self.size { - return Err(Error::new(ERANGE)); + if end > self.len { + return Err(Error::new(EINVAL)); } - let mmap_slice = Self::as_slice_mut(self); - let dest_slice = &mut mmap_slice[offset..end]; - dest_slice.copy_from_slice(buf); + unsafe { + let src_ptr = buf.as_ptr(); + let dst_ptr = (self.base as *mut u8).add(offset); + core::ptr::copy_nonoverlapping(src_ptr, dst_ptr, write_len); + } Ok(write_len) }