SELinux

SELinux implements mandatory access control in the Linux kernel. Standard Unix permissions are discretionary: a file’s owner decides who may read it, and a process runs with the full authority of the user who started it. SELinux adds a layer above that, where policy decides what a process may do regardless of what the user’s permissions would allow.

The premise is worth stating because it explains everything else. Assume a process will be compromised. A web server exploited through an application bug inherits its user’s authority, which under discretionary permissions is generally far more than the server needs. SELinux constrains the process to what a web server should legitimately do — read its content directories, bind its ports, and nothing more — so the compromise is contained rather than converted into user-level access.

How it works

Every process, file, socket, and port carries a label, and the policy is a set of rules about which labels may interact. The label on a file is stored in extended attributes and is independent of its path, which produces the most common operational surprise: moving a file preserves its label, copying it inherits the destination’s. A configuration file moved into place from elsewhere keeps a label that policy does not permit the service to read, and the service fails with a permission error that ordinary ls -l shows nothing wrong with.

restorecon resets labels to policy defaults and is the first thing to try when a service cannot read a file whose permissions look correct.

The reputation, and how much of it is deserved

SELinux is widely disabled, and the reason is that its failure mode is opaque. A denial surfaces as a generic permission error while the filesystem permissions plainly allow the access, so the error message points away from the actual cause.

The tooling has improved considerably. ausearch and audit2why explain denials in readable terms; permissive mode logs what would have been denied without denying it, which makes it possible to develop policy against a working system rather than a broken one.

The comparison with AppArmor is the practical question. AppArmor confines by path rather than by label, which is much easier to reason about and correspondingly easier to circumvent through hard links and bind mounts. SELinux is stronger and steeper. My honest position is that SELinux is worth the effort on systems with a defined role and a stable service set, and AppArmor is a better fit where the workload changes often — and either is worth vastly more than the very common third option of turning it off.

See also: AppArmor, auditd for the audit trail, host hardening patterns, and Linux administration in datacenters.