selinux
SELinux on Red Hat Enterprise Linux across RHEL 8, 9, 10: Mandatory Access Control, type enforcement, security contexts, booleans, file and port context management, custom policy modules, container SE
SKILL.mdplugins/os/skills/selinux/SKILL.md
GitHubSELinux (RHEL)
This skill covers SELinux on Red Hat Enterprise Linux across RHEL 8, 9, and 10. It provides deep knowledge of:
- Mandatory Access Control (MAC) framework and its relationship to DAC
- Type Enforcement (TE) architecture: domains, types, allow rules, transitions
- SELinux modes (enforcing, permissive, disabled) and per-domain permissive mode
- Security contexts (user:role:type:level) for processes, files, ports, and users
- Policy types (targeted, MLS, minimum) and policy module management
- Boolean management for enabling/disabling policy features without custom modules
- File context management with semanage fcontext and restorecon
- Port context management with semanage port
- Custom policy module development (.te, .fc, .if files and audit2allow workflows)
- Container SELinux integration (container-selinux, MCS isolation, :Z/:z volume labels, udica)
- MLS/MCS for multi-level and multi-category security including container isolation
- AVC denial analysis, audit2why, sealert, and systematic troubleshooting
When a question is version-specific, note the relevant version differences. When the version is unknown, provide general guidance and flag where behavior varies. For general RHEL administration, see the rhel skill.
How to Approach Tasks
Route by request type: troubleshooting → references/diagnostics.md; architecture → references/architecture.md; best practices/config → references/best-practices.md; health check → the diagnostic scripts; policy development → references/best-practices.md.
Identify the RHEL version first — available tooling shifts by version (CIL output requires RHEL 9+, Quadlet container integration requires RHEL 9.2+). Reason from the source domain, target type, object class, and permissions — not generic Linux security advice. Prefer the least-privilege fix: boolean > fcontext > port > custom module. Validate with ausearch, sealert, a restorecon -Rvn dry run, and getenforce confirmation.
Core Expertise
Mandatory Access Control (MAC)
SELinux implements MAC as a kernel-level enforcement mechanism layered on top of traditional UNIX DAC. Both must allow an access for it to succeed. The decision order is: DAC check first, then SELinux MAC check. Even root is subject to MAC rules.
SELinux registers with the Linux Security Modules (LSM) framework at boot time. The security server loads the compiled binary policy and evaluates access requests through LSM hooks at key kernel operations: file access, socket operations, process creation, IPC, and mount operations.
The Access Vector Cache (AVC) stores results of recent security decisions for performance. Cache misses generate audit messages. Denials are logged as AVC messages in /var/log/audit/audit.log.
Type Enforcement
Type Enforcement is the primary access control mechanism in SELinux targeted policy.
- Domain: the security type assigned to a process (e.g.,
httpd_t,sshd_t) - Type: the security type assigned to a file or object (e.g.,
httpd_sys_content_t,shadow_t)
Access is controlled by allow rules:
allow source_domain target_type : object_class { permissions };
Type transitions control automatic domain changes when a process executes a binary. When init_t executes /usr/sbin/httpd (labeled httpd_exec_t), the new process transitions to httpd_t.
Dontaudit rules suppress logging for known-harmless denials. To temporarily reveal hidden denials:
semodule -DB # Disable dontaudit rules
# ... investigate ...
semodule -B # Re-enable dontaudit rules
Security Contexts
Format: user:role:type:level
- user: SELinux user (
system_u,unconfined_u,staff_u,user_u) - role: RBAC role (
system_r,object_r,user_r,sysadm_r) - type: The domain or type (primary enforcement mechanism)
- level: MLS/MCS sensitivity and categories (
s0,s0:c1,c2)
Inspect contexts:
ps auxZ # Process contexts
ls -Z /path/to/file # File contexts
id -Z # Current user context
semanage port -l # Port contexts
SELinux Modes
| Mode | Behavior | Use Case |
|---|---|---|
| Enforcing | Policy enforced, denials blocked and logged | Production |
| Permissive | Policy evaluated, denials logged but not blocked | Troubleshooting |
| Disabled | SELinux inactive, no labeling or enforcement | Not recommended |
Persistent configuration: /etc/selinux/config
Per-domain permissive mode confines a single domain to permissive while the rest of the system enforces. Invaluable for troubleshooting one service without weakening the entire system:
semanage permissive -a httpd_t # Put httpd_t in permissive
semanage permissive -d httpd_t # Remove from permissive
Boolean Management
Booleans are pre-defined on/off switches that enable or disable specific policy rules without custom modules. They are the preferred first-line mechanism for adjusting SELinux policy.
getsebool -a | grep httpd # List booleans for a service
setsebool -P httpd_can_network_connect on # Set persistently
semanage boolean -l | awk '$3 != $4' # Show changed booleans
Common booleans by service:
- httpd:
httpd_can_network_connect,httpd_can_network_connect_db,httpd_use_nfs,httpd_enable_homedirs - samba:
samba_enable_home_dirs,samba_export_all_rw,samba_share_nfs - nfs:
use_nfs_home_dirs,use_samba_home_dirs - containers:
container_manage_cgroup,virt_use_nfs
File Context Management
SELinux maintains a file context database mapping path patterns to security contexts. Custom rules are added with semanage fcontext and applied with restorecon.
# Add context rule for custom web root
semanage fcontext -a -t httpd_sys_content_t "/srv/www(/.*)?"
restorecon -Rv /srv/www/
# Equivalence rule for relocated data
semanage fcontext -a -e /var/lib/pgsql /data/pgsql
restorecon -Rv /data/pgsql/
# Verify expected context
matchpathcon -V /var/www/html/index.html
Important: chcon makes temporary changes that are lost on relabel. Always use semanage fcontext + restorecon for persistent changes.
Port Context Management
Services binding to non-standard ports require SELinux port labels:
semanage port -l | grep http_port_t # Check existing labels
semanage port -a -t http_port_t -p tcp 8181 # Add port label
Container SELinux
The container-selinux package provides the container_t domain for container processes. MCS categories automatically isolate containers from each other -- each container receives a unique category pair.
Volume mount labels:
:Z-- Private label (relabel for this container only):z-- Shared label (relabel for shared access across containers)
WARNING: Never use :Z on system directories (/home, /etc, /var).
For complex container policies, use udica to generate least-privilege SELinux modules:
podman inspect mycontainer | udica mypolicy
semodule -i mypolicy.cil /usr/share/udica/templates/*.cil
Custom Policy Modules
When no boolean, file context, or port label covers the required access:
- Put the domain in per-domain permissive:
semanage permissive -a myapp_t - Reproduce the denied operations
- Collect denials:
ausearch -m AVC -c myapp | audit2allow - Generate module:
ausearch -m AVC -c myapp | audit2allow -M mypolicy - Review the generated
.tefile before installing - Install:
semodule -i mypolicy.pp - Remove permissive:
semanage permissive -d myapp_t
Module file types: .te (type enforcement rules), .fc (file contexts), .if (interfaces), .pp (compiled package).
Module priorities: 100 (base), 200 (contrib), 300 (local), 400 (custom overrides).
Troubleshooting Decision Tree
1. Confirm SELinux is causing the issue
+-- getenforce --> is it Enforcing?
+-- setenforce 0 --> does the problem go away?
+-- setenforce 1 --> re-enable immediately after confirming
2. Find AVC denials
+-- ausearch -m AVC -ts recent
+-- sealert -a /var/log/audit/audit.log
+-- journalctl -t setroubleshoot
3. Understand the denial
+-- ausearch -m AVC -ts recent | audit2why
+-- Identify: scontext (who), tcontext (what), tclass (class), perms
4. Determine the fix (least privilege first)
|
+-- Wrong file context?
| +-- semanage fcontext -a -t <type> "/path(/.*)?"
| +-- restorecon -Rv /path/
|
+-- Boolean available?
| +-- semanage boolean -l | grep <service>
| +-- setsebool -P <boolean> on
|
+-- Non-standard port?
| +-- semanage port -a -t <type> -p tcp <port>
|
+-- Container volume issue?
| +-- Add :Z or :z to volume mount
|
+-- None of the above?
+-- Per-domain permissive + audit2allow module
5. Test the fix
+-- Restart the affected service
+-- Verify no new denials: ausearch -m AVC -ts recent
6. Confirm enforcing mode
+-- getenforce --> must show Enforcing
Version-Specific Changes
| Feature | RHEL 8 | RHEL 9 | RHEL 10 |
|---|---|---|---|
| Policy store location | /var/lib/selinux/ |
Same | Same |
| udica (container policy) | Introduced (8.1) | Improved | Enhanced auto-labeling |
| container-selinux MCS | Full MCS isolation default | Improved transitions | Improved rootless confinement |
| audit2allow CIL output | Not available | --cil flag added |
CIL-first recommended |
| setroubleshoot accuracy | Baseline | Improved pattern matching | Further improvements |
| selinux-policy-doc man pages | Available | Expanded | Expanded |
| AVC cache performance | Baseline | ~5% overhead reduction | Further optimization |
| Per-service confinement | Expanded (cockpit, sssd) | keylime, grafana, IPA | More services confined |
| Policy development tools | audit2allow, sepolicy | CIL tooling | sepolicy generate improved |
| Confined user improvements | Baseline | staff_u/sysadm_r improved | Further expansion |
| Audit filtering | Standard | Standard | Granular AVC filters |
RHEL 8 Highlights
- Full MCS isolation for containers became default and well-tested
udicaintroduced in RHEL 8.1 for custom container SELinux policies- Targeted policy expanded to confine more system services (cockpit, sssd)
semanagegained--noheadingand-C(customizations only) flags- Policy store moved to
/var/lib/selinux/with/etc/selinux/for configuration
RHEL 9 Highlights
- AVC cache optimized for lower overhead on high-throughput workloads
audit2allow --cilgenerates native CIL policy (smaller, cleaner than .te macros)- New confined domains:
keylime_t,grafana_t, improvedpodman_t/container_t selinux-policy-docpackage provides per-service man pages (man httpd_selinux)- Improved
setroubleshootwith better fix suggestions for container and NFS scenarios - Improved
staff_uandsysadm_rconfigurations for user confinement
RHEL 10 Highlights
- CIL-first policy approach:
semoduleprefers CIL input,audit2allow --cilis recommended - Improved
container_tpolicy aligned with Podman 5.x model - Better automatic label management for container volumes in common scenarios
- Enhanced
sepolicytooling for generating policy scaffolds - Granular AVC audit filtering to reduce log noise in high-volume environments
- Continued expansion of confined domains, reducing the unconfined attack surface
Common Pitfalls
1. Using setenforce 0 and forgetting to re-enable
Permissive mode opens the entire system. Prefer per-domain permissive (semanage permissive -a <domain>) for targeted troubleshooting.
2. Using chcon instead of semanage fcontext + restorecon
chcon changes are temporary and lost during filesystem relabel. Always make persistent changes through the policy database.
3. Blindly running audit2allow -a | semodule
This generates allow rules for all denials on the system, potentially creating an overly permissive policy. Always filter to the specific domain and review the generated rules.
4. Using :Z on system directories
Relabeling /home, /etc, or /var with container-private labels breaks system services. Use dedicated directories for container bind mounts.
5. Disabling SELinux after encountering issues
Disabling SELinux removes all labels. Re-enabling requires a full filesystem relabel (touch /.autorelabel && reboot). Fix the specific issue instead.
Reference Files
Load these when you need deep knowledge for a specific area:
references/architecture.md-- MAC framework, type enforcement, MLS/MCS, modes, policy types, security contexts. Read for "how does X work" questions.references/diagnostics.md-- AVC analysis, audit2why, sealert, troubleshooting workflows, common issues and fixes. Read when troubleshooting.references/best-practices.md-- semanage workflows, boolean management, custom modules, container SELinux, file context management. Read for configuration and policy development.
Diagnostic Scripts
Run these for rapid SELinux assessment:
| Script | Purpose |
|---|---|
scripts/01-selinux-status.sh |
Mode, policy, modules, changed booleans, AVC counts |
scripts/02-avc-analysis.sh |
Recent denials, audit2why, top denied domains/types, suggested fixes |
scripts/03-context-audit.sh |
Processes in wrong domains, files with wrong contexts, custom port labels |
scripts/04-policy-modules.sh |
Custom modules, changed booleans, recent policy changes |
Key Paths and Files
| Path | Purpose |
|---|---|
/etc/selinux/config |
Mode and policy type configuration |
/var/log/audit/audit.log |
AVC denials and audit events |
/var/log/messages |
setroubleshoot human-readable summaries |
/etc/selinux/targeted/contexts/files/file_contexts |
Base file context database |
/etc/selinux/targeted/contexts/files/file_contexts.local |
Local fcontext overrides |
/sys/fs/selinux/ |
Live SELinux kernel interface |
/var/lib/selinux/targeted/active/ |
Active policy module store |
Key Commands Quick Reference
# Status
getenforce # Current mode
sestatus # Full status summary
# Denials
ausearch -m AVC -ts recent # Recent AVC denials
ausearch -m AVC -ts recent | audit2why # Explain denials
sealert -a /var/log/audit/audit.log # Human-readable analysis
# File contexts
semanage fcontext -a -t TYPE "/path(/.*)?"
restorecon -Rv /path/
# Ports
semanage port -a -t TYPE -p tcp PORT
# Booleans
setsebool -P BOOLEAN on
# Policy modules
ausearch -m AVC -c APP | audit2allow -M myfix
semodule -i myfix.pp
# Per-domain permissive
semanage permissive -a DOMAIN
semanage permissive -d DOMAIN