banger/internal
Thales Maciel 77043966d4
system: add ext4 toolkit for non-sudo work-disk writes
The daemon mounts every VM's work disk on the host via sudo, copies
files in as root, chmods+chowns them, and unmounts. That's ~18 of
banger's runtime RunSudo calls. The ext4 image is a regular file the
daemon user owns; e2cp / debugfs can write to it directly and bake
uid/gid/mode into the filesystem metadata without the caller being
root. `imagepull.ApplyOwnership` already proves this works in
production (OCI layer flattening writes 0/0/root-owned inodes from
an unprivileged daemon).

This commit adds the toolkit layer. Callers land in the next four
commits:

  - MkdirExt4 — idempotent directory create + metadata reset, single
    debugfs batch
  - WriteExt4FileOwned — e2cp + debugfs-driven uid/gid/mode, auto-
    cleans the host tempfile
  - SetExt4Ownership — sif + set_inode_field batch for existing
    inodes (no mkdir implied)
  - EnsureExt4RootPerms — fixes inode <2> (the fs root, which is
    `/root` once the work disk is mounted inside the guest), the
    thing sshd's StrictModes walks
  - Ext4PathExists — yes/no probe via `debugfs -R "stat ..."` with
    "File not found" detection
  - ReadExt4File — bytes-returning wrapper around the existing
    ReadDebugFSText with the same path rejection

Design notes:

  - extfsRun auto-switches Run ↔ RunSudo on imagePath's type: regular
    files get the unprivileged path, block devices (dm-snapshot,
    loops) get sudo. The same helper works for both patchRootOverlay
    (dm device) and work-disk writes (user-owned file). No caller
    flag needed — os.Stat tells us.
  - debugfsScript batches set_inode_field + sif + mkdir lines into
    one `debugfs -w -f -` stdin invocation on any Runner that
    implements StdinRunner (production's system.Runner does). Matches
    imagepull.ApplyOwnership's existing pattern; dramatically cheaper
    than per-call subprocesses.
  - Paths are escaped for debugfs on the way in: spaces get double-
    quoted, double-quote/backslash/newline are rejected outright
    (debugfs's hand-rolled parser doesn't reliably escape those and
    we'd rather fail fast than silently scribble over the wrong
    inode).

Tests: seven behaviour assertions via scripted + stdin-scripted
runners — existence probe (found + missing + rejection), read
passthrough, mkdir batch contents (new vs. pre-existing path), write
tempfile cleanup + mode line shape, root-inode addressing, and the
full rejectDebugfsUnsafePath matrix.

No production wiring change in this commit — the helpers land
unused. `make smoke` stays green (21/21) because nothing else
shifted.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 16:31:50 -03:00
..
api workspace: drop --readonly flag — advisory only against root guests 2026-04-23 13:04:33 -03:00
buildinfo Stamp shared build metadata into banger binaries 2026-03-22 17:14:06 -03:00
cli model: validate VM names as DNS labels at CLI + daemon 2026-04-23 14:06:40 -03:00
config cleanup: drop pre-v0.1 migration scaffolding + legacy-behavior refs 2026-04-23 13:56:32 -03:00
daemon daemon: persist teardown fallbacks and reject unsafe import paths 2026-04-23 16:21:59 -03:00
firecracker daemon: fix vm start (on a stopped VM) + regression coverage 2026-04-23 12:01:46 -03:00
guest ssh: trust-on-first-use host key pinning everywhere 2026-04-19 16:46:03 -03:00
guestconfig Refactor VM lifecycle around capabilities 2026-03-18 19:28:26 -03:00
guestnet Stop using kernel IP autoconfig for runtime VMs 2026-03-21 21:54:18 -03:00
hostnat coverage: medium batch — hostnat runner, store guest-sessions, daemon helpers 2026-04-18 18:03:37 -03:00
imagecat publish-golden-image: content-addressed tarball names 2026-04-18 15:26:57 -03:00
imagepull daemon: persist teardown fallbacks and reject unsafe import paths 2026-04-23 16:21:59 -03:00
kernelcat Prune legacy void/alpine + customize.sh flows 2026-04-18 15:39:53 -03:00
model daemon: persist teardown fallbacks and reject unsafe import paths 2026-04-23 16:21:59 -03:00
namegen coverage: make targets + close zero-cov gaps (namegen, sessionstream) 2026-04-18 17:44:37 -03:00
paths runtime sockets: close the local-user race window around control-plane creation 2026-04-20 12:53:47 -03:00
policy Add vsock-backed VM port inspection 2026-03-19 15:52:11 -03:00
rpc Propagate RPC cancellation to daemon requests 2026-03-16 18:28:33 -03:00
store cleanup: drop pre-v0.1 migration scaffolding + legacy-behavior refs 2026-04-23 13:56:32 -03:00
system system: add ext4 toolkit for non-sudo work-disk writes 2026-04-23 16:31:50 -03:00
toolingplan coverage: easy-wins batch across cli, system, paths, vmdns, toolingplan 2026-04-18 17:57:05 -03:00
vmdns coverage: easy-wins batch across cli, system, paths, vmdns, toolingplan 2026-04-18 17:57:05 -03:00
vsockagent Add vsock-backed VM port inspection 2026-03-19 15:52:11 -03:00