Respect the OCI USER config field (Dockerfile USER directive) #7

Closed
opened 2026-09-09 23:48:56 +02:00 by marvin · 0 comments
Collaborator

Problem

slim currently ignores the USER directive from the image config. The VM's init and the container's CMD/ENTRYPOINT always run as root (uid 0), regardless of any USER directive in the Dockerfile.

For example, a Dockerfile containing:

FROM alpine:latest
RUN adduser -D marvin
USER marvin
CMD ["/bin/sh"]

still boots with id reporting uid=0(root) inside the VM.

Root cause

The OCI image config exposes .Config.User (populated by the USER Dockerfile directive), but slim never reads it:

  • src/inject.rs:14-25 — the Config struct only deserializes cmd, entrypoint, env, working_dir. There is no user field, so serde silently drops it.
  • src/inject.rs:69-86build_exec_script only emits cd, export, and exec /bin/sh -c. There is no su/setpriv/setuid to drop privileges.
  • src/scripts/slim-init.sh:41-54 — the runtime (slim.cmd) path also execs the command directly as root (PID 1).
  • src/build.rs:78-80 — only env and working_dir are passed through; user isn't even a parameter.

Proposed implementation

  1. Add a user: Option<String> field to the Config struct in src/inject.rs (serde #[serde(rename_all = "PascalCase")] already maps it to User).
  2. Pass config.user through build_inner into build_exec_script.
  3. In build_exec_script, emit a privilege drop before the final exec. The user field may be a username, a uid, or uid:gid (OCI spec), so handle all forms. su is universally available (BusyBox su included), but setpriv --reuid/--regid is cleaner when present. A portable fallback:
    if [ -n "$SLIM_USER" ]; then
      exec su "$SLIM_USER" -c 'exec /bin/sh -c "..."'
    fi
    
  4. For the runtime override path (slim-init.sh), apply the same drop so slim run --cmd also respects the configured user.

Acceptance criteria

  • A Dockerfile with USER <name> results in id reporting that user inside the VM.
  • Both build-time CMD (/slim/exec) and run-time override (slim.cmd=) run as the configured user.
  • Supports user, uid, and uid:gid forms per the OCI image spec.
  • Falls back to root when USER is unset (current behavior).
## Problem slim currently ignores the `USER` directive from the image config. The VM's init and the container's CMD/ENTRYPOINT always run as **root (uid 0)**, regardless of any `USER` directive in the Dockerfile. For example, a Dockerfile containing: ```dockerfile FROM alpine:latest RUN adduser -D marvin USER marvin CMD ["/bin/sh"] ``` still boots with `id` reporting `uid=0(root)` inside the VM. ## Root cause The OCI image config exposes `.Config.User` (populated by the `USER` Dockerfile directive), but slim never reads it: - **`src/inject.rs:14-25`** — the `Config` struct only deserializes `cmd`, `entrypoint`, `env`, `working_dir`. There is **no `user` field**, so serde silently drops it. - **`src/inject.rs:69-86`** — `build_exec_script` only emits `cd`, `export`, and `exec /bin/sh -c`. There is **no `su`/`setpriv`/setuid** to drop privileges. - **`src/scripts/slim-init.sh:41-54`** — the runtime (`slim.cmd`) path also `exec`s the command directly as root (PID 1). - **`src/build.rs:78-80`** — only `env` and `working_dir` are passed through; `user` isn't even a parameter. ## Proposed implementation 1. Add a `user: Option<String>` field to the `Config` struct in `src/inject.rs` (serde `#[serde(rename_all = "PascalCase")]` already maps it to `User`). 2. Pass `config.user` through `build_inner` into `build_exec_script`. 3. In `build_exec_script`, emit a privilege drop before the final `exec`. The `user` field may be a username, a uid, or `uid:gid` (OCI spec), so handle all forms. `su` is universally available (BusyBox `su` included), but `setpriv --reuid`/`--regid` is cleaner when present. A portable fallback: ```sh if [ -n "$SLIM_USER" ]; then exec su "$SLIM_USER" -c 'exec /bin/sh -c "..."' fi ``` 4. For the runtime override path (`slim-init.sh`), apply the same drop so `slim run --cmd` also respects the configured user. ## Acceptance criteria - A Dockerfile with `USER <name>` results in `id` reporting that user inside the VM. - Both build-time CMD (`/slim/exec`) and run-time override (`slim.cmd=`) run as the configured user. - Supports `user`, `uid`, and `uid:gid` forms per the OCI image spec. - Falls back to root when `USER` is unset (current behavior).
Sign in to join this conversation.
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: hulthe/boco#7