From 6869e82a922782c8bc8f149724b7adaedec7c596 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Wed, 8 Jul 2020 15:36:59 +0200 Subject: [PATCH 1/3] Add mmap2. --- src/call.rs | 19 +++++++++++++++++-- src/data.rs | 34 ++++++++++++++++++++++++++++++++++ src/flag.rs | 3 +++ src/number.rs | 1 + src/scheme/scheme.rs | 17 +++++++++++++++++ src/scheme/scheme_block.rs | 21 +++++++++++++++++++-- src/scheme/scheme_block_mut.rs | 21 +++++++++++++++++++-- src/scheme/scheme_mut.rs | 21 +++++++++++++++++++-- 8 files changed, 129 insertions(+), 8 deletions(-) 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..747bf24 100644 --- a/src/flag.rs +++ b/src/flag.rs @@ -74,6 +74,9 @@ bitflags! { const MAP_SHARED = 0x0001; const MAP_PRIVATE = 0x0002; + + /// Only accepted for mmap2(2). + const MAP_FIXED = 0x0004; } } 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/scheme.rs b/src/scheme/scheme.rs index 7cf77b9..00e4839 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), @@ -118,6 +123,18 @@ pub trait Scheme { #[allow(unused_variables)] fn fmap(&self, id: usize, map: &Map) -> Result { + if map.flags.contains(MapFlags::MAP_FIXED) { + return Err(Error::new(EINVAL)); + } + self.fmap2(id, &Map2 { + offset: map.offset, + size: map.size, + flags: map.flags, + address: 0, + }) + } + #[allow(unused_variables)] + fn fmap2(&self, id: usize, map: &Map2) -> Result { Err(Error::new(EBADF)) } diff --git a/src/scheme/scheme_block.rs b/src/scheme/scheme_block.rs index 4428eaa..04be058 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 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)) } @@ -118,6 +123,18 @@ pub trait SchemeBlock { #[allow(unused_variables)] fn fmap(&self, id: usize, map: &Map) -> Result> { + if map.flags.contains(MapFlags::MAP_FIXED) { + return Err(Error::new(EINVAL)); + } + self.fmap2(id, &Map2 { + offset: map.offset, + size: map.size, + flags: map.flags, + address: 0, + }) + } + #[allow(unused_variables)] + fn fmap2(&self, id: usize, map: &Map2) -> Result> { Err(Error::new(EBADF)) } diff --git a/src/scheme/scheme_block_mut.rs b/src/scheme/scheme_block_mut.rs index c4a49b3..392fb10 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 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)) } @@ -118,6 +123,18 @@ pub trait SchemeBlockMut { #[allow(unused_variables)] fn fmap(&mut self, id: usize, map: &Map) -> Result> { + if map.flags.contains(MapFlags::MAP_FIXED) { + return Err(Error::new(EINVAL)); + } + self.fmap2(id, &Map2 { + offset: map.offset, + size: map.size, + flags: map.flags, + address: 0, + }) + } + #[allow(unused_variables)] + fn fmap2(&mut self, id: usize, map: &Map2) -> Result> { Err(Error::new(EBADF)) } diff --git a/src/scheme/scheme_mut.rs b/src/scheme/scheme_mut.rs index eea1331..391b6e3 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)) } @@ -118,6 +123,18 @@ pub trait SchemeMut { #[allow(unused_variables)] fn fmap(&mut self, id: usize, map: &Map) -> Result { + if map.flags.contains(MapFlags::MAP_FIXED) { + return Err(Error::new(EINVAL)); + } + self.fmap2(id, &Map2 { + offset: map.offset, + size: map.size, + flags: map.flags, + address: 0, + }) + } + #[allow(unused_variables)] + fn fmap2(&mut self, id: usize, map: &Map2) -> Result { Err(Error::new(EBADF)) } From 21b3cd34a8f01c446bbb92d2b2b6ded240f6b6c8 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Wed, 8 Jul 2020 17:35:24 +0200 Subject: [PATCH 2/3] Change the default fmap2 impl to use fmap. --- src/scheme/generate.sh | 1 + src/scheme/scheme.rs | 19 +++++++++---------- src/scheme/scheme_block.rs | 21 ++++++++++----------- src/scheme/scheme_block_mut.rs | 21 ++++++++++----------- src/scheme/scheme_mut.rs | 19 +++++++++---------- 5 files changed, 39 insertions(+), 42 deletions(-) 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 00e4839..0af8bb5 100644 --- a/src/scheme/scheme.rs +++ b/src/scheme/scheme.rs @@ -123,19 +123,18 @@ pub trait Scheme { #[allow(unused_variables)] fn fmap(&self, id: usize, map: &Map) -> Result { - if map.flags.contains(MapFlags::MAP_FIXED) { - return Err(Error::new(EINVAL)); - } - self.fmap2(id, &Map2 { - offset: map.offset, - size: map.size, - flags: map.flags, - address: 0, - }) + Err(Error::new(EBADF)) } #[allow(unused_variables)] fn fmap2(&self, id: usize, map: &Map2) -> Result { - Err(Error::new(EBADF)) + 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)] diff --git a/src/scheme/scheme_block.rs b/src/scheme/scheme_block.rs index 04be058..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 as isize, packet.d).map(|o| o as usize), + 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), @@ -123,19 +123,18 @@ pub trait SchemeBlock { #[allow(unused_variables)] fn fmap(&self, id: usize, map: &Map) -> Result> { - if map.flags.contains(MapFlags::MAP_FIXED) { - return Err(Error::new(EINVAL)); - } - self.fmap2(id, &Map2 { - offset: map.offset, - size: map.size, - flags: map.flags, - address: 0, - }) + Err(Error::new(EBADF)) } #[allow(unused_variables)] fn fmap2(&self, id: usize, map: &Map2) -> Result> { - Err(Error::new(EBADF)) + 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)] diff --git a/src/scheme/scheme_block_mut.rs b/src/scheme/scheme_block_mut.rs index 392fb10..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 as isize, packet.d).map(|o| o as usize), + 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), @@ -123,19 +123,18 @@ pub trait SchemeBlockMut { #[allow(unused_variables)] fn fmap(&mut self, id: usize, map: &Map) -> Result> { - if map.flags.contains(MapFlags::MAP_FIXED) { - return Err(Error::new(EINVAL)); - } - self.fmap2(id, &Map2 { - offset: map.offset, - size: map.size, - flags: map.flags, - address: 0, - }) + Err(Error::new(EBADF)) } #[allow(unused_variables)] fn fmap2(&mut self, id: usize, map: &Map2) -> Result> { - Err(Error::new(EBADF)) + 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)] diff --git a/src/scheme/scheme_mut.rs b/src/scheme/scheme_mut.rs index 391b6e3..1672067 100644 --- a/src/scheme/scheme_mut.rs +++ b/src/scheme/scheme_mut.rs @@ -123,19 +123,18 @@ pub trait SchemeMut { #[allow(unused_variables)] fn fmap(&mut self, id: usize, map: &Map) -> Result { - if map.flags.contains(MapFlags::MAP_FIXED) { - return Err(Error::new(EINVAL)); - } - self.fmap2(id, &Map2 { - offset: map.offset, - size: map.size, - flags: map.flags, - address: 0, - }) + Err(Error::new(EBADF)) } #[allow(unused_variables)] fn fmap2(&mut self, id: usize, map: &Map2) -> Result { - Err(Error::new(EBADF)) + 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)] From 27fcecb30fb3154a9b45f66756d64f8f48281a7b Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Wed, 8 Jul 2020 18:17:11 +0200 Subject: [PATCH 3/3] Add MAP_FIXED_NOREPLACE. --- src/flag.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/flag.rs b/src/flag.rs index 747bf24..195ecb6 100644 --- a/src/flag.rs +++ b/src/flag.rs @@ -77,6 +77,7 @@ bitflags! { /// Only accepted for mmap2(2). const MAP_FIXED = 0x0004; + const MAP_FIXED_NOREPLACE = 0x000C; } }