diff --git a/docs/stig-deviations.md b/docs/stig-deviations.md index c00aa8d..5f019e8 100644 --- a/docs/stig-deviations.md +++ b/docs/stig-deviations.md @@ -216,6 +216,38 @@ still work (nothing legit is untrusted — the 4 custom binaries + rpmdb are tru 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. +**VERIFIED 2026-07-04 (build `fapolicyd-tmpfs-12043d3`, host `comet-beacon-54`) — +enforcing, no false positives.** `fapolicyd active (running)`, `permissive = 0`, +`watch_fs = ...,overlay` (the fix took), `stat -f / /tmp` → both `overlayfs` (so the +test hits the overlay rule, not the pre-existing tmpfs one). A novel-hash binary +(`cp /bin/true /tmp/n; printf '\0' >>/tmp/n`) was **denied**: `bash: /tmp/n: Operation +not permitted`, `exit=126`, and the audit record confirms fapolicyd did it — +`type=FANOTIFY ... resp=2` (FAN_DENY) `obj_trust=0` (target not in trust db). The +**deny sweep was empty** (`journalctl -t fapolicyd -b | grep dec=deny` → nothing), +i.e. **zero false denials**: kiosk-session/weston/chromium + the NM dispatcher scripts +all ran trusted; admin SSH + `sudo` worked under `staff_u:staff_r:staff_t`. So the +exec guard went from **effectively OFF** (pre-fix, overlay unwatched) to **enforcing +on the whole overlay root** with nothing legit broken. My NM-dispatcher false-denial +worry did not materialise. + +**Scope caveat — this closes the UNTRUSTED-PATH half, not the MODIFIED-TRUSTED-PATH +half.** With `integrity = none`, trust is by **path**, so watching the overlay blocks +a *new* file at an *untrusted* path (`/tmp/n`) — proven above. It does **not** catch a +*trusted* path whose **content** was swapped: writing to e.g. `/usr/bin/bash` triggers +an overlayfs **copy-up** into the tmpfs upper — same path, new inode, **outside +dm-verity's coverage** (verity only protects the erofs lower, which is now shadowed) — +and the path-based rule still trusts it. Closing that residual gap needs either +`integrity = sha256` (fapolicyd re-hashes at exec, content ≠ trust-db hash → deny; the +rpmdb backend already carries SHA-256 digests, so it's a one-line `fapolicyd.conf` +change — cost is per-exec userspace hashing, partly redundant with verity on the +un-tampered lower) **or** an **un-shadowable `/usr`** so copy-up can't happen at all +(read-only mount → write fails EROFS, no tmpfs copy is ever created; path-trust becomes +sound again). The latter is tracked as **TODO #15** ("scope root overlay to per-subtree +tmpfs — un-shadowable `/usr`") and is the preferred fix since it removes the attack +surface rather than detecting abuse of it. Requires a write primitive to a root-owned +path either way (already-privileged context), which is fapolicyd's defense-in-depth +threat model — not an unprivileged bypass. + ## Things that are NOT deviations (kept / enforced) - **SELinux enforcing** (`selinux --enforcing`; labels preserved into the erofs).