Add sandboxing

This commit is contained in:
Tiffany Bennett 2016-08-13 23:38:12 -04:00
parent f29ccdae8b
commit f97b0f6311
4 changed files with 96 additions and 26 deletions

View file

@ -12,7 +12,8 @@ keywords = ["unit", "math", "conversion", "cli", "tool"]
[features]
default = ["rustyline", "chrono-humanize"]
ircbot = ["irc", "glob"]
web = ["hyper", "url"]
web = ["hyper", "url", "sandbox"]
sandbox = ["libc", "ipc-channel"]
[dependencies]
rust-gmp = "0.3.2"
@ -23,6 +24,8 @@ irc = { version = "0.11.3", optional = true }
glob = { version = "0.2.11", optional = true }
hyper = { version = "0.9.10", optional = true }
url = { version = "1.2.0", optional = true }
libc = { version = "0.2.14", optional = true }
ipc-channel = { version = "0.5.1", optional = true }
[[bin]]
name = "rink"

View file

@ -12,9 +12,22 @@ fn main() {
use glob::glob;
use std::thread;
fn run(config: &str) {
#[cfg(feature = "sandbox")]
fn eval(line: &str) -> String {
one_line_sandbox(line)
}
#[cfg(not(feature = "sandbox"))]
fn eval(line: &str) -> String {
let mut ctx = load().unwrap();
ctx.short_output = true;
match one_line(&mut ctx, line) {
Ok(v) => v,
Err(e) => e
}
}
fn run(config: &str) {
let server = IrcServer::new(config).unwrap();
server.identify().unwrap();
let nick = server.config().nickname.clone().unwrap();
@ -29,11 +42,8 @@ fn main() {
&*chan
};
let line = message_str[prefix.len()..].trim();
let reply = match one_line(&mut ctx, line) {
Ok(v) => v,
Err(e) => e
};
let mut i = 0;
let reply = eval(line);
for line in reply.lines() {
if line.trim().len() > 0 {
server.send(Command::NOTICE(reply_to.to_owned(), line.to_owned())).unwrap();

View file

@ -30,23 +30,6 @@ fn main() {
use std::env::args;
use std::io::{Read, Write};
use url::form_urlencoded;
use std::sync::mpsc;
use std::sync::Mutex;
use std::thread;
let (tx, rx) = mpsc::channel::<(String, mpsc::Sender<String>)>();
thread::spawn(move || {
let mut ctx = rink::load().unwrap();
while let Ok((req, tx)) = rx.recv() {
let reply = match rink::one_line(&mut ctx, &*req) {
Ok(v) => v,
Err(v) => v
};
tx.send(reply).unwrap();
}
});
let tx = Mutex::new(tx);
let req = move |mut req: Request, mut res: Response| {
match req.method {
@ -82,9 +65,7 @@ fn main() {
} else {
buf
};
let (tx2, rx2) = mpsc::channel();
tx.lock().unwrap().send((input, tx2)).unwrap();
let reply = rx2.recv().unwrap();
let reply = rink::one_line_sandbox(&*input);
write!(&mut res.start().unwrap(), "{}", reply).unwrap();
},
_ => *res.status_mut() = StatusCode::MethodNotAllowed

View file

@ -30,6 +30,10 @@ extern crate gmp;
extern crate chrono;
#[cfg(feature = "chrono-humanize")]
extern crate chrono_humanize;
#[cfg(feature = "sandbox")]
extern crate libc;
#[cfg(feature = "sandbox")]
extern crate ipc_channel;
pub mod unit_defs;
pub mod eval;
@ -117,6 +121,78 @@ pub fn one_line(ctx: &mut Context, line: &str) -> Result<String, String> {
ctx.eval_outer(&expr)
}
#[cfg(feature = "sandbox")]
pub fn one_line_sandbox(line: &str) -> String {
use libc;
use std::io::Error;
use ipc_channel::ipc::{IpcOneShotServer, IpcSender};
pub unsafe fn fork<F: FnOnce()>(child_func: F) -> libc::pid_t {
match libc::fork() {
-1 => panic!("Fork failed: {}", Error::last_os_error()),
0 => { child_func(); unreachable!() },
pid => pid,
}
}
let (server, server_name) = IpcOneShotServer::new().unwrap();
let child = || {
let tx = IpcSender::connect(server_name).unwrap();
tx.send("".to_owned()).unwrap();
unsafe {
libc::close(2);
let limit = libc::rlimit {
// 50 megabytes
rlim_cur: 50_000_000,
rlim_max: 50_000_000,
};
libc::setrlimit(libc::RLIMIT_AS, &limit);
let limit = libc::rlimit {
// 15 seconds
rlim_cur: 15,
rlim_max: 15
};
libc::setrlimit(libc::RLIMIT_CPU, &limit);
}
let mut ctx = load().unwrap();
ctx.short_output = true;
let reply = match one_line(&mut ctx, line) {
Ok(v) => v,
Err(e) => e
};
tx.send(reply).unwrap();
::std::process::exit(0)
};
let pid = unsafe { fork(child) };
let (rx, _) = server.accept().unwrap();
let status = unsafe {
let mut status = 0;
libc::waitpid(pid, &mut status, 0);
status
};
let res = match rx.try_recv() {
Ok(res) => res,
Err(_) if unsafe { libc::WIFSIGNALED(status) && libc::WTERMSIG(status) == libc::SIGXCPU } =>
format!("Calculation timed out"),
// :(
Err(ref e) if format!("{}", e) == "IoError: Connection reset by peer (os error 104)" =>
format!("Calculation ran out of memory"),
Err(e) => format!("{}", e)
};
res
}
fn btree_merge<K: ::std::cmp::Ord+Clone, V:Clone, F:Fn(&V, &V) -> Option<V>>(
left: &BTreeMap<K, V>, right: &BTreeMap<K, V>, merge_func: F
) -> BTreeMap<K, V> {