diff --git a/src/data.rs b/src/data.rs index 3afb8bb603..c93869793e 100644 --- a/src/data.rs +++ b/src/data.rs @@ -313,3 +313,44 @@ macro_rules! ptrace_event { } } } + +bitflags::bitflags! { + #[derive(Default)] + pub struct GrantFlags: usize { + const GRANT_READ = 0x0000_0001; + const GRANT_WRITE = 0x0000_0002; + const GRANT_EXEC = 0x0000_0004; + + const GRANT_SHARED = 0x0000_0008; + const GRANT_LAZY = 0x0000_0010; + const GRANT_SCHEME = 0x0000_0020; + const GRANT_PHYS = 0x0000_0040; + const GRANT_PINNED = 0x0000_0080; + } +} + +#[derive(Clone, Copy, Debug, Default)] +#[repr(C)] +pub struct GrantDesc { + pub base: usize, + pub size: usize, + pub flags: GrantFlags, + pub offset: u64, +} + +impl Deref for GrantDesc { + type Target = [u8]; + fn deref(&self) -> &[u8] { + unsafe { + slice::from_raw_parts(self as *const GrantDesc as *const u8, mem::size_of::()) + } + } +} + +impl DerefMut for GrantDesc { + fn deref_mut(&mut self) -> &mut [u8] { + unsafe { + slice::from_raw_parts_mut(self as *mut GrantDesc as *mut u8, mem::size_of::()) + } + } +} diff --git a/src/flag.rs b/src/flag.rs index dff3aa9eee..45a6e42e80 100644 --- a/src/flag.rs +++ b/src/flag.rs @@ -54,11 +54,18 @@ pub const FUTEX_WAKE: usize = 1; pub const FUTEX_REQUEUE: usize = 2; pub const FUTEX_WAIT64: usize = 3; +// packet.c = fd pub const SKMSG_FRETURNFD: usize = 0; +// packet.uid:packet.gid = offset, packet.c = base address, packet.d = page count +pub const SKMSG_PROVIDE_MMAP: usize = 1; + bitflags! { pub struct MapFlags: usize { + // TODO: Downgrade PROT_NONE to global constant? (bitflags specifically states zero flags + // can cause buggy behavior). const PROT_NONE = 0x0000_0000; + const PROT_EXEC = 0x0001_0000; const PROT_WRITE = 0x0002_0000; const PROT_READ = 0x0004_0000; @@ -66,9 +73,30 @@ bitflags! { const MAP_SHARED = 0x0001; const MAP_PRIVATE = 0x0002; - /// Only accepted for mmap2(2). const MAP_FIXED = 0x0004; const MAP_FIXED_NOREPLACE = 0x000C; + + /// For *userspace-backed mmaps*, return from the mmap call before all pages have been + /// provided by the scheme. This requires the scheme to be trusted, as the current context + /// can block indefinitely, if the scheme does not respond to the page fault handler's + /// request, as it tries to map the page by requesting it from the scheme. + /// + /// In some cases however, such as the program loader, the data needs to be trusted as much + /// with or without MAP_LAZY, and if so, mapping lazily will not cause insecureness by + /// itself. + /// + /// For kernel-backed mmaps, this flag has no effect at all. It is unspecified whether + /// kernel mmaps are lazy or not. + const MAP_LAZY = 0x0010; + } +} +bitflags! { + pub struct MunmapFlags: usize { + /// Indicates whether the funmap call must implicitly do an msync, for the changes to + /// become visible later. + /// + /// This flag will currently be set if and only if MAP_SHARED | PROT_WRITE are set. + const NEEDS_SYNC = 1; } } @@ -336,3 +364,11 @@ pub fn wexitstatus(status: usize) -> usize { pub fn wcoredump(status: usize) -> bool { (status & 0x80) != 0 } + +bitflags! { + pub struct MremapFlags: usize { + const FIXED = 1; + const FIXED_REPLACE = 3; + // TODO: MAYMOVE, DONTUNMAP + } +} diff --git a/src/number.rs b/src/number.rs index cb8471f257..d7c911c58b 100644 --- a/src/number.rs +++ b/src/number.rs @@ -25,10 +25,16 @@ pub const SYS_FCHMOD: usize = SYS_CLASS_FILE | 94; pub const SYS_FCHOWN: usize = SYS_CLASS_FILE | 207; pub const SYS_FCNTL: usize = SYS_CLASS_FILE | 55; pub const SYS_FEVENT: usize = SYS_CLASS_FILE | 927; + +// TODO: Rename FMAP/FUNMAP to MMAP/MUNMAP pub const SYS_FMAP_OLD: usize = SYS_CLASS_FILE | SYS_ARG_SLICE | 90; pub const SYS_FMAP: usize = SYS_CLASS_FILE | SYS_ARG_SLICE | 900; +// TODO: SYS_FUNMAP should be SYS_CLASS_FILE +// TODO: Remove FMAP/FMAP_OLD pub const SYS_FUNMAP_OLD: usize = SYS_CLASS_FILE | 91; pub const SYS_FUNMAP: usize = SYS_CLASS_FILE | 92; +pub const SYS_MREMAP: usize = 155; + pub const SYS_FPATH: usize = SYS_CLASS_FILE | SYS_ARG_MSLICE | 928; pub const SYS_FRENAME: usize = SYS_CLASS_FILE | SYS_ARG_PATH | 38; pub const SYS_FSTAT: usize = SYS_CLASS_FILE | SYS_ARG_MSLICE | 28; @@ -37,6 +43,18 @@ pub const SYS_FSYNC: usize = SYS_CLASS_FILE | 118; pub const SYS_FTRUNCATE: usize = SYS_CLASS_FILE | 93; pub const SYS_FUTIMENS: usize = SYS_CLASS_FILE | SYS_ARG_SLICE | 320; +// b = file, c = flags, d = required_page_count, uid:gid = offset +pub const KSMSG_MMAP: usize = SYS_CLASS_FILE | 72; + +// b = file, c = flags, d = page_count, uid:gid = offset +pub const KSMSG_MSYNC: usize = SYS_CLASS_FILE | 73; + +// b = file, c = page_count, uid:gid = offset +pub const KSMSG_MUNMAP: usize = SYS_CLASS_FILE | 74; + +// b = file, c = flags, d = page_count, uid:gid = offset +pub const KSMSG_MMAP_PREP: usize = SYS_CLASS_FILE | 75; + pub const SYS_CLOCK_GETTIME: usize = 265; pub const SYS_EXIT: usize = 1; pub const SYS_FUTEX: usize = 240; diff --git a/src/scheme/scheme.rs b/src/scheme/scheme.rs index 46e3abefac..ee09d697bf 100644 --- a/src/scheme/scheme.rs +++ b/src/scheme/scheme.rs @@ -36,18 +36,6 @@ pub trait Scheme { SYS_FCHOWN => self.fchown(packet.b, packet.c as u32, packet.d as u32), SYS_FCNTL => self.fcntl(packet.b, packet.c, packet.d), SYS_FEVENT => self.fevent(packet.b, EventFlags::from_bits_truncate(packet.c)).map(|f| f.bits()), - SYS_FMAP_OLD => if packet.d >= mem::size_of::() { - self.fmap_old(packet.b, unsafe { &*(packet.c as *const OldMap) }) - } else { - Err(Error::new(EFAULT)) - }, - SYS_FMAP => if packet.d >= mem::size_of::() { - self.fmap(packet.b, unsafe { &*(packet.c as *const Map) }) - } else { - Err(Error::new(EFAULT)) - }, - SYS_FUNMAP_OLD => self.funmap_old(packet.b), - SYS_FUNMAP => self.funmap(packet.b, packet.c), SYS_FPATH => self.fpath(packet.b, unsafe { slice::from_raw_parts_mut(packet.c as *mut u8, packet.d) }), SYS_FRENAME => if let Some(path) = unsafe { str_from_raw_parts(packet.c as *const u8, packet.d) } { self.frename(packet.b, path, packet.uid, packet.gid) @@ -72,6 +60,10 @@ pub trait Scheme { Err(Error::new(EFAULT)) }, SYS_CLOSE => self.close(packet.b), + + KSMSG_MMAP_PREP => self.mmap_prep(packet.b, u64::from(packet.uid) | (u64::from(packet.gid) << 32), packet.c, MapFlags::from_bits_truncate(packet.d)), + KSMSG_MUNMAP => self.munmap(packet.b, u64::from(packet.uid) | (u64::from(packet.gid) << 32), packet.c, MunmapFlags::from_bits_truncate(packet.d)), + _ => Err(Error::new(ENOSYS)) }; @@ -150,32 +142,6 @@ pub trait Scheme { Err(Error::new(EBADF)) } - #[allow(unused_variables)] - fn fmap_old(&self, id: usize, map: &OldMap) -> Result { - Err(Error::new(EBADF)) - } - #[allow(unused_variables)] - fn fmap(&self, id: usize, map: &Map) -> Result { - if map.flags.contains(MapFlags::MAP_FIXED) { - return Err(Error::new(EINVAL)); - } - self.fmap_old(id, &OldMap { - offset: map.offset, - size: map.size, - flags: map.flags, - }) - } - - #[allow(unused_variables)] - fn funmap_old(&self, address: usize) -> Result { - Ok(0) - } - - #[allow(unused_variables)] - fn funmap(&self, address: usize, length: usize) -> Result { - Ok(0) - } - #[allow(unused_variables)] fn fpath(&self, id: usize, buf: &mut [u8]) -> Result { Err(Error::new(EBADF)) @@ -215,4 +181,14 @@ pub trait Scheme { fn close(&self, id: usize) -> Result { Err(Error::new(EBADF)) } + + #[allow(unused_variables)] + fn mmap_prep(&self, id: usize, offset: u64, size: usize, flags: MapFlags) -> Result { + Err(Error::new(EOPNOTSUPP)) + } + + #[allow(unused_variables)] + fn munmap(&self, id: usize, offset: u64, size: usize, flags: MunmapFlags) -> Result { + Err(Error::new(EOPNOTSUPP)) + } } diff --git a/src/scheme/scheme_block.rs b/src/scheme/scheme_block.rs index 2db6c361ae..e74e3b7e2a 100644 --- a/src/scheme/scheme_block.rs +++ b/src/scheme/scheme_block.rs @@ -36,18 +36,6 @@ pub trait SchemeBlock { SYS_FCHOWN => self.fchown(packet.b, packet.c as u32, packet.d as u32), SYS_FCNTL => self.fcntl(packet.b, packet.c, packet.d), SYS_FEVENT => self.fevent(packet.b, EventFlags::from_bits_truncate(packet.c)).map(|f| f.map(|f| f.bits())), - SYS_FMAP_OLD => if packet.d >= mem::size_of::() { - self.fmap_old(packet.b, unsafe { &*(packet.c as *const OldMap) }) - } else { - Err(Error::new(EFAULT)) - }, - SYS_FMAP => if packet.d >= mem::size_of::() { - self.fmap(packet.b, unsafe { &*(packet.c as *const Map) }) - } else { - Err(Error::new(EFAULT)) - }, - SYS_FUNMAP_OLD => self.funmap_old(packet.b), - SYS_FUNMAP => self.funmap(packet.b, packet.c), SYS_FPATH => self.fpath(packet.b, unsafe { slice::from_raw_parts_mut(packet.c as *mut u8, packet.d) }), SYS_FRENAME => if let Some(path) = unsafe { str_from_raw_parts(packet.c as *const u8, packet.d) } { self.frename(packet.b, path, packet.uid, packet.gid) @@ -72,6 +60,10 @@ pub trait SchemeBlock { Err(Error::new(EFAULT)) }, SYS_CLOSE => self.close(packet.b), + + KSMSG_MMAP_PREP => self.mmap_prep(packet.b, u64::from(packet.uid) | (u64::from(packet.gid) << 32), packet.c, MapFlags::from_bits_truncate(packet.d)), + KSMSG_MUNMAP => self.munmap(packet.b, u64::from(packet.uid) | (u64::from(packet.gid) << 32), packet.c, MunmapFlags::from_bits_truncate(packet.d)), + _ => Err(Error::new(ENOSYS)) }; @@ -150,32 +142,6 @@ pub trait SchemeBlock { Err(Error::new(EBADF)) } - #[allow(unused_variables)] - fn fmap_old(&self, id: usize, map: &OldMap) -> Result> { - Err(Error::new(EBADF)) - } - #[allow(unused_variables)] - fn fmap(&self, id: usize, map: &Map) -> Result> { - if map.flags.contains(MapFlags::MAP_FIXED) { - return Err(Error::new(EINVAL)); - } - self.fmap_old(id, &OldMap { - offset: map.offset, - size: map.size, - flags: map.flags, - }) - } - - #[allow(unused_variables)] - fn funmap_old(&self, address: usize) -> Result> { - Ok(Some(0)) - } - - #[allow(unused_variables)] - fn funmap(&self, address: usize, length: usize) -> Result> { - Ok(Some(0)) - } - #[allow(unused_variables)] fn fpath(&self, id: usize, buf: &mut [u8]) -> Result> { Err(Error::new(EBADF)) @@ -215,4 +181,14 @@ pub trait SchemeBlock { fn close(&self, id: usize) -> Result> { Err(Error::new(EBADF)) } + + #[allow(unused_variables)] + fn mmap_prep(&self, id: usize, offset: u64, size: usize, flags: MapFlags) -> Result> { + Err(Error::new(EOPNOTSUPP)) + } + + #[allow(unused_variables)] + fn munmap(&self, id: usize, offset: u64, size: usize, flags: MunmapFlags) -> Result> { + Err(Error::new(EOPNOTSUPP)) + } } diff --git a/src/scheme/scheme_block_mut.rs b/src/scheme/scheme_block_mut.rs index 62302ea2c9..fd2c59069b 100644 --- a/src/scheme/scheme_block_mut.rs +++ b/src/scheme/scheme_block_mut.rs @@ -36,18 +36,6 @@ pub trait SchemeBlockMut { SYS_FCHOWN => self.fchown(packet.b, packet.c as u32, packet.d as u32), SYS_FCNTL => self.fcntl(packet.b, packet.c, packet.d), SYS_FEVENT => self.fevent(packet.b, EventFlags::from_bits_truncate(packet.c)).map(|f| f.map(|f| f.bits())), - SYS_FMAP_OLD => if packet.d >= mem::size_of::() { - self.fmap_old(packet.b, unsafe { &*(packet.c as *const OldMap) }) - } else { - Err(Error::new(EFAULT)) - }, - SYS_FMAP => if packet.d >= mem::size_of::() { - self.fmap(packet.b, unsafe { &*(packet.c as *const Map) }) - } else { - Err(Error::new(EFAULT)) - }, - SYS_FUNMAP_OLD => self.funmap_old(packet.b), - SYS_FUNMAP => self.funmap(packet.b, packet.c), SYS_FPATH => self.fpath(packet.b, unsafe { slice::from_raw_parts_mut(packet.c as *mut u8, packet.d) }), SYS_FRENAME => if let Some(path) = unsafe { str_from_raw_parts(packet.c as *const u8, packet.d) } { self.frename(packet.b, path, packet.uid, packet.gid) @@ -72,6 +60,10 @@ pub trait SchemeBlockMut { Err(Error::new(EFAULT)) }, SYS_CLOSE => self.close(packet.b), + + KSMSG_MMAP_PREP => self.mmap_prep(packet.b, u64::from(packet.uid) | (u64::from(packet.gid) << 32), packet.c, MapFlags::from_bits_truncate(packet.d)), + KSMSG_MUNMAP => self.munmap(packet.b, u64::from(packet.uid) | (u64::from(packet.gid) << 32), packet.c, MunmapFlags::from_bits_truncate(packet.d)), + _ => Err(Error::new(ENOSYS)) }; @@ -150,32 +142,6 @@ pub trait SchemeBlockMut { Err(Error::new(EBADF)) } - #[allow(unused_variables)] - fn fmap_old(&mut self, id: usize, map: &OldMap) -> Result> { - Err(Error::new(EBADF)) - } - #[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.fmap_old(id, &OldMap { - offset: map.offset, - size: map.size, - flags: map.flags, - }) - } - - #[allow(unused_variables)] - fn funmap_old(&mut self, address: usize) -> Result> { - Ok(Some(0)) - } - - #[allow(unused_variables)] - fn funmap(&mut self, address: usize, length: usize) -> Result> { - Ok(Some(0)) - } - #[allow(unused_variables)] fn fpath(&mut self, id: usize, buf: &mut [u8]) -> Result> { Err(Error::new(EBADF)) @@ -215,4 +181,14 @@ pub trait SchemeBlockMut { fn close(&mut self, id: usize) -> Result> { Err(Error::new(EBADF)) } + + #[allow(unused_variables)] + fn mmap_prep(&mut self, id: usize, offset: u64, size: usize, flags: MapFlags) -> Result> { + Err(Error::new(EOPNOTSUPP)) + } + + #[allow(unused_variables)] + fn munmap(&mut self, id: usize, offset: u64, size: usize, flags: MunmapFlags) -> Result> { + Err(Error::new(EOPNOTSUPP)) + } } diff --git a/src/scheme/scheme_mut.rs b/src/scheme/scheme_mut.rs index 229a5c866b..2eea4dcbc8 100644 --- a/src/scheme/scheme_mut.rs +++ b/src/scheme/scheme_mut.rs @@ -36,18 +36,6 @@ pub trait SchemeMut { SYS_FCHOWN => self.fchown(packet.b, packet.c as u32, packet.d as u32), SYS_FCNTL => self.fcntl(packet.b, packet.c, packet.d), SYS_FEVENT => self.fevent(packet.b, EventFlags::from_bits_truncate(packet.c)).map(|f| f.bits()), - SYS_FMAP_OLD => if packet.d >= mem::size_of::() { - self.fmap_old(packet.b, unsafe { &*(packet.c as *const OldMap) }) - } else { - Err(Error::new(EFAULT)) - }, - SYS_FMAP => if packet.d >= mem::size_of::() { - self.fmap(packet.b, unsafe { &*(packet.c as *const Map) }) - } else { - Err(Error::new(EFAULT)) - }, - SYS_FUNMAP_OLD => self.funmap_old(packet.b), - SYS_FUNMAP => self.funmap(packet.b, packet.c), SYS_FPATH => self.fpath(packet.b, unsafe { slice::from_raw_parts_mut(packet.c as *mut u8, packet.d) }), SYS_FRENAME => if let Some(path) = unsafe { str_from_raw_parts(packet.c as *const u8, packet.d) } { self.frename(packet.b, path, packet.uid, packet.gid) @@ -72,6 +60,10 @@ pub trait SchemeMut { Err(Error::new(EFAULT)) }, SYS_CLOSE => self.close(packet.b), + + KSMSG_MMAP_PREP => self.mmap_prep(packet.b, u64::from(packet.uid) | (u64::from(packet.gid) << 32), packet.c, MapFlags::from_bits_truncate(packet.d)), + KSMSG_MUNMAP => self.munmap(packet.b, u64::from(packet.uid) | (u64::from(packet.gid) << 32), packet.c, MunmapFlags::from_bits_truncate(packet.d)), + _ => Err(Error::new(ENOSYS)) }; @@ -150,32 +142,6 @@ pub trait SchemeMut { Err(Error::new(EBADF)) } - #[allow(unused_variables)] - fn fmap_old(&mut self, id: usize, map: &OldMap) -> Result { - Err(Error::new(EBADF)) - } - #[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.fmap_old(id, &OldMap { - offset: map.offset, - size: map.size, - flags: map.flags, - }) - } - - #[allow(unused_variables)] - fn funmap_old(&mut self, address: usize) -> Result { - Ok(0) - } - - #[allow(unused_variables)] - fn funmap(&mut self, address: usize, length: usize) -> Result { - Ok(0) - } - #[allow(unused_variables)] fn fpath(&mut self, id: usize, buf: &mut [u8]) -> Result { Err(Error::new(EBADF)) @@ -215,4 +181,14 @@ pub trait SchemeMut { fn close(&mut self, id: usize) -> Result { Err(Error::new(EBADF)) } + + #[allow(unused_variables)] + fn mmap_prep(&mut self, id: usize, offset: u64, size: usize, flags: MapFlags) -> Result { + Err(Error::new(EOPNOTSUPP)) + } + + #[allow(unused_variables)] + fn munmap(&mut self, id: usize, offset: u64, size: usize, flags: MunmapFlags) -> Result { + Err(Error::new(EOPNOTSUPP)) + } }