Skip to content

fix(core): write the OCI bundle config.json owner-only (0600) - #273

Merged
Lupus merged 1 commit into
mainfrom
fix/oci-config-owner-only-perms
Sep 1, 2026
Merged

Lupus merged 1 commit into
mainfrom
fix/oci-config-owner-only-perms

Conversation

@Lupus

@Lupus Lupus commented Sep 1, 2026

Copy link
Copy Markdown
Owner

What

write_oci_bundle explicitly widened the atomically-written oci/config.json from tempfile's 0600 default to 0644. This resolves SonarCloud rust:S2612 (MAJOR, "Make sure this permission is safe") at that call site.

Why 0600 is correct here (investigation, not a linter appeasement)

The concern worth checking before tightening: the OCI bundle dir is shared into the guest over virtiofs (izba-oci) and read in-guest by crun, under Option-A userns and, in docker mode, under the shifted uid map. If a non-root or uid-shifted guest reader needed the file, 0600 would break boot. It does not:

Reader Runs as Needs the mode bits?
Host izba / izbad the owning user (the writer itself) no
In-guest crun (crun run -b /rootfs/izba-oci) guest root, spawned by izba-init (PID 1) no — virtiofsd serves the share as the host owner, and guest root reads through CAP_DAC_OVERRIDE
The workload container image USER / shifted uid never reads it at all

Two independent confirmations that the guest path is not mode-dependent:

  • The sibling izba-ssh share already delivers the ssh host key at 0600 over the exact same virtiofs → guest-root channel, and init reads it on every boot.
  • The bundle's mount target only sits under /rootfs (= the container root) because that is where crun resolves -b. Nothing inside the container consumes the spec, and in docker mode the host owner's uid falls outside docker_shifted_map, so the file already presents as nobody in-container regardless of its mode.

So 0644 was exposing izba's runtime spec — uid maps, mount layout, env including the CA trust-env — to a hostile guest workload for no functional gain. Per the threat model (guest-is-hostile), removing that is a small real improvement, not just a green gate.

tempfile already creates at 0600, so the fix could have been to delete the block; the mode is instead pinned explicitly so it stays a test-asserted property rather than an inherited default, and the call site now carries the rationale so it is not "helpfully" widened again.

Tests

TDD: start_writes_oci_config_owner_only asserts mode & 0o777 == 0o600, written first and observed failing (left: 420, right: 384) before the change.

All workspace gates green, plus the out-of-workspace app/src-tauri gate.

Because this touches a host→guest delivery path, the real-VM KVM daemon e2e suite was run locally: 13/13 pass, including the three most likely to catch a permission regression:

  • vnc_docker_e2e (docker mode + VNC)
  • docker_publish_reaches_inner_container (docker mode, shifted uid map)
  • vnc_desktop_runs_as_image_user_e2e (non-root image USER)

Scope

One file, one finding. No wire/protocol change, no DAEMON_PROTO_VERSION bump.

🤖 Generated with Claude Code

Greptile Summary

Tightens the atomically written OCI bundle configuration from 0644 to 0600, limiting it to the host owner while retaining guest-root access through virtiofs.

  • Pins the owner-only permission explicitly and documents the host-to-guest access rationale.
  • Adds a Unix test asserting that the generated oci/config.json has mode 0600.

Confidence Score: 5/5

The PR appears safe to merge with no actionable correctness, security, or compatibility issues identified.

Guest PID 1 launches crun as uid 0 without dropping the capability needed to read the owner-only file, and the same read-only virtiofs path already carries a host-created 0600 SSH key successfully.

Important Files Changed

Filename Overview
crates/izba-core/src/sandbox.rs Safely narrows OCI configuration permissions and adds focused regression coverage without changing the bundle format or startup flow.

Reviews (1): Last reviewed commit: "fix(core): write the OCI bundle config.j..." | Re-trigger Greptile

`write_oci_bundle` explicitly widened the atomically-written
`oci/config.json` from tempfile's 0600 default to 0644 (SonarCloud
rust:S2612, MAJOR). No reader needs the group/other read bits.

Who reads the file, and as whom:

- Host: only the owning user's `izba`/`izbad` process, which wrote it.
- Guest: `crun`, spawned by izba-init (PID 1, guest root) as
  `crun run -b /rootfs/izba-oci`. virtiofsd serves the share as the host
  owner, and guest root reads through CAP_DAC_OVERRIDE, so the mode is
  irrelevant to it. The sibling `izba-ssh` share already delivers the ssh
  host key at 0600 over the same channel and init reads it fine — the
  behaviour was never mode-dependent.
- The workload container: never. The share's mount target only sits under
  `/rootfs` (= the container root) because that is where crun resolves the
  bundle path; nothing inside the container consumes the spec. In docker
  mode the host owner's uid falls outside `docker_shifted_map`, so the
  file already presents as `nobody` in-container regardless.

So 0644 exposed izba's runtime spec — uid maps, mounts, env, including
the CA trust-env layout — to a hostile guest workload for no functional
gain. 0600 removes that with no reader to break. The mode is now pinned
by a unit test instead of inherited from `tempfile`, and the call site
carries the rationale so it is not "helpfully" widened again.

Verified on real VMs, not just mocks: the full KVM daemon e2e suite
(13/13) passes, including `vnc_docker_e2e`,
`docker_publish_reaches_inner_container` and
`vnc_desktop_runs_as_image_user_e2e` — the docker-mode shifted-uid and
non-root-`USER` paths most likely to notice a permission regression.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@sonarqubecloud

sonarqubecloud Bot commented Sep 1, 2026

Copy link
Copy Markdown

@Lupus
Lupus merged commit e6981bf into main Sep 1, 2026
23 checks passed
@Lupus
Lupus deleted the fix/oci-config-owner-only-perms branch September 1, 2026 19:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant