SELinux (Security-Enhanced Linux) is a Linux Security Module that enforces mandatory access control in the kernel. In Linux security, it adds a second layer of authorization on top of the traditional user, group and permission bits: every process and every object carries a security label, and a central policy decides which labeled subjects may perform which operations on which labeled objects.
Because the policy is loaded into the kernel and cannot be overridden by file owners, SELinux confines processes even when they run as root. A compromised web server running under the label httpd_t can read only what the policy grants to that label, which is why SELinux is enabled by default on Fedora, RHEL and its rebuilds, and on Android in a related form.
How SELinux makes access decisions
Ordinary Linux permissions follow discretionary access control: the owner of a file decides who may use it. SELinux adds mandatory access control, in which the system policy decides and individual users cannot grant exceptions. The kernel first checks standard permissions, and only if they allow the operation does it consult SELinux, so SELinux can only restrict, never extend, what is permitted.
Each decision compares the source context of the process with the target context of the object and the requested permission class, such as file read or tcp_socket name_bind. Results are cached in the access vector cache, and denials are logged as AVC messages in the audit log.
| Field | Example | Purpose |
|---|---|---|
| User | system_u | SELinux identity, mapped from Linux users |
| Role | system_r | Limits which domains a user may enter |
| Type | httpd_t, httpd_sys_content_t | Main basis of type enforcement rules |
| Level | s0, s0:c1,c2 | Sensitivity and categories for MLS and MCS |
In practice, type enforcement carries almost all of the weight. A rule such as allow httpd_t httpd_sys_content_t:file { read open getattr }; lets processes of type httpd_t read files labeled httpd_sys_content_t, and anything not explicitly allowed is denied by default.
Modes, policies and booleans
SELinux runs in one of three modes, which can be checked with getenforce and set persistently in /etc/selinux/config.
| Mode | Behavior | When it is used |
|---|---|---|
| Enforcing | Denies and logs violations | Normal production operation |
| Permissive | Logs violations without denying | Troubleshooting and policy development |
| Disabled | No labeling and no checks | Not recommended; relabeling needed to re-enable |
Distributions ship the targeted policy by default, which confines selected network-facing and system services and leaves ordinary user sessions in the unconfined domain. The MLS policy implements multilevel security for government environments. Individual domains can also be made permissive with semanage permissive -a while the rest of the system stays enforcing.
Booleans switch optional parts of the policy without writing new rules. For example, setsebool -P httpd_can_network_connect_db on allows a web server to connect to a remote database, and getsebool -a lists all booleans with their current values.
File labeling and context management
Files store their context in the security.selinux extended attribute. The correct label for each path is defined by file context rules in the policy, and tools apply those rules when files are created, restored or relabeled. Most SELinux problems on servers are simply wrong file labels.
| Command | Purpose |
|---|---|
| ls -Z / ps -Z | Show contexts of files or processes |
| restorecon -Rv /path | Reset labels to the policy defaults |
| semanage fcontext -a | Add a persistent file context rule |
| semanage port -a | Allow a service on a nonstandard port |
| chcon | Change a label temporarily, lost on relabel |
| ausearch -m AVC | Find denial messages in the audit log |
| audit2why / audit2allow | Explain a denial or draft a policy module |
Files moved with mv keep their original label, while files copied with cp receive the label of the destination directory. This difference explains why content moved from a home directory into /var/www/html is often denied to the web server until restorecon is run.
SELinux compared with other Linux security mechanisms
SELinux is one of several kernel mechanisms that limit what a process may do, and they are designed to be combined rather than chosen exclusively.
| Mechanism | Basis of control | Granularity | Typical distributions |
|---|---|---|---|
| SELinux | Labels on all objects | Very fine, system-wide | Fedora, RHEL, Android |
| AppArmor | File path profiles per program | Fine, per application | Ubuntu, Debian, SUSE |
| Seccomp | Allowed system calls | Per process filter | Containers, browsers, systemd units |
| Linux capabilities | Split root privileges | About 40 distinct privileges | All distributions |
| PAM | Authentication modules | Login and session setup | All distributions |
The main practical difference from AppArmor is that SELinux labels follow the object rather than the path. A file keeps its type wherever it is linked, which is stronger against path tricks but requires correct labeling discipline.
Troubleshooting and common mistakes
A denial is not a bug in SELinux; it is a signal that the label, port or boolean does not match what the service is doing. The disciplined workflow is to read the AVC message, identify the mismatch and correct it with the narrowest possible change.
- Disabling SELinux to fix one service removes protection from every service; use a permissive domain instead.
- Running
audit2allow -Mblindly can grant far broader access than needed; review every generated rule. - Use
semanage fcontextplusrestoreconrather thanchcon, because chcon changes are lost on relabel. - Some denials are hidden by dontaudit rules;
semodule -DBtemporarily disables them for diagnosis. - Container hosts rely on MCS categories to isolate containers; volume mounts may need the
:Zor:zoption.
Explained without jargon
SELinux works like name badges in a secure building. Every program and every file wears a badge, and a rulebook says which badges may open which doors. It does not matter how senior a person is; without the right badge, the door stays shut.
This means that even if an attacker takes over a program, the attacker inherits only that program’s badge. The key benefit is damage containment: a broken-in web server cannot wander into password files or other services.
A typical use case
A team deploys a web application on RHEL and configures the web server to listen on port 8443 and to serve files from /srv/app/public. The service fails to start, and the audit log shows AVC denials for name_bind and file read. Instead of disabling SELinux, the administrator reads the messages with ausearch -m AVC -ts recent.
Two precise changes fix the problem: semanage port -a -t http_port_t -p tcp 8443 allows the port, and semanage fcontext -a -t httpd_sys_content_t "/srv/app/public(/.*)?" followed by restorecon -Rv /srv/app/public labels the content. The application runs in enforcing mode, and months later, when a plugin vulnerability lets an attacker execute code, the exploited process cannot read files outside its labels.