issue #772: added an memmap replacement to support selinux

This commit is contained in:
Benson Chau
2019-05-23 16:14:45 -04:00
committed by Dan Gohman
parent bfc1468688
commit 6a19866da2
2 changed files with 80 additions and 11 deletions

View File

@@ -17,10 +17,15 @@ region = "2.0.0"
libc = { version = "0.2.42" } libc = { version = "0.2.42" }
errno = "0.2.4" errno = "0.2.4"
target-lexicon = { version = "0.4.0" } target-lexicon = { version = "0.4.0" }
memmap = { version = "0.7.0", optional = true }
[target.'cfg(target_os = "windows")'.dependencies] [target.'cfg(target_os = "windows")'.dependencies]
winapi = { version = "0.3", features = ["winbase", "memoryapi"] } winapi = { version = "0.3", features = ["winbase", "memoryapi"] }
[features]
selinux-fix = ['memmap']
default = []
[dev-dependencies] [dev-dependencies]
cranelift = { path = "../cranelift-umbrella", version = "0.34.0" } cranelift = { path = "../cranelift-umbrella", version = "0.34.0" }
cranelift-frontend = { path = "../cranelift-frontend", version = "0.34.0" } cranelift-frontend = { path = "../cranelift-frontend", version = "0.34.0" }

View File

@@ -1,5 +1,12 @@
#[cfg(not(feature = "selinux-fix"))]
use errno; use errno;
#[cfg(not(feature = "selinux-fix"))]
use libc; use libc;
#[cfg(feature = "selinux-fix")]
use memmap::MmapMut;
use region; use region;
use std::mem; use std::mem;
use std::ptr; use std::ptr;
@@ -11,6 +18,9 @@ fn round_up_to_page_size(size: usize, page_size: usize) -> usize {
/// A simple struct consisting of a pointer and length. /// A simple struct consisting of a pointer and length.
struct PtrLen { struct PtrLen {
#[cfg(feature = "selinux-fix")]
map: Option<MmapMut>,
ptr: *mut u8, ptr: *mut u8,
len: usize, len: usize,
} }
@@ -19,6 +29,9 @@ impl PtrLen {
/// Create a new empty `PtrLen`. /// Create a new empty `PtrLen`.
fn new() -> Self { fn new() -> Self {
Self { Self {
#[cfg(feature = "selinux-fix")]
map: None,
ptr: ptr::null_mut(), ptr: ptr::null_mut(),
len: 0, len: 0,
} }
@@ -26,13 +39,34 @@ impl PtrLen {
/// Create a new `PtrLen` pointing to at least `size` bytes of memory, /// Create a new `PtrLen` pointing to at least `size` bytes of memory,
/// suitably sized and aligned for memory protection. /// suitably sized and aligned for memory protection.
#[cfg(not(target_os = "windows"))] #[cfg(all(not(target_os = "windows"), feature = "selinux-fix"))]
fn with_size(size: usize) -> Result<Self, String> {
let page_size = region::page::size();
let alloc_size = round_up_to_page_size(size, page_size);
let map = MmapMut::map_anon(alloc_size);
match map {
Ok(mut map) => {
// The order here is important; we assign the pointer first to get
// around compile time borrow errors.
Ok(Self {
ptr: map.as_mut_ptr(),
map: Some(map),
len: alloc_size,
})
}
Err(e) => Err(e.to_string()),
}
}
#[cfg(all(not(target_os = "windows"), not(feature = "selinux-fix")))]
fn with_size(size: usize) -> Result<Self, String> { fn with_size(size: usize) -> Result<Self, String> {
let mut ptr = ptr::null_mut(); let mut ptr = ptr::null_mut();
let page_size = region::page::size(); let page_size = region::page::size();
let alloc_size = round_up_to_page_size(size, page_size); let alloc_size = round_up_to_page_size(size, page_size);
unsafe { unsafe {
let err = libc::posix_memalign(&mut ptr, page_size, alloc_size); let err = libc::posix_memalign(&mut ptr, page_size, alloc_size);
if err == 0 { if err == 0 {
Ok(Self { Ok(Self {
ptr: ptr as *mut u8, ptr: ptr as *mut u8,
@@ -122,6 +156,20 @@ impl Memory {
pub fn set_readable_and_executable(&mut self) { pub fn set_readable_and_executable(&mut self) {
self.finish_current(); self.finish_current();
#[cfg(feature = "selinux-fix")]
{
for &PtrLen { ref map, ptr, len } in &self.allocations[self.executable..] {
if len != 0 && map.is_some() {
unsafe {
region::protect(ptr, len, region::Protection::ReadExecute)
.expect("unable to make memory readable+executable");
}
}
}
}
#[cfg(not(feature = "selinux-fix"))]
{
for &PtrLen { ptr, len } in &self.allocations[self.executable..] { for &PtrLen { ptr, len } in &self.allocations[self.executable..] {
if len != 0 { if len != 0 {
unsafe { unsafe {
@@ -131,11 +179,26 @@ impl Memory {
} }
} }
} }
}
/// Set all memory allocated in this `Memory` up to now as readonly. /// Set all memory allocated in this `Memory` up to now as readonly.
pub fn set_readonly(&mut self) { pub fn set_readonly(&mut self) {
self.finish_current(); self.finish_current();
#[cfg(feature = "selinux-fix")]
{
for &PtrLen { ref map, ptr, len } in &self.allocations[self.executable..] {
if len != 0 && map.is_some() {
unsafe {
region::protect(ptr, len, region::Protection::Read)
.expect("unable to make memory readonly");
}
}
}
}
#[cfg(not(feature = "selinux-fix"))]
{
for &PtrLen { ptr, len } in &self.allocations[self.executable..] { for &PtrLen { ptr, len } in &self.allocations[self.executable..] {
if len != 0 { if len != 0 {
unsafe { unsafe {
@@ -146,6 +209,7 @@ impl Memory {
} }
} }
} }
}
// TODO: Implement Drop to unprotect and deallocate the memory? // TODO: Implement Drop to unprotect and deallocate the memory?