Getting help with denials for SELinux

May 31, 2021

On some distributions, additional support tools are available that help us identify the cause of a denial. These tools have some knowledge of common mistakes (for instance, setting the right context on files to allow the web server to read them). Other distributions require us to use our experience to make proper decisions, supporting us through the distribution mailing lists, bug tracking sites, and other cooperation locations—for example, Internet Relay Chat (IRC).

Troubleshooting with setroubleshoot

In CentOS (and other Red Hat Enterprise Linux (RHEL)-related distributions such as Fedora), additional tools are present that help us troubleshoot denials. The tools work together to catch a denial, look for a plausible solution, and inform the administrator about the denial and its suggested resolutions.

When used on a graphical workstation, denials can even result in popups that ask the administrator to review them immediately. Install the setroubleshoot package to get this support. On servers without a graphical environment, administrators can see the information in the system logs or can even configure the system to send out SELinux denial messages via email. Install the setroubleshoot-server package to get this support.

Under the hood, it is the audit daemon that triggers its audit event dispatcher application (audispd). This application supports plugins, something the SELinux folks gratefully implemented. They built an application called sedispatch that will act as a plugin for audispd. The sedispatch application checks whether the audit event is an SELinux denial and, if so, forwards the events to D-Bus. D-Bus then forwards the events to the setroubleshootd application (or launches the application if it isn’t running yet), which analyzes the denial and prepares feedback for the administrator.

When running on a workstation, seapplet is triggered to show a popup on the administrator workstation. The administrator can then select Show to view more details. Administrators don’t need a graphical user interface to be informed about SELinux issues, though. You can find analyzed feedback on the filesystem, and in the system logs you can read how to easily reach this information, as illustrated in the following code snippet:

Mar 22 11:40:35 ppubssa3ed setroubleshoot[1544]: SELinux is preventing /usr/sbin/nginx from name_bind access on the tcp_socket port 89. For complete SELinux messages run: sealert -l f2914dba-04ef-44ca-9a0b-0f5e62ec72e4

We can look at a complete explanation through the sealert command (as mentioned in the log), as follows:

# sealert -l f2914dba-04ef-44ca-9a0b-0f5e62ec72e4
SELinux is preventing /usr/sbin/nginx from name_bind access on the tcp_socket port 89.
***** Plugin bind_ports (99.5 confidence) suggests ************************
If you want to allow /usr/sbin/nginx to bind to network port 89
Then you need to modify the port type.
Do
# semanage port -a -t PORT_TYPE -p tcp 89
 where PORT_TYPE is one of the following: http_cache_port_t, http_port_t, jboss_management_port_t, jboss_messaging_port_t, ntop_port_t, puppet_port_t.
***** Plugin catchall (1.49 confidence) suggests **************************
...

The sealert application is a command-line application that parses the information stored by the setroubleshoot daemon (in /var/lib/setroubleshoot).

This will provide us with a set of options to resolve the denial. In the case of the Apache-related denial shown earlier, sealert gives us one option with a certain confidence score. Depending on the problem, this tool might show multiple options, each with its own confidence figure (that is, how certain sealert is that this is the right resolution).

As we can see from this example, the setroubleshoot application itself uses plugins to analyze denials. These plugins (offered through the setroubleshoot-plugins package) look at a denial to check whether they match a particular, well-known use case (for example, when to change an SELinux Boolean or when a target resource has a wrong context) and give feedback to setroubleshoot about how certain the plugin is so that this denial can be resolved through its recommended method.

Sending emails when SELinux denials occur

Once a system is fine-tuned and denials no longer occur regularly, administrators can opt to have setroubleshootd send emails whenever a new denial comes up. This truly brings SELinux’s host intrusion detection/prevention capabilities on top, as administrators do not need to constantly watch their logs for information. However, keep in mind that this could lead to a sudden burst in emails, which might result in Denial of Service (DoS)-like behavior, if many denials are triggered. Administrators should only implement this if their email infrastructure has rate limiting or other Quality of Service (QoS) controls in place.

Open /etc/setroubleshoot/setroubleshoot.conf in a text editor and locate the [email] section. Update the parameters to match the local mailing infrastructure, as follows:

setroubleshoot.conf

# vi /etc/setroubleshoot/setroubleshoot.conf
[email]
recipients_filepath = /var/lib/setroubleshoot/email_alert_recipients
smtp_port = 25
smtp_host = localhost
from_address = selinux@infra.example.com
subject = [infra] SELinux Alert for host infra.example.com

Next, edit the email_alert_recipients  file (as referenced through the  recipients_filepath  variable), and add the email addresses that need to be notified when an SELinux alert comes up.

Finally, restart the D-Bus daemon, as follows:

# systemctl restart dbus

When working on a non-systemd system, use the following command instead:

# service dbus restart

The D-Bus restart is needed as D-Bus manages the setroubleshootd daemon.

Using audit2why

If setroubleshoot and sealert are not available in the Linux distribution, we can still get some information about a denial. Although it isn’t as extensive as the plugins offered by setroubleshoot, the audit2why utility (which is short for audit2allow -w) does provide some feedback on a denial. Sadly, it isn’t always right in its deduction.

Let’s try it out against the same denial for which we used sealert, as follows:

