From d3ecedefd98eae77fc69eef17e4019711ccd6b92 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Wed, 12 Jul 2023 15:33:18 +0200 Subject: [PATCH] Notify schemes when mmaps are unmapped. --- src/context/memory.rs | 2 -- src/scheme/proc.rs | 6 ++---- src/scheme/user.rs | 21 ++++++++++++++++++++- src/syscall/fs.rs | 12 +++++++++++- syscall | 2 +- 5 files changed, 34 insertions(+), 9 deletions(-) diff --git a/src/context/memory.rs b/src/context/memory.rs index 09e0f402..36b447b7 100644 --- a/src/context/memory.rs +++ b/src/context/memory.rs @@ -34,8 +34,6 @@ pub fn map_flags(page_flags: PageFlags<RmmA>) -> MapFlags { let mut flags = MapFlags::PROT_READ; if page_flags.has_write() { flags |= MapFlags::PROT_WRITE; } if page_flags.has_execute() { flags |= MapFlags::PROT_EXEC; } - // TODO: MAP_SHARED/MAP_PRIVATE (requires that grants keep track of what they borrow and if - // they borrow shared or CoW). flags } diff --git a/src/scheme/proc.rs b/src/scheme/proc.rs index 41537b5a..74aff40c 100644 --- a/src/scheme/proc.rs +++ b/src/scheme/proc.rs @@ -592,7 +592,7 @@ impl Scheme for ProcScheme { match handle.info.operation { Operation::AwaitingAddrSpaceChange { new, new_sp, new_ip } => { - stop_context(handle.info.pid, |context: &mut Context| unsafe { + let prev_addr_space = stop_context(handle.info.pid, |context: &mut Context| unsafe { if let Some(saved_regs) = ptrace::regs_for_mut(context) { #[cfg(target_arch = "aarch64")] { @@ -615,9 +615,7 @@ impl Scheme for ProcScheme { context.clone_entry = Some([new_ip, new_sp]); } - let _prev_addr_space = context.set_addr_space(new); - - Ok(()) + Ok(context.set_addr_space(new)) })?; let _ = ptrace::send_event(crate::syscall::ptrace_event!(PTRACE_EVENT_ADDRSPACE_SWITCH, 0)); } diff --git a/src/scheme/user.rs b/src/scheme/user.rs index 62db1810..b0a1c090 100644 --- a/src/scheme/user.rs +++ b/src/scheme/user.rs @@ -543,10 +543,15 @@ impl UserInner { }; let page_count_nz = NonZeroUsize::new(page_count).expect("already validated map.size != 0"); - let dst_base = dst_addr_space.write().mmap(dst_base, page_count_nz, map.flags | MAP_FIXED_NOREPLACE, &mut Vec::new(), |dst_base, flags, mapper, flusher| { + let mut notify_files = Vec::new(); + let dst_base = dst_addr_space.write().mmap(dst_base, page_count_nz, map.flags | MAP_FIXED_NOREPLACE, &mut notify_files, |dst_base, flags, mapper, flusher| { Grant::borrow_fmap(PageSpan::new(dst_base, page_count), page_flags(map.flags), file_ref, src, mapper, flusher) })?; + for map in notify_files { + let _ = map.unmap(); + } + Ok(dst_base.start_address().data()) } } @@ -829,6 +834,20 @@ impl KernelScheme for UserScheme { inner.fmap_inner(Arc::clone(addr_space), file, map) } + fn kfunmap(&self, number: usize, offset: usize, size: usize) -> Result<()> { + let inner = self.inner.upgrade().ok_or(Error::new(ENODEV))?; + + let res = inner.call_extended(CallerCtx { + pid: context::context_id().into(), + uid: offset as u32, + gid: (offset >> 32) as u32, + }, [KSMSG_MUNMAP, number, size, 0])?; + + match res { + Response::Regular(_) => Ok(()), + Response::Fd(_) => Err(Error::new(EIO)), + } + } fn as_user_inner(&self) -> Option<Result<Arc<UserInner>>> { Some(self.inner.upgrade().ok_or(Error::new(ENODEV))) diff --git a/src/syscall/fs.rs b/src/syscall/fs.rs index 68e399c1..cc97aee3 100644 --- a/src/syscall/fs.rs +++ b/src/syscall/fs.rs @@ -387,6 +387,12 @@ pub fn fstat(fd: FileHandle, user_buf: UserSliceWo) -> Result<usize> { } pub fn funmap(virtual_address: usize, length: usize) -> Result<usize> { + // Partial lengths in funmap are allowed according to POSIX, but not particularly meaningful; + // since the memory needs to SIGSEGV if later read, the entire page needs to disappear. + // + // Thus, while (temporarily) allowing unaligned lengths for compatibility, aligning the length + // should be done by libc. + let length_aligned = length.next_multiple_of(PAGE_SIZE); if length != length_aligned { log::warn!("funmap passed length {:#x} instead of {:#x}", length, length_aligned); @@ -395,7 +401,11 @@ pub fn funmap(virtual_address: usize, length: usize) -> Result<usize> { let addr_space = Arc::clone(context::current()?.read().addr_space()?); let span = PageSpan::validate_nonempty(VirtualAddress::new(virtual_address), length_aligned).ok_or(Error::new(EINVAL))?; let unpin = false; - addr_space.write().munmap(span, unpin)?; + let notify = addr_space.write().munmap(span, unpin)?; + + for map in notify { + let _ = map.unmap(); + } Ok(0) } diff --git a/syscall b/syscall index ff149946..ed28083b 160000 --- a/syscall +++ b/syscall @@ -1 +1 @@ -Subproject commit ff149946c07628dde39db05997e221b5024ccb95 +Subproject commit ed28083b73ed2b163e2d64ee3753f1d6ff6c94d1 -- GitLab