Diagnose and Fix SELinux Denials on Fedora Without Disabling Enforcement
A step-by-step diagnostic guide for resolving SELinux denials on Fedora while keeping enforcement active. Covers recognizing AVC messages, mapping denials to policy gaps, and applying targeted fixes including boolean toggles, file relabeling, and custom policy modules.
05 Mar 2026, 16:12 UTC

Recognizable Condition
An application fails with "Permission denied" despite correct discretionary access control (DAC) permissions. The service logs show no obvious filesystem errors, but journalctl -t setroubleshoot or ausearch -m AVC reveals recent SELinux denials with scontext/tcontext labels indicating a mandatory access control (MAC) block.
Cause and Diagnostic Reference
| Symptom Pattern | Likely Cause | Primary Evidence |
|---|---|---|
| New binary or script runs in wrong domain | Missing type transition rule | AVC shows scontext=unconfined_u:unconfined_r:unconfined_t but process needs httpd_t or similar |
| Service needs network, NIS, or other extended access | Required boolean is off | getsebool -a | grep httpd shows httpd_can_network_connect off |
| Files created outside standard locations | Non-standard file label | ls -Z /custom/path shows default_t instead of expected httpd_sys_content_t |
| Custom application or modified service | Policy gap for new operations | AVC references comm="myapp" with no matching allow rule |
| User login maps to wrong SELinux user | Confined user mapping mismatch | semanage login -l shows user_u instead of staff_u for admin account |
Ordered Diagnostic Checks
- Capture raw denials: Run
ausearch -m AVC -ts recentas root. This queries the audit log for AVC messages from the last boot. Look fordeniedentries withscontext/tcontextpairs. - Generate human-readable analysis: Pipe the audit log to
sealert -a /var/log/audit/audit.log. Each alert includes a UUID, summary, and suggested fix. Note the UUID for later verification. - Verify file contexts: Compare
ls -Z /path/to/fileoutput againstsemanage fcontext -l | grep /path/to/file. Mismatches indicate labeling issues. - Inspect relevant booleans: Run
getsebool -a | grep <service>(e.g.,httpd,ftpd,nfs). Booleans control high-level policy toggles. - Confirm process domain: Use
ps -eZ | grep <pid>to see the actual SELinux domain a process runs in. Compare with expected domain from policy. - Test with permissive domain (targeted debugging): Run
semanage permissive -a <domain_t>to put only that domain in permissive mode. This collects denials without blocking operations. Requires root; removes after debugging withsemanage permissive -d <domain_t>.
Fixes Tied to Findings
1. Missing Type Transition — Add File Context and Relabel
When a binary in a non-standard location (e.g., /opt/myapp/bin/server) runs as unconfined_t instead of the confined service domain:
# Add persistent file context rule
semanage fcontext -a -t httpd_exec_t '/opt/myapp/bin/server'
# Apply the label
restorecon -Rv /opt/myapp/bin/server
Where to run: Root shell on the host. Risk: Incorrect type assignment can over-privilege the binary. Verify with matchpathcon -V /opt/myapp/bin/server after relabel.
2. Boolean Off — Enable Persistently
For a web application needing outbound database connections:
setsebool -P httpd_can_network_connect on
Where to run: Root shell. Check: getsebool httpd_can_network_connect returns on. The -P flag writes to persistent policy store.
3. Non-Standard File Label — Targeted Relabel
After deploying content to /srv/webapp:
# Dry-run first
restorecon -n -v /srv/webapp
# Actual relabel
restorecon -Rv /srv/webapp
Where to run: Root shell. Limitation: Full filesystem relabel (autorelabel) takes significant time on large volumes; prefer targeted restorecon.
4. Custom Policy Gap — Build Local Module
For a custom daemon myapp generating denials:
# Generate policy from recent denials for this command
ausearch -c 'myapp' --raw | audit2allow -M local_myapp
# Review the generated .te file before compiling
cat local_myapp.te
# Install module
semodule -i local_myapp.pp
Where to run: Root shell. Critical caution: audit2allow generates allow rules that may be overly broad. Always review the .te file and narrow permissions to specific types/classes. Verification: semodule -l | grep local_myapp lists the module; semodule -V confirms version compatibility.
5. Confined User Mapping — Adjust Login Record
For an administrator needing staff_r role:
semanage login -m -s staff_u -r s0-s0:c0.c1023 myadmin
Where to run: Root shell. Effect: Takes effect on next login. Risk: Incorrect range can lock out the user; test with a secondary session first.
Escalation Criteria
- Denials persist after local module install: Check for
dontauditrules hiding secondary denials. Runsemodule -DBto disable dontaudit temporarily, reproduce, thensemodule -Bto re-enable. - Multiple domains involved: May require interface or filetype declarations in a more comprehensive policy module. Consider upstreaming if the service is packaged.
- Kernel audit shows
type=SELINUX_ERR: Possible policy corruption. Reload base policy withsemodule -R. - Critical service blocked (sshd, systemd): Boot with
enforcing=0kernel parameter, collect full audit log, file bug againstselinux-policycomponent. Do not leave system in permissive mode.
Verification Checklist
- Reproduce the original operation that triggered the denial.
- Run
ausearch -m AVC -ts recent— confirm no new AVC messages appear. - Run
sealert -a /var/log/audit/audit.log— verify the specific alert UUID is no longer reported. - Check service status:
systemctl status <service>shows active/running with successful operation logs. - Validate file contexts:
matchpathcon -V /corrected/pathshows "verified". - Confirm boolean persistence: reboot, then
getsebool <bool>still returnson. - For custom modules:
semodule -l | grep local_lists module;semodule -Vshows no version conflicts afterdnf update selinux-policy.
Limitations and Container Note
Fedora's targeted policy confines only selected services; processes running as unconfined_u bypass SELinux entirely. Container runtimes (Podman) use separate SELinux labels (container_file_t, container_runtime_t); host fixes do not apply inside containers. Custom modules survive policy updates but may conflict with upstream changes — audit after each dnf update selinux-policy.
Rollback Procedures
- Boolean change:
setsebool -P <bool> off - File context rule:
semanage fcontext -d '/path'thenrestorecon -Rv /path - Local policy module:
semodule -r local_<name> - Permissive domain:
semanage permissive -d <domain_t> - User mapping:
semanage login -m -s <original_seuser> <login>
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.