SELinux: enforcing, permissive, and contexts
Why a correctly-permissioned file can still be denied access under SELinux. · 11 min
SELinux (Security-Enhanced Linux), standard on RHEL-family distributions, enforces Mandatory Access Control: every process and every file has a security context (a label describing what type of thing it is, in SELinux's policy terms) and SELinux's policy defines which context types are allowed to interact with which other context types — completely independent of standard Unix file permissions. This is exactly why a web server process can have full standard read permission on a file and still be denied access: standard permissions said yes, but SELinux policy said this process's context isn't allowed to touch that file's context.
SELinux operates in one of three modes: `Enforcing` actively blocks disallowed actions and logs them. `Permissive` logs what would have been blocked without actually blocking anything — genuinely useful for testing a new policy or diagnosing an application before committing to enforcement. `Disabled` turns SELinux off entirely. The common, understandable, but wrong instinct when hitting a confusing SELinux denial is to disable it outright — this removes a real security layer permanently instead of fixing the specific, narrow context mismatch that caused the one denial.
The correct troubleshooting path: `ausearch -m avc -ts recent` or checking `/var/log/audit/audit.log` shows recent denials. `ls -Z` shows a file's current context. `restorecon` resets a file's context back to the policy-defined default for its location — the single most common actual fix, for the common case of a file being moved or created somewhere its context doesn't match. `semanage` adjusts persistent policy (like permanently allowing a non-standard port for a service). `getsebool`/`setsebool` toggle specific policy booleans — pre-defined, documented policy switches for common scenarios, safer than writing custom policy from scratch.
| Command | Purpose | Example |
|---|---|---|
| getenforce | Show current SELinux mode (Enforcing/Permissive/Disabled) | — |
| sestatus | Show detailed SELinux status | — |
| setenforce 0 | Temporarily switch to Permissive mode (not persistent across reboot) | — |
| ls -Z | Show SELinux context for files | — |
| restorecon -Rv path | Reset a file/directory's context to its policy-defined default | — |
| ausearch -m avc -ts recent | Search the audit log for recent SELinux denials | — |
| getsebool -a | List all SELinux policy booleans and their current state | — |
| setsebool -P name on | Persistently enable a specific policy boolean | — |
Common Mistakes
- ⚠ Running `setenforce 0` (or fully disabling SELinux) as the fix for a denial instead of diagnosing the specific context mismatch
- ⚠ Moving or copying a file into a service directory with `cp` from an unexpected location, silently carrying the wrong SELinux context with it — `restorecon` after such moves is a genuinely common, easy-to-forget step
Hands-On Lab
Diagnose and fix an SELinux denial without disabling it
Objectives
- ✓ Reproduce a realistic SELinux denial
- ✓ Diagnose it using ausearch, not guesswork
- ✓ Fix it with restorecon instead of disabling SELinux
Instructions
- With Apache installed and running, create a test HTML file in your home directory, then copy it to `/var/www/html/test.html` with `cp`.
- Attempt to load it in a browser or via `curl localhost/test.html` from the server — expect a 403 Forbidden, even though standard file permissions look correct.
- Run `ausearch -m avc -ts recent` and confirm you see a denial referencing httpd and the file's context.
- Compare the file's context (`ls -Z /var/www/html/test.html`) against a known-working file in the same directory's context.
- Run `sudo restorecon -v /var/www/html/test.html` and re-test — the file should now load correctly.
Hints (1)
- The root cause here is that files copied from a user's home directory carry the home directory's SELinux context, not the web content context `/var/www/html` expects — restorecon is exactly the fix for this specific, very common scenario.
Quick Check
A file has correct standard Unix permissions (readable by the web server's user), but Apache still gets a 403 error on RHEL. What is the most likely cause?
Takeaway: A correctly-permissioned file that still gets "permission denied" on a RHEL-family system is the classic signature of an SELinux context mismatch — check `ausearch` and try `restorecon` before ever considering disabling SELinux.