Skip to content

Commit

Permalink
Return MAP_FAILED when mmap fails
Browse files Browse the repository at this point in the history
  • Loading branch information
saethlin committed Dec 10, 2023
1 parent 9828125 commit 24ffa00
Show file tree
Hide file tree
Showing 3 changed files with 86 additions and 4 deletions.
2 changes: 1 addition & 1 deletion src/shims/unix/linux/mem.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
if flags & this.eval_libc_i32("MREMAP_MAYMOVE") == 0 {
// We only support MREMAP_MAYMOVE, so not passing the flag is just a failure
this.set_last_error(Scalar::from_i32(this.eval_libc_i32("EINVAL")))?;
return Ok(Scalar::from_maybe_pointer(Pointer::null(), this));
return Ok(this.eval_libc("MAP_FAILED"));
}

let old_address = Machine::ptr_from_addr_cast(this, old_address)?;
Expand Down
6 changes: 3 additions & 3 deletions src/shims/unix/mem.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
// First, we do some basic argument validation as required by mmap
if (flags & (map_private | map_shared)).count_ones() != 1 {
this.set_last_error(Scalar::from_i32(this.eval_libc_i32("EINVAL")))?;
return Ok(Scalar::from_maybe_pointer(Pointer::null(), this));
return Ok(this.eval_libc("MAP_FAILED"));
}
if length == 0 {
this.set_last_error(Scalar::from_i32(this.eval_libc_i32("EINVAL")))?;
return Ok(Scalar::from_maybe_pointer(Pointer::null(), this));
return Ok(this.eval_libc("MAP_FAILED"));
}

// If a user tries to map a file, we want to loudly inform them that this is not going
Expand All @@ -72,7 +72,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
// Miri doesn't support MAP_FIXED or any any protections other than PROT_READ|PROT_WRITE.
if flags & map_fixed != 0 || prot != prot_read | prot_write {
this.set_last_error(Scalar::from_i32(this.eval_libc_i32("ENOTSUP")))?;
return Ok(Scalar::from_maybe_pointer(Pointer::null(), this));
return Ok(this.eval_libc("MAP_FAILED"));
}

// Miri does not support shared mappings, or any of the other extensions that for example
Expand Down
82 changes: 82 additions & 0 deletions tests/pass-dep/shims/mmap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#![feature(strict_provenance)]

use std::{ptr, slice};
use std::io::{Error, ErrorKind};

fn test_mmap() {
let page_size = page_size::get();
Expand Down Expand Up @@ -32,6 +33,71 @@ fn test_mmap() {
let just_an_address = ptr::invalid_mut(ptr.addr());
let res = unsafe { libc::munmap(just_an_address, page_size) };
assert_eq!(res, 0i32);

// Test all of our error conditions
let ptr = unsafe {
libc::mmap(
ptr::null_mut(),
page_size,
libc::PROT_READ | libc::PROT_WRITE,
libc::MAP_PRIVATE | libc::MAP_SHARED, // Can't be both private and shared
-1,
0,
)
};
assert_eq!(ptr, libc::MAP_FAILED);
assert_eq!(Error::last_os_error().kind(), ErrorKind::InvalidInput);

let ptr = unsafe {
libc::mmap(
ptr::null_mut(),
0, // Can't map no memory
libc::PROT_READ | libc::PROT_WRITE,
libc::MAP_PRIVATE | libc::MAP_ANONYMOUS,
-1,
0,
)
};
assert_eq!(ptr, libc::MAP_FAILED);
assert_eq!(Error::last_os_error().kind(), ErrorKind::InvalidInput);

let ptr = unsafe {
libc::mmap(
ptr::invalid_mut(page_size * 64),
page_size,
libc::PROT_READ | libc::PROT_WRITE,
// We don't support MAP_FIXED
libc::MAP_PRIVATE | libc::MAP_ANONYMOUS | libc::MAP_FIXED,
-1,
0,
)
};
assert_eq!(ptr, libc::MAP_FAILED);
// We return ENOTSUP as the man pages specify, but std translates that into
// ErrorKind::Uncategorized instead of ErrorKind::Unsupported:
// https://github.com/rust-lang/rust/pull/78880#issuecomment-778495108
// So for our ENOTSUP cases, we check raw_os_error.
assert_eq!(Error::last_os_error().raw_os_error().unwrap(), libc::ENOTSUP);

// We don't support protections other than read+write
for prot in [libc::PROT_NONE, libc::PROT_EXEC, libc::PROT_READ, libc::PROT_WRITE] {
let ptr = unsafe {
libc::mmap(
ptr::null_mut(),
page_size,
prot,
libc::MAP_PRIVATE | libc::MAP_ANONYMOUS,
-1,
0,
)
};
assert_eq!(ptr, libc::MAP_FAILED);
assert_eq!(Error::last_os_error().raw_os_error().unwrap(), libc::ENOTSUP);
}

let res = unsafe { libc::munmap(ptr::invalid_mut(1), page_size) };
assert_eq!(res, -1);
assert_eq!(Error::last_os_error().kind(), ErrorKind::InvalidInput);
}

#[cfg(target_os = "linux")]
Expand Down Expand Up @@ -61,6 +127,22 @@ fn test_mremap() {

let res = unsafe { libc::munmap(ptr, page_size * 2) };
assert_eq!(res, 0i32);

// Test all of our error conditions
// Not aligned
let ptr = unsafe { libc::mremap(ptr::invalid_mut(1), page_size, page_size, libc::MREMAP_MAYMOVE) };
assert_eq!(ptr, libc::MAP_FAILED);
assert_eq!(Error::last_os_error().kind(), ErrorKind::InvalidInput);

// Zero size
let ptr = unsafe { libc::mremap(ptr::null_mut(), page_size, 0, libc::MREMAP_MAYMOVE) };
assert_eq!(ptr, libc::MAP_FAILED);
assert_eq!(Error::last_os_error().kind(), ErrorKind::InvalidInput);

// Not setting MREMAP_MAYMOVE
let ptr = unsafe { libc::mremap(ptr::null_mut(), page_size, page_size, 0) };
assert_eq!(ptr, libc::MAP_FAILED);
assert_eq!(Error::last_os_error().kind(), ErrorKind::InvalidInput);
}

fn main() {
Expand Down

0 comments on commit 24ffa00

Please sign in to comment.