Skip to content

Intermediate · SELinux and SSH · topic 32 of 57 · 30 min

Troubleshooting SELinux denials

Explanation

When SELinux blocks something, it writes an AVC denial to /var/log/audit/audit.log. ausearch -m AVC finds them, sealert (from setroubleshoot-server) explains them in plain words and suggests a fix, and the journal shows a short summary. Read the source type, target type and action, then choose: label, boolean or port.

Is it SELinux at all?

Before blaming SELinux, check the usual suspects: is the service running, are normal permissions right, is the firewall open, does the app log say anything? If all that is fine and you still get "Permission denied", look for denials. A quick test, only for a few minutes on a lab or with approval: setenforce 0; if the problem disappears, it was SELinux. Then setenforce 1 and fix it properly.

Reading an AVC denial

bash
# ausearch -m AVC -ts recent
----
time->Mon Oct 19 14:02:11 2026
type=AVC msg=audit(1729326731.402:812): avc:  denied  { read } for  pid=1301 comm="httpd" name="index.html" dev="vdb1" ino=131 scontext=system_u:system_r:httpd_t:s0 tcontext=unconfined_u:object_r:default_t:s0 tclass=file permissive=0
-ts recent means the last 10 minutes; -ts today also works.
PartMeaning here
denied { read }The action that was blocked
comm="httpd"The program that tried
name="index.html"The file (or path=, port= for other objects)
scontext=...httpd_tSource type: the process's domain
tcontext=...default_tTarget type: the file's label
tclass=fileKind of object: file, dir, tcp_socket...
permissive=0It was really blocked (1 would mean only logged)

Here the fix is clear: httpd_t should read web content, and the file is default_t. That is a labelling problem: semanage fcontext + restorecon.

Let sealert explain

bash
# dnf install -y setroubleshoot-server
# journalctl -t setroubleshoot --since "10 min ago"
Oct 19 14:02:14 web01 setroubleshoot[5120]: SELinux is preventing /usr/sbin/httpd from read access on the file index.html. For complete SELinux messages run: sealert -l 7d8a3c1e-...
# sealert -l 7d8a3c1e-...
SELinux is preventing /usr/sbin/httpd from read access on the file index.html.

*****  Plugin restorecon (92.2 confidence) suggests   ************************
If you want to fix the label.
/web/index.html default label should be httpd_sys_content_t.
Then you can run restorecon.
Do
# /sbin/restorecon -v /web/index.html
...
# sealert -a /var/log/audit/audit.log      # analyse all denials in the log

sealert ranks suggestions by confidence. The top one is usually right, but read them all with judgement. If it suggests a boolean, check what the boolean allows before turning it on.

Choosing the fix

Denial looks likeUsual fix
Service reading/writing files with a wrong type (default_t, user_home_t)semanage fcontext -a -t <right_type> + restorecon
Service doing optional things (connect out, read home dirs, use NFS)setsebool -P <boolean> on
name_bind on a port, or "could not bind"semanage port -a -t <service>_port_t -p tcp <port>
Nothing above fits (custom software)Ask the vendor; as a last resort build a small local policy module (audit2allow), reviewed carefully
Careful: audit2allow -M mymodule turns denials straight into allow rules. Used blindly, it can allow exactly what an attacker was trying to do. Use it only after the other three fixes are ruled out, and read the generated rules.

A few more tools

  • audit2why < /var/log/audit/audit.log: explains why each denial happened (missing boolean, wrong label, and so on).
  • Denials that are expected and harmless may be hidden by "dontaudit" rules. semodule -DB disables them temporarily so you can see everything; semodule -B turns them back on.
  • If the audit service is not running, denials go to the journal and dmesg instead.

Common mistakes

  • Searching the whole log with grep and reading old, unrelated denials. Reproduce the problem, then use ausearch -ts recent.
  • Fixing with setenforce 0 and leaving it.
  • Using audit2allow first instead of last.

Need help?

Stuck on a word or an idea? Search this course, or every course, and jump straight to the explanation or a worked question.

Try:

Watch the lesson

Troubleshooting SELinux denials · 1/6

service → perms → firewall → SELinux

