mirror of
https://chromium.googlesource.com/crosvm/crosvm
synced 2024-12-28 06:27:13 +00:00
sys_util: add mmap with offset support
This is needed to support the plugin process API, which may register guest memory mapped at an offset from the beginning of a file. TEST=cargo test BUG=None Change-Id: Idf1e9f0287df5510728ab2bcf4dd090f9e81a5bf Reviewed-on: https://chromium-review.googlesource.com/849495 Commit-Ready: Zach Reizner <zachr@chromium.org> Tested-by: Zach Reizner <zachr@chromium.org> Reviewed-by: Zach Reizner <zachr@chromium.org> Reviewed-by: Dylan Reid <dgreid@chromium.org>
This commit is contained in:
parent
89f81a761b
commit
a13839564c
2 changed files with 58 additions and 2 deletions
|
@ -8,7 +8,7 @@
|
|||
use std;
|
||||
use std::io::{Read, Write};
|
||||
use std::ptr::null_mut;
|
||||
use std::os::unix::io::{AsRawFd, FromRawFd};
|
||||
use std::os::unix::io::AsRawFd;
|
||||
|
||||
use libc;
|
||||
|
||||
|
@ -21,6 +21,8 @@ use data_model::DataInit;
|
|||
pub enum Error {
|
||||
/// Requested memory out of range.
|
||||
InvalidAddress,
|
||||
/// Requested offset is out of range of `libc::off_t`.
|
||||
InvalidOffset,
|
||||
/// Requested memory range spans past the end of the region.
|
||||
InvalidRange(usize, usize),
|
||||
/// Couldn't read from the given source.
|
||||
|
@ -79,6 +81,19 @@ impl MemoryMapping {
|
|||
/// * `fd` - File descriptor to mmap from.
|
||||
/// * `size` - Size of memory region in bytes.
|
||||
pub fn from_fd(fd: &AsRawFd, size: usize) -> Result<MemoryMapping> {
|
||||
MemoryMapping::from_fd_offset(fd, size, 0)
|
||||
}
|
||||
|
||||
/// Maps the `size` bytes starting at `offset` bytes of the given `fd`.
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `fd` - File descriptor to mmap from.
|
||||
/// * `size` - Size of memory region in bytes.
|
||||
/// * `offset` - Offset in bytes from the beginning of `fd` to start the mmap.
|
||||
pub fn from_fd_offset(fd: &AsRawFd, size: usize, offset: usize) -> Result<MemoryMapping> {
|
||||
if offset > libc::off_t::max_value() as usize {
|
||||
return Err(Error::InvalidOffset);
|
||||
}
|
||||
// This is safe because we are creating a mapping in a place not already used by any other
|
||||
// area in this process.
|
||||
let addr = unsafe {
|
||||
|
@ -87,7 +102,7 @@ impl MemoryMapping {
|
|||
libc::PROT_READ | libc::PROT_WRITE,
|
||||
libc::MAP_SHARED,
|
||||
fd.as_raw_fd(),
|
||||
0)
|
||||
offset as libc::off_t)
|
||||
};
|
||||
if addr == libc::MAP_FAILED {
|
||||
return Err(Error::SystemCallFailed(errno::Error::last()));
|
||||
|
@ -363,6 +378,7 @@ impl Drop for MemoryMapping {
|
|||
mod tests {
|
||||
use super::*;
|
||||
use data_model::{VolatileMemory, VolatileMemoryError};
|
||||
use std::os::unix::io::FromRawFd;
|
||||
|
||||
#[test]
|
||||
fn basic_map() {
|
||||
|
@ -439,4 +455,15 @@ mod tests {
|
|||
let res = m.get_slice(3, 3).unwrap_err();
|
||||
assert_eq!(res, VolatileMemoryError::OutOfBounds { addr: 6 });
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_fd_offset_invalid() {
|
||||
let fd = unsafe { std::fs::File::from_raw_fd(-1) };
|
||||
let res = MemoryMapping::from_fd_offset(&fd, 4096, (libc::off_t::max_value() as usize) + 1)
|
||||
.unwrap_err();
|
||||
match res {
|
||||
Error::InvalidOffset => {}
|
||||
e => panic!("unexpected error: {:?}", e),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -190,4 +190,33 @@ mod tests {
|
|||
assert_eq!(mmap2.get_ref::<u8>(i).unwrap().load(), 0x45u8);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn mmap_page_offset() {
|
||||
if !kernel_has_memfd() {
|
||||
return;
|
||||
}
|
||||
let mut shm = SharedMemory::new(None).expect("failed to create shared memory");
|
||||
shm.set_size(8092)
|
||||
.expect("failed to set shared memory size");
|
||||
|
||||
let mmap1 =
|
||||
MemoryMapping::from_fd_offset(&shm, shm.size() as usize, 4096)
|
||||
.expect("failed to map shared memory");
|
||||
let mmap2 =
|
||||
MemoryMapping::from_fd(&shm, shm.size() as usize).expect("failed to map shared memory");
|
||||
|
||||
mmap1
|
||||
.get_slice(0, 4096)
|
||||
.expect("failed to get mmap slice")
|
||||
.read_from(&mut repeat(0x45))
|
||||
.expect("failed to fill mmap slice");
|
||||
|
||||
for i in 0..4096 {
|
||||
assert_eq!(mmap2.get_ref::<u8>(i).unwrap().load(), 0);
|
||||
}
|
||||
for i in 4096..8092 {
|
||||
assert_eq!(mmap2.get_ref::<u8>(i).unwrap().load(), 0x45u8);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue