SELinux BasicsLesson 3 of 3
Booleans and troubleshooting denials
Switch policy features with booleans, read an AVC message, and choose the smallest correct fix instead of turning SELinux off.
getseboolsetsebool -Psemanage booleanausearchaureportsealertaudit2whyjournalctl -t setroubleshoot/var/log/audit/audit.log
After this lesson you can
- List booleans, change one for now and permanently, and say when a boolean is the right fix.
- Find denials in the audit log with ausearch, and read scontext, tcontext, class and permission.
- Follow a repeatable workflow to decide between a label fix, a port label, a boolean or (rarely) a custom module.
The idea
Booleans
The policy ships with booleans: switches that turn optional behaviours on or off without writing any policy. httpd_can_network_connect lets Apache open outbound connections (needed for a reverse proxy), httpd_enable_homedirs lets it serve users’ home directories, use_nfs_home_dirs allows NFS home directories, and hundreds more.
| Task | Command |
|---|---|
| List all | getsebool -a |
| One | getsebool httpd_can_network_connect |
| With description and default | semanage boolean -l |
| Only what you changed | semanage boolean -l -C |
| Change until reboot | setsebool NAME on |
| Change permanently | setsebool -P NAME on |
The -P is the whole difference between a task you pass and one you fail: without it the value reverts at reboot. Use getsebool -a | grep KEYWORD to find the one you need.
Denials: where they go
Every refusal is an AVC (Access Vector Cache) message in /var/log/audit/audit.log, written by auditd. Search it with ausearch:
sudo ausearch -m avc -ts recent # last 10 minutes
sudo ausearch -m avc -ts today
sudo ausearch -m avc -ts boot
A denial reads like a sentence:
avc: denied { read } for pid=3401 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
The process of type
httpd_twas deniedreadon afileof typedefault_t.
The four things to extract: scontext (who: the process type), tcontext (what: the object’s type), tclass (kind of object: file, dir, tcp_socket, …) and the permission in braces. permissive=1 means it was only logged.
ausearch ... | audit2why explains each denial and often names the boolean or says “allow this by relabeling”. The setroubleshoot-server package adds sealert -a /var/log/audit/audit.log (plain-language reports with suggested commands) and puts short messages in the journal under the tag setroubleshoot.
The decision ladder
Do not guess; follow this order and stop at the first that applies:
- Wrong label on files (most common):
restorecon -Rv PATH, or add a rule withsemanage fcontextif the location is non-standard. - Port not labelled for the service:
semanage port -a -t TYPE -p tcp PORT. - A boolean covers the behaviour:
setsebool -P NAME on. - A genuinely new permission: write a small policy module with
audit2allow -M mymoduleandsemodule -i mymodule.pp. This is a last resort: read the generated rules first, becauseaudit2allowwill happily allow an attack.
Never fix a denial with setenforce 0 and walk away, and do not disable SELinux “because it was in the way”. Permissive mode is for diagnosis: set it, reproduce the problem, read what was logged (all the denials appear at once instead of one at a time), set enforcing again, apply the proper fix.
Try it
getsebool -a | grep httpd_enable_homedirs
sudo semanage boolean -l | grep httpd_enable_homedirs
httpd_enable_homedirs --> off
httpd_enable_homedirs (off , off) Allow httpd to enable homedirs
The pair is (current, default).
sudo setsebool httpd_enable_homedirs on
sudo semanage boolean -l -C
sudo setsebool -P httpd_enable_homedirs on
sudo semanage boolean -l -C
SELinux boolean State Default Description
httpd_enable_homedirs (on , on) Allow httpd to enable homedirs
The first -C listing printed nothing: the runtime change was not recorded. After -P it is listed. Switch it off again with -P ... off.
Read a denial
sudo ausearch -m avc -ts recent | tail -1
sudo ausearch -m avc -ts recent | audit2why
type=AVC msg=audit(1762171201.431:340): avc: denied { read } for pid=3512 comm="httpd" name="moved.html" dev="vda3" ino=140 scontext=system_u:system_r:httpd_t:s0 tcontext=unconfined_u:object_r:user_tmp_t:s0 tclass=file permissive=0
Was caused by:
Missing type enforcement (TE) allow rule.
You can use audit2allow to generate a loadable module to allow this access.
For a label problem audit2why often says “Missing type enforcement rule”, which is not a recommendation to add a rule: look at tcontext. A user_tmp_t file in the web root is mislabelled, and restorecon -Rv /web is the fix. For a boolean, audit2why says Was caused by: The boolean httpd_enable_homedirs was set incorrectly. Allow access by executing: setsebool -P httpd_enable_homedirs 1.
sealert
sudo dnf install -y setroubleshoot-server
sudo sealert -a /var/log/audit/audit.log | head -12
100% done
found 1 alerts in /var/log/audit/audit.log
--------------------------------------------------------------------------------
SELinux is preventing /usr/sbin/httpd from read access on the file moved.html.
***** Plugin restorecon (99.5 confidence) suggests ************************
If you want to fix the label.
/web/moved.html default label should be httpd_sys_content_t.
Then you can run restorecon. The access attempt may have been stopped due to insufficient permissions to access a parent directory in which case try to change the following command accordingly.
Do
# /sbin/restorecon -v /web/moved.html
Four failures, four fixes
| Symptom | Ladder step | Fix |
|---|---|---|
| 403 on files restored from a backup | Label | restorecon -Rv /web |
| Service will not start on port 5433 | Port | semanage port -a -t postgresql_port_t -p tcp 5433 |
| Apache proxy cannot reach a backend | Boolean | setsebool -P httpd_can_network_connect on |
| A custom script denied for no visible reason | Read the AVC, then module | `ausearch … |
Going further
aureport -a summarises AVC denials; aureport --avc --summary shows counts by command. semodule -l lists loaded modules and semodule -r NAME removes one you added. sesearch -A -s httpd_t -b httpd_enable_homedirs shows what a boolean actually allows. For containers, container_t and the container_file_t label (:Z or :z on volume mounts) follow exactly the same logic. Finally, getenforce, ls -Z, ausearch -m avc -ts recent is the three-command opening to any SELinux investigation.
Practice
0 of 5 done
Do these on your own system. They get harder. Check each result, then tick it off.
- Warm-up
Find the boolean for the job
List all booleans that mention
httpdandhomedirs, read the description ofhttpd_enable_homedirs, and state its current and default values.Check your result
getsebool -a | grep httpd_enable_homedirsprintshttpd_enable_homedirs --> off.sudo semanage boolean -l | grep httpd_enable_homedirsshows(off , off)and the description.Hint
getsebool -alists everything;semanage boolean -ladds the state pair (current, default) and a description.Solution
getsebool -a | grep httpd | grep homedirs sudo semanage boolean -l | grep httpd_enable_homedirs - Practice
Runtime or permanent?
Turn
httpd_enable_homedirson only for now, check, then turn it on permanently and prove the difference by looking at the list of locally changed booleans. Finally turn it back off permanently.Check your result
setsebool httpd_enable_homedirs onchangesgetseboolbutsemanage boolean -l -Cshows nothing. With-Pthe boolean appears in the-Clist as(on , on). After-P ... offthe list is empty.Hint
-Pwrites to the policy store, so the value survives reboot. Without it the change is lost at reboot.-Ptakes a few seconds.Solution
sudo setsebool httpd_enable_homedirs on getsebool httpd_enable_homedirs sudo semanage boolean -l -C sudo setsebool -P httpd_enable_homedirs on sudo semanage boolean -l -C sudo setsebool -P httpd_enable_homedirs off - Practice
Read an AVC message
Using the 403 from the previous lesson (or by
mv-ing a file into/webagain), find the newest denial and write down in a sentence: who was refused (scontexttype), what they tried to touch (tcontexttype andtclass), and which permission. Use two commands:ausearchandaudit2whyon its output.Check your result
sudo ausearch -m avc -ts recentprintstype=AVC ... denied { read } ... scontext=...httpd_t... tcontext=...user_tmp_t... tclass=file.audit2whysuggests relabeling, or names a boolean.Hint
ausearch -m avc -ts recent | audit2why(packagepolicycoreutils-python-utils). Time words:recent,today,boot.Solution
sudo ausearch -m avc -ts recent | tail -3 sudo ausearch -m avc -ts recent | audit2why - Practice
Let the tool explain it
Install
setroubleshoot-server, restartauditdthe supported way if needed, trigger a denial again and read the plain-language explanation withsealert(or from the journal). Note what fix it recommends and compare it with what you would have chosen.Check your result
sudo sealert -a /var/log/audit/audit.logprintsSELinux is preventing httpd from read access on the file ...with a suggestedrestoreconorsemanagecommand.journalctl -t setroubleshootcarries a short version.Hint
sudo dnf install -y setroubleshoot-server. sealert's top suggestion is usually, but not always, right: read the confidence figure.Solution
sudo dnf install -y setroubleshoot-server sudo sealert -a /var/log/audit/audit.log | head -30 sudo journalctl -t setroubleshoot --no-pager | tail -3 - Challenge
Pick the right fix for four failures
For each failure name the fix and the command: (a) Apache returns 403 for files you copied from a backup archive; (b) a database service will not start on port 5433; (c) Apache cannot connect to an application server on another host (
proxy); (d) a script that works as root fails under cron with a denial you cannot explain by labels or ports.Check your result
(a) wrong label:
restorecon -Rv; (b) port label:semanage port -a -t postgresql_port_t -p tcp 5433; (c) boolean:setsebool -P httpd_can_network_connect on; (d) read the AVC, thenaudit2allowonly as a last resort.Hint
Work down the list of fixes from the least to the most invasive: label, port, boolean, custom module.
Solution
# (a) sudo restorecon -Rv /web # (b) sudo semanage port -a -t postgresql_port_t -p tcp 5433 # (c) sudo setsebool -P httpd_can_network_connect on # (d) sudo ausearch -m avc -ts recent | audit2why