Domain 11 · Security

Manage
security

SELinux modes, file and process contexts, booleans, port labeling, and troubleshooting denials with audit2allow and ausearch on RHEL 9.

8objectives
6topic areas
8quiz questions
SELinuxprimary focus

Objectives

What the exam tests

  • Configure SELinux to enforce or permissive mode persistently
  • List and identify SELinux file and process context labels
  • Restore default file contexts using restorecon
  • Use boolean settings to modify SELinux policy behavior
  • Diagnose and address routine SELinux policy violations
  • Manage SELinux port labels to allow services on non-standard ports
  • Investigate SELinux AVC denials with ausearch and the audit log
  • Generate and apply policy modules with audit2allow

SELinux is tested on every RHCSA exam. The most common scenario: a service is running but inaccessible — the fix is either a context relabel (restorecon), a boolean change, or a port label addition. Never set SELinux to Disabled on the exam unless explicitly required.

Coverage weight by topic

Context management
Critical
Troubleshooting denials
Very high
Booleans
Very high
Port labels
High
Mode management
High
audit2allow / policy modules
Medium

SELinux decision flow

When a process tries to access a resource, the kernel checks both DAC (standard Unix permissions) and MAC (SELinux). Both must allow the access.

DAC — Discretionary Access Control

  • Standard Unix rwx permissions
  • ACLs (getfacl / setfacl)
  • Controlled by the file owner
  • Checked first by the kernel

MAC — Mandatory Access Control

  • SELinux policy rules
  • Cannot be overridden by owner
  • Based on context labels, not ownership
  • Checked after DAC passes

If DAC denies access, SELinux is never consulted. If DAC allows but SELinux denies, the denial is logged in /var/log/audit/audit.log as an AVC denial.

SELinux modes

The three SELinux modes

ModePolicy enforced?Denials logged?Use for
Enforcing ProductionYes — access blockedYesNormal operation. RHEL 9 default.
Permissive DebugNo — access allowedYes — all would-be denialsTroubleshooting without breaking services
Disabled AvoidNoNoNever on exam unless required. Re-enabling requires full relabel.

Checking and changing SELinux mode

── CHECK CURRENT MODE ──────────────────────────────────────── getenforce # prints: Enforcing / Permissive / Disabled sestatus # detailed: mode, policy name, booleans, etc. sestatus -v # verbose: include process and file contexts ── CHANGE MODE TEMPORARILY (runtime — lost on reboot) ──────── setenforce 1 # switch to Enforcing setenforce 0 # switch to Permissive setenforce Enforcing # by name (also accepted) setenforce Permissive ── CHANGE MODE PERMANENTLY (survives reboot) ───────────────── # Edit /etc/selinux/config: # SELINUX=enforcing ← change this line # SELINUX=permissive # SELINUX=disabled (requires reboot + relabel to re-enable) # Use sed to change it non-interactively: sed -i 's/^SELINUX=.*/SELINUX=enforcing/' /etc/selinux/config # Verify grep ^SELINUX= /etc/selinux/config

setenforce 0 is a runtime change only. If the server reboots, it returns to the mode set in /etc/selinux/config. Always edit the config file for persistent changes.

Per-process permissive domains

# Set only httpd to permissive (leave everything else enforcing) semanage permissive -a httpd_t semanage permissive -d httpd_t # remove permissive override semanage permissive -l # list permissive domains

Per-domain permissive mode is more targeted than setting the whole system to permissive during troubleshooting — only the specific service domain is unconfined, leaving all other policies active.

SELinux contexts

SELinux context format

Every file, directory, process, and network port has a security context label with four colon-separated components.

system_uuser
object_rrole
httpd_sys_content_ttype
s0level (MLS)

For the RHCSA exam, the type field (third field) is what matters. SELinux policy rules are primarily type-based — they define which process types can access which file types.

ComponentTypical valuesExam importance
Usersystem_u, unconfined_u, user_uLow
Roleobject_r (files), system_r (processes)Low
Typehttpd_sys_content_t, sshd_t, var_tCritical
Levels0 (standard), range for MLSIgnore on RHCSA

Viewing contexts

# File and directory contexts ls -Z /var/www/html/ # show context in ls output ls -lZ /etc/httpd/conf/httpd.conf # long format + context stat /var/www/html/index.html # includes context in output # Process contexts ps -eZ # all processes with context ps -eZ | grep httpd # filter ps auxZ | grep sshd # Current shell / user context id -Z

restorecon — restore default context

# Restore context of a single file to the policy default restorecon /var/www/html/index.html # Recursive restore for a directory tree restorecon -Rv /var/www/html/ # -R recursive, -v verbose restorecon -RFv /var/www/html/ # -F force even if context looks right # Trigger full filesystem relabel at next boot touch /.autorelabel # create the flag file reboot # relabel happens during boot

restorecon only sets contexts according to the policy database — it does not change the policy itself. If the policy database has no entry for a path, use semanage fcontext first to add a rule, then restorecon to apply it.

semanage fcontext — managing file context rules

── LIST context rules ──────────────────────────────────────── semanage fcontext -l semanage fcontext -l | grep /var/www semanage fcontext -l | grep httpd ── ADD a new context rule ──────────────────────────────────── # Make /srv/mywebsite/ behave like /var/www/html/ for Apache semanage fcontext -a -t httpd_sys_content_t '/srv/mywebsite(/.*)?' # Apply the rule to existing files restorecon -Rv /srv/mywebsite/ ── MODIFY an existing rule ─────────────────────────────────── semanage fcontext -m -t httpd_sys_rw_content_t '/srv/mywebsite(/.*)?' ── DELETE a custom rule ────────────────────────────────────── semanage fcontext -d '/srv/mywebsite(/.*)?' ── chcon — temporary context change (not persistent!) ──────── chcon -t httpd_sys_content_t /srv/mywebsite/index.html chcon -R -t httpd_sys_content_t /srv/mywebsite/ # WARNING: chcon changes are lost on restorecon or relabel!
chcon changes contexts directly but those changes are overwritten by restorecon or a system relabel. Always use semanage fcontext -a to add a permanent rule, then restorecon to apply it.

Common SELinux file type reference

SELinux typeTypical pathUsed by
httpd_sys_content_t/var/www/html/Apache web content (read-only)
httpd_sys_rw_content_t/var/www/html/uploads/Apache writable content
httpd_log_t/var/log/httpd/Apache log files
sshd_key_t/etc/ssh/ssh_host_*SSH host keys
var_t/var/Generic /var content
etc_t/etc/Configuration files
user_home_t/home/user/User home directories
tmp_t/tmp/Temporary files
svirt_sandbox_file_tContainer mountsPodman / container volumes
container_file_tContainer bind mountsRootless container volumes

SELinux booleans

What are SELinux booleans?

Booleans are on/off switches that control specific behaviors within the SELinux policy without requiring a full policy recompile. They allow administrators to enable optional features that the policy ships with but disables by default.

Runtime change (lost on reboot)

setsebool httpd_can_network_connect on

Persistent change (survives reboot)

setsebool -P httpd_can_network_connect on

Managing booleans

── VIEW booleans ───────────────────────────────────────────── getsebool -a # list all booleans and their state getsebool httpd_can_network_connect # check one boolean semanage boolean -l # list with description and persistent value semanage boolean -l | grep httpd # filter by service ── SET booleans ────────────────────────────────────────────── setsebool httpd_can_network_connect on # runtime only setsebool httpd_can_network_connect off setsebool -P httpd_can_network_connect on # persistent (-P flag) setsebool -P httpd_enable_homedirs on # allow Apache to serve ~/public_html ── SET MULTIPLE at once ────────────────────────────────────── setsebool -P httpd_can_network_connect on httpd_can_sendmail on

