Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ability to change memory protection on std::os::MemoryMap. #17805

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 71 additions & 0 deletions src/libstd/os.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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)
};
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of duplicating the logic above, could it be refactored into a helper function? (same for unix)


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 {
Expand Down
19 changes: 19 additions & 0 deletions src/test/run-pass/mem-protect.rs
Original file line number Diff line number Diff line change
@@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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;
}
}