Skip to content

fix(box): Linux/KVM runtime fixes — bridge/Compose as root, overlay fs commands, snapshot restore, image integrity#5

Merged
ZhiXiao-Lin merged 4 commits into
release/v2.0.4from
fix/linux-kvm-runtime
May 31, 2026
Merged

fix(box): Linux/KVM runtime fixes — bridge/Compose as root, overlay fs commands, snapshot restore, image integrity#5
ZhiXiao-Lin merged 4 commits into
release/v2.0.4from
fix/linux-kvm-runtime

Conversation

@ZhiXiao-Lin
Copy link
Copy Markdown
Contributor

Summary

Fixes a set of correctness, security, and lifecycle bugs found by exercising the
full command surface on a real Linux x86_64 + KVM host (libkrun). Several of
these completely broke core features when a3s-box runs as root (the common
server/KVM case). All changes are scoped to the Linux/overlay path and are
cross-platform safe (platform-specific code is cfg-gated; verified to compile
clean on macOS arm64).

Fixes (4 commits)

  1. Bridge networking & Compose work as root. passt drops privileges to
    nobody, then could not create its socket under the box's 0700 ~/.a3s
    home → every run --network and compose up failed with "passt socket did
    not appear". Socket now lives in the world-traversable runtime socket dir
    (next to exec/PTY sockets) with appropriate permissions; passt stderr is
    captured and early exit is detected (no more misleading 5s timeout).
  2. diff/export/commit on the overlay provider. They hard-coded
    <box_dir>/rootfs, which only exists for the plain provider; the default
    Linux overlay provider uses <box_dir>/merged. Added resolve_box_rootfs()
    (prefers merged, falls back to rootfs).
  3. Snapshot restore preserves the filesystem. create now captures the real
    rootfs; restore writes a marker and the runtime boots the restored box from
    the captured rootfs instead of rebuilding from the image. Also hardens
    guest-init selection: reject dynamically-linked ELFs (a glibc host build can
    never be picked as PID 1) and rank musl-static builds first.
  4. Image integrity + input validation. Apply OCI whiteouts during layer
    extraction (deleted files no longer reappear); verify the SHA-256 of pulled
    config/layer blobs before storing; reject /0 subnets in Ipam (was a
    shift-overflow panic).

Verification (real KVM host)

  • core_smoke: 14/14 (was 9/14 before these fixes)
  • command_coverage: 6/6 · host_smoke VM matrix + Compose: pass
  • New unit tests: OCI whiteout (incl. opaque dirs), Ipam /0 & overflow — pass
  • cargo clippy -D warnings clean; macOS arm64 cargo check clean

Targets release/v2.0.4 (the branch these were built and verified against).
main has diverged; forward-porting needs a separate rebase + retest.

Roy Lin added 4 commits May 30, 2026 23:00
When a3s-box runs as root, passt drops privileges to `nobody` and then
cannot create its control socket under the box's 0700 `~/.a3s` home, so the
runtime times out ("passt socket did not appear within 5 seconds") and every
bridge-mode `run --network` and all `compose up` boots fail.

Place the passt socket in the world-traversable runtime socket directory
(alongside the exec/PTY sockets) and widen that directory's permissions under
cfg(unix) so the dropped user can bind it. Also capture passt's stderr instead
of discarding it to /dev/null and detect immediate child exit, so a real spawn
failure surfaces instead of a misleading 5s timeout.

Verified on a real Linux/KVM host: bridge boxes get an eth0 IP and `compose up`
starts services.
diff/export/commit hard-coded `<box_dir>/rootfs`, which only exists for the
plain/copy provider. The default Linux overlay provider materializes the rootfs
at `<box_dir>/merged`, so all three commands failed with "Rootfs not found".

Add a shared `resolve_box_rootfs()` helper that prefers the overlay `merged`
directory and falls back to `rootfs`, and use it in all three commands. The
diff baseline snapshot is taken against the same resolved rootfs.

Verified: export tars the full rootfs, commit produces a runnable image, and
diff reports added files correctly.
…tion

snapshot create captured `<box_dir>/rootfs` (empty under overlay) and restore
booted the restored box from the image, losing all filesystem changes.

- snapshot create now captures the resolved rootfs (overlay `merged`).
- snapshot restore writes a `.snapshot-rootfs` marker; prepare_layout boots
  directly from `<box_dir>/rootfs` when that marker is present, so the restored
  box reflects the snapshot. The marker gate guarantees normal boxes (which
  never have `rootfs` under overlay) are unaffected.

Also harden guest-init selection (layout.rs): is_linux_elf rejects dynamically
linked ELFs (no PT_INTERP) so a glibc host build can never be chosen as PID 1,
and candidates rank musl-static builds first on all platforms.

Verified: restored box contains files written before the snapshot.
…subnet

- oci/layers: apply OCI whiteout semantics during extraction (.wh.<name> and
  .wh..wh..opq), so files deleted in upper layers don't reappear and markers are
  not written into the rootfs. Normal entries delegate to unpack_in to preserve
  symlink/perm/mtime fidelity. (+ unit tests)
- oci/registry: verify the SHA-256 of each pulled config/layer blob against the
  manifest before storing it content-addressed.
- core/network: Ipam::new rejects prefix_len 0 (and uses checked arithmetic for
  the gateway) to fix a shift-overflow panic / garbage subnet. (+ unit tests)
@ZhiXiao-Lin ZhiXiao-Lin merged commit c1982a9 into release/v2.0.4 May 31, 2026
@ZhiXiao-Lin ZhiXiao-Lin deleted the fix/linux-kvm-runtime branch May 31, 2026 03:07
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