diff --git a/diskless.pkr.hcl b/diskless.pkr.hcl index 84f70ee..12cebaf 100644 --- a/diskless.pkr.hcl +++ b/diskless.pkr.hcl @@ -810,6 +810,25 @@ build { " for f in /usr/local/bin/kiosk-session /usr/local/bin/fleet-sb-enroll /usr/local/bin/fleet-hostapi /usr/sbin/fleet-enrol; do { [ -f \"$f\" ] && fapolicyd-cli --file add \"$f\"; } || true; done", " fapolicyd-cli --update 2>/dev/null || true", " echo '==> fapolicyd: trusted custom binaries (kiosk-session, fleet-sb-enroll, fleet-hostapi) + rebuilt trust db'", + # watch_fs: the diskless root is OVERLAYFS (systemd.volatile=overlay), but the + # shipped watch_fs lacks 'overlay', so fapolicyd marks NO overlay mount and + # therefore intercepts NO exec on / — the exec guard for the writable overlay + # (the whole reason we keep fapolicyd; dm-verity can't cover the tmpfs upper) + # is effectively OFF at runtime. VERIFIED on the bench 2026-07-03: a novel + # non-RPM binary in /tmp (overlayfs) ran freely under `permissive=0`. Add + # 'overlay' so fapolicyd actually watches the root; trust is path-based + # (integrity=none) so overlay paths resolve against the rpmdb trust as normal. + # The #15 tmpfs getattr allow supports this (fapolicyd statfs's the overlay's + # tmpfs upper). Idempotent. BENCH-VERIFY HARD — this turns app-allowlisting ON + # for the WHOLE root at runtime for the first time: boot + kiosk render + admin + # SSH + sudo + TPM enrolment must ALL still work (nothing legit is untrusted), + # a novel /tmp binary must now be BLOCKED (EPERM), and watch for new AVCs. + # enable_stig=false is the escape hatch if it regresses the boot/secure path. + " if [ -f /etc/fapolicyd/fapolicyd.conf ]; then", + " grep -Eq '^watch_fs.*overlay' /etc/fapolicyd/fapolicyd.conf || sed -ri '/^watch_fs *=/ s/$/,overlay/' /etc/fapolicyd/fapolicyd.conf", + " grep -Eq '^watch_fs.*overlay' /etc/fapolicyd/fapolicyd.conf || { echo 'ERROR: failed to add overlay to fapolicyd watch_fs' >&2; exit 1; }", + " echo '==> fapolicyd: watch_fs now includes overlay (guards the volatile-overlay root)'", + " fi", "fi", ] } diff --git a/docs/stig-deviations.md b/docs/stig-deviations.md index aa55ad6..c00aa8d 100644 --- a/docs/stig-deviations.md +++ b/docs/stig-deviations.md @@ -197,6 +197,25 @@ overlay tmpfs) while the trusted kiosk/appliance binaries still run; (c) hash stability across two builds (same concern as #12/#14). NB: only shipped when `enable_stig=true`; a non-STIG enforcing build would still see the AVC and the gap. +**UPDATE 2026-07-03 — the getattr allow alone did NOT close the exec gap; the real +enabler is `watch_fs`.** Bench test on `comet-beacon-54`: with the `.te` installed +(AVC gone, `fapolicyd active`, `permissive=0`), a **novel** non-RPM executable in +`/tmp` (hash NOT in the trust db) still **ran** (`exit=0`). Root cause: the diskless +root is **overlayfs** (`stat -f /` → `overlayfs`, `/tmp` too), but the shipped +`watch_fs = ext2,ext3,ext4,tmpfs,xfs,vfat,iso9660,btrfs` has **no `overlay`**. +fapolicyd marks mounts by fs type, so it never marks the overlay = it intercepts +**no exec on `/`** — the whole root, `/usr` and `/tmp` alike. So the exec guard was +effectively **OFF at runtime** on every diskless host. Fix: the 2c-STIG fapolicyd +step now appends **`overlay` to `watch_fs`** in `fapolicyd.conf` (idempotent) so +fapolicyd watches the overlay root; trust is path-based (`integrity=none`) so overlay +paths resolve against the rpmdb trust normally. The `fapolicyd_tmpfs` `.te` above is +still needed — it supports fapolicyd statfs'ing the overlay's tmpfs upper. **This +turns app-allowlisting ON for the whole root at runtime for the first time**, so +**BENCH-VERIFY HARD:** boot + kiosk render + admin SSH + sudo + TPM enrolment all +still work (nothing legit is untrusted — the 4 custom binaries + rpmdb are trusted), +a novel `/tmp` binary is now **blocked** (EPERM), and no new AVCs (extend the `.te` +if any). `enable_stig=false` is the escape hatch if it regresses the boot/secure path. + ## Things that are NOT deviations (kept / enforced) - **SELinux enforcing** (`selinux --enforcing`; labels preserved into the erofs).