stig: ship SELinux allow module for chrony DHCP-NTP dispatcher (stop chronyd AVC)
The NM dispatcher 10-chrony-dhcp-ntp runs `chronyc reload sources` to load DHCP option-42 NTP servers. That chronyc runs in the confined custom-dispatcher domain (NetworkManager_dispatcher_custom_t), so its reply socket carries that label and the shipped policy has no rule for chronyd_t to sendto it. Under enforcing, chronyd does the reload but its ack is denied — chronyc reports failure and the AVC floods the SIEM (seen 2026-07-03; permissive=1 only because the box was booted enforcing=0). Ship a minimal local allow module (files/stig/chrony-dhcp-dispatcher.te): allow chronyd_t NetworkManager_dispatcher_custom_t:unix_dgram_socket sendto; Built + semodule -i'd in the 2c-STIG provisioner (checkpolicy installed if absent), with an install assertion. `allow` not `dontaudit` — it also lets the reload ack succeed so chronyc returns cleanly. Documented as docs/stig-deviations.md #14 (not a rule waiver — a local functional allow). BENCH-VERIFY: enforcing boot shows no AVC, chronyc reload returns 0, a DHCP-handed NTP server appears in `chronyc sources`; and re-check verity-hash reproducibility (semodule rebuilds the policy store, like the semanage step).
This commit is contained in:
@@ -716,6 +716,20 @@ build {
|
|||||||
"evaluated=$(grep -oE '<result>(pass|fixed|fail)</result>' /root/stig-arf.xml | wc -l)",
|
"evaluated=$(grep -oE '<result>(pass|fixed|fail)</result>' /root/stig-arf.xml | wc -l)",
|
||||||
"[ \"$evaluated\" -gt 0 ] || { echo 'ERROR: STIG scan evaluated 0 rules (all notapplicable/notselected) — SSG datastream/CPE mismatch for this distro. Hardening did NOT run; aborting.' >&2; exit 1; }",
|
"[ \"$evaluated\" -gt 0 ] || { echo 'ERROR: STIG scan evaluated 0 rules (all notapplicable/notselected) — SSG datastream/CPE mismatch for this distro. Hardening did NOT run; aborting.' >&2; exit 1; }",
|
||||||
"echo \"==> STIG scan evaluated $evaluated rules (pass/fixed/fail)\"",
|
"echo \"==> STIG scan evaluated $evaluated rules (pass/fixed/fail)\"",
|
||||||
|
# SELinux: allow chronyd to reply to the chronyc our NM dispatcher runs for
|
||||||
|
# DHCP option-42 NTP (10-chrony-dhcp-ntp -> `chronyc reload sources`). The
|
||||||
|
# dispatcher's confined domain (NetworkManager_dispatcher_custom_t) labels
|
||||||
|
# chronyc's reply socket, and the shipped policy denies chronyd_t sendto to
|
||||||
|
# it -> AVC flood + failed reload under enforcing. Ship a minimal allow
|
||||||
|
# module (docs/stig-deviations.md). NB: rebuilds the policy store — include
|
||||||
|
# in the reproducibility check alongside semanage (verity hash stability).
|
||||||
|
"echo '==> supplemental: SELinux module chrony_dhcp_dispatcher (chronyd reply to NM-dispatcher chronyc)'",
|
||||||
|
"command -v checkmodule >/dev/null 2>&1 || dnf install -y checkpolicy",
|
||||||
|
"checkmodule -M -m -o /tmp/chrony_dhcp_dispatcher.mod /tmp/stig/chrony-dhcp-dispatcher.te",
|
||||||
|
"semodule_package -o /tmp/chrony_dhcp_dispatcher.pp -m /tmp/chrony_dhcp_dispatcher.mod",
|
||||||
|
"semodule -i /tmp/chrony_dhcp_dispatcher.pp",
|
||||||
|
"rm -f /tmp/chrony_dhcp_dispatcher.mod /tmp/chrony_dhcp_dispatcher.pp",
|
||||||
|
"semodule -l | grep -q '^chrony_dhcp_dispatcher' && echo '==> SELinux module chrony_dhcp_dispatcher installed' || { echo 'ERROR: chrony_dhcp_dispatcher module not installed' >&2; exit 1; }",
|
||||||
"rm -rf /tmp/stig",
|
"rm -rf /tmp/stig",
|
||||||
"echo '==> STIG remediation complete (report at /root/stig-report.html, ARF at /root/stig-arf.xml)'",
|
"echo '==> STIG remediation complete (report at /root/stig-report.html, ARF at /root/stig-arf.xml)'",
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -138,6 +138,35 @@ down (kiosk autologin to a single locked browser; no getty shell on tty1;
|
|||||||
`debug_shell` is lab-only and never shipped). If a future deployment wants the
|
`debug_shell` is lab-only and never shipped). If a future deployment wants the
|
||||||
hotkey disabled (e.g. a physically exposed terminal), re-select both rule IDs.
|
hotkey disabled (e.g. a physically exposed terminal), re-select both rule IDs.
|
||||||
|
|
||||||
|
## 14. Local SELinux policy module `chrony_dhcp_dispatcher` (added 2026-07-03)
|
||||||
|
|
||||||
|
Not a STIG-rule waiver — a **minimal local `allow` module** shipped to keep a
|
||||||
|
legitimate function working under enforcing SELinux. Source:
|
||||||
|
`files/stig/chrony-dhcp-dispatcher.te`; built + `semodule -i`'d in the 2c-STIG
|
||||||
|
provisioner.
|
||||||
|
|
||||||
|
**The one rule:** `allow chronyd_t NetworkManager_dispatcher_custom_t:unix_dgram_socket sendto;`
|
||||||
|
|
||||||
|
**Why:** the NM dispatcher script `10-chrony-dhcp-ntp` loads DHCP option-42 NTP
|
||||||
|
servers by running `chronyc reload sources`. That `chronyc` runs in the confined
|
||||||
|
custom-dispatcher domain (`NetworkManager_dispatcher_custom_t`), so its reply
|
||||||
|
socket carries that label; the shipped policy has no rule for `chronyd_t` to
|
||||||
|
`sendto` it. Under enforcing, chronyd processes the reload but its **ack is
|
||||||
|
denied** — `chronyc` reports failure and the AVC floods the SIEM (seen
|
||||||
|
2026-07-03). An **`allow`** (not `dontaudit`) is used deliberately: it both stops
|
||||||
|
the noise and lets the reload ack succeed, so `chronyc` returns cleanly.
|
||||||
|
|
||||||
|
**Scope:** one direction, one class/perm, two well-known types. It grants no
|
||||||
|
network/file access and nothing beyond the chronyd↔dispatcher reply the DHCP-NTP
|
||||||
|
path needs. **BENCH-VERIFY:** (a) on an *enforcing* boot the AVC is gone and
|
||||||
|
`chronyc reload sources` from the dispatcher returns 0 (confirm a DHCP-handed NTP
|
||||||
|
server appears in `chronyc sources`); (b) no follow-on AVC (extend the `.te` if
|
||||||
|
one shows); (c) **reproducibility** — `semodule -i` rebuilds the policy store, so
|
||||||
|
re-check the verity hash is stable across two builds (same concern as the
|
||||||
|
`semanage` step, #12/sudo elevation). NB: only shipped when `enable_stig=true`
|
||||||
|
(the module install lives in the STIG-gated provisioner); a non-STIG *enforcing*
|
||||||
|
build would still see the AVC.
|
||||||
|
|
||||||
## Things that are NOT deviations (kept / enforced)
|
## Things that are NOT deviations (kept / enforced)
|
||||||
|
|
||||||
- **SELinux enforcing** (`selinux --enforcing`; labels preserved into the erofs).
|
- **SELinux enforcing** (`selinux --enforcing`; labels preserved into the erofs).
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
policy_module(chrony_dhcp_dispatcher, 1.0.0)
|
||||||
|
|
||||||
|
########################################
|
||||||
|
# Let chronyd reply to the chronyc that our NetworkManager dispatcher script
|
||||||
|
# runs. files/etc/NetworkManager/dispatcher.d/10-chrony-dhcp-ntp loads DHCP
|
||||||
|
# option-42 NTP servers with `chronyc reload sources`. That chronyc runs in the
|
||||||
|
# confined custom-dispatcher domain (NetworkManager_dispatcher_custom_t), so its
|
||||||
|
# reply socket is labeled with that domain, and the shipped policy has no rule
|
||||||
|
# for chronyd_t -> that socket. Result (enforcing): chronyd processes the reload
|
||||||
|
# but its ack `sendto` is DENIED — chronyc reports failure and the AVC floods the
|
||||||
|
# SIEM. This one allow closes it. Minimal + auditable; justified in
|
||||||
|
# docs/stig-deviations.md. If a follow-on AVC appears on the bench, extend here.
|
||||||
|
########################################
|
||||||
|
|
||||||
|
require {
|
||||||
|
type chronyd_t;
|
||||||
|
type NetworkManager_dispatcher_custom_t;
|
||||||
|
class unix_dgram_socket sendto;
|
||||||
|
}
|
||||||
|
|
||||||
|
allow chronyd_t NetworkManager_dispatcher_custom_t:unix_dgram_socket sendto;
|
||||||
Reference in New Issue
Block a user