Always use setsebool -P (with the -P flag) for persistent changes. Without -P, the change is lost when the system reboots.

Common booleans for the exam

BooleanWhen to enable
httpd_can_network_connectApache needs to connect to a backend (proxy, database)
httpd_can_network_connect_dbApache needs to connect to a database server
httpd_enable_homedirsApache needs to serve files from user home directories (~/public_html)
httpd_use_nfsApache serves content from an NFS mount
httpd_use_cifsApache serves content from a Samba/CIFS mount
ftp_home_dirFTP server can access user home directories
ftpd_anon_writeFTP server allows anonymous uploads
samba_enable_home_dirsSamba can share home directories
allow_httpd_anon_writeApache can write to public_content_rw_t areas
ssh_sysadm_loginAllow sysadm_r role to SSH in directly
container_use_devicesContainers can use host device files
virt_use_nfsVirtual machines can use NFS storage

SELinux port labels

SELinux port labeling — why it matters

SELinux controls which ports a confined process can listen on. If you configure a service to use a non-standard port (e.g., Apache on port 8443 instead of 443), SELinux will deny the bind unless that port has the correct label.

── LIST port labels ────────────────────────────────────────── semanage port -l # all labeled ports semanage port -l | grep http # ports labeled for httpd semanage port -l | grep ssh # ports labeled for sshd ── ADD a port label ────────────────────────────────────────── # Allow Apache to listen on port 8443 (TCP) semanage port -a -t http_port_t -p tcp 8443 # Allow SSH to also use port 2222 semanage port -a -t ssh_port_t -p tcp 2222 # Allow FTP data on a custom port semanage port -a -t ftp_data_t -p tcp 30000 ── MODIFY an existing label ────────────────────────────────── semanage port -m -t http_port_t -p tcp 8443 ── DELETE a custom port label ──────────────────────────────── semanage port -d -t http_port_t -p tcp 8443 ── Verify after adding ─────────────────────────────────────── semanage port -l | grep 8443

Common port type labels

SELinux typeDefault portsService
http_port_t80, 443, 8008, 8009, 8443Apache httpd, nginx
ssh_port_t22OpenSSH sshd
ftp_port_t21vsftpd control port
smtp_port_t25, 465, 587Postfix, sendmail
dns_port_t53named / bind
mysqld_port_t3306MySQL / MariaDB
postgresql_port_t5432PostgreSQL
nfs_port_t2049NFS server

Troubleshooting SELinux denials

Finding AVC denials in the audit log

# Raw audit log — all AVC (Access Vector Cache) denials cat /var/log/audit/audit.log | grep "avc: denied" # ausearch — better filtering ausearch -m avc # all AVC messages ausearch -m avc -ts recent # recent messages (since last boot) ausearch -m avc -ts today # messages from today ausearch -m avc -c httpd # denials for httpd processes ausearch -m avc -ts recent -c httpd # combine filters # journalctl — SELinux messages from systemd journal journalctl -t setroubleshoot # setroubleshoot daemon messages journalctl | grep "SELinux"

audit2allow and audit2why

# Translate AVC denials into human-readable policy descriptions ausearch -m avc -ts recent | audit2why # Generate a policy module to allow the denied action ausearch -m avc -ts recent | audit2allow # Generate AND install a policy module automatically ausearch -m avc -ts recent | audit2allow -M mypolicy semodule -i mypolicy.pp # install the compiled module # View installed policy modules semodule -l semodule -l | grep mypolicy # Remove a policy module semodule -r mypolicy

audit2allow should be a last resort — it generates policy rules that match what happened, but may be broader than intended. Always try restorecon, then booleans, then port labels before generating custom policy modules.

sealert — user-friendly denial analysis

