🔒 SELinux Basics

SELinux Series: Part 1 — Basics  |  Part 2 — Contexts  |  Part 3 — Booleans  |  Part 4 — Troubleshooting

What is SELinux?

Security-Enhanced Linux (SELinux) is a mandatory access control (MAC) framework built into the Linux kernel. Developed by the NSA and integrated into RHEL, CentOS, Fedora, and many other distributions, it enforces security policies that go far beyond traditional Unix permissions.

Where standard Unix permissions ask "Who owns this file and what group is it in?", SELinux asks "Is this process type allowed to access this file type, in this way, under this policy?" Even root can be denied access by SELinux policy.

SELinux Modes

🔴 Enforcing

Policy is active and enforced. Violations are blocked and logged. This is the correct production setting.

🟡 Permissive

Policy is active but NOT enforced. Violations are logged only — nothing is blocked. Used for troubleshooting and policy development.

⚫ Disabled

SELinux is completely off. No logging, no enforcement. Requires reboot to re-enable. Avoid in production.

⚠️ Never disable SELinux in production. The correct response to an SELinux denial is to fix the policy or context — not to disable SELinux. Disabling it is a security regression and on RHEL/CentOS it also requires a full filesystem relabel on re-enable, which can take a long time on large systems.

Examples

1
Check Current SELinux Status — getenforce and sestatus

The first commands to know — find out what mode SELinux is running in:

# Quick one-word answer: Enforcing, Permissive, or Disabled
getenforce

# Full status report
sestatus

# Verbose sestatus
sestatus -v

# Check from a script — exit code 0 = enforcing
if [ "$(getenforce)" = "Enforcing" ]; then
    echo "SELinux is enforcing"
fi
getenforce output:
Enforcing
sestatus output:
SELinux status: enabled SELinuxfs mount: /sys/fs/selinux SELinux mount point: /sys/fs/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
💡 Two modes to note: sestatus shows both the current mode (runtime) and the mode from config file (persistent). If they differ, a setenforce was used to temporarily change the runtime mode without editing the config file.
2
Temporarily Change Mode — setenforce

setenforce changes the runtime mode — takes effect immediately, does NOT survive reboot:

# Switch to Permissive (for troubleshooting — does NOT disable SELinux)
sudo setenforce 0
sudo setenforce Permissive   # same thing

# Switch back to Enforcing
sudo setenforce 1
sudo setenforce Enforcing    # same thing

# Verify
getenforce
Permissive vs Disabled: setenforce 0 sets Permissive mode — SELinux is still active, still labeling files, still logging denials, just not blocking anything. This is the safe way to temporarily relax SELinux for troubleshooting. You cannot use setenforce to disable SELinux — that requires editing the config file and rebooting.
💡 Troubleshooting pattern: If something breaks and you suspect SELinux, set Permissive with setenforce 0 and test. If it works in Permissive, SELinux policy is the cause. Check /var/log/audit/audit.log for the AVC denials, then fix the context or boolean rather than leaving it in Permissive.
3
Persistent Mode — /etc/selinux/config

To make a mode change survive reboots, edit the SELinux config file:

# View current persistent config
cat /etc/selinux/config
Output:
# This file controls the state of SELinux on the system. # SELINUX= can take one of these three values: # enforcing - SELinux security policy is enforced. # permissive - SELinux prints warnings instead of enforcing. # disabled - No SELinux policy is loaded. SELINUX=enforcing # SELINUXTYPE= can take one of these three values: # targeted - Targeted processes are protected, # minimum - Modification of targeted policy. # mls - Multi Level Security protection. SELINUXTYPE=targeted
# Change mode persistently with sed (no editor needed)
sudo sed -i 's/^SELINUX=.*/SELINUX=permissive/' /etc/selinux/config

# Or use the dedicated tool (RHEL 8+ / Fedora)
sudo semanage --help   # semanage handles many SELinux settings

# Verify the change
grep ^SELINUX= /etc/selinux/config
⚠️ Disabled → Enforcing requires relabel: If you change from SELINUX=disabled back to enforcing or permissive, the filesystem must be relabeled on next boot. Create the trigger file before rebooting:
sudo touch /.autorelabel
The relabel runs automatically on next boot and may take several minutes on large filesystems.
4
SELinux Policies — targeted vs mls

The SELINUXTYPE setting in the config file selects the policy:

# Check current policy type
sestatus | grep "Loaded policy"

# List installed policies
ls /etc/selinux/
Output:
Loaded policy name: targeted /etc/selinux/ config targeted/
PolicyDescriptionUse Case
targeted Only specific "targeted" daemons are confined by SELinux policy. Most processes run unconfined. Default on RHEL/CentOS. Best for most production servers.
mls Multi-Level Security — full Bell-LaPadula model with sensitivity labels. Every process and file has a sensitivity level. High-security environments — government, classified systems. Very complex to manage.
minimum Minimal subset of targeted policy. Only the most critical processes are confined. Resource-constrained systems. Rarely used in practice.
💡 Almost always use targeted. Unless you have a specific regulatory or security requirement for MLS, targeted is the right choice. It protects the daemons most likely to be attacked (httpd, sshd, named, etc.) without confining every process on the system.
5
Check What SELinux Is Doing — AVC Denials