First check the service, permissions and firewall. Then look for SELinux denials.

Prefer a video by a teacher? Find free videos on “selinux troubleshooting ausearch sealert audit log tutorial” on YouTube ↗

In real life: A reverse proxy that returned 502 at a SaaS company

A Pune SaaS company put nginx in front of its Node.js API on port 3000. Every request got "502 Bad Gateway". The nginx error log said "connect() to 127.0.0.1:3000 failed (13: Permission denied)". ausearch showed a name_connect denial from httpd_t (nginx runs in that domain) to a port labelled for something else. sealert suggested the boolean httpd_can_network_connect, which the team turned on with -P. SELinux stayed enforcing.

bash
# ausearch -m AVC -ts recent | grep -o 'denied.*tclass=[a-z_]*'
denied  { name_connect } for  pid=2210 comm="nginx" dest=3000 scontext=system_u:system_r:httpd_t:s0 tcontext=system_u:object_r:ntop_port_t:s0 tclass=tcp_socket
# setsebool -P httpd_can_network_connect on

Practice (0/4 done)

Task 1 · Question

Where are SELinux denials logged when auditd is running?

Task 2 · Code · Python

Write parse_avc(line) for an AVC denial line. Return a dict with: action (the word inside { }), comm (without quotes), stype (the third field of scontext), ttype (the third field of tcontext) and tclass. Example line: type=AVC msg=audit(1729326731.402:812): avc: denied { read } for pid=1301 comm="httpd" name="index.html" scontext=system_u:system_r:httpd_t:s0 tcontext=unconfined_u:object_r:default_t:s0 tclass=file permissive=0

Task 3 · Question

A denial shows: denied { name_bind } ... comm="httpd" src=8282 ... tcontext=...unreserved_port_t ... tclass=tcp_socket. Best fix?

Task 4 · Practice

Create a denial on purpose and fix it using only the tools from this lesson: put index.html in your home directory, mv it into /var/www/html, request it with curl, then find and fix the denial.

Quick quiz

Question 1

1.Which command shows SELinux denials from the last few minutes?

Question 2

2.In an AVC line, what is scontext?

Question 3

3.Which package gives you sealert?

Question 4

4.When is audit2allow the right tool?

Read more (free)

Open a question to see the answer and why. The first ones are this topic's own quiz, so try the quiz above before you peek.

Which command shows SELinux denials from the last few minutes?

Answer: ausearch -m AVC -ts recent

ausearch filters audit records by type and time.

In an AVC line, what is scontext?

Answer: The label of the process that tried the action

Source context = the process.

Which package gives you sealert?

Answer: setroubleshoot-server

setroubleshoot-server provides sealert and the journal summaries.

When is audit2allow the right tool?

Answer: Only after label, boolean and port fixes are ruled out, with the rules reviewed

It can allow too much if used blindly.

Which command shows booleans with descriptions?Related

Answer: semanage boolean -l

semanage boolean -l includes descriptions.

From SELinux booleans and port labels

Can setenforce disable SELinux?Related

Answer: No, it only switches between enforcing and permissive

Disabling needs a boot-time change.

From SELinux: what it is and its modes

A file moved with mv from /home/asha to /var/www/html gives 403. Why?Related

Answer: mv keeps the old user_home_t label

Moved files keep their context; run restorecon.

From Contexts and file labels: ls -Z, semanage fcontext and restorecon

Without /var/log/journal, where does journald keep logs?Related

Answer: /run/log/journal, lost at reboot

With Storage=auto and no /var/log/journal, logs stay in /run (RAM).

From Logs: journalctl, rsyslog and a persistent journal

Pass the quiz (60% or more) or mark this topic as done when you are ready.

Your progress is saved on this device only.

Next steps

  1. 1 more topic in “SELinux and SSH” before its exam: SSH: keys, ssh-copy-id and hardening sshd.
  2. Module 6 exam: SELinux and SSH · 13 questions · 25 min, without help. 5 topics of this module still to finish first.
  3. Then the next module, Automation basics: scheduling, archives and shell scripts. 57 topics left in the course before the final exam.

← Previous: SELinux booleans and port labels