SELinux Troubleshooting

Quick Reference

# Check SELinux status
getenforce
sestatus

# Temporarily disable (for testing only)
setenforce 0    # Permissive
setenforce 1    # Enforcing

# Check AVC denials
ausearch -m AVC -ts recent
journalctl -t setroubleshoot

# Fix file contexts
restorecon -Rv /path/to/files

# Check boolean
getsebool httpd_can_network_connect

# Set boolean
setsebool -P httpd_can_network_connect on

# Generate policy from denials
audit2allow -a -M mypolicy
semodule -i mypolicy.pp

Understanding SELinux

What is SELinux?

Security-Enhanced Linux (SELinux) is a Mandatory Access Control (MAC) system:

  • Label-based - Every file, process, port has a security context

  • Policy-driven - Rules define what access is allowed

  • Default deny - Anything not explicitly allowed is denied

  • Fine-grained - Controls specific operations, not just file permissions

SELinux Modes

Mode Description Use Case

Enforcing

Denies access and logs violations

Production systems

Permissive

Allows access but logs violations

Troubleshooting, policy development

Disabled

SELinux completely off

Not recommended (breaks relabeling)

Security Contexts

# Format: user:role:type:level

# Example file context
ls -Z /var/www/html/
# -rw-r--r--. root root unconfined_u:object_r:httpd_sys_content_t:s0 index.html

# Example process context
ps -eZ | grep httpd
# system_u:system_r:httpd_t:s0    httpd

# Components:
# user     - SELinux user (system_u, unconfined_u)
# role     - Role for RBAC (object_r for files)
# type     - Most important! Determines access (httpd_t, httpd_sys_content_t)
# level    - MLS/MCS sensitivity level (s0)

Checking SELinux Status

Current Mode

# Quick check
getenforce
# Returns: Enforcing, Permissive, or Disabled

# Detailed status
sestatus
# SELinux status:                 enabled
# SELinuxfs mount:                /sys/fs/selinux
# SELinux root directory:         /etc/selinux
# Loaded policy name:             targeted
# Current mode:                   enforcing
# Mode from config file:          enforcing

Configuration File

# /etc/selinux/config
cat /etc/selinux/config

# SELINUX=enforcing       # Mode at boot
# SELINUXTYPE=targeted    # Policy type

# Change mode (requires reboot)
sudo sed -i 's/SELINUX=enforcing/SELINUX=permissive/' /etc/selinux/config

Change Mode Temporarily

# Switch to permissive (for troubleshooting)
sudo setenforce 0

# Switch back to enforcing
sudo setenforce 1

# Note: This doesn't survive reboot
# Note: Cannot switch from Disabled to Enforcing without reboot

Finding SELinux Denials

Using ausearch

# Recent denials
ausearch -m AVC -ts recent

# Today's denials
ausearch -m AVC -ts today

# Denials for specific command
ausearch -m AVC -c httpd

# Denials for specific time range
ausearch -m AVC -ts 10:00 -te 11:00

# Denials for specific type
ausearch -m AVC | grep httpd_t

Using journalctl

# setroubleshoot messages
journalctl -t setroubleshoot

# All SELinux-related
journalctl | grep -i selinux

# Follow real-time
journalctl -f | grep -i avc

Using audit.log

# Direct log access
cat /var/log/audit/audit.log | grep AVC

# Using grep for specific type
grep "httpd_t" /var/log/audit/audit.log

# Parse AVC messages
ausearch -m AVC -ts today | audit2why

Understanding AVC Messages

# Example AVC denial:
# type=AVC msg=audit(1234567890.123:456): avc: denied { read } for
# pid=1234 comm="httpd" name="config.txt" dev="sda1" ino=12345
# scontext=system_u:system_r:httpd_t:s0
# tcontext=unconfined_u:object_r:user_home_t:s0 tclass=file

# Breakdown:
# denied { read }    - Operation that was denied
# comm="httpd"       - Process name
# name="config.txt"  - Target file/resource
# scontext=...httpd_t - Source (process) context
# tcontext=...user_home_t - Target (file) context
# tclass=file        - Object class

Fixing Common Issues

Wrong File Context

Most common issue: files have wrong SELinux type.

# Check expected context
semanage fcontext -l | grep /var/www

# Check actual context
ls -Z /var/www/html/

# Restore default context
restorecon -Rv /var/www/html/

# Restore single file
restorecon -v /var/www/html/index.html

Files in Non-Standard Location

# Apache serving from /data/www instead of /var/www

