Level 1

Understanding Enforcing Mode

Difficulty: Beginner | Reward: +100 XP | Prerequisites: Basic Linux CLI

Mission Briefing

You have inherited a RHEL 9 server. The previous admin left SELinux in permissive mode "because it was causing problems." Your job is to understand what the three SELinux modes do, switch the system to enforcing mode, and fix whatever breaks. Disabling SELinux is not an option.

The Three Modes

SELinux operates in exactly three modes. Understanding what each one does - and does not do - is the foundation of everything that comes after.

Enforcing is the only mode that provides real security. In enforcing mode, the kernel checks every access attempt against the loaded SELinux policy. If the policy does not explicitly allow the access, the kernel denies it and logs an AVC (Access Vector Cache) denial to the audit log. Processes that violate policy are stopped in their tracks.

Permissive mode loads the policy and evaluates every access attempt, but it never actually denies anything. Instead, it logs what would have been denied. This mode is useful for debugging and for building custom policy modules, but it provides zero security. An attacker exploiting a vulnerability on a permissive system faces no additional restrictions from SELinux.

Disabled means SELinux is completely off. The kernel does not load a policy, does not evaluate access, and does not log anything. Worse, if you disable SELinux and later re-enable it, all files created while SELinux was off will have no security labels. You will need to relabel the entire filesystem, which takes time and can itself cause problems.

Checking the Current Mode

The getenforce command tells you the current runtime mode in a single word:

[root@gamehost ~]# getenforce
Permissive

For more detail, use sestatus:

[root@gamehost ~]# sestatus
SELinux status: enabled
SELinuxfs mount: /sys/fs/selinux
SELinux root directory: /etc/selinux
Loaded policy name: targeted
Current mode: permissive
Mode from config file: permissive
Policy MLS status: enabled
Policy deny_unknown status: allowed
Memory protection checking: actual (secure)
Max kernel policy version: 33

Notice the distinction between "Current mode" (the runtime state) and "Mode from config file" (what happens on next boot). These can differ if someone used setenforce to change the mode at runtime without editing the config.

Switching Modes at Runtime

The setenforce command toggles between enforcing and permissive without a reboot:

[root@gamehost ~]# setenforce 1
[root@gamehost ~]# getenforce
Enforcing

The argument is simple: 1 for enforcing, 0 for permissive. You cannot switch to disabled at runtime - that requires a config change and a reboot. This is by design: once the kernel has loaded the policy, it cannot fully unload it without restarting.

Making It Permanent

Runtime changes do not survive a reboot. To set the mode permanently, edit /etc/selinux/config:

[root@gamehost ~]# 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

The targeted policy is the default on RHEL, CentOS, and Fedora. It confines specific high-risk daemons (httpd, sshd, named, etc.) while leaving unconfined processes mostly unrestricted. For most servers, targeted is the right choice.

What Happens When You Switch to Enforcing

If a system has been running in permissive or disabled mode, switching to enforcing will likely break things. Services that were accessing files, ports, or other resources outside their allowed policy will suddenly be denied. This is not a bug - it is the system finally doing its job.

The audit log at /var/log/audit/audit.log is where you find out what went wrong:

[root@gamehost ~]# ausearch -m AVC --start recent
type=AVC msg=audit(1710000000.123:456): avc: denied { read } for
pid=1234 comm="httpd" name="index.html" dev="vda1" ino=67890
scontext=system_u:system_r:httpd_t:s0
tcontext=system_u:object_r:default_t:s0 tclass=file permissive=0

This AVC denial tells you that the httpd process (running as type httpd_t) tried to read a file labeled default_t. The targeted policy does not allow httpd_t to read default_t files. The fix is not to disable SELinux - it is to give that file the correct label, which you will learn in Level 2.

Challenge: The Broken Web Server

You switched the system to enforcing mode and now Apache returns 403 errors for a site that was working five minutes ago. The document root is /srv/webapp/public.

Your tasks:

  1. Confirm SELinux is in enforcing mode using getenforce
  2. Check the audit log for AVC denials related to httpd
  3. Identify the incorrect file context on the document root
  4. Determine what the correct context should be (hint: httpd_sys_content_t)

Bonus objective: Verify that /etc/selinux/config is set to enforcing so the fix persists after reboot.

Key Commands Reference

# Check current mode
$ getenforce
$ sestatus

# Switch to enforcing at runtime
# setenforce 1

# Set mode permanently
# vi /etc/selinux/config

# Search for recent AVC denials
# ausearch -m AVC --start recent
# ausearch -m AVC -ts today

Common Mistakes

ACHIEVEMENT UNLOCKED

First Enforcer

You understand the three SELinux modes and can switch between them safely. +100 XP

Next: Level 2 - Contexts and Labels