Skip to main content
  1. Index/

SELinux (Security-Enhanced Linux)

SELinux (Security-Enhanced Linux) is a Mandatory Access Control (MAC) implementation developed by the NSA and released as open source in 2000, merged into the mainline Linux kernel in 2.6 via the LSM framework in 2003. Its defining characteristic is default deny: unlike the standard Linux Discretionary Access Control model (file permission bits), where anything not explicitly forbidden is permitted, SELinux refuses all access that is not explicitly allowed by policy. Every process and every object — every file, socket, pipe, device node, and IPC object — carries a security context (also called a label) of the form user:role:type:level. The policy is a compiled set of rules, loaded at boot, that defines precisely which combinations of process context and object context may interact and how. An Apache web server process running in the httpd_t domain can read files labelled httpd_sys_content_t but is denied access to files labelled user_home_t or shadow_t, regardless of what Unix file permission bits say. If the web server is compromised, the attacker is confined to what httpd_t permits — typically a narrow, well-defined set of files and network operations — rather than having the full access of the user account running Apache.

The dominant SELinux policy component is Type Enforcement (TE), where the type field in the security context is the primary axis of access control. Each process type (called a domain) has a defined set of access rules for each object type — what it can read, write, execute, connect to, or signal. On top of TE, SELinux supports Role-Based Access Control (RBAC), where a user’s role constrains which domains they can transition into (preventing a developer account from transitioning into an administrator domain), and Multi-Level Security (MLS) and Multi-Category Security (MCS), which implement Bell-LaPadula confidentiality classifications (secret processes cannot read top-secret data) and are used in government deployments and container isolation (MCS categories separate containers from each other using unique s0:c1,c2-style labels). In practice, most RHEL/Fedora deployments use the targeted policy: a pragmatic subset that applies type enforcement to high-risk daemons (network-facing services, CUPS, DBus, the container runtime) while leaving most user processes in the unconfined_t domain, which has essentially no MAC restrictions. Three operating modes are supported: Enforcing (violations are blocked and logged as AVC denials), Permissive (violations are logged but not blocked, used during policy development and debugging), and Disabled (no SELinux policy loaded at all, requiring a filesystem relabel to re-enable). Switching from Disabled to Permissive requires booting with autorelabel, since files created while SELinux was off carry no context and must be labelled according to the policy’s file context database before MAC can be correctly applied.

SELinux is the default MAC system on RHEL, CentOS Stream, Fedora, and their derivatives, and is mandatory for OpenShift nodes — SCCs on OpenShift build directly on SELinux contexts, with the SCC admission plugin setting MCS labels on pod processes to ensure containers cannot access each other’s files even if they run as the same UID. Container runtimes (containerd, CRI-O, Podman) automatically assign unique MCS category pairs to each container, and the OCI runtime spec’s linux.selinuxOptions field allows administrators to override the label for specific containers. The most common operational pain point with SELinux is mislabelled files: any file created by a process outside the context SELinux expects (a configuration file dropped by a custom install script, a bind mount from an unexpected path) may carry the wrong type and trigger AVC denials that appear as mysterious permission failures with correct Unix permissions. The tooling chain for diagnosis is ausearch -m AVC, audit2why, and audit2allow; the correct long-term fix is a file context rule (semanage fcontext), not disabling enforcement. SELinux is one of the few Linux security controls that is simultaneously mandatory in high-assurance government deployments (Common Criteria EAL4+ certified in targeted policy form) and widely deployed in commodity cloud infrastructure.

Related

AppArmor (Application Armor)

AppArmor (Application Armor) is a Mandatory Access Control (MAC) system implemented as a major LSM (Linux Security Module), developed originally by Immunix and now maintained by Canonical. It is the default MAC system on Ubuntu, Debian, and their derivatives, and the default container confinement mechanism for containerd and Docker on those distributions. Where SELinux assigns security labels to every object on the system and enforces policy based on label interactions, AppArmor takes a fundamentally different approach: it confines programs by filesystem path. A profile for nginx lists the specific file paths that nginx is allowed to read, write, and execute, the network operations it may perform, and the Linux capabilities it may use — anything not listed is denied. No relabelling of the filesystem is required and no extended attributes are set: AppArmor’s confinement decisions are made purely from the path of the file being accessed and the identity of the confined process. This path-based model makes AppArmor profiles far simpler to read, write, and audit than SELinux policy, and eliminates the mislabelled-file failure mode that is the most common SELinux operational problem.

LSM (Linux Security Module)

Linux Security Modules (LSM) is a hook-based framework integrated into the Linux kernel since 2.6 (2003) that provides a general mechanism for implementing Mandatory Access Control (MAC) without modifying the core kernel. Its origin is the NSA’s presentation of SELinux at the 2001 Linux Kernel Summit: Linus Torvalds accepted the need for flexible access control but refused to hardcode a single security model, directing instead the development of a framework into which any security model could be plugged. The result is LSM: a set of strategically placed hook functions throughout the kernel’s execution paths — over 240 hooks in recent kernels — at points where security-relevant decisions occur: file open, process creation, capability checks, socket operations, IPC access, memory mapping, and more. Each hook is a call into the currently active security module(s), which examine the operation’s context and return allow or deny. The core kernel enforces whatever the security module decides.

Syscall (System Call)

A system call (syscall) is the formal interface through which a user-space process asks the kernel to perform a privileged operation on its behalf — opening a file, allocating memory, creating a process, establishing a network connection, sending a signal, or any other action that requires kernel mediation. User-space code runs at CPU privilege level 3 (ring 3) and cannot directly access hardware, manipulate kernel data structures, or perform I/O; the kernel runs at ring 0 with unrestricted access. A syscall is the crossing point: the process places its request in a defined register convention and issues a syscall instruction (on x86-64) that atomically switches the CPU to ring 0 and transfers control to the kernel’s syscall dispatch table. The kernel validates the request, performs the operation if permitted by standard Unix permissions and any active LSM hooks, and returns the result. From a security perspective, the syscall boundary is the complete list of what a process can ask the kernel to do — and therefore the complete list of operations that security controls like seccomp and BPF LSM can police.