Last active
February 15, 2016 19:46
-
-
Save valpackett/9c13c245e9f4051236dd to your computer and use it in GitHub Desktop.
Early prototype of rusty-sandbox, using a shared memory arena like in sandblast
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
extern crate libc; | |
use std::{io, process, mem, ptr}; | |
pub struct Shared<T> { | |
data: *mut T | |
} | |
pub struct SharedArena { | |
max_size: isize, | |
mem: *mut libc::c_void | |
} | |
impl Drop for SharedArena { | |
fn drop(&mut self) { | |
unsafe { libc::munmap(self.mem, self.max_size as libc::size_t); } | |
} | |
} | |
impl SharedArena { | |
fn new(len: isize) -> io::Result<SharedArena> { | |
let reserved_size = mem::size_of::<isize>() as isize + mem::size_of::<libc::intptr_t>() as isize; | |
let max_size = len + reserved_size; | |
let mem = unsafe { | |
libc::mmap(ptr::null_mut(), | |
max_size as libc::size_t, | |
libc::PROT_READ | libc::PROT_WRITE, | |
libc::MAP_SHARED | libc::MAP_ANON, | |
-1, | |
0) | |
}; | |
if mem == libc::MAP_FAILED { | |
Err(io::Error::last_os_error()) | |
} else { | |
let cur_size : &mut isize = unsafe { mem::transmute(mem) }; | |
*cur_size = reserved_size; | |
Ok(SharedArena { | |
max_size: max_size, | |
mem: mem, | |
}) | |
} | |
} | |
fn cur_size(&mut self) -> &mut isize { | |
unsafe { mem::transmute(self.mem) } | |
} | |
fn ret_val(&mut self) -> &mut *mut libc::intptr_t { | |
unsafe { mem::transmute(self.mem.offset((mem::size_of::<isize>() / mem::size_of::<libc::c_void>()) as isize)) } | |
} | |
pub fn copy<T: Copy>(&mut self, obj: T) -> io::Result<Shared<T>> { | |
let osize = mem::size_of::<T>() as isize; | |
if *self.cur_size() + osize > self.max_size { | |
Err(io::Error::new(io::ErrorKind::Other, "Out of memory on the SharedArena")) | |
} else { | |
let ptr : &mut T = unsafe { mem::transmute(self.mem.offset(*self.cur_size())) }; | |
*ptr = obj; | |
let ret = Shared { data: ptr }; | |
*self.cur_size() += osize; | |
Ok(ret) | |
} | |
} | |
} | |
pub fn sandboxify<F, T: Copy>(memory_size: isize, fun: F) -> io::Result<T> where F: Fn(&mut SharedArena) -> Shared<T> { | |
let mut arena = try!(SharedArena::new(memory_size)); | |
let pid = unsafe { libc::fork() }; | |
if pid < 0 { | |
Err(io::Error::new(io::ErrorKind::Other, "fork() failed")) | |
} else if pid > 0 { // parent | |
let mut status = 0; | |
unsafe { libc::waitpid(pid, &mut status, 0) }; | |
if status == 0 { | |
let result : &T = unsafe { mem::transmute(*arena.ret_val()) }; | |
Ok(*result) | |
} else { | |
Err(io::Error::new(io::ErrorKind::Other, "Sandboxed child process exited with non-zero status")) | |
} | |
} else { // child | |
let ret = fun(&mut arena).data; | |
*arena.ret_val() = unsafe { mem::transmute(ret) }; | |
mem::forget(ret); | |
process::exit(0); | |
} | |
} | |
#[cfg(test)] | |
mod tests { | |
use super::sandboxify; | |
#[test] | |
fn test_simple() { | |
assert_eq!(sandboxify(4, |a| { a.copy(7 as u32).unwrap() }).unwrap(), 7); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment