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:
@@ -0,0 +1,31 @@
|
||||
# Raw module-policy syntax (compiled with `checkmodule -M -m`), NOT the refpolicy
|
||||
# `policy_module()` m4 macro — that macro is only expanded by the refpolicy
|
||||
# Makefile and checkmodule rejects it. See chrony-dhcp-dispatcher.te for the why.
|
||||
module fapolicyd_tmpfs 1.0.0;
|
||||
|
||||
########################################
|
||||
# Let fapolicyd statfs (getattr) tmpfs filesystems.
|
||||
#
|
||||
# fapolicyd is the app-allowlisting EXEC GUARD for the writable RAM overlay:
|
||||
# dm-verity covers only the read-only erofs lower, so an executable dropped into
|
||||
# the tmpfs overlay upper is exactly what fapolicyd must catch. fapolicyd statfs's
|
||||
# mounts to decide which to watch, and tmpfs is in its default watch_fs. This
|
||||
# host's root is `systemd.volatile=overlay`, so statfs("/") returns the overlay
|
||||
# UPPER — a tmpfs (the audit shows dev=tmpfs ino=1, name="/") — and the shipped
|
||||
# policy has no `fapolicyd_t tmpfs_t:filesystem getattr` rule (no normal host has
|
||||
# its root on tmpfs). Result 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 exec-guard gap, not just SIEM noise.
|
||||
# This single allow closes it. Minimal + auditable; justified in
|
||||
# docs/stig-deviations.md. BENCH-VERIFY: after this, fapolicyd blocks a non-RPM
|
||||
# executable dropped in /tmp (the overlay). If a follow-on fapolicyd AVC on the
|
||||
# overlay appears on the bench, extend here.
|
||||
########################################
|
||||
|
||||
require {
|
||||
type fapolicyd_t;
|
||||
type tmpfs_t;
|
||||
class filesystem getattr;
|
||||
}
|
||||
|
||||
allow fapolicyd_t tmpfs_t:filesystem getattr;
|
||||
Reference in New Issue
Block a user