bunpen: move rtext:: -> rt::ext::
This commit is contained in:
@@ -7,7 +7,7 @@ use os;
|
|||||||
use path;
|
use path;
|
||||||
use restrict;
|
use restrict;
|
||||||
use rt;
|
use rt;
|
||||||
use rtext;
|
use rt::ext;
|
||||||
|
|
||||||
// the user requested to see help.
|
// the user requested to see help.
|
||||||
export type help = !void;
|
export type help = !void;
|
||||||
|
@@ -5,7 +5,7 @@ use log;
|
|||||||
use log::tree;
|
use log::tree;
|
||||||
use restrict;
|
use restrict;
|
||||||
use rt;
|
use rt;
|
||||||
use rtext;
|
use rt::ext;
|
||||||
use strings;
|
use strings;
|
||||||
use os;
|
use os;
|
||||||
use os::exec;
|
use os::exec;
|
||||||
@@ -18,7 +18,7 @@ fn do_exec(path: str, args: []str) (os::exec::error | void) = {
|
|||||||
log::printfln("exec ({}): {}", path, joined);
|
log::printfln("exec ({}): {}", path, joined);
|
||||||
};
|
};
|
||||||
|
|
||||||
errors::ext::check("exec", rtext::execve(path, args, os::getenvs()));
|
errors::ext::check("exec", rt::ext::execve(path, args, os::getenvs()));
|
||||||
|
|
||||||
// XXX: os::exec::exec offers no way to preserve argv0, but it does
|
// XXX: os::exec::exec offers no way to preserve argv0, but it does
|
||||||
// work if you don't care about that:
|
// work if you don't care about that:
|
||||||
@@ -46,7 +46,7 @@ export fn main() void = {
|
|||||||
case let other: config::cli_request => yield other;
|
case let other: config::cli_request => yield other;
|
||||||
};
|
};
|
||||||
|
|
||||||
rtext::no_new_privs()!;
|
rt::ext::no_new_privs()!;
|
||||||
restrict::namespace_restrict(&req.resources);
|
restrict::namespace_restrict(&req.resources);
|
||||||
// XXX: landlock prevents other sandboxers like `bwrap` from executing,
|
// XXX: landlock prevents other sandboxers like `bwrap` from executing,
|
||||||
// because it forbids all future `mount` syscalls. so don't landlock.
|
// because it forbids all future `mount` syscalls. so don't landlock.
|
||||||
|
@@ -5,35 +5,35 @@ use log;
|
|||||||
use os;
|
use os;
|
||||||
use path;
|
use path;
|
||||||
use rt;
|
use rt;
|
||||||
use rtext;
|
use rt::ext;
|
||||||
|
|
||||||
fn access_fs_roughly_read() rtext::landlock_access_fs_set = return
|
fn access_fs_roughly_read() rt::ext::landlock_access_fs_set = return
|
||||||
rtext::landlock_access_fs::EXECUTE |
|
rt::ext::landlock_access_fs::EXECUTE |
|
||||||
rtext::landlock_access_fs::READ_FILE |
|
rt::ext::landlock_access_fs::READ_FILE |
|
||||||
rtext::landlock_access_fs::READ_DIR
|
rt::ext::landlock_access_fs::READ_DIR
|
||||||
;
|
;
|
||||||
fn access_fs_roughly_write() rtext::landlock_access_fs_set = return
|
fn access_fs_roughly_write() rt::ext::landlock_access_fs_set = return
|
||||||
rtext::landlock_access_fs::WRITE_FILE |
|
rt::ext::landlock_access_fs::WRITE_FILE |
|
||||||
rtext::landlock_access_fs::REMOVE_DIR |
|
rt::ext::landlock_access_fs::REMOVE_DIR |
|
||||||
rtext::landlock_access_fs::REMOVE_FILE |
|
rt::ext::landlock_access_fs::REMOVE_FILE |
|
||||||
rtext::landlock_access_fs::MAKE_CHAR |
|
rt::ext::landlock_access_fs::MAKE_CHAR |
|
||||||
rtext::landlock_access_fs::MAKE_DIR |
|
rt::ext::landlock_access_fs::MAKE_DIR |
|
||||||
rtext::landlock_access_fs::MAKE_REG |
|
rt::ext::landlock_access_fs::MAKE_REG |
|
||||||
rtext::landlock_access_fs::MAKE_SOCK |
|
rt::ext::landlock_access_fs::MAKE_SOCK |
|
||||||
rtext::landlock_access_fs::MAKE_FIFO |
|
rt::ext::landlock_access_fs::MAKE_FIFO |
|
||||||
rtext::landlock_access_fs::MAKE_BLOCK |
|
rt::ext::landlock_access_fs::MAKE_BLOCK |
|
||||||
rtext::landlock_access_fs::MAKE_SYM |
|
rt::ext::landlock_access_fs::MAKE_SYM |
|
||||||
rtext::landlock_access_fs::REFER |
|
rt::ext::landlock_access_fs::REFER |
|
||||||
rtext::landlock_access_fs::TRUNCATE |
|
rt::ext::landlock_access_fs::TRUNCATE |
|
||||||
rtext::landlock_access_fs::IOCTL_DEV
|
rt::ext::landlock_access_fs::IOCTL_DEV
|
||||||
;
|
;
|
||||||
fn access_fs_roughly_rw() rtext::landlock_access_fs_set = return access_fs_roughly_read() | access_fs_roughly_write();
|
fn access_fs_roughly_rw() rt::ext::landlock_access_fs_set = return access_fs_roughly_read() | access_fs_roughly_write();
|
||||||
fn access_file() rtext::landlock_access_fs_set = return
|
fn access_file() rt::ext::landlock_access_fs_set = return
|
||||||
rtext::landlock_access_fs::EXECUTE |
|
rt::ext::landlock_access_fs::EXECUTE |
|
||||||
rtext::landlock_access_fs::WRITE_FILE |
|
rt::ext::landlock_access_fs::WRITE_FILE |
|
||||||
rtext::landlock_access_fs::READ_FILE |
|
rt::ext::landlock_access_fs::READ_FILE |
|
||||||
rtext::landlock_access_fs::TRUNCATE |
|
rt::ext::landlock_access_fs::TRUNCATE |
|
||||||
rtext::landlock_access_fs::IOCTL_DEV
|
rt::ext::landlock_access_fs::IOCTL_DEV
|
||||||
;
|
;
|
||||||
|
|
||||||
fn allow_path_fd(ruleset_fd: u64, path_fd: i32) (void | fs::error | rt::errno) = {
|
fn allow_path_fd(ruleset_fd: u64, path_fd: i32) (void | fs::error | rt::errno) = {
|
||||||
@@ -46,7 +46,7 @@ fn allow_path_fd(ruleset_fd: u64, path_fd: i32) (void | fs::error | rt::errno) =
|
|||||||
access = access & access_file();
|
access = access & access_file();
|
||||||
};
|
};
|
||||||
|
|
||||||
rtext::landlock_add_rule(ruleset_fd, &rtext::landlock_path_beneath_attr {
|
rt::ext::landlock_add_rule(ruleset_fd, &rt::ext::landlock_path_beneath_attr {
|
||||||
allowed_access = access,
|
allowed_access = access,
|
||||||
parent_fd = path_fd,
|
parent_fd = path_fd,
|
||||||
})?;
|
})?;
|
||||||
@@ -58,25 +58,25 @@ fn allow_path(ruleset_fd: u64, path_str: str) (void | fs::error | rt::errno) = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export fn landlock_restrict(what: *resources) void = {
|
export fn landlock_restrict(what: *resources) void = {
|
||||||
let abi = rtext::landlock_create_ruleset(null, rtext::landlock_create_ruleset_flag::VERSION)!;
|
let abi = rt::ext::landlock_create_ruleset(null, rt::ext::landlock_create_ruleset_flag::VERSION)!;
|
||||||
log::printfln("[landlock] found version {}", abi);
|
log::printfln("[landlock] found version {}", abi);
|
||||||
|
|
||||||
// determine the access modes we can ask this kernel to restrict on:
|
// determine the access modes we can ask this kernel to restrict on:
|
||||||
let ruleset_attr = rtext::landlock_ruleset_attr {
|
let ruleset_attr = rt::ext::landlock_ruleset_attr {
|
||||||
handled_access_fs = access_fs_roughly_rw(),
|
handled_access_fs = access_fs_roughly_rw(),
|
||||||
handled_access_net = rtext::landlock_access_net::BIND_TCP | rtext::landlock_access_net::CONNECT_TCP,
|
handled_access_net = rt::ext::landlock_access_net::BIND_TCP | rt::ext::landlock_access_net::CONNECT_TCP,
|
||||||
};
|
};
|
||||||
if (abi == 1) {
|
if (abi == 1) {
|
||||||
ruleset_attr.handled_access_fs &= ~rtext::landlock_access_fs::REFER;
|
ruleset_attr.handled_access_fs &= ~rt::ext::landlock_access_fs::REFER;
|
||||||
};
|
};
|
||||||
if (abi <= 2) {
|
if (abi <= 2) {
|
||||||
ruleset_attr.handled_access_fs &= ~rtext::landlock_access_fs::TRUNCATE;
|
ruleset_attr.handled_access_fs &= ~rt::ext::landlock_access_fs::TRUNCATE;
|
||||||
};
|
};
|
||||||
if (abi <= 3) {
|
if (abi <= 3) {
|
||||||
ruleset_attr.handled_access_net &= ~(rtext::landlock_access_net::BIND_TCP | rtext::landlock_access_net::CONNECT_TCP);
|
ruleset_attr.handled_access_net &= ~(rt::ext::landlock_access_net::BIND_TCP | rt::ext::landlock_access_net::CONNECT_TCP);
|
||||||
};
|
};
|
||||||
if (abi <= 4) {
|
if (abi <= 4) {
|
||||||
ruleset_attr.handled_access_fs &= ~rtext::landlock_access_fs::IOCTL_DEV;
|
ruleset_attr.handled_access_fs &= ~rt::ext::landlock_access_fs::IOCTL_DEV;
|
||||||
};
|
};
|
||||||
|
|
||||||
if (what.net) {
|
if (what.net) {
|
||||||
@@ -85,7 +85,7 @@ export fn landlock_restrict(what: *resources) void = {
|
|||||||
ruleset_attr.handled_access_net = 0;
|
ruleset_attr.handled_access_net = 0;
|
||||||
}; // XXX: `what.net` only affects TCP. UDP, and ICMP remain possible always
|
}; // XXX: `what.net` only affects TCP. UDP, and ICMP remain possible always
|
||||||
|
|
||||||
let ruleset_fd = rtext::landlock_create_ruleset(&ruleset_attr)!;
|
let ruleset_fd = rt::ext::landlock_create_ruleset(&ruleset_attr)!;
|
||||||
|
|
||||||
for (let pathbuf .. what.paths) {
|
for (let pathbuf .. what.paths) {
|
||||||
let pathstr = path::string(&pathbuf);
|
let pathstr = path::string(&pathbuf);
|
||||||
@@ -93,7 +93,7 @@ export fn landlock_restrict(what: *resources) void = {
|
|||||||
errors::ext::swallow("[landlock/path] omitting from sandbox: failed to add path", allow_path(ruleset_fd, pathstr));
|
errors::ext::swallow("[landlock/path] omitting from sandbox: failed to add path", allow_path(ruleset_fd, pathstr));
|
||||||
};
|
};
|
||||||
|
|
||||||
rtext::landlock_restrict_self(ruleset_fd)!;
|
rt::ext::landlock_restrict_self(ruleset_fd)!;
|
||||||
|
|
||||||
log::println("landlock restrictions activated");
|
log::println("landlock restrictions activated");
|
||||||
};
|
};
|
||||||
|
@@ -8,7 +8,7 @@ use os;
|
|||||||
use os::exec;
|
use os::exec;
|
||||||
use path;
|
use path;
|
||||||
use rt;
|
use rt;
|
||||||
use rtext;
|
use rt::ext;
|
||||||
use strings;
|
use strings;
|
||||||
use unix;
|
use unix;
|
||||||
|
|
||||||
@@ -20,25 +20,25 @@ export fn namespace_restrict(what: *resources) void = {
|
|||||||
|
|
||||||
// unshare as much as possible, by default:
|
// unshare as much as possible, by default:
|
||||||
let what_to_unshare =
|
let what_to_unshare =
|
||||||
rtext::clone_flag::NEWCGROUP |
|
rt::ext::clone_flag::NEWCGROUP |
|
||||||
rtext::clone_flag::NEWIPC |
|
rt::ext::clone_flag::NEWIPC |
|
||||||
rtext::clone_flag::NEWNET |
|
rt::ext::clone_flag::NEWNET |
|
||||||
rtext::clone_flag::NEWNS |
|
rt::ext::clone_flag::NEWNS |
|
||||||
rtext::clone_flag::NEWPID |
|
rt::ext::clone_flag::NEWPID |
|
||||||
rtext::clone_flag::NEWUSER |
|
rt::ext::clone_flag::NEWUSER |
|
||||||
rtext::clone_flag::NEWUTS
|
rt::ext::clone_flag::NEWUTS
|
||||||
;
|
;
|
||||||
if (what.net) {
|
if (what.net) {
|
||||||
log::println("[namespace] keeping net namespace");
|
log::println("[namespace] keeping net namespace");
|
||||||
what_to_unshare &= ~rtext::clone_flag::NEWNET;
|
what_to_unshare &= ~rt::ext::clone_flag::NEWNET;
|
||||||
};
|
};
|
||||||
if (what.pid) {
|
if (what.pid) {
|
||||||
log::println("[namespace] keeping pid namespace");
|
log::println("[namespace] keeping pid namespace");
|
||||||
what_to_unshare &= ~rtext::clone_flag::NEWPID;
|
what_to_unshare &= ~rt::ext::clone_flag::NEWPID;
|
||||||
};
|
};
|
||||||
|
|
||||||
log::printfln("[namespace] unshare {}", what_to_unshare: u64);
|
log::printfln("[namespace] unshare {}", what_to_unshare: u64);
|
||||||
rtext::unshare(what_to_unshare)!;
|
rt::ext::unshare(what_to_unshare)!;
|
||||||
|
|
||||||
// before mounting anything, set up the uids and gids in this namespace.
|
// before mounting anything, set up the uids and gids in this namespace.
|
||||||
// without this, everything shows up as 65534 a.k.a. 'nobody' a.k.a. 'overflow',
|
// without this, everything shows up as 65534 a.k.a. 'nobody' a.k.a. 'overflow',
|
||||||
@@ -92,7 +92,7 @@ fn fork_and_propagate() (void | os::exec::error) = {
|
|||||||
fn isolate_paths(paths: []path::buffer) void = {
|
fn isolate_paths(paths: []path::buffer) void = {
|
||||||
// allow new mounts to propagate from the parent namespace into the child
|
// allow new mounts to propagate from the parent namespace into the child
|
||||||
// namespace, but not vice versa:
|
// namespace, but not vice versa:
|
||||||
errors::ext::check("[namespace] reconfigure / as MS_SLAVE", rtext::mount("/", "/", "", rtext::mount_flag::SLAVE | rtext::mount_flag::REC, null));
|
errors::ext::check("[namespace] reconfigure / as MS_SLAVE", rt::ext::mount("/", "/", "", rt::ext::mount_flag::SLAVE | rt::ext::mount_flag::REC, null));
|
||||||
|
|
||||||
// in order to mount ANY directory from the old root into the new root,
|
// in order to mount ANY directory from the old root into the new root,
|
||||||
// they have to be totally disparate. if we kept the old root at / and the new
|
// they have to be totally disparate. if we kept the old root at / and the new
|
||||||
@@ -103,16 +103,16 @@ fn isolate_paths(paths: []path::buffer) void = {
|
|||||||
// 2. create a new rootfs at `new` and bind stuff into it.
|
// 2. create a new rootfs at `new` and bind stuff into it.
|
||||||
// 3. then pivot a 2nd time, into `new` (and drop `old` altogether)
|
// 3. then pivot a 2nd time, into `new` (and drop `old` altogether)
|
||||||
|
|
||||||
errors::ext::check("[namespace] mount -t tmpfs tmpfs /tmp", rtext::mount("tmpfs", "/tmp", "tmpfs", rtext::mount_flag::NODEV | rtext::mount_flag::NOSUID, null));
|
errors::ext::check("[namespace] mount -t tmpfs tmpfs /tmp", rt::ext::mount("tmpfs", "/tmp", "tmpfs", rt::ext::mount_flag::NODEV | rt::ext::mount_flag::NOSUID, null));
|
||||||
|
|
||||||
pivot_into("/tmp", "old");
|
pivot_into("/tmp", "old");
|
||||||
// now we have `/`, empty except for the old rootfs available at `/old`
|
// now we have `/`, empty except for the old rootfs available at `/old`
|
||||||
|
|
||||||
// prepare a new rootfs. it has to be its own mount (tmpfs), not just a dir.
|
// prepare a new rootfs. it has to be its own mount (tmpfs), not just a dir.
|
||||||
errors::ext::check("[namespace] mkdir new", rt::mkdir("new", 0o755));
|
errors::ext::check("[namespace] mkdir new", rt::mkdir("new", 0o755));
|
||||||
errors::ext::check("[namespace] mount -t tmpfs tmpfs new", rtext::mount("tmpfs", "new", "tmpfs", 0, null));
|
errors::ext::check("[namespace] mount -t tmpfs tmpfs new", rt::ext::mount("tmpfs", "new", "tmpfs", 0, null));
|
||||||
// errors::ext::check("[namespace] mount -t tmpfs tmpfs new", rtext::mount("tmpfs", "new", "tmpfs", rtext::mount_flag::NODEV | rtext::mount_flag::NOSUID, null));
|
// errors::ext::check("[namespace] mount -t tmpfs tmpfs new", rt::ext::mount("tmpfs", "new", "tmpfs", rt::ext::mount_flag::NODEV | rt::ext::mount_flag::NOSUID, null));
|
||||||
// errors::ext::check("[namespace] mount -o rbind new new", rtext::mount("new", "new", "", rtext::mount_flag::BIND | rtext::mount_flag::REC, null));
|
// errors::ext::check("[namespace] mount -o rbind new new", rt::ext::mount("new", "new", "", rt::ext::mount_flag::BIND | rt::ext::mount_flag::REC, null));
|
||||||
|
|
||||||
// try to mount a new /proc.
|
// try to mount a new /proc.
|
||||||
// - this is "safe" because we're not doing anything
|
// - this is "safe" because we're not doing anything
|
||||||
@@ -127,14 +127,14 @@ fn isolate_paths(paths: []path::buffer) void = {
|
|||||||
// but in practice there are namespacing bugs at least as recently as 2021:
|
// but in practice there are namespacing bugs at least as recently as 2021:
|
||||||
// <https://github.com/opencontainers/runc/issues/2826#issuecomment-915683044>
|
// <https://github.com/opencontainers/runc/issues/2826#issuecomment-915683044>
|
||||||
errors::ext::swallow("[namespace] mkdir new/proc", rt::mkdir("new/proc", 0o755));
|
errors::ext::swallow("[namespace] mkdir new/proc", rt::mkdir("new/proc", 0o755));
|
||||||
errors::ext::swallow("[namespace] mount /new/proc", rtext::mount(
|
errors::ext::swallow("[namespace] mount /new/proc", rt::ext::mount(
|
||||||
"proc", "new/proc", "proc", rtext::mount_flag::NOSUID | rtext::mount_flag::NOEXEC | rtext::mount_flag::NODEV, null
|
"proc", "new/proc", "proc", rt::ext::mount_flag::NOSUID | rt::ext::mount_flag::NOEXEC | rt::ext::mount_flag::NODEV, null
|
||||||
));
|
));
|
||||||
|
|
||||||
|
|
||||||
// provide a new `/tmp` too.
|
// provide a new `/tmp` too.
|
||||||
errors::ext::swallow("[namespace] mkdir new/tmp", rt::mkdir("new/tmp", 0o777));
|
errors::ext::swallow("[namespace] mkdir new/tmp", rt::mkdir("new/tmp", 0o777));
|
||||||
errors::ext::swallow("[namespace] mount -t tmpfs tmpfs new/tmp", rtext::mount("tmpfs", "new/tmp", "tmpfs", 0, null));
|
errors::ext::swallow("[namespace] mount -t tmpfs tmpfs new/tmp", rt::ext::mount("tmpfs", "new/tmp", "tmpfs", 0, null));
|
||||||
|
|
||||||
// bind all the user-requested paths from `old/$p` into `new/$p`.
|
// bind all the user-requested paths from `old/$p` into `new/$p`.
|
||||||
// use the `dirfd` abstraction so that paths meant for `old` can't crawl out
|
// use the `dirfd` abstraction so that paths meant for `old` can't crawl out
|
||||||
@@ -232,8 +232,8 @@ fn bind_leaf(old_fs: *fs::fs, new_fs: *fs::fs, user_path: *path::buffer) void =
|
|||||||
};
|
};
|
||||||
|
|
||||||
log::printfln("[namespace/bind] mount {} {}", path::string(&old_pathbuf), path::string(&new_pathbuf));
|
log::printfln("[namespace/bind] mount {} {}", path::string(&old_pathbuf), path::string(&new_pathbuf));
|
||||||
errors::ext::swallow("[namespace/bind] bind_leaf: mount", rtext::mount(
|
errors::ext::swallow("[namespace/bind] bind_leaf: mount", rt::ext::mount(
|
||||||
path::string(&old_pathbuf), path::string(&new_pathbuf), "", rtext::mount_flag::BIND | rtext::mount_flag::REC, null
|
path::string(&old_pathbuf), path::string(&new_pathbuf), "", rt::ext::mount_flag::BIND | rt::ext::mount_flag::REC, null
|
||||||
));
|
));
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -286,11 +286,11 @@ fn pivot_into(new_root: str, stash_old_root: (str|void) = void) void = {
|
|||||||
match (stash_old_root) {
|
match (stash_old_root) {
|
||||||
case let old: str =>
|
case let old: str =>
|
||||||
errors::ext::check("[namespace] mkdir <stash_old_root>", rt::mkdir(old, 0o755));
|
errors::ext::check("[namespace] mkdir <stash_old_root>", rt::mkdir(old, 0o755));
|
||||||
errors::ext::check("[namespace] pivot_root . <stash_old_root>", rtext::pivot_root(".", old));
|
errors::ext::check("[namespace] pivot_root . <stash_old_root>", rt::ext::pivot_root(".", old));
|
||||||
case void =>
|
case void =>
|
||||||
errors::ext::check("[namespace] pivot_root . .", rtext::pivot_root(".", "."));
|
errors::ext::check("[namespace] pivot_root . .", rt::ext::pivot_root(".", "."));
|
||||||
// drop the old rootfs. weird idiom, but documented in `man 2 pivot_root`.
|
// drop the old rootfs. weird idiom, but documented in `man 2 pivot_root`.
|
||||||
errors::ext::check("[namespace] umount .", rt::umount2(".", rtext::umount_flag::MNT_DETACH));
|
errors::ext::check("[namespace] umount .", rt::umount2(".", rt::ext::umount_flag::MNT_DETACH));
|
||||||
};
|
};
|
||||||
errors::ext::check("[namespace] cd /", os::chdir("/"));
|
errors::ext::check("[namespace] cd /", os::chdir("/"));
|
||||||
};
|
};
|
||||||
|
Reference in New Issue
Block a user