# ausearch -m avc -ts recent | audit2why
type=AVC msg=audit(1584880436.644:385): avc:  denied  { name_bind } for  pid=5119 comm="nginx" src=89 scontext=system_u:system_r:httpd_t:s0 tcontext=system_u:object_r:reserved_port_t:s0 tclass=tcp_socket permissive=0
  Was caused by:
    Missing type enforcement (TE) allow rule.
    You can use audit2allow to generate a loadable module to allow this access.

The audit2why utility here didn’t consider that the context of the target location was wrong, and it suggests that the policy be updated to allow the web server to bind to the unreserved_port_t type, unlike the information provided by setroubleshoot, which was more accurate, recommending that the target port be relabeled instead.

As the output of the command mentions, another tool exists called audit2allow, which can convert a denial into an SELinux policy.

Interacting with systemd-journal

Alongside the Linux audit system, which is used for most SELinux logging and events, we can also gather information through other logging systems. systemd’s journal, for instance, captures SELinux context information with the events and allows administrators to use this information while querying the journal.

For instance, to see the events in systemd-journal that are generated by an application associated with the system_u:system_r:sssd_t:s0 context, the following command can be used:

# journalctl _SELINUX_CONTEXT="system_u:system_r:sssd_t:s0"
-- Logs begin at Sun 2020-03-22 10:43:48 UTC, end at Sun 2020-03-22 12:40:12 UTC. --
Mar 22 10:43:51 ppubssa3ed sssd[545]: Starting up
Mar 22 10:43:51 ppubssa3ed sssd[be[implicit_files]][623]: Starting up
Mar 22 10:43:51 ppubssa3ed sssd[nss][630]: Starting up

Because systemd-journal adds the SELinux context of the originating application, it is harder for malicious applications to generate fake events. Whereas regular system loggers just capture string events, systemd-journal retrieves the SELinux context from the system. Using the SELinux context, it is easy to group events across different but strongly related applications and have a higher guarantee that events come from a particular application.

When the bash-completion package is installed, we can even use it to see which SELinux contexts are present in the systemd-journal logs, which makes querying the journal logs much easier, as follows:

# journalctl _SELINUX_CONTEXT=<tab><tab>
kernel
system_u:system_r:auditd_t:s0
system_u:system_r:chronyd_t:s0
...

To find messages related to nginx, use the embedded grep filter, as follows:

# journalctl -g nginx
-- Logs begin at Sun 2020-03-22 10:43:48 UTC, end at Sun 2020-03-22 12:52:26 UTC. --
Mar 22 11:40:32 ppubssa3ed systemd[1]: Starting The nginx HTTP and reverse proxy server...
Mar 22 11:40:32 ppubssa3ed nginx[1538]: nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
Mar 22 11:40:32 ppubssa3ed nginx[1538]: nginx: [emerg] bind() to 0.0.0.0:89 failed (13: Permission denied)
...
Mar 22 11:40:35 ppubssa3ed setroubleshoot[1544]: SELinux is preventing /usr/sbin/nginx from name_bind access on the tcp_socket port 89. For complete SELinux messages run: sealert -l f2914dba-04ef-44ca-9a0b-0f5e62ec72e4

The benefit of the embedded grep filter is that journalctl will still show the multiline messages, whereas actually redirecting the journalctl output through grep would only show the individual lines that match the expression.

Using common sense

Common sense is not easy to document, but reading a denial often leads to the right solution when we have some experience with file labels (and what they are used for). If we get a denial about a web server failing to read its files, and the context of the file is (for instance) user_home_t, then that should ring a bell. End user home files, for instance, use the user_home_t context, which is not suitable for system files that the web server reads.

One way to make sure that the context of the target resource is correct is to verify it with matchpathcon. This utility returns the context as it should be according to the SELinux policy, as follows:

$ matchpathcon /srv/www/html/index.html
/srv/www/html/index.html	system_u:object_r:httpd_sys_content_t:s0

Performing this for denials related to files and directories might help in finding a proper solution quickly.

Furthermore, many domains have specific manual pages that inform the reader about types commonly used for each domain, as well as how to deal with the domain in more detail (for example, the available booleans, common mistakes made, and so on). These manual pages start with the main service and are suffixed with _selinux, as illustrated here:

$ man ftpd_selinux

In most cases, the approach to handling denials can be best described as follows:

  • Is the target resource label (such as the file label) the right one? Verify this with matchpathcon, or compare with labels of working (accessible) resources.
  • Is the source label (the domain) the expected one? An SSH daemon should run in the sshd_t domain, not the init_t domain. If this is not the case, make sure that the labels of the application itself (such as its executable binary) are correct (again, use matchpathcon for this).
  • Is the denial one that might be covered by an SELinux boolean? In that case, the policy might already have the appropriate rules in place, only requiring a change in an SELinux boolean value. setroubleshootd will report this if it is the case. Usually, the manual page of the domain (such as httpd_selinux) will also cover the available SELinux Booleans. 

To close off this article, common sense will be your most prolific approach to managing SELinux denials, but the aforementioned tools will be of assistance to begin with.

Related Articles

No Results Found

The page you requested could not be found. Try refining your search, or use the navigation above to locate the post.

Lorem ipsum dolor sit amet consectetur

0 Comments

Submit a Comment

Your email address will not be published. Required fields are marked *

one × 2 =