SELinux Introduction: Your First Step to Reading Denial Logs
What Is SELinux?
SELinux (Security-Enhanced Linux) is a mandatory access control (MAC) system built into the Linux kernel. It adds an extra layer of security on top of standard Unix permissions (DAC). On RHEL, CentOS, and Fedora systems it is enabled by default — blocking processes like Apache or PostgreSQL from accessing files they should not touch.
Standard chmod / chown (DAC) only asks: "Is this the file owner? Is the process in the right group?" SELinux additionally enforces: "Does this process type have policy permission to perform this operation on this resource type?"
Operating Modes
| Mode | Behavior |
|---|---|
| Enforcing | Policy violations are denied and logged. Normal production mode. |
| Permissive | Violations are logged but not denied. Use for troubleshooting. |
| Disabled | SELinux completely off. Requires reboot to change. |
Switching to Disabled requires editing /etc/selinux/config and rebooting. Returning to Enforcing afterward may require a full filesystem relabel.
How to Check the Current Mode
getenforce gives you the quickest answer. sestatus provides the full picture.
$ getenforce Enforcing
$ sestatus SELinux status: enabled SELinuxfs mount: /sys/fs/selinux SELinux mount point: /sys/fs/selinux Loaded policy name: targeted Current mode: enforcing Mode from config file: enforcing Policy MLS status: enabled Policy deny_unknown status: allowed Memory protection checking: actual (secure) Max kernel policy version: 33
Check both Current mode (runtime) and Mode from config file (what survives a reboot).
Switching to Permissive Temporarily
setenforce changes the mode at runtime without a reboot. The change reverts on the next reboot.
$ sudo setenforce 0 # Switch to Permissive $ sudo setenforce 1 # Switch back to Enforcing
Troubleshooting rule of thumb: Run setenforce 0, then reproduce the problem. If it disappears, SELinux is the culprit. Switch back to Enforcing immediately after confirming.
How to Read AVC Denial Logs
When SELinux blocks an action, it records an AVC (Access Vector Cache) log entry. The primary log file is /var/log/audit/audit.log.
type=AVC msg=audit(1748780400.123:1234): avc: denied { read } for pid=1122 comm="httpd" name="app.conf" dev="sda1" ino=56789 scontext=system_u:system_r:httpd_t:s0 tcontext=unconfined_u:object_r:user_home_t:s0 tclass=file permissive=0
Key fields explained:
| Field | Meaning | In the example above |
|---|---|---|
denied { read } |
Denied operation | read access denied |
comm="httpd" |
Process name | Apache |
name="app.conf" |
Target file name | app.conf |
scontext=...httpd_t... |
Source context (process) | httpd_t type |
tcontext=...user_home_t... |
Target context (file) | user_home_t type |
tclass=file |
Resource class | regular file |
permissive=0 |
Enforcing mode active | actually denied |
The most common root cause is a type mismatch between scontext and tcontext. When httpd_t tries to access a file labeled user_home_t, SELinux blocks it. The file should be labeled httpd_sys_content_t.
Check a File's Context
$ ls -Z /var/www/html/app.conf unconfined_u:object_r:user_home_t:s0 /var/www/html/app.conf
This file carries the user_home_t label, which is why httpd_t cannot read it. The correct label for web content is httpd_sys_content_t.
Filtering Denial Logs with ausearch
Rather than grepping /var/log/audit/audit.log directly, use ausearch for efficient filtering.
# Recent AVC denials (last 10 minutes) $ sudo ausearch -m AVC -ts recent # All AVC denials since midnight today $ sudo ausearch -m AVC --start today # Filter by process name $ sudo ausearch -m AVC -ts recent -c httpd # Filter by file name $ sudo ausearch -m AVC --start today | grep "app.conf"
-ts recent covers the last 10 minutes. --start today covers since midnight.
Using audit2why to Understand Denials
audit2why translates AVC log entries into plain English explanations. Pipe ausearch output into it.
$ sudo ausearch -m AVC -ts recent | audit2why
type=AVC msg=audit(1748780400.123:1234): avc: denied { read } for pid=1122 comm="httpd" ...
Was caused by:
Missing type enforcement (TE) allow rule.
You can use audit2allow to generate a loadable module to allow this access.
"Missing type enforcement (TE) allow rule" means there is no policy rule granting this access.
audit2why explains the cause — it does not fix anything. Use audit2allow if you need to generate a policy module, but avoid doing so in production without fully understanding what you are allowing.
Common Fix Patterns
Restore File Context to Default
Files copied from another location often inherit the wrong context. restorecon applies the correct default context based on the file's path in the filesystem policy.
# Restore a single file $ sudo restorecon -v /var/www/html/app.conf Relabeled /var/www/html/app.conf from unconfined_u:object_r:user_home_t:s0 to system_u:object_r:httpd_sys_content_t:s0 # Restore a directory recursively $ sudo restorecon -Rv /var/www/html/
Set Context Manually with chcon
Use chcon to change a file's context temporarily. Note that restorecon or a full relabel will overwrite this change.
$ sudo chcon -t httpd_sys_content_t /var/www/html/app.conf
Adjust Policy with Booleans
SELinux policies include Booleans — named on/off switches for specific behaviors. For example, to allow Apache to serve files from user home directories:
# List current Booleans related to httpd $ getsebool -a | grep httpd # Enable a Boolean persistently (-P keeps it after reboot) $ sudo setsebool -P httpd_enable_homedirs on
Prefer fixing file contexts or adjusting Booleans over disabling SELinux entirely. Disabling removes a real security layer and is almost never the right answer.
Summary: Troubleshooting Checklist
getenforce— confirm the mode is Enforcingsetenforce 0, reproduce the issue — if it disappears, SELinux is the causesudo ausearch -m AVC -ts recent | audit2why— identify the denialls -Z— check the file's current contextrestorecon -vto restore the correct context, orsetseboolto adjust policysetenforce 1— switch back to Enforcing
Never disable SELinux as a workaround. Most issues are fixed by correcting file contexts with restorecon or enabling the right Boolean with setsebool.