In the landscape of Linux security, Discretionary Access Control (DAC) has long been the default mechanism, relying on user IDs (UIDs) and group IDs (GIDs) to regulate access. However, DAC has limitations: it trusts users to manage their own permissions, leaving systems vulnerable to insider threats or compromised processes. Enter SELinux (Security-Enhanced Linux), a Mandatory Access Control (MAC) framework that enforces fine-grained access policies based on predefined rules, regardless of user intent. SELinux, developed by the National Security Agency (NSA) and later integrated into the Linux kernel, adds a critical layer of security by mediating access between subjects (processes) and objects (files, sockets, etc.) through a flexible policy system. This blog aims to demystify SELinux, from core concepts to practical usage, empowering you to leverage its power to harden your Linux systems.
Table of Contents
- Introduction
- Understanding SELinux Fundamentals
- SELinux Modes and Policies
- Core SELinux Components
- Working with SELinux: Commands and Tools
- Common SELinux Scenarios and Troubleshooting
- Best Practices for SELinux Implementation
- Conclusion
- References
Understanding SELinux Fundamentals
DAC vs. MAC: Why SELinux Matters
Linux traditionally uses Discretionary Access Control (DAC), where file owners and root control permissions (e.g., chmod, chown). DAC has a critical flaw: if a user or process is compromised, an attacker can access all resources that user/process is allowed to access.
Mandatory Access Control (MAC), implemented by SELinux, adds a second layer of security. Access is determined by a central policy, not just user intent. Even if a process is compromised, SELinux restricts it to predefined actions, limiting damage.
SELinux Architecture Overview
SELinux operates via the Linux Security Modules (LSM) framework, a kernel interface for security extensions. At its core, SELinux mediates all interactions between subjects (processes) and objects (files, sockets, etc.) using a predefined policy.
Key Concepts: Subjects, Objects, and Security Contexts
- Subjects: Processes (e.g.,
httpd,sshd) that request access to resources. - Objects: Resources (e.g., files, network ports, shared memory) that subjects interact with.
- Security Contexts: Labels assigned to subjects and objects, defining their SELinux identity.
Security Context Format
A security context has four components: user:role:type:level (level is optional for most policies):
user: SELinux user (e.g.,unconfined_ufor regular users,system_ufor system processes).role: Defines privileges (e.g.,unconfined_rfor unconfined roles,httpd_rfor Apache).type: Critical for access control (e.g.,httpd_tfor Apache processes,httpd_sys_content_tfor Apache-readable files).level: Used in Multi-Level Security (MLS) policies (e.g.,s0:c0.c1023for sensitivity/category levels).
Example: A web server process might have the context system_u:system_r:httpd_t:s0, and its log files system_u:object_r:httpd_log_t:s0.
SELinux Modes and Policies
SELinux Modes: Enforcing, Permissive, and Disabled
SELinux operates in three modes, configurable at runtime or boot:
| Mode | Behavior | Use Case |
|---|---|---|
| Enforcing | Denies access violating policy and logs denials. | Production environments (default). |
| Permissive | Logs denials but does not block access (policy is not enforced). | Troubleshooting or policy testing. |
| Disabled | SELinux is inactive; no policy is loaded or enforced. | Not recommended (loses security benefits). |
To persistently set the mode, edit /etc/selinux/config (set SELINUX=enforcing|permissive|disabled and reboot).
SELinux Policies: Targeted, Strict, and MLS
SELinux policies define rules for allow/deny decisions. Common policies include:
- Targeted (Default): Focuses on confining network-facing daemons (e.g.,
httpd,sshd). Most user processes run inunconfined_t(not restricted by SELinux). - Strict: Confines all processes, including user processes. Rarely used today.
- Multi-Level Security (MLS): Enforces confidentiality based on security levels (e.g., “Top Secret” vs. “Public”). Used in high-security environments.
Core SELinux Components
Security Server
The kernel-based Security Server acts as the “gatekeeper,” checking every subject-object interaction against the SELinux policy. It grants or denies access based on policy rules.
Policy Database
A compiled set of rules stored in /etc/selinux/<policy>/policy/policy.<version>. The policy defines:
- Which subjects can access which objects.
- Actions allowed (e.g., read, write, execute, bind to a port).
Access Vector Cache (AVC)
To avoid rechecking identical access requests, SELinux caches decisions in the Access Vector Cache (AVC). This improves performance by reducing redundant policy lookups.
Working with SELinux: Commands and Tools
Checking SELinux Status
Use sestatus to verify SELinux state, policy, and mode:
sestatus
# Sample Output:
SELinux status: enabled
SELinuxfs mount: /sys/fs/selinux
SELinux root directory: /etc/selinux
Loaded policy name: targeted
Current mode: enforcing
Mode from config file: enforcing
Policy MLS status: enabled
Policy deny_unknown status: allowed
Memory protection checking: actual (secure)
Max kernel policy version: 33
Modifying SELinux Modes
Temporarily switch modes with setenforce (persist with /etc/selinux/config):
# Check current mode
getenforce # Output: Enforcing
# Switch to permissive mode (log denials, don't block)
setenforce 0 # or setenforce Permissive
# Switch back to enforcing
setenforce 1 # or setenforce Enforcing
Managing File Contexts
Files and directories inherit security contexts from their parent directory. If contexts are misconfigured (e.g., after moving files with mv instead of cp), use restorecon to reset them:
# Restore context for a file (verbose mode)
restorecon -v /var/www/html/customfile.html
# Restore context for a directory recursively
restorecon -Rv /var/www/html/customdir/
To view a file’s context, use ls -Z:
ls -Z /var/www/html/
# Output: -rw-r--r--. root root system_u:object_r:httpd_sys_content_t:s0 index.html
Configuring Network Ports
SELinux restricts which processes can bind to specific ports. Use semanage port to add/modify port contexts:
Example: Allow Apache to bind to port 8080 (default Apache ports are 80/tcp and 443/tcp):
# Add port 8080 to http_port_t (Apache's allowed port type)
semanage port -a -t http_port_t -p tcp 8080
# Verify the port was added
semanage port -l | grep http_port_t
# Output: http_port_t tcp 80, 8080, 443, 488, 8008, 8009, 8443, 9000
Analyzing and Allowing Access (audit2allow)
When SELinux blocks access, it logs denials to /var/log/audit/audit.log (or /var/log/messages if auditd is disabled). Use audit2allow to parse logs and generate policy rules.
Example Workflow:
-
Identify the denial in audit logs:
tail -f /var/log/audit/audit.log | grep AVC # Sample AVC Denial: type=AVC msg=audit(1620000000.123:456): avc: denied { read } for pid=1234 comm="httpd" name="data.txt" dev="sda1" ino=789 scontext=system_u:system_r:httpd_t:s0 tcontext=unconfined_u:object_r:user_home_t:s0 tclass=file permissive=0 -
Generate a policy rule with
audit2allow:# Analyze all denials and suggest a rule audit2allow -a # Output: #============= httpd_t ============== allow httpd_t user_home_t:file read; -
Create and load a custom policy module:
# Generate a module (saves as myhttpd.pp) audit2allow -a -M myhttpd # Load the module semodule -i myhttpd.pp # Verify the module is loaded semodule -l | grep myhttpd
Common SELinux Scenarios and Troubleshooting
Scenario 1: Apache Can’t Access a Custom Directory
Problem: Apache (httpd) fails to serve files from /data/web despite correct DAC permissions (chmod 755 /data/web).
Troubleshooting:
-
Check the directory’s SELinux context:
ls -Z /data/ # Output: drwxr-xr-x. root root unconfined_u:object_r:default_t:s0 web/default_tis not allowed for Apache. Apache expectshttpd_sys_content_t. -
Fix the context with
semanage fcontext(persistent) andrestorecon:# Define a persistent context for /data/web and subdirectories semanage fcontext -a -t httpd_sys_content_t "/data/web(/.*)?" # Apply the context restorecon -Rv /data/web/
Scenario 2: SSH Fails After File System Relocation
Problem: SSH (sshd) fails to start after moving /home to a new partition.
Troubleshooting:
-
Check
sshdlogs (/var/log/audit/audit.log):grep sshd /var/log/audit/audit.log | grep AVC # Denial: avc: denied { read } for pid=5678 comm="sshd" name="passwd" dev="sdb1" ... tcontext=system_u:object_r:default_t:s0 -
The new
/homepartition may have an incorrect context. Fix with:# Restore default contexts for the root filesystem (includes /home) restorecon -Rv /
Best Practices for SELinux Implementation
- Keep SELinux Enabled: Disabling SELinux removes a critical security layer. Troubleshoot denials instead.
- Use Permissive Mode for Testing: When deploying new services, run SELinux in permissive mode first to identify policy gaps.
- Leverage Built-in Policies: Use the default
targetedpolicy unless you needMLSorstrict. - Avoid Manual Context Changes: Use
semanage fcontext(persistent) andrestoreconinstead ofchcon(temporary). - Monitor Audit Logs: Regularly check
/var/log/audit/audit.logfor AVC denials to proactively resolve issues. - Use SELinux Booleans for Flexibility: Booleans (e.g.,
httpd_can_network_connect) toggle policy rules without recompiling. List booleans withgetsebool -aand modify withsetsebool -P(persistent):# Allow Apache to connect to the network setsebool -P httpd_can_network_connect on
Conclusion
SELinux is a powerful MAC framework that significantly enhances Linux security by enforcing granular access controls beyond traditional DAC. While it adds complexity, mastering SELinux—including security contexts, policy management, and troubleshooting tools like audit2allow and restorecon—is critical for securing modern Linux systems. By following best practices (e.g., keeping SELinux enabled, using permissive mode for testing), you can leverage SELinux to mitigate breaches and protect critical resources.
References
- SELinux Project Wiki
- Red Hat Enterprise Linux SELinux Guide
- CentOS SELinux Documentation
manpages:sestatus(8),semanage(8),restorecon(8),audit2allow(1)