# 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 fleet_agent_chronyc 1.0.0; ######################################## # Let the fleet-agent's chrony probe transition to chronyc_t under NoNewPrivileges. # # fleet-agent (telemetry) shells out to `chronyc -n tracking` to report the host's # clock offset / NTP source / stratum. The agent runs as unconfined_service_t, and # the shipped chrony policy has a type_transition so executing chronyc moves the # child into the confined chronyc_t domain. BUT the fleet-agent unit is hardened # with NoNewPrivileges (set explicitly AND forced by DynamicUser + SystemCallFilter # + MemoryDenyWriteExecute), and SELinux forbids an NNP process from transitioning # domains unless process2:nnp_transition is granted for that source->target pair. # The shipped policy has no such grant, so under enforcing the exec is DENIED: # avc: denied { nnp_transition } comm="fleet-agent" # scontext=...:unconfined_service_t tcontext=...:chronyc_t tclass=process2 # chronyc never runs, chronyTracking() returns empty, and every chrony_* health # field stays unset (the UI shows chrony as "—"). uptime/cpu/mem are unaffected — # they read /proc directly and need no domain transition. # # This single allow lets the transition proceed to the MORE-confined chronyc_t # domain (the safe direction NNP's nnp_transition permission exists to gate), with # no loosening of the agent's own sandbox. Minimal + auditable; justified in # docs/stig-deviations.md #16. # # NB this is necessary but NOT sufficient: the agent reaches chronyd over the # LOOPBACK UDP command socket (`chronyc -h 127.0.0.1 tracking`; the image binds it # via `bindcmdaddress 127.0.0.1`, see stig-deviations #17) because the unix socket # is unusable under the agent's sandbox. Under enforcing, once chronyc runs in # chronyc_t it must also be allowed to reach chronyd_t on UDP 323 — the base chrony # policy is expected to cover chronyc_t's command traffic, but BENCH-VERIFY on the # first enforcing boot and, if a FOLLOW-ON chronyc_t AVC appears (e.g. a corenet # udp_socket/name_connect denial to chronyd), extend here. ######################################## require { type unconfined_service_t; type chronyc_t; class process2 nnp_transition; } allow unconfined_service_t chronyc_t:process2 nnp_transition;