secure-ntp: label /run/chrony-dhcp so chronyd can read the NTS source under SELinux

Second bench defect after removing the distro 20-chrony-dhcp clobberer
(secure-ntp-5a3eaed, comet-beacon-54): the dispatcher wrote the correct
`server ntp.fleet.lab iburst nts` line, but chrony loaded ZERO sources --
`chronyc reload sources` returned 200 OK yet authdata/sources stayed empty.

Root cause (AVC): chronyd_t was DENIED read on the .sources files because they and
/run/chrony-dhcp itself were labeled generic var_run_t; chronyd_t may only read its
own chronyd_var_run_t. The dispatcher's `mkdir -p` creates the dir as var_run_t and
files inherit it. The distro 20-chrony-dhcp we removed had been restorecon-ing them
to the readable label, so removing it exposed a latent labelling gap.

Stock RHEL policy already maps /run/chrony-dhcp -> chronyd_var_run_t (a restorecon
relabels it and chrony immediately reaches NTS Cook 8). Fix: ship
/etc/tmpfiles.d/chrony-dhcp.conf so systemd-tmpfiles pre-creates the dir with that
fcontext at sysinit, before any NM event -- the dispatcher's files then inherit
chronyd_var_run_t and chronyd can read them. No SELinux allow rules needed
(bench-verified: after the fix a real NM event wrote the source as chronyd_var_run_t,
no AVC, authdata -> NTS Cook 8). Applies in both secure_ntp modes.

Also: the dispatcher now skips `lo` -- it was writing a spurious lo.sources
duplicate of the same server (the distro script had skipped loopback).

BENCH-VERIFY on the next clean build: a normal boot leaves the source file labeled
chronyd_var_run_t (ls -Z), no lo.sources, and authdata reaches NTS/cookies>0 with no
manual step.
This commit is contained in:
Audiobuzz
2026-07-12 02:53:05 +00:00
parent 5a3eaedec5
commit 5294860e74
5 changed files with 79 additions and 6 deletions
+10
View File
@@ -457,6 +457,16 @@ build {
# dispatcher supersedes it in BOTH modes, so drop it unconditionally. Leave
# 20-chrony-onoffline (only marks sources online/offline — harmless).
"rm -f /usr/lib/NetworkManager/dispatcher.d/20-chrony-dhcp",
# ...but the distro script was ALSO (accidentally) labelling /run/chrony-dhcp so
# chronyd could read the sources. Removing it exposed that gap: our dispatcher's
# `mkdir -p` makes the dir generic var_run_t and the source files inherit it, and
# chronyd_t (which only reads chronyd_var_run_t) is SELinux-DENIED reading them →
# NTS silently loads 0 sources (bench 2026-07-12, comet-beacon-54). This tmpfiles.d
# entry pre-creates /run/chrony-dhcp at sysinit with the stock chronyd_var_run_t
# fcontext (before any NM event), so the dispatcher's files inherit a readable
# label — no SELinux allow rules needed. Applies in BOTH modes.
"install -D -m0644 /tmp/etc-stage/tmpfiles.d/chrony-dhcp.conf /etc/tmpfiles.d/chrony-dhcp.conf",
"restorecon /etc/tmpfiles.d/chrony-dhcp.conf",
"sed -i -E 's/^[[:space:]]*(pool|server)[[:space:]]/#&/' /etc/chrony.conf",
"grep -q '^sourcedir /run/chrony-dhcp' /etc/chrony.conf || echo 'sourcedir /run/chrony-dhcp' >> /etc/chrony.conf",
"if [ \"${var.secure_ntp}\" = \"true\" ]; then echo '==> secure NTP: NTS via <${var.ntp_prefix}>.<dhcp-domain> (fleet-CA-authenticated)'; { printf '\\n# Secure NTP (NTS, RFC 8915) — verify the server against the fleet CA. docs/secure-ntp-design.md\\n'; printf 'ntstrustedcerts /etc/dot1x/radius-ca.pem\\n'; printf 'nocerttimecheck 1\\n'; } >> /etc/chrony.conf; else echo '==> legacy NTP: unauthenticated DHCP option-42'; fi",