# Install setroubleshoot-server for sealert dnf install -y setroubleshoot-server # Analyze audit.log for human-readable explanations sealert -a /var/log/audit/audit.log # sealert shows: # - What was denied # - Why (which policy rule) # - How to fix it (ranked suggestions) # 1. restorecon (if wrong context) # 2. setsebool (if boolean needed) # 3. semanage fcontext (if new path) # 4. audit2allow (if nothing else works)

SELinux troubleshooting decision tree

Confirm SELinux is causing the problem
setenforce 0 # switch to permissive # If the issue disappears → SELinux is the cause # If issue persists → SELinux is NOT the cause (check permissions, firewall) setenforce 1 # switch back to enforcing
Find the denial in the audit log
ausearch -m avc -ts recent | audit2why
Check if it's a wrong file context
ls -Z /path/to/file # compare to expected type restorecon -Rv /path/ # restore if wrong
Check if a boolean needs to be enabled
semanage boolean -l | grep httpd # find relevant booleans setsebool -P httpd_can_network_connect on
Check if a non-standard port needs labeling
semanage port -l | grep http semanage port -a -t http_port_t -p tcp 8443
If nothing else works — generate a policy module
ausearch -m avc -ts recent | audit2allow -M mypol semodule -i mypol.pp

Reading an AVC denial message

# Example AVC denial from /var/log/audit/audit.log: type=AVC msg=audit(1712600000.123:456): avc: denied { read } for pid=1234 comm="httpd" name="index.html" dev="sda1" ino=123456 scontext=system_u:system_r:httpd_t:s0 tcontext=unconfined_u:object_r:user_home_t:s0 tclass=file permissive=0 # Breakdown: # denied { read } — what was attempted # comm="httpd" — which process # scontext=httpd_t — source (process) type # tcontext=user_home_t— target (file) type # tclass=file — object class # Fix: file has wrong context — should be httpd_sys_content_t # Solution: restorecon or semanage fcontext + restorecon

