Home/Linux Administration/SELinux & AppArmor
🛡️

Level 11 of 24

SELinux & AppArmor

Mandatory access control on RHEL and Ubuntu, and why "just disable it" is the wrong fix.

Standard file permissions answer "who can access this file". Mandatory Access Control (MAC) systems like SELinux and AppArmor answer a stricter question: "even if the permissions allow it, should this specific process be allowed to do this specific thing at all?" This level explains why "just disable it" is almost always the wrong fix.

Prerequisites

  • • Level 4: Users & Permissions
  • • Level 6: Package Management

By the end of this level, you can

  • ✓ Explain what SELinux and AppArmor add on top of standard permissions
  • ✓ Check SELinux status and diagnose a denial without disabling it
  • ✓ Compare SELinux and AppArmor's approach at a conceptual level

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.

CommandPurposeExample
getenforceShow current SELinux mode (Enforcing/Permissive/Disabled)—
sestatusShow detailed SELinux status—
setenforce 0Temporarily switch to Permissive mode (not persistent across reboot)—
ls -ZShow SELinux context for files—
restorecon -Rv pathReset a file/directory's context to its policy-defined default—
ausearch -m avc -ts recentSearch the audit log for recent SELinux denials—
getsebool -aList all SELinux policy booleans and their current state—
setsebool -P name onPersistently 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

  1. 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`.
  2. 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.
  3. Run `ausearch -m avc -ts recent` and confirm you see a denial referencing httpd and the file's context.
  4. Compare the file's context (`ls -Z /var/www/html/test.html`) against a known-working file in the same directory's context.
  5. 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.

AppArmor, and how it compares to SELinux

Ubuntu's path-based alternative to SELinux's label-based model. · 7 min

AppArmor, standard on Ubuntu and Debian, achieves a similar goal to SELinux — confining what a process is allowed to do beyond standard permissions — through a different mechanism: path-based profiles rather than SELinux's label/context-based policy. An AppArmor profile for a given program explicitly lists which file paths it can read, write, or execute, and what capabilities it has, rather than relying on abstract security-context labels applied to every file system-wide.

Like SELinux, AppArmor profiles can run in `enforce` mode (actively blocking and logging violations) or `complain` mode (logging only, useful for building or testing a new profile without breaking the application while you refine it). `aa-status` shows which profiles are loaded and in which mode; violations show up in the system log (`journalctl` or `/var/log/syslog`), and `aa-logprof` can help interactively build a profile from observed complain-mode log entries.

The practical comparison: SELinux's label-based model is more granular and consistent system-wide but has a steeper learning curve and denials can feel less intuitive to trace back to a cause. AppArmor's path-based model is generally easier to read and reason about directly (a profile literally lists the paths it governs) but is inherently tied to specific file paths, which can be less robust if a file legitimately needs to move. Neither is "more secure" in the abstract — they represent different design tradeoffs, and which one you're working with is determined entirely by which distribution family you're on, not a choice you typically make yourself on a given server.

CommandPurposeExample
aa-statusShow loaded AppArmor profiles and their mode (enforce/complain)—
sudo aa-enforce /path/to/profileSet a specific profile to enforce mode—
sudo aa-complain /path/to/profileSet a specific profile to complain (log-only) mode—
  • • SELinux (RHEL family) — label/context-based, more granular, steeper learning curve
  • • AppArmor (Ubuntu/Debian) — path-based, more directly readable profiles, tied to specific file paths
  • • Both support enforce and complain/permissive modes for safe testing before full enforcement
  • • Neither should be disabled outright as a routine fix for a denial

Takeaway: SELinux and AppArmor solve the same problem with genuinely different mechanisms — which one you troubleshoot is decided entirely by the distribution family, not a preference you exercise per server.

Sponsor / Advertisement