From b9bd7a55f9b50964cae25d8c9ed5f40908cf4cf7 Mon Sep 17 00:00:00 2001 From: Jake Greenfield Date: Sun, 5 Oct 2014 16:31:36 -0400 Subject: [PATCH] Add ability to change memory protection on std::os::MemoryMap. --- src/libstd/os.rs | 71 ++++++++++++++++++++++++++++++++ src/test/run-pass/mem-protect.rs | 19 +++++++++ 2 files changed, 90 insertions(+) create mode 100644 src/test/run-pass/mem-protect.rs diff --git a/src/libstd/os.rs b/src/libstd/os.rs index d904e657e403b..12ba3debf9c34 100644 --- a/src/libstd/os.rs +++ b/src/libstd/os.rs @@ -1502,6 +1502,36 @@ impl MemoryMap { } } + /// Change protection attributes of this map. + /// + /// Only accepts protection-related MapOptions (MapReadable, MapWritable, MapExecutable) + pub fn protect(&mut self, options: &[MapOption]) -> Result<(), MapError> { + let mut prot = 0; + + for &o in options.iter() { + match o { + MapReadable => { prot |= libc::PROT_READ; }, + MapWritable => { prot |= libc::PROT_WRITE; }, + MapExecutable => { prot |= libc::PROT_EXEC; }, + a => { fail!("Invalid memory protection option"); } + } + } + + let r = unsafe { + libc::mprotect(self.data as *mut c_void, self.len as libc::size_t, prot) + }; + + if r == -1 { + Err(match errno() as c_int { + libc::EACCES => ErrFdNotAvail, + libc::ENOMEM => ErrNoMem, + code => ErrUnknown(code as int) + }) + } else { + Ok(()) + } + } + /// Granularity that the offset or address must be for `MapOffset` and /// `MapAddr` respectively. pub fn granularity() -> uint { @@ -1616,6 +1646,47 @@ impl MemoryMap { } } + /// Change protection attributes of this map. + /// Only accepts protection-related MapOptions (MapReadable, MapWritable, MapExecutable) + pub fn protect(&mut self, option: &[MapOption]) -> Result<(), MapError> { + use libc::types::os::arch::extra::{LPVOID, DWORD, SIZE_T, LPDWORD}; + + let mut readable = false; + let mut writable = false; + let mut executable = false; + + for &o in options.iter() { + match o { + MapReadable => { readable = true; }, + MapWritable => { writable = true; }, + MapExecutable => { executable = true; }, + a => { fail!("Invalid memory protection option"); } + } + } + + let flProtect = match (executable, readable, writable) { + (false, false, false) if fd == -1 => libc::PAGE_NOACCESS, + (false, true, false) => libc::PAGE_READONLY, + (false, true, true) => libc::PAGE_READWRITE, + (true, false, false) if fd == -1 => libc::PAGE_EXECUTE, + (true, true, false) => libc::PAGE_EXECUTE_READ, + (true, true, true) => libc::PAGE_EXECUTE_READWRITE, + _ => return Err(ErrUnsupProt) + }; + + let old: DWORD = 0; + + let r = unsafe { + libc::VirtualProtect(self.data as LPVOID, self.size as SIZE_T, + flProtect as DWORD, old as LPDWORD) + }; + + match r as uint { + 0 => Err(ErrUnknown(errno())), + _ => Ok(()), + } + } + /// Granularity of MapAddr() and MapOffset() parameter values. /// This may be greater than the value returned by page_size(). pub fn granularity() -> uint { diff --git a/src/test/run-pass/mem-protect.rs b/src/test/run-pass/mem-protect.rs new file mode 100644 index 0000000000000..49f0635c318f8 --- /dev/null +++ b/src/test/run-pass/mem-protect.rs @@ -0,0 +1,19 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::os::{MemoryMap, MapReadable, MapWritable}; + +pub fn main() { + let mut m = MemoryMap::new(4096, &[MapReadable]).unwrap(); + m.protect(&[MapReadable, MapWritable]).unwrap(); + unsafe { + *(m.data()) = 42; + } +}