diff --git a/cmd/httpd/sandbox+darwin.ha b/cmd/httpd/sandbox+darwin.ha new file mode 100644 index 0000000..a934a4c --- /dev/null +++ b/cmd/httpd/sandbox+darwin.ha @@ -0,0 +1,45 @@ +use io::{mode}; +use io; +use os::exec; +use os; +use strings; +use temp; +use fs; +use fmt; + +export fn run_code(code: str) (str, str) = { + let tmp_dir = temp::dir(); + defer os::rmdirall(tmp_dir)!; + + let path = fmt::asprintf("{}/main.ha", tmp_dir); + defer free(path); + + let fp = os::create(path, 0o644)!; + io::writeall(fp, strings::toutf8(code))!; + io::close(fp)!; + + let cmd = exec::cmd("hare", "run", path)!; + + 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 status = exec::wait(&proc)!; + + 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 stdout = strings::fromutf8(stdout_data) as str; + let stderr = strings::fromutf8(stderr_data) as str; + + return (stdout, stderr); +}; diff --git a/cmd/httpd/sandbox+linux.ha b/cmd/httpd/sandbox+linux.ha new file mode 100644 index 0000000..0f05086 --- /dev/null +++ b/cmd/httpd/sandbox+linux.ha @@ -0,0 +1,115 @@ +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 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 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()); +};