Drop --clearenv; control the sandbox's environment at exec time
Moves responsibility for the sandboxed command's environment out of bwrap's own --clearenv/--setenv flags and into the process-launching code itself: build_sandbox_env() (bwrap.cpp) constructs the exact environment (PATH, HOME, PWD, TERM if present), and run_bwrap() passes it to run_process_foreground()'s new optional env override, which replaces the forked child's entire environment via clearenv()/setenv() (plain POSIX, not the GNU-only execvpe(), since the target platform includes musl) right before exec. bwrap, nsenter (when interposed), and slocker-lite-priv-drop all just forward whatever environment they're launched with, so controlling it once at the outermost exec is sufficient. Also adds PWD=/ to the constructed environment: per bwrap's own man page, --clearenv never actually unset PWD in the first place (bwrap manages it separately, alongside --chdir), so the old --clearenv/ --setenv sequence was leaving it unset by omission rather than by choice. Hardcoded to "/" to match --chdir's own value. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Gv3s5jckJKzh6JkMoi2Akz
This commit is contained in:
@@ -140,6 +140,19 @@ Source layout (all under `src/`):
|
||||
`release_session_lock()` once `run_process_foreground()` returns (covering
|
||||
every exit path — normal, nonzero, or a forwarded-signal exit — since that call
|
||||
always blocks until the child has actually exited).
|
||||
`build_bwrap_args()` no longer passes `--clearenv`/`--setenv` to `bwrap` itself;
|
||||
instead, `build_sandbox_env()` builds the sandboxed command's exact environment
|
||||
(`PATH`, `HOME`, `PWD` — hardcoded to `"/"`, matching `--chdir`'s own value; note
|
||||
per bwrap's own man page `--clearenv` never actually unset `PWD` in the first
|
||||
place, so this isn't a straight port of a prior `--setenv` — and `TERM`, only
|
||||
if the host process has one) and `run_bwrap()` passes it straight to
|
||||
`run_process_foreground()`'s own `env` override (see `process.{h,cpp}` below).
|
||||
This works because `bwrap` (and `nsenter`, when interposed via
|
||||
`wrap_for_root_namespace()`) doesn't alter its own inherited environment unless
|
||||
told to, and neither does `slocker-lite-priv-drop` (just
|
||||
`setgroups()`/`setgid()`/`setuid()`/`execvp()`, no env manipulation) — so
|
||||
controlling it once, at the outermost exec, is sufficient for it to reach the
|
||||
final sandboxed command unchanged.
|
||||
- `priv_drop_helper.cpp` → the separate `slocker-lite-priv-drop` binary (its own
|
||||
`executable()` target in `meson.build`, **built with `-static`**). Deliberately
|
||||
has zero dependencies on the rest of this project (no fmt/spdlog/etc.) and is
|
||||
@@ -163,9 +176,9 @@ Source layout (all under `src/`):
|
||||
carries `home`, looked up by the final resolved uid's `/etc/passwd` entry (field 5)
|
||||
regardless of whether `user` was given as a name or a number; falls back to
|
||||
`"/root"` for uid 0 or `"/"` otherwise when there's no matching row.
|
||||
`build_bwrap_args()` (`bwrap.cpp`) sets the sandboxed process's `HOME` from this —
|
||||
`"/root"` only when no user override applies at all (no `--user`, no image-declared
|
||||
`config.User`). `run_container()` (`main.cpp`) calls `resolve_user_and_group()`
|
||||
`build_sandbox_env()` (`bwrap.cpp`) sets the sandboxed process's `HOME` from
|
||||
this — `"/root"` only when no user override applies at all (no `--user`, no
|
||||
image-declared `config.User`). `run_container()` (`main.cpp`) calls `resolve_user_and_group()`
|
||||
with either the explicit `--user`/`--group` flags, or, when `--user` wasn't given,
|
||||
the image's own declared `config.User` (`OciImageConfig::user`/`group`) — so a
|
||||
container defaults to running as whatever user the image itself declares, not
|
||||
@@ -185,7 +198,13 @@ Source layout (all under `src/`):
|
||||
itself execs into something else first (e.g. `nsenter` handing off to the final
|
||||
command via its own in-place `execvp()` — a pid never changes across `exec()`).
|
||||
`run_bwrap()` (`bwrap.cpp`) is the one caller that uses it, for session pid-file
|
||||
tracking (see `pid_file.{h,cpp}` below).
|
||||
tracking (see `pid_file.{h,cpp}` below). `run_process_foreground()` also takes
|
||||
an optional `env` (list of key/value pairs): when set, the forked child
|
||||
replaces its entire environment via `clearenv()`/`setenv()` (plain POSIX, not
|
||||
the GNU-only `execvpe()` — the target platform includes musl) before `execvp()`,
|
||||
instead of inheriting this process's own. `nullopt` (the default) leaves the
|
||||
child's environment untouched. `run_bwrap()` is again the one caller that uses
|
||||
this, via `build_sandbox_env()` (`bwrap.cpp`) — see there.
|
||||
- `pid_file.{h,cpp}` — tracks one running `-r/--run` session (a live `bwrap`
|
||||
process) as a locked pid file, so an outside process (or a later
|
||||
`slocker-lite` invocation) can tell whether it's still running.
|
||||
|
||||
Reference in New Issue
Block a user