full bubblewrap
This commit is contained in:
parent
fc2f0d0dd2
commit
e87a34e3fa
|
@ -149,10 +149,60 @@ export fn handle_exec(buf: *io::stream, serv_req: *http::server_request) void =
|
||||||
return;
|
return;
|
||||||
case let body: io::handle =>
|
case let body: io::handle =>
|
||||||
let payload = json::load(body)!;
|
let payload = json::load(body)!;
|
||||||
|
// defer json::finish(payload);
|
||||||
yield payload;
|
yield payload;
|
||||||
};
|
};
|
||||||
|
|
||||||
json::dump(buf, payload)!;
|
defer json::finish(payload);
|
||||||
|
|
||||||
|
let payload = match (payload) {
|
||||||
|
case let obj: json::object => yield obj;
|
||||||
|
case =>
|
||||||
|
handle_notfound(buf, serv_req);
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
let files = match (json::get(&payload, "files")) {
|
||||||
|
case void =>
|
||||||
|
handle_notfound(buf, serv_req);
|
||||||
|
return;
|
||||||
|
case let j: *json::value => yield j;
|
||||||
|
};
|
||||||
|
|
||||||
|
let files = match (*files) {
|
||||||
|
case let o: json::object => yield o;
|
||||||
|
case =>
|
||||||
|
handle_notfound(buf, serv_req);
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
let code = match (json::get(&files, "")) {
|
||||||
|
case void =>
|
||||||
|
handle_notfound(buf, serv_req);
|
||||||
|
return;
|
||||||
|
case let j: *json::value => yield j;
|
||||||
|
};
|
||||||
|
|
||||||
|
let code = match (*code) {
|
||||||
|
case let c: str => yield c;
|
||||||
|
case =>
|
||||||
|
handle_notfound(buf, serv_req);
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
let (stdout, stderr) = run_code(code);
|
||||||
|
defer free(stderr);
|
||||||
|
defer free(stdout);
|
||||||
|
|
||||||
|
let obj = json::newobject();
|
||||||
|
defer json::finish(obj);
|
||||||
|
json::set(&obj, "stdout", stdout);
|
||||||
|
json::set(&obj, "stderr", stderr);
|
||||||
|
json::set(&obj, "id", "123");
|
||||||
|
json::set(&obj, "ok", true);
|
||||||
|
json::set(&obj, "duration", 0.0);
|
||||||
|
|
||||||
|
json::dump(buf, obj)!;
|
||||||
|
|
||||||
http::response_write(
|
http::response_write(
|
||||||
serv_req.socket,
|
serv_req.socket,
|
||||||
|
|
150
backend/cmd/httpd/sandbox.ha
Normal file
150
backend/cmd/httpd/sandbox.ha
Normal file
|
@ -0,0 +1,150 @@
|
||||||
|
use fmt;
|
||||||
|
use io;
|
||||||
|
use os;
|
||||||
|
use os::exec;
|
||||||
|
use strings;
|
||||||
|
use temp;
|
||||||
|
use unix;
|
||||||
|
|
||||||
|
const static_args = [
|
||||||
|
"--ro-bind", "/usr", "/usr",
|
||||||
|
"--dir", "/tmp",
|
||||||
|
"--dir", "/var",
|
||||||
|
"--symlink", "../tmp", "/var/tmp",
|
||||||
|
"--proc", "/proc",
|
||||||
|
"--dev", "/dev",
|
||||||
|
"--ro-bind", "/etc/resolv.conf", "/etc/resolv.conf",
|
||||||
|
"--symlink", "usr/lib", "/lib",
|
||||||
|
"--symlink", "usr/lib64", "/lib64",
|
||||||
|
"--symlink", "usr/bin", "/bin",
|
||||||
|
"--symlink", "usr/sbin", "/sbin",
|
||||||
|
"--unshare-all",
|
||||||
|
"--die-with-parent",
|
||||||
|
"--clearenv",
|
||||||
|
"--setenv", "PATH", "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
|
||||||
|
"--setenv", "HAREPATH", "/usr/local/src/hare/stdlib",
|
||||||
|
];
|
||||||
|
|
||||||
|
const HARE_COMMAND = "/usr/local/bin/hare";
|
||||||
|
|
||||||
|
/// Default command timeout in seconds.
|
||||||
|
const DEFAULT_TIMEOUT = 30;
|
||||||
|
|
||||||
|
export fn run_code(code: str) (str, str) = {
|
||||||
|
let (uid, gid) = getids();
|
||||||
|
|
||||||
|
let args = strings::dupall(static_args);
|
||||||
|
|
||||||
|
let app_dir = shared_app_dir(&args);
|
||||||
|
// defer runs in reverse order.
|
||||||
|
defer os::rmdirall(app_dir)!;
|
||||||
|
|
||||||
|
home_dir(&args, uid);
|
||||||
|
|
||||||
|
let (passwd_r, group_r) = passwd_files(&args, uid, gid);
|
||||||
|
defer io::close(passwd_r)!;
|
||||||
|
defer io::close(group_r)!;
|
||||||
|
|
||||||
|
let code_path = fmt::asprintf("{}/main.ha", app_dir);
|
||||||
|
defer free(code_path);
|
||||||
|
let code_fp = os::create(code_path, 0o644)!;
|
||||||
|
io::writeall(code_fp, strings::toutf8(code))!;
|
||||||
|
io::close(code_fp)!;
|
||||||
|
|
||||||
|
command(&args, "/app/main.ha");
|
||||||
|
|
||||||
|
let cmd = exec::cmd("bwrap", args...)!;
|
||||||
|
|
||||||
|
let stdout_pipe = exec::pipe();
|
||||||
|
exec::addfile(&cmd, os::stdout_file, stdout_pipe.1);
|
||||||
|
|
||||||
|
let stderr_pipe = exec::pipe();
|
||||||
|
exec::addfile(&cmd, os::stderr_file, stderr_pipe.1);
|
||||||
|
|
||||||
|
let proc = exec::start(&cmd)!;
|
||||||
|
io::close(stdout_pipe.1)!;
|
||||||
|
io::close(stderr_pipe.1)!;
|
||||||
|
|
||||||
|
let stdout_data = io::drain(stdout_pipe.0)!;
|
||||||
|
io::close(stdout_pipe.0)!;
|
||||||
|
|
||||||
|
let stderr_data = io::drain(stderr_pipe.0)!;
|
||||||
|
io::close(stderr_pipe.0)!;
|
||||||
|
|
||||||
|
let status = exec::wait(&proc)!;
|
||||||
|
|
||||||
|
let stdout = strings::fromutf8(stdout_data) as str;
|
||||||
|
let stderr = strings::fromutf8(stderr_data) as str;
|
||||||
|
|
||||||
|
return (stdout, stderr);
|
||||||
|
};
|
||||||
|
|
||||||
|
fn passwd_files(args: *[]str, uid: u32, gid: u32) (io::file, io::file) = {
|
||||||
|
const passwd = `root:x:0:0:root:/root:/bin/bash
|
||||||
|
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin`;
|
||||||
|
const group = `root:x:0:
|
||||||
|
nogroup:x:65534:`;
|
||||||
|
|
||||||
|
let uid = fmt::asprintf("{}", uid);
|
||||||
|
// defer free(uid);
|
||||||
|
|
||||||
|
let gid = fmt::asprintf("{}", gid);
|
||||||
|
// defer free(gid);
|
||||||
|
|
||||||
|
let (passwd_r, passwd_w) = exec::pipe();
|
||||||
|
io::writeall(passwd_w, strings::toutf8(passwd))!;
|
||||||
|
io::close(passwd_w)!;
|
||||||
|
|
||||||
|
let (group_r, group_w) = exec::pipe();
|
||||||
|
io::writeall(group_w, strings::toutf8(group))!;
|
||||||
|
io::close(group_w)!;
|
||||||
|
|
||||||
|
append(args, "--file");
|
||||||
|
append(args, fmt::asprintf("{}", passwd_r: int));
|
||||||
|
append(args, "/etc/passwd");
|
||||||
|
|
||||||
|
append(args, "--file");
|
||||||
|
append(args, fmt::asprintf("{}", group_r: int));
|
||||||
|
append(args, "/etc/group");
|
||||||
|
|
||||||
|
return (passwd_r, group_r);
|
||||||
|
};
|
||||||
|
|
||||||
|
fn home_dir(args: *[]str, uid: u32) void = {
|
||||||
|
let user_dir = fmt::asprintf("/run/user/{}", uid);
|
||||||
|
let home_dir = fmt::asprintf("{}/home", user_dir);
|
||||||
|
|
||||||
|
append(args, "--dir");
|
||||||
|
append(args, home_dir);
|
||||||
|
append(args, "--setenv");
|
||||||
|
append(args, "HOME");
|
||||||
|
append(args, home_dir);
|
||||||
|
append(args, "--setenv");
|
||||||
|
append(args, "XDG_RUNTIME_DIR");
|
||||||
|
append(args, user_dir);
|
||||||
|
};
|
||||||
|
|
||||||
|
fn shared_app_dir(args: *[]str) str = {
|
||||||
|
let tmp_app_dir = temp::dir();
|
||||||
|
|
||||||
|
append(args, "--bind");
|
||||||
|
append(args, tmp_app_dir);
|
||||||
|
append(args, "/app");
|
||||||
|
append(args, "--chdir");
|
||||||
|
append(args, "/app");
|
||||||
|
|
||||||
|
return tmp_app_dir;
|
||||||
|
};
|
||||||
|
|
||||||
|
fn command(args: *[]str, app_file: str) void = {
|
||||||
|
append(args, "/usr/bin/timeout");
|
||||||
|
let timeout = fmt::asprintf("{}", DEFAULT_TIMEOUT);
|
||||||
|
append(args, timeout);
|
||||||
|
append(args, HARE_COMMAND);
|
||||||
|
append(args, "run");
|
||||||
|
append(args, app_file);
|
||||||
|
};
|
||||||
|
|
||||||
|
fn getids() (uint, uint) = {
|
||||||
|
return (unix::getuid(), unix::getgid());
|
||||||
|
};
|
Loading…
Reference in a new issue