When SELinux blocks something, it logs an AVC (Access Vector Cache) denial. Knowing where to look is fundamental:

# View recent AVC denials in the audit log
sudo ausearch -m avc -ts recent

# View all denials since last boot
sudo ausearch -m avc -ts boot

# Using journalctl
sudo journalctl -t setroubleshoot

# Quick scan of audit log
sudo grep "denied" /var/log/audit/audit.log | tail -20

# sealert gives human-readable explanations (setroubleshoot-server pkg)
sudo sealert -a /var/log/audit/audit.log
Typical AVC denial in audit.log:
type=AVC msg=audit(1712345678.123:456): avc: denied { read } for pid=1234 comm="httpd" name="myapp.conf" dev="sda1" ino=987654 scontext=system_u:system_r:httpd_t:s0 tcontext=system_u:object_r:admin_home_t:s0 tclass=file permissive=0
Reading the denial: The key fields are: httpd_t is not allowed to read files labeled admin_home_t — fix by relabeling the file to httpd_sys_content_t.
6
Per-Process Permissive Mode

Rather than setting the entire system to Permissive, you can set a single SELinux domain to Permissive while keeping everything else Enforcing:

# Set a single domain permissive (httpd_t in this example)
sudo semanage permissive -a httpd_t

# List all permissive domains
sudo semanage permissive -l

# Remove permissive from a domain (back to enforcing)
sudo semanage permissive -d httpd_t
semanage permissive -l output:
Builtin Permissive Types Customized Permissive Types httpd_t
💡 Surgical approach: Per-domain permissive mode is far better than system-wide permissive when troubleshooting a specific service. Everything else stays enforced while you work out the policy for just the problem domain. This is the professional way to debug SELinux issues.
7
Install SELinux Management Tools

Many SELinux tools are not installed by default — get them first:

# RHEL 8/9 / CentOS Stream / Rocky / AlmaLinux
sudo dnf install -y \
    policycoreutils \
    policycoreutils-python-utils \
    setools-console \
    setroubleshoot-server \
    selinux-policy-devel

# RHEL 7 / CentOS 7
sudo yum install -y \
    policycoreutils \
    policycoreutils-python \
    setools-console \
    setroubleshoot-server

# Ubuntu / Debian (SELinux not default — AppArmor is)
sudo apt install -y \
    selinux-basics \
    selinux-policy-default \
    auditd
PackageProvides
policycoreutilsCore tools: getenforce, setenforce, restorecon, sestatus
policycoreutils-python-utilssemanage — manage contexts, booleans, ports, users
setools-consolesesearch, seinfo — query and analyze policy
setroubleshoot-serversealert — human-readable denial explanations
selinux-policy-develTools for writing custom policy modules
auditdAudit daemon — writes AVC denials to audit.log
8
Essential Status Commands at a Glance
# What mode am I in?
getenforce

# Full status
sestatus

# What policy is loaded?
sestatus | grep policy

# Any recent denials?
sudo ausearch -m avc -ts recent 2>/dev/null | tail -20

# Count denials in audit log
sudo grep -c "denied" /var/log/audit/audit.log

# Is auditd running? (needed for AVC logging)
systemctl is-active auditd

# What domains are currently permissive?
sudo semanage permissive -l

# Show SELinux filesystem mount
ls /sys/fs/selinux

Quick Reference

CommandWhat it does
getenforcePrint current mode: Enforcing, Permissive, or Disabled
sestatusFull SELinux status report
sestatus -vVerbose status including file context checks
setenforce 1Set Enforcing mode (runtime only)
setenforce 0Set Permissive mode (runtime only)
cat /etc/selinux/configView persistent mode and policy settings
semanage permissive -a httpd_tSet one domain permissive, rest enforcing
semanage permissive -lList permissive domains
ausearch -m avc -ts recentShow recent AVC denials
grep denied /var/log/audit/audit.logRaw audit log denial search
sealert -a /var/log/audit/audit.logHuman-readable denial analysis
touch /.autorelabelTrigger filesystem relabel on next boot

Key Files and Directories

PathPurpose
/etc/selinux/configPersistent mode and policy configuration
/etc/selinux/targeted/Targeted policy files
/sys/fs/selinux/SELinux filesystem — runtime interface to kernel
/var/log/audit/audit.logAVC denials and audit events
/var/log/messagessetroubleshoot summaries (human readable)
/.autorelabelPresence triggers full filesystem relabel on boot

← Back to SELinux Index ↑ Back to EXPANDED