diff --git a/src/call.rs b/src/call.rs index 79fa089..ae6a184 100644 --- a/src/call.rs +++ b/src/call.rs @@ -1,5 +1,5 @@ use super::arch::*; -use super::data::{Map, SigAction, Stat, StatVfs, TimeSpec}; +use super::data::{Map, Map2, SigAction, Stat, StatVfs, TimeSpec}; use super::error::Result; use super::flag::*; use super::number::*; @@ -104,11 +104,26 @@ pub fn fexec(fd: usize, args: &[[usize; 2]], vars: &[[usize; 2]]) -> Result Result { syscall3(SYS_FMAP, fd, map as *const Map as usize, mem::size_of::()) } +/// +/// Map a file into memory, but with the ability to set the address to map into, either as a hint +/// or as a requirement of the map. +/// +/// # Errors +/// `EACCES` - the file descriptor was not open for reading +/// `EBADF` - if the file descriptor was invalid +/// `ENODEV` - mmapping was not supported +/// `EINVAL` - invalid combination of flags +/// `EEXIST` - if [`MapFlags::MAP_FIXED`] was set, and the address specified was already in use. +/// +pub unsafe fn fmap2(fd: usize, map: &Map2) -> Result { + syscall3(SYS_FMAP2, fd, map as *const Map2 as usize, mem::size_of::()) +} + /// Unmap a memory-mapped file pub unsafe fn funmap(addr: usize) -> Result { syscall1(SYS_FUNMAP, addr) diff --git a/src/data.rs b/src/data.rs index de3e934..0635d05 100644 --- a/src/data.rs +++ b/src/data.rs @@ -77,6 +77,40 @@ impl DerefMut for Map { } } } +#[derive(Copy, Clone, Debug, Default)] +#[repr(C)] +pub struct Map2 { + /// The offset inside the file that is being mapped. + pub offset: usize, + + /// The size of the memory map. + pub size: usize, + + /// Contains both prot and map flags. + pub flags: MapFlags, + + /// Functions as a hint to where in the virtual address space of the running process, to place + /// the memory map. If [`MapFlags::MAP_FIXED`] is set, then this address must be the address to + /// map to. + pub address: usize, +} + +impl Deref for Map2 { + type Target = [u8]; + fn deref(&self) -> &[u8] { + unsafe { + slice::from_raw_parts(self as *const Map2 as *const u8, mem::size_of::()) + } + } +} + +impl DerefMut for Map2 { + fn deref_mut(&mut self) -> &mut [u8] { + unsafe { + slice::from_raw_parts_mut(self as *mut Map2 as *mut u8, mem::size_of::()) + } + } +} #[derive(Copy, Clone, Debug, Default)] #[repr(C)] diff --git a/src/flag.rs b/src/flag.rs index 4566765..195ecb6 100644 --- a/src/flag.rs +++ b/src/flag.rs @@ -74,6 +74,10 @@ bitflags! { const MAP_SHARED = 0x0001; const MAP_PRIVATE = 0x0002; + + /// Only accepted for mmap2(2). + const MAP_FIXED = 0x0004; + const MAP_FIXED_NOREPLACE = 0x000C; } } diff --git a/src/number.rs b/src/number.rs index 4e85c92..49c19be 100644 --- a/src/number.rs +++ b/src/number.rs @@ -28,6 +28,7 @@ pub const SYS_FCNTL: usize = SYS_CLASS_FILE | 55; pub const SYS_FEVENT: usize = SYS_CLASS_FILE | 927; pub const SYS_FEXEC: usize = SYS_CLASS_FILE | 11; pub const SYS_FMAP: usize = SYS_CLASS_FILE | SYS_ARG_SLICE | 90; +pub const SYS_FMAP2: usize = SYS_CLASS_FILE | SYS_ARG_SLICE | 900; pub const SYS_FUNMAP: usize = SYS_CLASS_FILE | 91; pub const SYS_FPATH: usize = SYS_CLASS_FILE | SYS_ARG_MSLICE | 928; pub const SYS_FRENAME: usize = SYS_CLASS_FILE | SYS_ARG_PATH | 38; diff --git a/src/scheme/generate.sh b/src/scheme/generate.sh index f95bf8a..36a651e 100755 --- a/src/scheme/generate.sh +++ b/src/scheme/generate.sh @@ -12,6 +12,7 @@ sed 's/trait Scheme/trait SchemeBlock/' scheme.rs \ | sed 's/fn handle(\&self, packet: \&mut Packet)/fn handle(\&self, packet: \&Packet) -> Option/' \ | sed 's/packet.a = Error::mux(res);/res.transpose().map(Error::mux)/' \ | sed 's/\.map(|f| f\.bits())/\.map(|f| f.map(|f| f.bits()))/' \ +| sed 's/\.map(|o| o as usize)/.map(|o| o.map(|o| o as usize))/' \ | sed 's/Result<\([^>]\+\)>/Result>/g' \ > scheme_block.rs diff --git a/src/scheme/scheme.rs b/src/scheme/scheme.rs index 7cf77b9..0af8bb5 100644 --- a/src/scheme/scheme.rs +++ b/src/scheme/scheme.rs @@ -26,6 +26,11 @@ pub trait Scheme { } else { Err(Error::new(EFAULT)) }, + SYS_FMAP2 => if packet.d >= mem::size_of::() { + self.fmap2(packet.b, unsafe { &*(packet.c as *const Map2) }) + } else { + Err(Error::new(EFAULT)) + }, SYS_FUNMAP => self.funmap(packet.b), SYS_FPATH => self.fpath(packet.b, unsafe { slice::from_raw_parts_mut(packet.c as *mut u8, packet.d) }), SYS_FRENAME => self.frename(packet.b, unsafe { slice::from_raw_parts(packet.c as *const u8, packet.d) }, packet.uid, packet.gid), @@ -120,6 +125,17 @@ pub trait Scheme { fn fmap(&self, id: usize, map: &Map) -> Result { Err(Error::new(EBADF)) } + #[allow(unused_variables)] + fn fmap2(&self, id: usize, map: &Map2) -> Result { + if map.flags.contains(MapFlags::MAP_FIXED) { + return Err(Error::new(EINVAL)); + } + self.fmap(id, &Map { + offset: map.offset, + size: map.size, + flags: map.flags, + }) + } #[allow(unused_variables)] fn funmap(&self, address: usize) -> Result { diff --git a/src/scheme/scheme_block.rs b/src/scheme/scheme_block.rs index 4428eaa..5b51e22 100644 --- a/src/scheme/scheme_block.rs +++ b/src/scheme/scheme_block.rs @@ -16,7 +16,7 @@ pub trait SchemeBlock { SYS_DUP => self.dup(packet.b, unsafe { slice::from_raw_parts(packet.c as *const u8, packet.d) }), SYS_READ => self.read(packet.b, unsafe { slice::from_raw_parts_mut(packet.c as *mut u8, packet.d) }), SYS_WRITE => self.write(packet.b, unsafe { slice::from_raw_parts(packet.c as *const u8, packet.d) }), - SYS_LSEEK => self.seek(packet.b, packet.c, packet.d), + SYS_LSEEK => self.seek(packet.b, packet.c as isize, packet.d).map(|o| o.map(|o| o as usize)), SYS_FCHMOD => self.fchmod(packet.b, packet.c as u16), SYS_FCHOWN => self.fchown(packet.b, packet.c as u32, packet.d as u32), SYS_FCNTL => self.fcntl(packet.b, packet.c, packet.d), @@ -26,6 +26,11 @@ pub trait SchemeBlock { } else { Err(Error::new(EFAULT)) }, + SYS_FMAP2 => if packet.d >= mem::size_of::() { + self.fmap2(packet.b, unsafe { &*(packet.c as *const Map2) }) + } else { + Err(Error::new(EFAULT)) + }, SYS_FUNMAP => self.funmap(packet.b), SYS_FPATH => self.fpath(packet.b, unsafe { slice::from_raw_parts_mut(packet.c as *mut u8, packet.d) }), SYS_FRENAME => self.frename(packet.b, unsafe { slice::from_raw_parts(packet.c as *const u8, packet.d) }, packet.uid, packet.gid), @@ -92,7 +97,7 @@ pub trait SchemeBlock { } #[allow(unused_variables)] - fn seek(&self, id: usize, pos: usize, whence: usize) -> Result> { + fn seek(&self, id: usize, pos: isize, whence: usize) -> Result> { Err(Error::new(EBADF)) } @@ -120,6 +125,17 @@ pub trait SchemeBlock { fn fmap(&self, id: usize, map: &Map) -> Result> { Err(Error::new(EBADF)) } + #[allow(unused_variables)] + fn fmap2(&self, id: usize, map: &Map2) -> Result> { + if map.flags.contains(MapFlags::MAP_FIXED) { + return Err(Error::new(EINVAL)); + } + self.fmap(id, &Map { + offset: map.offset, + size: map.size, + flags: map.flags, + }) + } #[allow(unused_variables)] fn funmap(&self, address: usize) -> Result> { diff --git a/src/scheme/scheme_block_mut.rs b/src/scheme/scheme_block_mut.rs index c4a49b3..a006318 100644 --- a/src/scheme/scheme_block_mut.rs +++ b/src/scheme/scheme_block_mut.rs @@ -16,7 +16,7 @@ pub trait SchemeBlockMut { SYS_DUP => self.dup(packet.b, unsafe { slice::from_raw_parts(packet.c as *const u8, packet.d) }), SYS_READ => self.read(packet.b, unsafe { slice::from_raw_parts_mut(packet.c as *mut u8, packet.d) }), SYS_WRITE => self.write(packet.b, unsafe { slice::from_raw_parts(packet.c as *const u8, packet.d) }), - SYS_LSEEK => self.seek(packet.b, packet.c, packet.d), + SYS_LSEEK => self.seek(packet.b, packet.c as isize, packet.d).map(|o| o.map(|o| o as usize)), SYS_FCHMOD => self.fchmod(packet.b, packet.c as u16), SYS_FCHOWN => self.fchown(packet.b, packet.c as u32, packet.d as u32), SYS_FCNTL => self.fcntl(packet.b, packet.c, packet.d), @@ -26,6 +26,11 @@ pub trait SchemeBlockMut { } else { Err(Error::new(EFAULT)) }, + SYS_FMAP2 => if packet.d >= mem::size_of::() { + self.fmap2(packet.b, unsafe { &*(packet.c as *const Map2) }) + } else { + Err(Error::new(EFAULT)) + }, SYS_FUNMAP => self.funmap(packet.b), SYS_FPATH => self.fpath(packet.b, unsafe { slice::from_raw_parts_mut(packet.c as *mut u8, packet.d) }), SYS_FRENAME => self.frename(packet.b, unsafe { slice::from_raw_parts(packet.c as *const u8, packet.d) }, packet.uid, packet.gid), @@ -92,7 +97,7 @@ pub trait SchemeBlockMut { } #[allow(unused_variables)] - fn seek(&mut self, id: usize, pos: usize, whence: usize) -> Result> { + fn seek(&mut self, id: usize, pos: isize, whence: usize) -> Result> { Err(Error::new(EBADF)) } @@ -120,6 +125,17 @@ pub trait SchemeBlockMut { fn fmap(&mut self, id: usize, map: &Map) -> Result> { Err(Error::new(EBADF)) } + #[allow(unused_variables)] + fn fmap2(&mut self, id: usize, map: &Map2) -> Result> { + if map.flags.contains(MapFlags::MAP_FIXED) { + return Err(Error::new(EINVAL)); + } + self.fmap(id, &Map { + offset: map.offset, + size: map.size, + flags: map.flags, + }) + } #[allow(unused_variables)] fn funmap(&mut self, address: usize) -> Result> { diff --git a/src/scheme/scheme_mut.rs b/src/scheme/scheme_mut.rs index eea1331..1672067 100644 --- a/src/scheme/scheme_mut.rs +++ b/src/scheme/scheme_mut.rs @@ -16,7 +16,7 @@ pub trait SchemeMut { SYS_DUP => self.dup(packet.b, unsafe { slice::from_raw_parts(packet.c as *const u8, packet.d) }), SYS_READ => self.read(packet.b, unsafe { slice::from_raw_parts_mut(packet.c as *mut u8, packet.d) }), SYS_WRITE => self.write(packet.b, unsafe { slice::from_raw_parts(packet.c as *const u8, packet.d) }), - SYS_LSEEK => self.seek(packet.b, packet.c, packet.d), + SYS_LSEEK => self.seek(packet.b, packet.c as isize, packet.d).map(|o| o as usize), SYS_FCHMOD => self.fchmod(packet.b, packet.c as u16), SYS_FCHOWN => self.fchown(packet.b, packet.c as u32, packet.d as u32), SYS_FCNTL => self.fcntl(packet.b, packet.c, packet.d), @@ -26,6 +26,11 @@ pub trait SchemeMut { } else { Err(Error::new(EFAULT)) }, + SYS_FMAP2 => if packet.d >= mem::size_of::() { + self.fmap2(packet.b, unsafe { &*(packet.c as *const Map2) }) + } else { + Err(Error::new(EFAULT)) + }, SYS_FUNMAP => self.funmap(packet.b), SYS_FPATH => self.fpath(packet.b, unsafe { slice::from_raw_parts_mut(packet.c as *mut u8, packet.d) }), SYS_FRENAME => self.frename(packet.b, unsafe { slice::from_raw_parts(packet.c as *const u8, packet.d) }, packet.uid, packet.gid), @@ -92,7 +97,7 @@ pub trait SchemeMut { } #[allow(unused_variables)] - fn seek(&mut self, id: usize, pos: usize, whence: usize) -> Result { + fn seek(&mut self, id: usize, pos: isize, whence: usize) -> Result { Err(Error::new(EBADF)) } @@ -120,6 +125,17 @@ pub trait SchemeMut { fn fmap(&mut self, id: usize, map: &Map) -> Result { Err(Error::new(EBADF)) } + #[allow(unused_variables)] + fn fmap2(&mut self, id: usize, map: &Map2) -> Result { + if map.flags.contains(MapFlags::MAP_FIXED) { + return Err(Error::new(EINVAL)); + } + self.fmap(id, &Map { + offset: map.offset, + size: map.size, + flags: map.flags, + }) + } #[allow(unused_variables)] fn funmap(&mut self, address: usize) -> Result {