SELinux local policy maintenance workflow
noteHistorical technical note from 2018. Environment-specific identifiers and credentials have been anonymized. Commands reflect the technology and operating-system generation used at the time and should be reviewed before reuse on a current system.
This note turns the original iterative systemd-machined example into a generic procedure for maintaining a local SELinux module without retaining host-specific policy names or permissions.
1. Reproduce and collect
$ ausearch -m AVC,USER_AVC -ts recent2. Diagnose
$ ausearch -m AVC -ts recent | audit2why $ ausearch -m AVC -ts recent | audit2allow -R
Treat output as analysis, not as a policy to install automatically.
3. Verify labels
$ ls -lZ /path $ matchpathcon /path
If the label is wrong, fix it persistently with semanage fcontext and restorecon.
4. Update module source
Add only the interface or narrowly scoped rule that matches intended behavior. Increment the local module version in source control and document why each non-standard permission exists.
5. Build and install
$ make -f /usr/share/selinux/devel/Makefile localpolicy.pp $ semodule -i localpolicy.pp
6. Verify
Re-run the operation and inspect recent AVCs again. A successful command is not sufficient; confirm the new rule did not hide a broader labeling or confinement problem.
References
- Red Hat - Writing a custom SELinux policy: https://docs.redhat.com/en/documentation/red_hat_enterprise_linux/9/html/using_selinux/writing-a-custom-selinux-policy_using-selinux
- semodule(8): https://man7.org/linux/man-pages/man8/semodule.8.html
Current practice (checked 2026-10)
noteThe article above is kept as it was written in 2018. This section lists what has changed since and what to do instead today.
- Still valid: the loop above (collect AVCs, analyse, check labels, edit the module source, rebuild, verify) matches the procedure in the current Red Hat documentation, including
audit2allow -Ras a suggestion to review and not a policy to install. - Message types: search for
AVC,USER_AVC,SELINUX_ERR,USER_SELINUX_ERR, not only AVC records; the last two show policy and transition errors that never appear as an AVC. - Hidden denials: if the operation fails without any AVC, a
dontauditrule is hiding it. Disable those rules temporarily withsemodule -DB, reproduce, then restore them withsemodule -B. - New module skeleton: for a new confined service,
sepolicy generate --init /path/to/daemonwrites the.te,.ifand.fcfiles plus a setup script that builds, installs and relabels. - Module priorities:
semodule -iinstalls at priority 400 by default and-Xselects another priority. Usesemodule -lfullto see which priority of a module is active, and remove a module at the priority it was installed with.
$ # ausearch -m AVC,USER_AVC,SELINUX_ERR,USER_SELINUX_ERR -ts recent $ # semodule -lfull | grep localpolicy
Sources: