mirror of
https://github.com/tiffany352/rink-rs
synced 2024-11-10 13:44:15 +00:00
Add sandboxing
This commit is contained in:
parent
f29ccdae8b
commit
f97b0f6311
4 changed files with 96 additions and 26 deletions
|
@ -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"
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
|
|
76
src/lib.rs
76
src/lib.rs
|
@ -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> {
|
||||
|
|
Loading…
Reference in a new issue