# Add context rule
semanage fcontext -a -t httpd_sys_content_t "/data/www(/.*)?"

# Apply the context
restorecon -Rv /data/www

# Verify
ls -Z /data/www/

# List custom context rules
semanage fcontext -l -C

Process Needs Network Access

# httpd can't connect to network (for proxying)
# Check related booleans
getsebool -a | grep httpd | grep network

# Enable network connection
setsebool -P httpd_can_network_connect on

# For database connections
setsebool -P httpd_can_network_connect_db on

Non-Standard Port

# Service running on non-default port
# httpd on port 8080 instead of 80

# Check current port labels
semanage port -l | grep http

# Add port to allowed list
semanage port -a -t http_port_t -p tcp 8080

# Verify
semanage port -l | grep 8080

Home Directory Access

# Enable user home directory serving (httpd)
setsebool -P httpd_enable_homedirs on

# For read-only access
setsebool -P httpd_read_user_content on

# Fix context for public_html
restorecon -Rv /home/*/public_html

SELinux Booleans

What are Booleans?

Booleans are on/off switches for policy features:

# List all booleans
getsebool -a

# List booleans with descriptions
semanage boolean -l

# Search for specific service
getsebool -a | grep httpd
getsebool -a | grep samba

# Check specific boolean
getsebool httpd_can_network_connect

Common Booleans

# Web server (httpd)
httpd_can_network_connect        # Connect to any port
httpd_can_network_connect_db     # Connect to databases
httpd_can_network_relay          # Act as relay/proxy
httpd_enable_homedirs            # Serve ~/public_html
httpd_use_nfs                    # Access NFS mounts
httpd_use_cifs                   # Access CIFS/SMB mounts
httpd_execmem                    # Execute memory (PHP, etc.)

# Samba
samba_enable_home_dirs           # Share home directories
samba_export_all_ro              # Export all files read-only
samba_export_all_rw              # Export all files read-write

# NFS
nfs_export_all_ro                # Export all read-only
nfs_export_all_rw                # Export all read-write
use_nfs_home_dirs                # Use NFS for home dirs

# SSH
ssh_sysadm_login                 # Allow sysadm_r to login

# FTP
ftpd_anon_write                  # Anonymous FTP write
ftpd_full_access                 # FTP access to all files

Set Booleans

# Temporary (until reboot)
setsebool httpd_can_network_connect on

# Persistent (-P flag)
setsebool -P httpd_can_network_connect on

# Multiple booleans
setsebool -P httpd_can_network_connect=on httpd_enable_homedirs=on

# Turn off
setsebool -P httpd_can_network_connect off

Managing File Contexts

View File Contexts

# Single file
ls -Z /var/www/html/index.html

# Directory listing
ls -laZ /var/www/html/

# Check default context rule
semanage fcontext -l | grep "/var/www"

# Check context for path
matchpathcon /var/www/html/
matchpathcon /etc/httpd/

Add Custom Context

# Add context rule for new directory
semanage fcontext -a -t httpd_sys_content_t "/srv/www(/.*)?"

# Apply context
restorecon -Rv /srv/www

# Add context rule for specific file
semanage fcontext -a -t httpd_sys_rw_content_t "/srv/www/uploads(/.*)?"
restorecon -Rv /srv/www/uploads

Modify Context Rule

# Modify existing rule
semanage fcontext -m -t httpd_sys_rw_content_t "/srv/www(/.*)?"
restorecon -Rv /srv/www

Delete Custom Rule

# Delete custom context rule
semanage fcontext -d "/srv/www(/.*)?"

# List only custom rules
semanage fcontext -l -C

Change Context Temporarily

# Temporary change (until restorecon)
chcon -t httpd_sys_content_t /path/to/file

# Recursive
chcon -R -t httpd_sys_content_t /path/to/directory

# Copy context from reference file
chcon --reference=/var/www/html/index.html /path/to/newfile

Managing Port Contexts

View Port Labels

# All port labels
semanage port -l

# Specific service
semanage port -l | grep http
semanage port -l | grep ssh

# Search by port number
semanage port -l | grep "8080"

Add Port Label

# Add TCP port
semanage port -a -t http_port_t -p tcp 8080

# Add UDP port
semanage port -a -t dns_port_t -p udp 5353

# Add port range
semanage port -a -t http_port_t -p tcp 8080-8090

Modify Port Label

# Change port type (if already exists)
semanage port -m -t http_port_t -p tcp 8080

Delete Port Label

# Delete custom port label
semanage port -d -t http_port_t -p tcp 8080

# List custom port rules
semanage port -l -C

Creating Custom Policies

Using audit2allow

# Generate policy from recent denials
audit2allow -a

# Generate loadable module
audit2allow -a -M mymodule
# Creates mymodule.pp and mymodule.te

# Review what would be allowed
audit2allow -a -w    # With explanations

# Install the module
semodule -i mymodule.pp

From Specific Denials

# Generate from specific log
cat /var/log/audit/audit.log | audit2allow -M mymodule

# Generate from recent denials
ausearch -m AVC -ts recent | audit2allow -M mymodule

# For specific process
ausearch -m AVC -c httpd | audit2allow -M httpd_custom

Module Management

# List installed modules
semodule -l

# Install module
semodule -i mymodule.pp

# Remove module
semodule -r mymodule

# Disable module
semodule -d mymodule

# Enable module
semodule -e mymodule

Troubleshooting Workflow

Step-by-Step Process

# 1. Identify the problem
# Application fails, check logs

# 2. Check if SELinux is blocking
ausearch -m AVC -ts recent

# 3. Understand the denial
ausearch -m AVC -ts recent | audit2why

# 4. Try common fixes first:
#    - Check file contexts
#    - Check booleans
#    - Check port labels

# 5. If custom policy needed
audit2allow -a -M myfix
semodule -i myfix.pp

# 6. Verify fix works
# Test application
ausearch -m AVC -ts recent   # Should be empty

Using setroubleshoot

# Install setroubleshoot
# RHEL/CentOS
sudo dnf install setroubleshoot-server

# View suggestions
sealert -a /var/log/audit/audit.log

# Real-time notification
# setroubleshoot daemon provides desktop notifications
# and detailed solutions in /var/log/messages

Permissive Mode Testing

# Switch to permissive to test
setenforce 0

# Run application, collect denials
ausearch -m AVC -ts recent

# Generate policy
audit2allow -a -M testpolicy

# Review policy before installing
cat testpolicy.te

# Switch back to enforcing
setenforce 1

# Install policy if appropriate
semodule -i testpolicy.pp

Common Scenarios

Web Server Custom Content

# Scenario: Apache serving from /data/websites

# 1. Add context rule
semanage fcontext -a -t httpd_sys_content_t "/data/websites(/.*)?"

# 2. For writable directories (uploads)
semanage fcontext -a -t httpd_sys_rw_content_t "/data/websites/uploads(/.*)?"

# 3. Apply contexts
restorecon -Rv /data/websites

# 4. Enable network if needed
setsebool -P httpd_can_network_connect on

Container/Podman Issues

# Scenario: Podman container can't access host files

# 1. Check volume mount has correct label
podman run -v /data:/data:Z myimage    # Private label
podman run -v /data:/data:z myimage    # Shared label

# 2. Or use container-specific booleans
setsebool -P container_manage_cgroup on

# 3. Check container SELinux status
ps -eZ | grep container

Database Access from Web App

# Scenario: PHP can't connect to MySQL

# 1. Check boolean
getsebool httpd_can_network_connect_db

# 2. Enable if needed
setsebool -P httpd_can_network_connect_db on

# 3. For remote database
setsebool -P httpd_can_network_connect on

SSH Custom Port

# Scenario: SSH on port 2222

# 1. Add port label
semanage port -a -t ssh_port_t -p tcp 2222

# 2. Verify
semanage port -l | grep ssh

# 3. Restart sshd
systemctl restart sshd

Quick Command Reference

# Status
getenforce                               # Current mode
sestatus                                 # Detailed status
setenforce 0|1                           # Set permissive|enforcing

# Finding denials
ausearch -m AVC -ts recent               # Recent denials
ausearch -m AVC -ts today                # Today's denials
journalctl -t setroubleshoot             # Setroubleshoot messages

# File contexts
ls -Z /path                              # View context
semanage fcontext -l | grep PATH         # List rules
semanage fcontext -a -t TYPE "PATH"      # Add rule
restorecon -Rv /path                     # Apply context
chcon -t TYPE /path                      # Temporary change

# Booleans
getsebool -a | grep KEYWORD              # List booleans
setsebool -P BOOLEAN on|off              # Set persistent

# Ports
semanage port -l | grep TYPE             # List ports
semanage port -a -t TYPE -p tcp PORT     # Add port

# Policy modules
audit2allow -a -M module                 # Create module
semodule -i module.pp                    # Install module
semodule -l                              # List modules
semodule -r module                       # Remove module