diff --git a/crates/wasmtime/src/runtime/vm/mmap.rs b/crates/wasmtime/src/runtime/vm/mmap.rs index 144c50d8a00b..9ba78441d15b 100644 --- a/crates/wasmtime/src/runtime/vm/mmap.rs +++ b/crates/wasmtime/src/runtime/vm/mmap.rs @@ -287,6 +287,24 @@ impl Mmap { self.sys.len() } + /// Panics if the range start or end aren't in bounds, in the proper order, + /// or page-aligned. Returns whether the range is non-zero size and thus + /// merits further action. + fn check_range(&self, range: &Range) -> bool { + assert!(range.start <= self.len()); + assert!(range.end <= self.len()); + assert!(range.start <= range.end); + assert!( + range.start % crate::runtime::vm::host_page_size() == 0, + "changing of protections isn't page-aligned", + ); + + // A zero-sized mprotect (or equivalent) is allowed on some + // platforms but not others (notably Windows). Treat it as a no-op + // everywhere. + range.start != range.end + } + /// Makes the specified `range` within this `Mmap` to be read/execute. /// /// # Unsafety @@ -304,74 +322,50 @@ impl Mmap { range: Range, enable_branch_protection: bool, ) -> Result<()> { - assert!(range.start <= self.len()); - assert!(range.end <= self.len()); - assert!(range.start <= range.end); - assert!( - range.start % crate::runtime::vm::host_page_size() == 0, - "changing of protections isn't page-aligned", - ); - - if range.start == range.end { - // A zero-sized mprotect (or equivalent) is allowed on some - // platforms but not others (notably Windows). Treat it as a no-op - // everywhere. - return Ok(()); - } - - unsafe { - self.sys - .make_executable(range, enable_branch_protection) - .context("failed to make memory executable") + if self.check_range(&range) { + return unsafe { + self.sys + .make_executable(range, enable_branch_protection) + .context("failed to make memory executable") + }; } + Ok(()) } /// Makes the specified `range` within this `Mmap` to be readonly. pub unsafe fn make_readonly(&self, range: Range) -> Result<()> { - assert!(range.start <= self.len()); - assert!(range.end <= self.len()); - assert!(range.start <= range.end); - assert!( - range.start % crate::runtime::vm::host_page_size() == 0, - "changing of protections isn't page-aligned", - ); - - if range.start == range.end { - // A zero-sized mprotect (or equivalent) is allowed on some - // platforms but not others (notably Windows). Treat it as a no-op - // everywhere. - return Ok(()); - } - - unsafe { - self.sys - .make_readonly(range) - .context("failed to make memory readonly") + if self.check_range(&range) { + return unsafe { + self.sys + .make_readonly(range) + .context("failed to make memory readonly") + }; } + Ok(()) } /// Makes the specified `range` within this `Mmap` to be read-write. pub unsafe fn make_readwrite(&self, range: Range) -> Result<()> { - assert!(range.start <= self.len()); - assert!(range.end <= self.len()); - assert!(range.start <= range.end); - assert!( - range.start % crate::runtime::vm::host_page_size() == 0, - "changing of protections isn't page-aligned", - ); - - if range.start == range.end { - // A zero-sized mprotect (or equivalent) is allowed on some - // platforms but not others (notably Windows). Treat it as a no-op - // everywhere. - return Ok(()); + if self.check_range(&range) { + return unsafe { + self.sys + .make_readwrite(range) + .context("failed to make memory read-write") + }; } + Ok(()) + } - unsafe { - self.sys - .make_readwrite(range) - .context("failed to make memory read-write") + /// Makes the specified `range` within this `Mmap` inaccessible. + pub unsafe fn make_inaccessible(&self, range: Range) -> Result<()> { + if self.check_range(&range) { + return unsafe { + self.sys + .make_inaccessible(range) + .context("failed to make memory inaccessible") + }; } + Ok(()) } } diff --git a/crates/wasmtime/src/runtime/vm/sys/custom/mmap.rs b/crates/wasmtime/src/runtime/vm/sys/custom/mmap.rs index 30a9242b5e3a..71a3ed9c7209 100644 --- a/crates/wasmtime/src/runtime/vm/sys/custom/mmap.rs +++ b/crates/wasmtime/src/runtime/vm/sys/custom/mmap.rs @@ -78,49 +78,34 @@ impl Mmap { self.memory.as_ptr().len() } + unsafe fn change_protections(&self, range: Range, permissions: u32) -> Result<()> { + let base = unsafe { self.memory.as_ptr().byte_add(range.start).cast() }; + let len = range.end - range.start; + + unsafe { cvt(capi::wasmtime_mprotect(base, len, permissions)) } + } + pub unsafe fn make_executable( &self, range: Range, enable_branch_protection: bool, ) -> Result<()> { - unsafe { - let base = self.memory.as_ptr().byte_add(range.start).cast(); - let len = range.end - range.start; - - // not mapped into the C API at this time. - let _ = enable_branch_protection; + // not mapped into the C API at this time. + let _ = enable_branch_protection; - cvt(capi::wasmtime_mprotect( - base, - len, - capi::PROT_READ | capi::PROT_EXEC, - ))?; - } - Ok(()) + unsafe { self.change_protections(range, capi::PROT_READ | capi::PROT_EXEC) } } pub unsafe fn make_readonly(&self, range: Range) -> Result<()> { - unsafe { - let base = self.memory.as_ptr().byte_add(range.start).cast(); - let len = range.end - range.start; - - cvt(capi::wasmtime_mprotect(base, len, capi::PROT_READ))?; - } - Ok(()) + unsafe { self.change_protections(range, capi::PROT_READ) } } pub unsafe fn make_readwrite(&self, range: Range) -> Result<()> { - unsafe { - let base = self.memory.as_ptr().byte_add(range.start).cast(); - let len = range.end - range.start; + unsafe { self.change_protections(range, capi::PROT_READ | capi::PROT_WRITE) } + } - cvt(capi::wasmtime_mprotect( - base, - len, - capi::PROT_READ | capi::PROT_WRITE, - ))?; - } - Ok(()) + pub unsafe fn make_inaccessible(&self, range: Range) -> Result<()> { + unsafe { self.change_protections(range, 0) } } } diff --git a/crates/wasmtime/src/runtime/vm/sys/miri/mmap.rs b/crates/wasmtime/src/runtime/vm/sys/miri/mmap.rs index e33f23676022..38f7b1964308 100644 --- a/crates/wasmtime/src/runtime/vm/sys/miri/mmap.rs +++ b/crates/wasmtime/src/runtime/vm/sys/miri/mmap.rs @@ -117,6 +117,10 @@ impl Mmap { pub unsafe fn make_readwrite(&self, _range: Range) -> Result<()> { Ok(()) } + + pub unsafe fn make_inaccessible(&self, _range: Range) -> Result<()> { + Ok(()) + } } impl Drop for Mmap { diff --git a/crates/wasmtime/src/runtime/vm/sys/unix/mmap.rs b/crates/wasmtime/src/runtime/vm/sys/unix/mmap.rs index 5b2301c760b8..5220af7298e1 100644 --- a/crates/wasmtime/src/runtime/vm/sys/unix/mmap.rs +++ b/crates/wasmtime/src/runtime/vm/sys/unix/mmap.rs @@ -190,26 +190,31 @@ impl Mmap { Ok(()) } - pub unsafe fn make_readonly(&self, range: Range) -> Result<()> { + unsafe fn change_protections( + &self, + range: Range, + permissions: MprotectFlags, + ) -> Result<()> { let base = unsafe { self.memory.as_ptr().byte_add(range.start).cast() }; let len = range.end - range.start; unsafe { - mprotect(base, len, MprotectFlags::READ)?; + mprotect(base, len, permissions)?; } Ok(()) } - pub unsafe fn make_readwrite(&self, range: Range) -> Result<()> { - let base = unsafe { self.memory.as_ptr().byte_add(range.start).cast() }; - let len = range.end - range.start; + pub unsafe fn make_readonly(&self, range: Range) -> Result<()> { + unsafe { self.change_protections(range, MprotectFlags::READ) } + } - unsafe { - mprotect(base, len, MprotectFlags::READ | MprotectFlags::WRITE)?; - } + pub unsafe fn make_readwrite(&self, range: Range) -> Result<()> { + unsafe { self.change_protections(range, MprotectFlags::READ | MprotectFlags::WRITE) } + } - Ok(()) + pub unsafe fn make_inaccessible(&self, range: Range) -> Result<()> { + unsafe { self.change_protections(range, MprotectFlags::empty()) } } } diff --git a/crates/wasmtime/src/runtime/vm/sys/windows/mmap.rs b/crates/wasmtime/src/runtime/vm/sys/windows/mmap.rs index 792946a292ba..465efd2d7ef8 100644 --- a/crates/wasmtime/src/runtime/vm/sys/windows/mmap.rs +++ b/crates/wasmtime/src/runtime/vm/sys/windows/mmap.rs @@ -235,11 +235,15 @@ impl Mmap { Ok(()) } - pub unsafe fn make_readonly(&self, range: Range) -> Result<()> { + unsafe fn change_protections( + &self, + range: Range, + permissions: PAGE_PROTECTION_FLAGS, + ) -> Result<()> { let mut old = 0; unsafe { let base = self.as_send_sync_ptr().as_ptr().add(range.start).cast(); - let result = VirtualProtect(base, range.end - range.start, PAGE_READONLY, &mut old); + let result = VirtualProtect(base, range.end - range.start, permissions, &mut old); if result == 0 { bail!(io::Error::last_os_error()); } @@ -247,16 +251,16 @@ impl Mmap { Ok(()) } + pub unsafe fn make_readonly(&self, range: Range) -> Result<()> { + unsafe { self.change_protections(range, PAGE_READONLY) } + } + pub unsafe fn make_readwrite(&self, range: Range) -> Result<()> { - let mut old = 0; - unsafe { - let base = self.as_send_sync_ptr().as_ptr().add(range.start).cast(); - let result = VirtualProtect(base, range.end - range.start, PAGE_READWRITE, &mut old); - if result == 0 { - bail!(io::Error::last_os_error()); - } - } - Ok(()) + unsafe { self.change_protections(range, PAGE_READWRITE) } + } + + pub unsafe fn make_inaccessible(&self, range: Range) -> Result<()> { + unsafe { self.change_protections(range, PAGE_NOACCESS) } } }