Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
104 changes: 49 additions & 55 deletions crates/wasmtime/src/runtime/vm/mmap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,24 @@ impl<T> Mmap<T> {
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<usize>) -> 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
Expand All @@ -304,74 +322,50 @@ impl<T> Mmap<T> {
range: Range<usize>,
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<usize>) -> 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<usize>) -> 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<usize>) -> Result<()> {
if self.check_range(&range) {
return unsafe {
self.sys
.make_inaccessible(range)
.context("failed to make memory inaccessible")
};
}
Ok(())
}
}

Expand Down
45 changes: 15 additions & 30 deletions crates/wasmtime/src/runtime/vm/sys/custom/mmap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,49 +78,34 @@ impl Mmap {
self.memory.as_ptr().len()
}

unsafe fn change_protections(&self, range: Range<usize>, 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<usize>,
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<usize>) -> 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<usize>) -> 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<usize>) -> Result<()> {
unsafe { self.change_protections(range, 0) }
}
}

Expand Down
4 changes: 4 additions & 0 deletions crates/wasmtime/src/runtime/vm/sys/miri/mmap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,10 @@ impl Mmap {
pub unsafe fn make_readwrite(&self, _range: Range<usize>) -> Result<()> {
Ok(())
}

pub unsafe fn make_inaccessible(&self, _range: Range<usize>) -> Result<()> {
Ok(())
}
}

impl Drop for Mmap {
Expand Down
23 changes: 14 additions & 9 deletions crates/wasmtime/src/runtime/vm/sys/unix/mmap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -190,26 +190,31 @@ impl Mmap {
Ok(())
}

pub unsafe fn make_readonly(&self, range: Range<usize>) -> Result<()> {
unsafe fn change_protections(
&self,
range: Range<usize>,
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<usize>) -> 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<usize>) -> Result<()> {
unsafe { self.change_protections(range, MprotectFlags::READ) }
}

unsafe {
mprotect(base, len, MprotectFlags::READ | MprotectFlags::WRITE)?;
}
pub unsafe fn make_readwrite(&self, range: Range<usize>) -> Result<()> {
unsafe { self.change_protections(range, MprotectFlags::READ | MprotectFlags::WRITE) }
}

Ok(())
pub unsafe fn make_inaccessible(&self, range: Range<usize>) -> Result<()> {
unsafe { self.change_protections(range, MprotectFlags::empty()) }
}
}

Expand Down
26 changes: 15 additions & 11 deletions crates/wasmtime/src/runtime/vm/sys/windows/mmap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -235,28 +235,32 @@ impl Mmap {
Ok(())
}

pub unsafe fn make_readonly(&self, range: Range<usize>) -> Result<()> {
unsafe fn change_protections(
&self,
range: Range<usize>,
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());
}
}
Ok(())
}

pub unsafe fn make_readonly(&self, range: Range<usize>) -> Result<()> {
unsafe { self.change_protections(range, PAGE_READONLY) }
}

pub unsafe fn make_readwrite(&self, range: Range<usize>) -> 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<usize>) -> Result<()> {
unsafe { self.change_protections(range, PAGE_NOACCESS) }
}
}

Expand Down
Loading