bunpen: kill --bunpen-{home,run}-path in favor of shell-style expansion/parameterization

This commit is contained in:
2024-12-15 22:45:29 +00:00
parent 843fdb0dfe
commit 3da9874176
3 changed files with 24 additions and 28 deletions

View File

@@ -31,8 +31,8 @@ let
[ "--bunpen-path" "/dev/net/tun" "--bunpen-net-dev" n ];
netGateway = netGateway: [ "--bunpen-net-gateway" netGateway ];
path.unqualified = p: [ "--bunpen-path" p ];
path.home = p: [ "--bunpen-home-path" p ];
path.run = p: [ "--bunpen-run-path" p ];
path.home = p: [ "--bunpen-path" "$HOME/${p}" ];
path.run = p: [ "--bunpen-path" "$XDG_RUNTIME_DIR/${p}" ];
tryKeepUsers = [ "--bunpen-try-keep-users" ];
whitelistPwd = [ "--bunpen-path" "." ];
};

View File

@@ -17,14 +17,12 @@ export type cli_opts = struct {
env: []str,
// `--bunpen-help`
help: bool,
home_paths: []str,
keep_all_caps: bool,
keep_caps: []rt::ext::cap,
keep_ipc: bool,
keep_net: bool,
keep_pid: bool,
paths: []str,
run_paths: []str,
try_keep_users: bool,
net_dev: str,
@@ -48,12 +46,10 @@ export fn usage() void = {
fmt::println(" instead of running the program, drop into an interactive shell")!;
fmt::println(" --bunpen-env FOO=VALUE")!;
fmt::println(" set the environment variable FOO to VALUE within the launched program")!;
fmt::println(" certain shell-style substitutions are performed on the raw string ('FOO=VALUE'), including:")!;
fmt::println(" $HOME")!;
fmt::println(" $XDG_RUNTIME_DIR")!;
fmt::println(" $$ to escape a literal $")!;
fmt::println(" a limited set of env vars are expanded within each expression: see PARAMETERIZATION")!;
fmt::println(" --bunpen-autodetect <existing|existingFile|existingFileOrParent|existingDirOrParent|existingOrParent|parent>")!;
fmt::println(" add files which appear later as CLI arguments into the sandbox")!;
fmt::println(" shell expansion (PARAMETERIZATION) is NOT performed on these paths")!;
fmt::println(" --bunpen-cap <all|sys_admin|net_raw|net_admin|...>")!;
fmt::println(" allow the sandboxed program to use the provided linux capability (both inside and outside the sandbox)")!;
fmt::println(" special cap 'all' to preserve all capabilities possible")!;
@@ -68,16 +64,14 @@ export fn usage() void = {
fmt::println(" --bunpen-path <path>")!;
fmt::println(" allow access to the host <path> within the sandbox")!;
fmt::println(" path is interpreted relative to the working directory if not absolute")!;
fmt::println(" --bunpen-home-path <path>")!;
fmt::println(" allow access to the host <path>, relative to HOME")!;
fmt::println(" --bunpen-run-path <path>")!;
fmt::println(" allow access to the host <path>, relative to XDG_RUNTIME_DIR")!;
fmt::println(" a limited set of env vars are expanded within each path: see PARAMETERIZATION")!;
fmt::println("")!;
fmt::println("net proxy settings (typical invocation specifies either ALL or NONE of these):")!;
fmt::println(" --bunpen-net-dev <iface>")!;
fmt::println(" --bunpen-net-gateway <ip-address>")!;
fmt::println(" --bunpen-dns <server>")!;
fmt::println("")!;
fmt::println("ENVIRONMENT")!;
fmt::println("the following environment variables are also considered and propagated to children:")!;
fmt::println(" BUNPEN_DEBUG=n")!;
fmt::println(" equivalent to `--bunpen-debug=n`")!;
@@ -91,6 +85,13 @@ export fn usage() void = {
fmt::println(" consider BUNPEN_DISABLE='host$' to be more targeted")!;
fmt::println(" BUNPEN_APPEND=--bunpen-flag1 --bunpen-flag2 ...")!;
fmt::println(" act as though the provided arg string appeared at the end of the CLI")!;
fmt::println("")!;
fmt::println("PARAMETERIZATION")!;
fmt::println("where noted, the following variables are expanded in the style of shell expansion:")!;
fmt::println(" $HOME")!;
fmt::println(" $XDG_RUNTIME_DIR")!;
fmt::println(" $$ to escape a literal $")!;
// fmt::println(" --bunpen-add-pwd")!;
// fmt::println(" shorthand for `--bunpen-path $PWD`")!;
// fmt::println("")!;
@@ -165,14 +166,12 @@ fn parse_args_into(parsed: *cli_opts, args: []str) (void | errors::invalid) = {
case "--bunpen-drop-shell" => parsed.drop_shell = true;
case "--bunpen-env" => idx += 1; append(parsed.env, expect_arg("--bunpen-env", next)?);
case "--bunpen-help" => parsed.help = true;
case "--bunpen-home-path" => idx += 1; append(parsed.home_paths, expect_arg("--bunpen-home-path", next)?);
case "--bunpen-keep-ipc" => parsed.keep_ipc = true;
case "--bunpen-keep-net" => parsed.keep_net = true;
case "--bunpen-keep-pid" => parsed.keep_pid = true;
case "--bunpen-net-dev" => idx += 1; parsed.net_dev = expect_arg("--bunpen-net-dev", next)?;
case "--bunpen-net-gateway" => idx += 1; parsed.net_gateway = expect_arg("--bunpen-net-gateway", next)?;
case "--bunpen-path" => idx += 1; append(parsed.paths, expect_arg("--bunpen-path", next)?);
case "--bunpen-run-path" => idx += 1; append(parsed.run_paths, expect_arg("--bunpen-run-path", next)?);
case "--bunpen-try-keep-users" => parsed.try_keep_users = true;
case => append(parsed.cmd, arg);
};

View File

@@ -122,8 +122,6 @@ export fn ingest_cli_opts(opts: cli_opts) (cli_request | exec_params | help) = {
//---- ingest `caps` ----//
req.resources.caps = restrict::cap_array_to_caps(opts.keep_caps);
//---- ingest `home_paths` ----//
ingest_paths(&req.resources.paths, opts.home_paths, env, env.home);
//---- ingest `keep_all_caps` ----//
if (opts.keep_all_caps)
req.resources.caps = rt::ext::CAPS_ALL;
@@ -149,10 +147,7 @@ export fn ingest_cli_opts(opts: cli_opts) (cli_request | exec_params | help) = {
req.resources.pid = opts.keep_pid;
//---- ingest `paths` ----//
ingest_paths(&req.resources.paths, opts.paths, env, env.pwd, true);
//---- ingest `run_paths` ----//
ingest_paths(&req.resources.paths, opts.run_paths, env, env.xdg_runtime_dir);
ingest_paths(&req.resources.paths, opts.paths, env);
//---- ingest `try_keep_users` ----//
req.resources.try_users = opts.try_keep_users;
@@ -162,7 +157,7 @@ export fn ingest_cli_opts(opts: cli_opts) (cli_request | exec_params | help) = {
case let method: autodetect =>
// N.B.: skip first arg, since that's the name of the executable and
// surely not an argument
ingest_paths(&req.resources.paths, req.exec_params.args[1..], env, env.pwd, true, method);
ingest_paths(&req.resources.paths, req.exec_params.args[1..], env, method);
case void => void;
};
@@ -178,10 +173,13 @@ export fn ingest_cli_opts(opts: cli_opts) (cli_request | exec_params | help) = {
return req;
};
// convert each item in `from` to a path, relative to `base`, and append to `into`.
// if `allow_abs`, then paths with start with `/` are treated as absolute,
// instead of as relative to `base`.
fn ingest_paths(into: *[]path::buffer, from: []str, env: env, base: (str | void), allow_abs: bool = false, method: (void | autodetect) = void) void = {
// convert each item in `from` to a path, and append to `into`.
// non-absolute paths are interpreted as relative to `env.pwd`.
// a limited set of environment variables are expanded for each path; see `env_subst`.
// optional `autodetect` flag, to query each path on-disk and filter or map it
// based on the desired environment.
// in this mode, environment variables are *not* expanded.
fn ingest_paths(into: *[]path::buffer, from: []str, env: env, method: (void | autodetect) = void) void = {
// enforce file mode requirements as per autodetect (if specified)
let (do_env_subst, allow_nonexistent, allow_file, allow_dir, allow_parent) = match (method) {
case void => yield (true, true, true, true, false);
@@ -200,7 +198,7 @@ fn ingest_paths(into: *[]path::buffer, from: []str, env: env, base: (str | void)
path_str = env_subst(env, path_str);
};
errors::ext::swallow("[config/path] omitting path {}",
try_as_path(into, path_str, base, allow_abs, allow_nonexistent, allow_file, allow_dir, allow_parent),
try_as_path(into, path_str, env.pwd, allow_nonexistent, allow_file, allow_dir, allow_parent),
path_str
);
};
@@ -212,13 +210,12 @@ fn try_as_path(
into: *[]path::buffer,
path_arg: str,
base: (str | void),
allow_abs: bool,
allow_nonexistent: bool,
allow_file: bool,
allow_dir: bool,
allow_parent: bool,
) (void | fs::error | path::error) = {
let path_buf = if (allow_abs && path::abs(path_arg)) {
let path_buf = if (path::abs(path_arg)) {
yield path::init(path_arg)?;
} else match (base) {
case let b: str => yield path::init(b, path_arg)?;