3 of 3

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.

  • getsebool
  • setsebool -P
  • semanage boolean
  • ausearch
  • aureport
  • sealert
  • audit2why
  • journalctl -t setroubleshoot
  • /var/log/audit/audit.log

50 min5 exercises

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.

TaskCommand
List allgetsebool -a
Onegetsebool httpd_can_network_connect
With description and defaultsemanage boolean -l
Only what you changedsemanage boolean -l -C
Change until rebootsetsebool NAME on
Change permanentlysetsebool -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_t was denied read on a file of type default_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:

  1. Wrong label on files (most common): restorecon -Rv PATH, or add a rule with semanage fcontext if the location is non-standard.
  2. Port not labelled for the service: semanage port -a -t TYPE -p tcp PORT.
  3. A boolean covers the behaviour: setsebool -P NAME on.
  4. A genuinely new permission: write a small policy module with audit2allow -M mymodule and semodule -i mymodule.pp. This is a last resort: read the generated rules first, because audit2allow will 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

SymptomLadder stepFix
403 on files restored from a backupLabelrestorecon -Rv /web
Service will not start on port 5433Portsemanage port -a -t postgresql_port_t -p tcp 5433
Apache proxy cannot reach a backendBooleansetsebool -P httpd_can_network_connect on
A custom script denied for no visible reasonRead 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.

  1. Warm-up

    Find the boolean for the job

    List all booleans that mention httpd and homedirs, read the description of httpd_enable_homedirs, and state its current and default values.

    Check your result

    getsebool -a | grep httpd_enable_homedirs prints httpd_enable_homedirs --> off. sudo semanage boolean -l | grep httpd_enable_homedirs shows (off , off) and the description.

    Hint

    getsebool -a lists everything; semanage boolean -l adds the state pair (current, default) and a description.

    Solution
    getsebool -a | grep httpd | grep homedirs
    sudo semanage boolean -l | grep httpd_enable_homedirs
  2. Practice

    Runtime or permanent?

    Turn httpd_enable_homedirs on 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 on changes getsebool but semanage boolean -l -C shows nothing. With -P the boolean appears in the -C list as (on , on). After -P ... off the list is empty.

    Hint

    -P writes to the policy store, so the value survives reboot. Without it the change is lost at reboot. -P takes 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
  3. Practice

    Read an AVC message

    Using the 403 from the previous lesson (or by mv-ing a file into /web again), find the newest denial and write down in a sentence: who was refused (scontext type), what they tried to touch (tcontext type and tclass), and which permission. Use two commands: ausearch and audit2why on its output.

    Check your result

    sudo ausearch -m avc -ts recent prints type=AVC ... denied { read } ... scontext=...httpd_t... tcontext=...user_tmp_t... tclass=file. audit2why suggests relabeling, or names a boolean.

    Hint

    ausearch -m avc -ts recent | audit2why (package policycoreutils-python-utils). Time words: recent, today, boot.

    Solution
    sudo ausearch -m avc -ts recent | tail -3
    sudo ausearch -m avc -ts recent | audit2why
  4. Practice

    Let the tool explain it

    Install setroubleshoot-server, restart auditd the supported way if needed, trigger a denial again and read the plain-language explanation with sealert (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.log prints SELinux is preventing httpd from read access on the file ... with a suggested restorecon or semanage command. journalctl -t setroubleshoot carries 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
  5. 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, then audit2allow only 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