The most important fields in an AVC denial are scontext (what process is trying to access) and tcontext (what the target's context is). The tcontext type often tells you immediately what the fix is — if it shows user_home_t where you expected httpd_sys_content_t, the file has the wrong context.

Cheat sheet

Most-tested commands — quick reference

Check SELinux mode
getenforce
Detailed status
sestatus
Set permissive (runtime)
setenforce 0
Set enforcing (runtime)
setenforce 1
Persistent mode change
sed -i 's/^SELINUX=.*/SELINUX=enforcing/' /etc/selinux/config
View file context
ls -Z /path/to/file
View process context
ps -eZ | grep httpd
Restore context
restorecon -Rv /var/www/html/
Add context rule
semanage fcontext -a -t httpd_sys_content_t '/srv/web(/.*)?'
List context rules
semanage fcontext -l | grep /srv
Temp context change
chcon -t httpd_sys_content_t /file
Full filesystem relabel
touch /.autorelabel && reboot
List all booleans
getsebool -a
Check one boolean
getsebool httpd_can_network_connect
Set boolean (persistent)
setsebool -P httpd_can_network_connect on
List booleans + desc
semanage boolean -l | grep httpd
List port labels
semanage port -l | grep http
Add port label
semanage port -a -t http_port_t -p tcp 8443
Delete port label
semanage port -d -t http_port_t -p tcp 8443
Find AVC denials
ausearch -m avc -ts recent
Translate denials
ausearch -m avc -ts recent | audit2why
Generate policy module
ausearch -m avc -ts recent | audit2allow -M mypol
Install policy module
semodule -i mypol.pp
List installed modules
semodule -l

semanage subcommand reference

SubcommandManagesKey flags
semanage fcontextFile context rules-a add, -m modify, -d delete, -l list, -t type
semanage portPort labels-a add, -m modify, -d delete, -l list, -t type, -p protocol
semanage booleanBoolean listing/info-l list with descriptions and persistent values
semanage permissivePer-domain permissive-a add, -d delete, -l list
semanage userSELinux user mappings-l list (rarely needed on RHCSA)

Non-standard port — exam template

Configure the service to use the new port
# e.g., change Apache Listen directive to 8443 vim /etc/httpd/conf/httpd.conf
Add SELinux port label
semanage port -a -t http_port_t -p tcp 8443
Open the port in firewalld
firewall-cmd --permanent --add-port=8443/tcp firewall-cmd --reload
Restart the service
systemctl restart httpd
Verify port is listening
ss -tlnp | grep 8443

Practice quiz

Question 1 of 8

You copy a web file to /var/www/html/ but Apache returns a 403 Forbidden error. Standard permissions look correct. The file has context user_home_t. What is the correct fix?

The file has the wrong SELinux type (user_home_t instead of httpd_sys_content_t). This happens when files are copied from a home directory — they inherit the source context. restorecon -Rv /var/www/html/ resets all contexts in that directory to the policy defaults. Option C disables SELinux enforcement (wrong approach — never disable SELinux to fix a context issue). Option D changes Unix permissions — not the SELinux issue.

Question 2 of 8

You want Apache to serve content from /srv/webdata/ permanently. Which is the correct sequence?

For a new path not covered by the default policy, you must: (1) add a rule with semanage fcontext -a -t, then (2) apply it with restorecon -Rv. Option A (chcon) works temporarily but is lost on relabel. Option C alone will not work because the policy has no entry for /srv/webdata/restorecon would reset it to var_t or similar. Option D references a non-existent boolean.

Question 3 of 8

Which command persistently enables the SELinux boolean httpd_can_network_connect?

The -P flag in setsebool makes the change persistent — it writes to the policy store so it survives reboots. Without -P, Option A changes only the runtime value and is lost on reboot. Option C — semanage boolean is for listing only, not setting. Option D — getsebool is for reading values, not setting them.

Question 4 of 8

You configure sshd to listen on port 2345. After restarting sshd it fails with an SELinux denial. Which command fixes this?

semanage port -a -t ssh_port_t -p tcp 2345 adds port 2345 to the list of ports allowed for the ssh_port_t type, permitting sshd to bind to it. Option A — there is no such boolean as ssh_allow_nonstandard_ports. Option C — restorecon fixes file contexts, not port labels. Option D — chcon is for file contexts, not port labels.

Question 5 of 8

What does setenforce 0 do, and is the change persistent?

setenforce 0 switches SELinux to permissive mode at runtime only. The change is lost on reboot — the system returns to whatever mode is set in /etc/selinux/config. It does not disable SELinux (that requires editing the config file and rebooting). Permissive mode still loads the policy and logs what would be denied, but does not block access.

Question 6 of 8

You add a context rule with semanage fcontext -a but the files still have the wrong context. What additional step is required?

semanage fcontext -a adds a rule to the policy database but does not change the context of existing files. You must run restorecon -Rv /path/ to apply the rule to files that already exist. New files created in the path will automatically get the correct context from the policy. A reboot is not necessary.

Question 7 of 8

Which command shows the most human-readable explanation of what is causing an SELinux denial and how to fix it?

ausearch -m avc -ts recent | audit2why filters the audit log for recent AVC messages and pipes them to audit2why, which translates the raw denial into a human-readable explanation of the policy rule that was violated — and often suggests the fix. Option A shows raw binary-style audit log entries which are hard to read. Option C shows SELinux status but not specific denials.

Question 8 of 8

In SELinux context system_u:object_r:httpd_sys_content_t:s0, which field is most important for the RHCSA exam and determines what processes can access the file?

The type field (httpd_sys_content_t) is the most important component for the RHCSA exam. SELinux policy in targeted mode (RHEL default) is based almost entirely on type enforcement — rules define which process types can perform which operations on which file types. The user and role fields are largely fixed, and the MLS level (s0) is not used in standard RHEL targeted policy.