SELinux
SELinux (Security-Enhanced Linux) is the default MAC system on RHEL, Fedora, and CentOS. It labels every file, process, and network port with a security context, then enforces rules about which labels can interact with which. Even if an attacker exploits a web server running as root, SELinux confines it to what httpd is allowed to do.
Security Contexts and Labels
What is a SELinux label?
Every object (file, process, socket) gets a security context: a 4-part label. Format: user:role:type:level. The type is the most important part for policy — rules say "processes of type X can perform operation Y on objects of type Z." Labels are stored as extended attributes on files (xattr) and assigned to processes at exec time.
# See process labels:
ps -Z
# LABEL PID COMMAND
# system_u:system_r:httpd_t:s0 1234 httpd
# system_u:system_r:sshd_t:s0 5678 sshd
# unconfined_u:unconfined_r:unconfined_t:s0 9012 bash
# See file labels:
ls -Z /var/www/html/
# system_u:object_r:httpd_sys_content_t:s0 index.html
# system_u:object_r:httpd_sys_content_t:s0 style.css
ls -Z /etc/passwd
# system_u:object_r:passwd_file_t:s0 /etc/passwd
# Get context of a specific file:
stat -c "%C" /etc/httpd/conf/httpd.conf
# system_u:object_r:httpd_config_t:s0
Reading AVC Denial Messages
# AVC = Access Vector Cache — where SELinux logs denials
# View denials in audit log:
ausearch -m AVC -ts recent
# Example denial:
# type=AVC msg=audit(1234567890.123:456): avc: denied { read }
# for pid=1234 comm="httpd" name="secret.txt"
# dev="sda1" ino=5678
# scontext=system_u:system_r:httpd_t:s0
# tcontext=system_u:object_r:admin_home_t:s0
# tclass=file permissive=0
# Decoded:
# process: httpd (httpd_t)
# tried to: read
# the file: secret.txt
# which has type: admin_home_t
# result: DENIED (httpd_t cannot read admin_home_t files)
# Human-readable:
sealert -a /var/log/audit/audit.log
Fixing SELinux Denials
# Option 1: Fix the file label (usually correct approach)
# Wrong label on a web file:
ls -Z /var/www/html/myfile.txt
# unconfined_u:object_r:user_home_t:s0 myfile.txt ← wrong!
# Fix the label:
restorecon -v /var/www/html/myfile.txt
# Relabeled: user_home_t -> httpd_sys_content_t
# Recursively fix a directory:
restorecon -Rv /var/www/html/
# Change file type permanently:
chcon -t httpd_sys_content_t /var/www/html/myfile.txt
# Option 2: Enable a boolean (predefined policy switch)
getsebool -a | grep httpd
# httpd_can_network_connect --> off
# httpd_can_sendmail --> off
# httpd_enable_cgi --> on
# Allow httpd to connect to network (e.g., proxy to backend):
setsebool -P httpd_can_network_connect 1
# -P = persistent across reboots
# Option 3: Write a custom policy module
audit2allow -M mypolicy < /var/log/audit/audit.log
semodule -i mypolicy.pp
SELinux Modes
# Three modes:
getenforce
# Enforcing = policy enforced, denials logged
# Permissive = not enforced but denials logged (testing mode)
# Disabled = completely off (requires reboot to change)
# Switch to permissive (for debugging — useful to see what WOULD be denied):
setenforce 0 # temporary
getenforce
# Permissive
setenforce 1 # back to enforcing
# Permanent mode (/etc/selinux/config):
# SELINUX=enforcing
# SELINUXTYPE=targeted (targeted = only specific processes confined)
# Per-process permissive mode (leave rest enforcing):
semanage permissive -a httpd_t # make just httpd_t permissive
semanage permissive -l # list permissive domains