1
Fork 0
hare-playground/backend/src/sandbox.rs

136 lines
3.6 KiB
Rust
Raw Normal View History

2024-05-24 19:58:49 +00:00
use std::fs::File;
use std::io::Write;
use std::process::Command;
2024-05-24 20:33:33 +00:00
use tempfile::{TempDir, NamedTempFile};
2024-05-24 19:58:49 +00:00
#[rustfmt::skip]
const STATIC_ARGS: &[&str] = &[
"--ro-bind", "/usr", "/usr",
"--dir", "/tmp",
"--dir", "/var",
2024-05-24 20:33:33 +00:00
"--symlink", "../tmp", "/var/tmp",
2024-05-24 19:58:49 +00:00
"--proc", "/proc",
"--dev", "/dev",
"--ro-bind", "/etc/resolv.conf", "/etc/resolv.conf",
2024-05-24 21:42:04 +00:00
"--symlink", "usr/lib", "/lib",
"--symlink", "usr/lib64", "/lib64",
"--symlink", "usr/bin", "/bin",
"--symlink", "usr/sbin", "/sbin",
2024-05-24 19:58:49 +00:00
"--unshare-all",
"--die-with-parent",
"--clearenv",
2024-05-24 21:42:04 +00:00
"--setenv", "PATH", "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
"--setenv", "HAREPATH", "/usr/local/src/hare/stdlib",
2024-05-24 19:58:49 +00:00
];
2024-05-24 21:42:04 +00:00
const HARE_COMMAND: &str = "/usr/local/bin/hare";
2024-05-24 19:58:49 +00:00
/// Default command timeout in seconds.
const DEFAULT_TIMEOUT: u32 = 10;
2024-05-24 20:33:33 +00:00
fn passwd_files(uid: u32, gid: u32) -> (NamedTempFile, NamedTempFile, Vec<String>) {
2024-05-24 19:58:49 +00:00
let uid = uid.to_string();
let passwd = Command::new("getent")
.args(["passwd", &uid, "65534"])
.output()
.expect("failed to run getent passwd");
let gid = gid.to_string();
let group = Command::new("getent")
.args(["group", &gid, "65534"])
.output()
.expect("failed to run getent passwd");
2024-05-24 20:33:33 +00:00
let mut passwd_file = tempfile::NamedTempFile::new().unwrap();
2024-05-24 19:58:49 +00:00
passwd_file.write_all(&passwd.stdout).unwrap();
passwd_file.flush().unwrap();
2024-05-24 20:33:33 +00:00
let mut group_file = tempfile::NamedTempFile::new().unwrap();
2024-05-24 19:58:49 +00:00
group_file.write_all(&group.stdout).unwrap();
group_file.flush().unwrap();
let args = vec![
2024-05-24 20:33:33 +00:00
"--ro-bind".to_string(),
passwd_file.path().display().to_string(),
2024-05-24 19:58:49 +00:00
"/etc/passwd".to_string(),
2024-05-24 20:33:33 +00:00
"--ro-bind".to_string(),
group_file.path().display().to_string(),
2024-05-24 19:58:49 +00:00
"/etc/group".to_string(),
];
(passwd_file, group_file, args)
}
fn home_dir(uid: u32) -> Vec<String> {
let user_dir = format!("/run/user/{uid}");
let home_dir = format!("{user_dir}/home");
vec![
"--dir".to_string(),
user_dir.clone(),
"--setenv".to_string(),
"HOME".to_string(),
home_dir,
"--setenv".to_string(),
"XDG_RUNTIME_DIR".to_string(),
user_dir,
]
}
fn shared_app_dir() -> (TempDir, Vec<String>) {
let tmp_app_dir = tempfile::tempdir().unwrap();
let app_dir_path = tmp_app_dir.path().display().to_string();
(
tmp_app_dir,
2024-05-24 20:33:33 +00:00
vec![
"--bind".to_string(),
app_dir_path,
"/app".to_string(),
"--chdir".to_string(),
"/app".to_string(),
],
2024-05-24 19:58:49 +00:00
)
}
fn command(app_file: &str) -> Vec<String> {
vec![
HARE_COMMAND.to_string(),
"run".to_string(),
app_file.to_string(),
]
}
fn getids() -> (u32, u32) {
2024-05-24 20:33:33 +00:00
unsafe { (libc::getuid(), libc::getgid()) }
2024-05-24 19:58:49 +00:00
}
2024-05-24 21:52:52 +00:00
pub fn run_code(code: &str) -> std::process::Output {
2024-05-24 19:58:49 +00:00
let (uid, gid) = getids();
let mut bwrap_cmd = Command::new("bwrap");
bwrap_cmd.args(STATIC_ARGS);
let (app_dir, dir_arg) = shared_app_dir();
bwrap_cmd.args(dir_arg);
let home_args = home_dir(uid);
bwrap_cmd.args(home_args);
let (_passwd, _group, file_args) = passwd_files(uid, gid);
bwrap_cmd.args(file_args);
{
2024-05-24 20:33:33 +00:00
let code_path = app_dir.path().join("main.ha");
2024-05-24 19:58:49 +00:00
let mut code_file = File::create(code_path).unwrap();
code_file.write_all(code.as_bytes()).unwrap();
}
let cmd_args = command("/app/main.ha");
bwrap_cmd.args(cmd_args);
2024-05-24 20:00:27 +00:00
let output = bwrap_cmd.output().expect("running bwrap failed");
2024-05-24 21:52:52 +00:00
output
2024-05-24 19:58:49 +00:00
}