Default -r's user/group to the image's own declared user

When --user isn't given, run the sandboxed process as whatever user the
image's own config.User declares (already parsed into OciImageConfig::user/
group), instead of always defaulting to root. An explicit --user/--group on
the command line still takes precedence.

read_oci_image_config() is now called unconditionally in run_container()
(it was previously gated behind "no command given") and shared for both the
default command and the default user/group, rather than growing another
special-case guard.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Gv3s5jckJKzh6JkMoi2Akz
This commit is contained in:
2026-08-21 07:28:14 +00:00
parent 4e1e1b206d
commit e64f885c2e
2 changed files with 35 additions and 14 deletions
+17 -7
View File
@@ -17,6 +17,11 @@ this repo as still early-stage.
Source layout (all under `src/`):
- `main.cpp` — CLI entry point, dependency checks, orchestration (`mount_image()`,
`run_container()`, `cleanup_image()`, `unmount_image()`, `list_images_command()`).
`run_container()` unconditionally calls `read_oci_image_config()` and reuses the
result for two independent defaults: the command to run (`Entrypoint ++ Cmd`) when
none is given on the command line, and, when `--user` wasn't given, the sandboxed
process's user/group (`config.User`, split into `OciImageConfig::user`/`group`) —
an explicit `--user`/`--group` on the command line always takes precedence.
- `oci_image.{h,cpp}` — validates/parses the OCI Image Layout tar (libarchive +
nlohmann_json) and extracts layer blobs. `list_oci_images()` scans a directory
(non-recursively) for `*.tar`/`*.tar.*` files and, for each valid OCI archive,
@@ -24,10 +29,11 @@ Source layout (all under `src/`):
(`io.containerd.image.name` preferred, else `org.opencontainers.image.ref.name`),
falling back to the archive's filename and `"latest"` respectively.
`read_oci_image_config()` reads the image config blob referenced by the manifest
and extracts `User`, `ExposedPorts`, `Env`, `Volumes`, and the effective default
command (`Entrypoint ++ Cmd`); `-r/--run` uses its command when none is given on
the command line. Only the default command is actually consumed today — the rest
is captured for when volumes/networking are implemented.
and extracts `User` (split on `:` into `OciImageConfig::user`/`group`),
`ExposedPorts`, `Env`, `Volumes`, and the effective default command
(`Entrypoint ++ Cmd`). `user`/`group` and the default command are consumed by
`-r/--run` (see `main.cpp` above) — `ExposedPorts`/`Env`/`Volumes` are still just
captured for when networking/volumes are implemented.
- `containers_storage.{h,cpp}` — wraps the `containers-storage` CLI (`import-layer`,
`mount`, `unmount`, `layer --json`, `delete-layer`), forcing `fuse-overlayfs` as the
overlay `mount_program`. `cleanup_layer_chain()` walks a layer's parent chain
@@ -71,11 +77,15 @@ Source layout (all under `src/`):
`find_priv_drop_helper()` (`src/bwrap.cpp`) locates it next to `slocker_lite`'s own
binary (via `/proc/self/exe`'s directory), which holds both when run straight from
`buildDir/` and after a real `meson install`.
- `user_spec.{h,cpp}``resolve_user_and_group()` resolves `--user`/`--group` (each
- `user_spec.{h,cpp}``resolve_user_and_group()` resolves a user/group spec (each
a name or numeric id) against the *mounted image's own* `/etc/passwd`/`/etc/group`
(not the host's), since names like `git` only mean anything inside that image's own
user database. A numeric `--user` with no `--group` and no matching `/etc/passwd`
entry defaults gid to the same numeric value as the uid.
user database. A numeric user with no group and no matching `/etc/passwd` entry
defaults gid to the same numeric value as the uid. `run_container()` (`main.cpp`)
calls this 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 root, unless the image declares none.
- `process.{h,cpp}` — argv-based subprocess helpers (fork/execvp, no shell):
`run_process()` captures stdout (used for `containers-storage` calls),
`run_process_foreground()` inherits all of stdio (used for the interactive `bwrap`