Make bwrap's --unshare-xxx namespaces configurable via global.unshare-*
Adds six global.unshare-{user,ipc,pid,net,uts,cgroup} config-file keys
(1/on/yes/true or 0/off/no/false, case-insensitive, default on) that
gate whether -r/--run requests each bwrap --unshare-xxx flag when the
kernel also supports it. Replaces the previous hardcoded skip of
--unshare-net, which is now policy-driven like the other five types
and defaults to enabled -- preparation for real network namespace
isolation (slirp4netns) next, on this same branch.
This commit is contained in:
@@ -197,11 +197,28 @@ Source layout (all under `src/`):
|
||||
what `volume_mount.cpp`'s copy-into-an-empty-volume step uses to reach the
|
||||
image's content when running rootless (see below); `run_bwrap()` itself now just
|
||||
calls it once on the assembled `bwrap` argv.
|
||||
`build_bwrap_args()` deliberately drops `--unshare-net` from what's actually passed
|
||||
to `bwrap` even when the kernel supports it — without any network setup (e.g.
|
||||
`slirp4netns`), unsharing it just leaves the sandbox with no network at all. Re-add
|
||||
once network isolation is implemented; `detect_bwrap_unshare_args()` itself still
|
||||
probes/reports it (e.g. via `-t/--test`), since that's kernel capability, not policy.
|
||||
`build_bwrap_args()`/`run_bwrap()` also take a `NamespaceConfig` (`bwrap.h`) — one
|
||||
plain `bool` field per `namespace_probes` entry (`user`/`ipc`/`pid`/`net`/`uts`/
|
||||
`cgroup`, default `true`), resolved by `run_container()` (`commands.cpp`) from
|
||||
`AppConfig`'s six `global.unshare-*` keys (`config_file.h`, see above) once, up
|
||||
front — `bwrap.{h,cpp}` itself never touches `AppConfig`/YAML, only this
|
||||
already-resolved struct. For each flag `detect_bwrap_unshare_args()` finds the
|
||||
kernel supports, `build_bwrap_args()` additionally requires the matching
|
||||
`NamespaceConfig` field to be `true` (looked up via a `.cpp`-local
|
||||
`namespace_policy_enabled()` if-chain over `namespace_probes`' `name`s) before
|
||||
actually passing it to `bwrap` — kernel support and policy are separate gates,
|
||||
both must allow a type. This replaced an earlier hardcoded special case that
|
||||
always dropped `--unshare-net` regardless of policy or kernel support (without
|
||||
any network setup, e.g. `slirp4netns`, unsharing it just left the sandbox with no
|
||||
network at all) — `net` now goes through the exact same policy path as every
|
||||
other type, defaulting to enabled like the rest. **This is a deliberate,
|
||||
user-acknowledged transitional behavior change**: as of this, a plain `-r/--run`
|
||||
with no config file override gets a real network namespace and thus no network
|
||||
access at all, until `slirp4netns` integration (the next task on this same
|
||||
branch) actually sets one up; `global.unshare-net: off` restores the prior
|
||||
no-isolation behavior in the meantime. `detect_bwrap_unshare_args()` itself is
|
||||
untouched by any of this — still an unfiltered kernel-capability probe, so
|
||||
`-t/--test`'s diagnostic report continues to reflect raw kernel support, not policy.
|
||||
`build_bwrap_args()`/`run_bwrap()` also take an optional `hostname` (from
|
||||
`--hostname`, long-option only): passed through as bwrap's own `--hostname` only
|
||||
when `--unshare-uts` is actually among the flags `bwrap` is being given (bwrap
|
||||
@@ -666,25 +683,41 @@ Source layout (all under `src/`):
|
||||
- `config_file.{h,cpp}` — `load_config_file()` reads and parses (via libyaml's
|
||||
document API, `<yaml.h>`) the `global` and `volumes` sections of the local YAML
|
||||
config file located by `config_file_path()` (`$XDG_CONFIG_HOME/slocker-lite/config.yaml`,
|
||||
falling back to `$HOME/.config/slocker-lite/config.yaml`). `global.log-level` is the
|
||||
only supported `global` key — other long options are one-shot flags, not settings,
|
||||
so they don't belong in a persistent config file. A missing file returns a
|
||||
default-constructed (empty) `AppConfig`, not an error; unknown sections/keys (and
|
||||
malformed individual volume entries) are ignored for forward-compatibility;
|
||||
malformed YAML syntax is a hard error. `main()` applies `config->log_level` (via
|
||||
the existing `apply_log_level()`) right after `spdlog::cfg::load_env_levels()` and
|
||||
before parsing CLI options, so an explicit `--log-level` on the command line always
|
||||
overwrites it afterward — same precedence pattern already used for `SPDLOG_LEVEL`.
|
||||
falling back to `$HOME/.config/slocker-lite/config.yaml`). Supported `global` keys:
|
||||
`log-level`, and six `unshare-<type>` keys (`unshare-user`/`unshare-ipc`/
|
||||
`unshare-pid`/`unshare-net`/`unshare-uts`/`unshare-cgroup`, one per
|
||||
`bwrap.cpp`'s own `namespace_probes` entry) controlling whether `-r/--run`
|
||||
requests each of bwrap's `--unshare-xxx` flags — every other long option is a
|
||||
one-shot flag, not a setting, so it doesn't belong in a persistent config file.
|
||||
Each `unshare-*` key accepts `"1"`/`"on"`/`"yes"`/`"true"` (enabled) or
|
||||
`"0"`/`"off"`/`"no"`/`"false"` (disabled), case-insensitively (`.cpp`-local
|
||||
`parse_bool_flag()`); an unset key defaults to enabled, and an unrecognized
|
||||
value logs a `spdlog::warn` and is treated as unset (default enabled) rather
|
||||
than failing the whole config load — consistent with this file's existing
|
||||
forward-compatible/ignore-malformed-entries policy (only malformed *YAML
|
||||
syntax* is a hard error). A missing file returns a default-constructed
|
||||
(empty) `AppConfig`, not an error; unknown sections/keys (and malformed
|
||||
individual volume entries) are likewise ignored for forward-compatibility.
|
||||
`main()` applies `config->log_level` (via the existing `apply_log_level()`)
|
||||
right after `spdlog::cfg::load_env_levels()` and before parsing CLI options,
|
||||
so an explicit `--log-level` on the command line always overwrites it
|
||||
afterward — same precedence pattern already used for `SPDLOG_LEVEL`.
|
||||
`write_config_file()` writes the whole file back out (via libyaml's
|
||||
document-building/emitter API, symmetric to the read side) — used by
|
||||
`-v/--volume` (`create_volume_command()`, `commands.cpp`) to persist a new
|
||||
`VolumeEntry {name, directory}` into the `volumes` section, preserving `global`
|
||||
untouched. **`VolumeEntry`/the `volumes` section is a distinct concept from
|
||||
`OciImageConfig::volumes`**: this is a user-defined `name -> host directory`
|
||||
mapping created via `-v/--volume`, not an image's own declared mount points (still
|
||||
unconsumed, see `oci_image.{h,cpp}` above). `AppConfig`/`config.volumes` is looked
|
||||
up by name in `resolve_volume_mount()` (`volume_mount.{h,cpp}`, see below), which
|
||||
is how `-r/--run`'s own `-v` usage finds a named volume's host directory.
|
||||
`VolumeEntry {name, directory}` into the `volumes` section, preserving
|
||||
`global` (including any set `unshare-*` keys, re-serialized as canonical
|
||||
`"true"`/`"false"`) untouched. **`VolumeEntry`/the `volumes` section is a
|
||||
distinct concept from `OciImageConfig::volumes`**: this is a user-defined
|
||||
`name -> host directory` mapping created via `-v/--volume`, not an image's
|
||||
own declared mount points (still unconsumed, see `oci_image.{h,cpp}` above).
|
||||
`AppConfig`/`config.volumes` is looked up by name in `resolve_volume_mount()`
|
||||
(`volume_mount.{h,cpp}`, see below), which is how `-r/--run`'s own `-v` usage
|
||||
finds a named volume's host directory. `run_container()` (`commands.cpp`)
|
||||
resolves the six `unshare-*` fields (each `value_or(true)`) into a
|
||||
`NamespaceConfig` (`bwrap.h`, see below) once, up front, and passes it to
|
||||
`run_bwrap()` — `bwrap.{h,cpp}` itself has no dependency on this file or on
|
||||
YAML parsing at all, only on the already-resolved, defaults-applied struct.
|
||||
- `volume_mount.{h,cpp}` — `is_valid_volume_name()` (no `/`, checked by both
|
||||
`create_volume_command()` and to tell a `-v` spec's name/path apart) and
|
||||
`resolve_volume_mount()`, called once per `-v` occurrence from `run_container()`
|
||||
|
||||
Reference in New Issue
Block a user