stig: ship fapolicyd_tmpfs SELinux module — close overlay exec-guard gap
fapolicyd is the app-allowlisting exec guard for the writable RAM overlay
(dm-verity covers only the read-only erofs lower). It statfs's mounts to decide
which to watch, and tmpfs is in its default watch_fs. This image's root is
systemd.volatile=overlay, so statfs("/") returns the overlay upper — a tmpfs —
and the shipped policy has no 'fapolicyd_t tmpfs_t:filesystem getattr' (no
ordinary host roots on tmpfs). Under enforcing the getattr is DENIED (audit:
dev=tmpfs ino=1 name="/", permissive=0, seen 2026-07-03 on comet-beacon-54),
so fapolicyd can't fully mark the tmpfs mounts (/, /tmp, /dev/shm) and its guard
over the writable overlay is incomplete — a real exec-guard gap, not just SIEM
noise.
Ship a minimal local allow module (allow, not dontaudit — we want fapolicyd to
see the tmpfs), compiled + semodule -i'd in 2c-STIG right after the chrony one.
Registered as deviation #15.
BENCH-VERIFY: the AVC is gone on an enforcing boot AND fapolicyd blocks a non-RPM
executable dropped in /tmp (proves the guard now covers the overlay), trusted
kiosk/appliance binaries still run, and the verity hash is reproducible across
two builds (semodule rebuilds the policy store).
This commit is contained in:
@@ -167,6 +167,36 @@ re-check the verity hash is stable across two builds (same concern as the
|
||||
(the module install lives in the STIG-gated provisioner); a non-STIG *enforcing*
|
||||
build would still see the AVC.
|
||||
|
||||
## 15. Local SELinux policy module `fapolicyd_tmpfs` (added 2026-07-03)
|
||||
|
||||
Not a STIG-rule waiver — a **minimal local `allow` module** shipped to close an
|
||||
**exec-guard gap** under enforcing SELinux. Source: `files/stig/fapolicyd-tmpfs.te`;
|
||||
built + `semodule -i`'d in the 2c-STIG provisioner (right after #14).
|
||||
|
||||
**The one rule:** `allow fapolicyd_t tmpfs_t:filesystem getattr;`
|
||||
|
||||
**Why:** fapolicyd is the app-allowlisting **exec guard for the writable RAM
|
||||
overlay** — dm-verity covers only the read-only erofs lower, so a binary dropped
|
||||
into the tmpfs overlay upper is exactly what fapolicyd must catch (this is why we
|
||||
KEEP fapolicyd; see "Things that are NOT deviations"). fapolicyd `statfs`'s mounts
|
||||
to decide which to watch, and **tmpfs is in its default `watch_fs`**. This image's
|
||||
root is `systemd.volatile=overlay`, so `statfs("/")` returns the overlay **upper**
|
||||
— a tmpfs (audit: `dev=tmpfs ino=1 name="/"`, `fapolicyd_t → tmpfs_t:filesystem
|
||||
getattr`, `permissive=0`, seen 2026-07-03). The shipped policy has no such rule
|
||||
(no ordinary host has its root on tmpfs), so under enforcing the `getattr` is
|
||||
**denied**, fapolicyd cannot fully mark the tmpfs mounts (`/`, `/tmp`, `/dev/shm`),
|
||||
and its guard over the writable overlay is **incomplete** — a real gap, not just
|
||||
SIEM noise. An **`allow`** (not `dontaudit`): we *want* fapolicyd to see the tmpfs.
|
||||
|
||||
**Scope:** one perm (`getattr`) on one class (`filesystem`), two well-known types.
|
||||
Grants no file read/write, only the `statfs` fapolicyd needs to classify + watch
|
||||
the mount. **BENCH-VERIFY:** (a) the AVC is gone on an enforcing boot; (b) fapolicyd
|
||||
**blocks a non-RPM executable dropped in `/tmp`** (proves the guard now covers the
|
||||
overlay tmpfs) while the trusted kiosk/appliance binaries still run; (c)
|
||||
**reproducibility** — `semodule -i` rebuilds the policy store, so re-check verity
|
||||
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.
|
||||
|
||||
## Things that are NOT deviations (kept / enforced)
|
||||
|
||||
- **SELinux enforcing** (`selinux --enforcing`; labels preserved into the erofs).
|
||||
|
||||
Reference in New Issue
Block a user