RED HAT ENTERPRISE LINUX
Set Enforcing and
Permissive Modes for SELinux
Set enforcing and permissive modes for SELinux
CIS126RH | RHEL System Administration 1
Mesa Community College
SELinux (Security-Enhanced Linux) is a mandatory access control system built into the Linux kernel. Where standard Linux permissions ask "who owns this file?", SELinux asks "is this process allowed to perform this action on this resource according to policy?". On RHEL 9, SELinux is enabled and enforcing by default — providing a critical second layer of protection. Administrators must be able to check SELinux status, switch between modes, make mode changes persistent, and understand why keeping SELinux enforcing matters. These skills are tested on the RHCSA exam.
Learning Objectives
- Explain the SELinux security model — Describe how SELinux adds mandatory access control beyond standard Linux permissions, and the role of security contexts and policy
-
Check and interpret SELinux status —
Use
getenforceandsestatusto determine the current mode and policy in effect -
Switch SELinux modes at runtime and persistently —
Use
setenforceto change the runtime mode and/etc/selinux/configto make the change persist across reboots - Explain the three SELinux modes and when to use each — Distinguish enforcing, permissive, and disabled, and understand why permissive is preferred over disabled for troubleshooting
What is SELinux?
SELinux is a Mandatory Access Control (MAC) system. Unlike standard Linux permissions (Discretionary Access Control / DAC), SELinux policy is enforced by the kernel regardless of user or root decisions.
- Standard permissions: owner decides who can access a file (discretionary)
- SELinux: central policy enforced by the kernel — even root cannot bypass it
- Every process and file has a security context (label)
- The SELinux policy defines which process contexts can access which file contexts
- Access is denied unless the policy explicitly allows it
For a process to access a resource, both standard permissions AND SELinux policy must allow it. SELinux denials appear as "Permission denied" even when the standard file permissions look correct — this is the most common SELinux diagnostic scenario.
SELinux Security Contexts
Every process and file has a security context — a label that SELinux policy uses to determine whether an access is allowed.
# View security context of files (-Z flag)
$ ls -Z /var/www/html/index.html
system_u:object_r:httpd_sys_content_t:s0 /var/www/html/index.html
# ^user ^role ^type ^level
# View security context of a running process (-Z flag)
$ ps auxZ | grep httpd
system_u:system_r:httpd_t:s0 ... /usr/sbin/httpd
# The type field (third field) is what SELinux policy primarily uses
# httpd_t process CAN read httpd_sys_content_t files — policy allows it
# httpd_t process CANNOT read shadow_t files — policy denies it
# View context of the current shell process
$ id -Z
unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
# unconfined_t = standard users run unconfined (no SELinux restrictions)
The Three SELinux Modes
| Mode | Policy enforced? | Denials logged? | Context labels? | Use |
|---|---|---|---|---|
| Enforcing | Yes — access denied | Yes | Yes | Normal production operation — maximum protection |
| Permissive | No — access allowed | Yes | Yes | Troubleshooting — log what would be denied without blocking |
| Disabled | No — SELinux off | No | No | Avoid — requires full relabel at next boot to re-enable |
Switching from disabled to enforcing requires a full filesystem relabel at the next reboot, which can take many minutes and may leave files mislabelled. Permissive achieves the same diagnostic goal without this cost. The RHCSA exam expects SELinux to remain enabled (either enforcing or permissive).
Checking SELinux Status
# Quick check: current mode only
$ getenforce
Enforcing
# Full status report
$ sestatus
SELinux status: enabled
SELinuxfs mount: /sys/fs/selinux
SELinux mount point: /sys/fs/selinux
SELinuxfs mount: /sys/fs/selinux
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
Policy type: targeted
# Note: "Current mode" vs "Mode from config file"
# These can differ when setenforce has been used without editing the config file
"Current mode" = the mode SELinux is in right now (from setenforce).
"Mode from config file" = the mode that will apply after the next reboot
(from /etc/selinux/config). When they differ, a reboot will
change the mode.
Changing Mode at Runtime: setenforce
setenforce changes the SELinux mode immediately without rebooting.
The change is temporary — lost after the next reboot.
# Switch to permissive mode (for troubleshooting)
$ sudo setenforce 0 # 0 = permissive
$ sudo setenforce Permissive # equivalent
# Switch back to enforcing mode
$ sudo setenforce 1 # 1 = enforcing
$ sudo setenforce Enforcing # equivalent
# Verify the change
$ getenforce
Permissive
$ sestatus
Current mode: permissive ← runtime mode changed
Mode from config file: enforcing ← config still says enforcing
# Note: setenforce cannot switch to disabled or from disabled
# Disabled requires editing /etc/selinux/config and rebooting
$ sudo setenforce 0
# If already in disabled mode, setenforce gives:
setenforce: SELinux is disabled
Persistent Mode: /etc/selinux/config
To make a mode change survive reboots, edit /etc/selinux/config
— the file the kernel reads at boot to determine the SELinux starting mode.
# View the current SELinux configuration file
$ cat /etc/selinux/config
# 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 to permissive (persistent across reboots)
$ sudo sed -i 's/^SELINUX=.*/SELINUX=permissive/' /etc/selinux/config
# Or edit with vim
$ sudo vim /etc/selinux/config
# Change: SELINUX=enforcing → SELINUX=permissive
# Verify the change
$ grep ^SELINUX= /etc/selinux/config
SELINUX=permissive
The Complete Mode Change Workflow
To change the SELinux mode both immediately AND persistently, two steps are always required.
Switch from Enforcing to Permissive (with persistence)
# Step 1: Change runtime mode immediately
$ sudo setenforce 0
# Step 2: Make it persistent in the config file
$ sudo sed -i 's/^SELINUX=.*/SELINUX=permissive/' /etc/selinux/config
# Verify both runtime and persistent modes match
$ sestatus
Current mode: permissive
Mode from config file: permissive
Switch from Permissive back to Enforcing (with persistence)
# Step 1: Change runtime mode immediately
$ sudo setenforce 1
# Step 2: Make it persistent
$ sudo sed -i 's/^SELINUX=.*/SELINUX=enforcing/' /etc/selinux/config
# Verify
$ getenforce
Enforcing
The exam grader checks both the current runtime mode AND the persistent config. Always do both steps. setenforce alone is not persistent; config file alone requires a reboot.
SELinux AVC Denials: The Audit Log
When SELinux denies an action (in enforcing mode) or would deny it (in permissive mode), it logs an AVC (Access Vector Cache) denial to the audit log.
# View SELinux denials in the audit log
$ sudo grep AVC /var/log/audit/audit.log | tail -5
type=AVC msg=audit(1716638401.123:456): avc: denied { read } for
pid=1234 comm="httpd" name="data.txt" dev="sda1" ino=67890
scontext=system_u:system_r:httpd_t:s0
tcontext=system_u:object_r:user_home_t:s0 tclass=file
# httpd_t (Apache) was denied READ access to a user_home_t file
# Use ausearch for filtered, human-readable output
$ sudo ausearch -m avc -ts recent
# Use audit2why to explain what the denial means
$ sudo ausearch -m avc -ts recent | audit2why
Was caused by:
Missing type enforcement (TE) allow rule.
You can use audit2allow to generate a loadable module...
Why Permissive is Better Than Disabled
When SELinux is causing problems, the temptation is to disable it. This is almost always wrong. Permissive mode achieves the same diagnostic goal safely.
| Aspect | Permissive | Disabled |
|---|---|---|
| Files created while in this mode | Correctly labelled with SELinux contexts | No SELinux contexts — mislabelled |
| Re-enabling SELinux | Run setenforce 1 — immediate, no relabel | Edit config, reboot, full filesystem relabel (can take hours) |
| Denial logging | Yes — AVC denials logged for diagnosis | No — no way to know what policy violations exist |
| Security during troubleshooting | Standard DAC permissions still enforce | Both MAC and some protections unavailable |
| Troubleshooting value | High — logs what would be denied | None — hides the problem rather than revealing it |
The exam environment uses SELinux enforcing. Setting SELinux to disabled is a severe exam penalty — many tasks depend on correct SELinux configuration. Use permissive only temporarily for troubleshooting; return to enforcing when done.
Viewing Contexts and the . Indicator
The security context appears in many command outputs using the -Z flag.
The . at the end of permissions in ls -l indicates
an SELinux context is set.
# The dot after permissions = SELinux context is present
$ ls -l /etc/passwd
-rw-r--r--. 1 root root 2803 May 25 10:00 /etc/passwd
# ^ dot = SELinux context assigned
# View context with -Z
$ ls -lZ /etc/passwd
-rw-r--r--. root root system_u:object_r:passwd_file_t:s0 /etc/passwd
# View context of a directory
$ ls -ldZ /var/www/html
drwxr-xr-x. root root system_u:object_r:httpd_sys_content_t:s0 /var/www/html
# View context of processes
$ ps -eZ | grep httpd
system_u:system_r:httpd_t:s0 1234 ? 00:00:00 httpd
# A + after permissions = ACL is set (not SELinux)
-rw-r--r--+ 1 alice alice 0 May 25 10:00 acl-file
SELinux Mode Management Quick Reference
| Task | Command or file |
|---|---|
| Check current SELinux mode (quick) | getenforce |
| Check full SELinux status | sestatus |
| Switch to permissive (temporary) | sudo setenforce 0 |
| Switch to enforcing (temporary) | sudo setenforce 1 |
| Make permissive persistent | Set SELINUX=permissive in /etc/selinux/config |
| Make enforcing persistent | Set SELINUX=enforcing in /etc/selinux/config |
| Verify config file setting | grep ^SELINUX= /etc/selinux/config |
| View file SELinux context | ls -Z FILE or ls -lZ FILE |
| View process SELinux context | ps -eZ | grep PROCESS |
| View recent AVC denials | sudo ausearch -m avc -ts recent |
| Explain an AVC denial | sudo ausearch -m avc -ts recent | audit2why |
| View audit log for denials | sudo grep AVC /var/log/audit/audit.log |
Booting with SELinux Mode Options
The SELinux mode can also be overridden at boot time via kernel parameters — useful for recovery when the config file cannot be edited.
# Boot into permissive mode (one-time override at GRUB menu)
# At the GRUB menu, press 'e', then add to the kernel line:
enforcing=0
# This boots permissive regardless of /etc/selinux/config
# Check if SELinux was overridden at boot
$ cat /sys/fs/selinux/enforce
0 # 0=permissive, 1=enforcing
# The /etc/selinux/config SELINUX= is read at boot
# The kernel parameter enforcing=0 overrides it for one boot only
# Trigger a full filesystem relabel on next boot (after re-enabling from disabled)
$ sudo touch /.autorelabel
$ sudo reboot
# The relabel may take several minutes on large filesystems
When a misconfigured SELinux policy prevents booting or login, adding
enforcing=0 to the kernel line at the GRUB menu boots into
permissive mode — enough to diagnose and fix the problem.
Common Mistakes
| Mistake | What goes wrong | Correct approach |
|---|---|---|
Setting SELINUX=disabled instead of permissive |
Files created without contexts; re-enabling requires full relabel; exam penalty | Always use SELINUX=permissive for troubleshooting — never disabled |
Using only setenforce without editing the config file |
Mode reverts to config file value after next reboot — change is not persistent | Always do both: setenforce (runtime) AND edit /etc/selinux/config (persistent) |
Editing only the config file without running setenforce |
Config change is correct but does not take effect until next reboot | Run setenforce for immediate effect; edit config for persistence |
| Confusing setenforce 0 and 1 | Sets wrong mode: 0=permissive (off), 1=enforcing (on) | Mnemonic: 1=enforcing (one = on); 0=permissive (zero = off/relaxed) |
| Assuming SELinux is the only cause when a service fails | Wastes time on SELinux when the real cause is firewall, config, or permissions | Check standard permissions and firewall first; use ausearch -m avc to confirm SELinux is involved |
Using setenforce when SELinux is disabled in config |
setenforce returns: "SELinux is disabled" — cannot change to enforcing this way | Edit /etc/selinux/config to set enforcing and reboot |
Practical Troubleshooting Workflow
Scenario: Apache cannot serve a page that appears to have correct permissions. Is SELinux the cause?
# Step 1: Check if SELinux is enforcing
$ getenforce
Enforcing
# Step 2: Check for recent AVC denials
$ sudo ausearch -m avc -ts recent
...denied { read } for comm="httpd" scontext=httpd_t tcontext=user_home_t...
# SELinux is blocking httpd from reading a user_home_t file
# Step 3: Temporarily switch to permissive to confirm SELinux is the cause
$ sudo setenforce 0
# Step 4: Test the service — if it now works, SELinux was the cause
$ curl http://localhost/data.html
<!DOCTYPE html>... ← works in permissive!
# Step 5: Fix the root cause (e.g. restore correct file context)
# (covered in the SELinux contexts module)
# Step 6: Return to enforcing
$ sudo setenforce 1
$ getenforce
Enforcing
Knowledge Check
Answer these before moving to the next slide.
- What are the three SELinux modes, and what is the key difference between permissive and disabled?
- Write the command to check the current SELinux mode and the command that shows both the runtime mode AND the persistent config file mode.
- Write the two commands to switch SELinux to permissive mode both immediately AND persistently across reboots.
- After running
sudo setenforce 0,sestatusshows "Current mode: permissive" but "Mode from config file: enforcing". What does this mean, and what happens after the next reboot? - Why should you never set
SELINUX=disabled? What should you use instead, and why is it safer? - Write the command to verify the persistent SELinux mode setting in the configuration file without opening the file in an editor.
Knowledge Check — Answers
- The three modes are enforcing (policy enforced, denials logged), permissive (policy not enforced but denials logged, contexts maintained), and disabled (SELinux completely inactive, no contexts applied). The key difference: permissive still maintains SELinux contexts on files and logs denials, making it easy to re-enable. Disabled removes all context labels, requiring a full filesystem relabel to re-enable.
- Quick mode check:
getenforce
Full status (runtime + persistent):sestatus - (1)
sudo setenforce 0— changes runtime mode immediately
(2)sudo sed -i 's/^SELINUX=.*/SELINUX=permissive/' /etc/selinux/config— makes it persistent. Also accept: edit/etc/selinux/configwith vim and change SELINUX=enforcing to SELINUX=permissive. - The runtime mode is permissive (setenforce 0 was applied). The config file still says enforcing — the config file was not edited. After the next reboot, the system will read the config file and boot into enforcing mode — the setenforce change was not persistent.
- Setting
SELINUX=disabledmeans files created while disabled receive no SELinux context labels. When you re-enable SELinux, a full filesystem relabel is required at the next reboot — this can take many minutes. Additionally, no AVC denials are logged while disabled, so you learn nothing about what SELinux would block. UseSELINUX=permissiveinstead — it keeps context labels on all files and logs denials without enforcing them. grep ^SELINUX= /etc/selinux/config
Expected output:SELINUX=enforcingorSELINUX=permissive
Key Takeaways
- SELinux has three modes: enforcing, permissive, and disabled. Enforcing = policy enforced, denials blocked. Permissive = denials logged but allowed. Disabled = SELinux completely off, no contexts. Never use disabled — use permissive for troubleshooting.
-
Check mode with
getenforce; check both runtime and persistent withsestatus. sestatus shows "Current mode" (runtime) and "Mode from config file" (persistent). When they differ, a reboot will change the mode. -
Two steps for a complete persistent mode change.
Runtime:
sudo setenforce 0(permissive) orsudo setenforce 1(enforcing). Persistent: editSELINUX=in/etc/selinux/config. Do both — one alone is incomplete. -
Permissive is for troubleshooting — always return to enforcing.
In permissive mode, AVC denials are logged but not blocked — use
ausearch -m avc -ts recentto identify what SELinux is denying. Fix the root cause, thensetenforce 1and update the config file to enforcing.
Graded Lab
- Run
getenforceandsestatusto record the current SELinux mode and the mode configured in the config file. Confirm they match. View the/etc/selinux/configfile and identify the SELINUX= line. - Switch SELinux to permissive mode with
sudo setenforce 0. Verify withgetenforce(should show Permissive). Runsestatusand observe that "Current mode" is permissive but "Mode from config file" still shows the original value — demonstrating the change is not yet persistent. - Make the permissive mode persistent by editing
/etc/selinux/configand settingSELINUX=permissive. Verify withgrep ^SELINUX= /etc/selinux/config. Runsestatusagain and confirm both "Current mode" and "Mode from config file" now show permissive. - Switch back to enforcing mode:
sudo setenforce 1for runtime, then edit/etc/selinux/configto setSELINUX=enforcing. Verify withgetenforceandsestatusthat both match enforcing. - Run
ls -lZ /etc/passwd /var/www/htmlto view SELinux contexts on these files. Identify the type field (third colon-separated field) in each context. Runid -Zto see your own process context. - Run
sudo ausearch -m avc -ts recent. If there are recent denials, pipe one throughaudit2whyto get a human-readable explanation. If there are no denials, confirm SELinux is enforcing correctly withgetenforce.
"Set enforcing and permissive modes for SELinux."
Runtime: setenforce 0|1. Persistent: edit SELINUX=
in /etc/selinux/config. Verify: getenforce and
sestatus. Never use disabled.