Chapter 1. Getting started with SELinux
Security Enhanced Linux (SELinux) provides an additional layer of system security. SELinux fundamentally answers the question: May <subject> do <action> to <object>?, for example: May a web server access files in users' home directories?
1.1. Introduction to SELinux
The standard access policy based on the user, group, and other permissions, known as Discretionary Access Control (DAC), does not enable system administrators to create comprehensive and fine-grained security policies, such as restricting specific applications to only viewing log files, while allowing other applications to append new data to the log files.
Security Enhanced Linux (SELinux) implements Mandatory Access Control (MAC). Every process and system resource has a special security label called an SELinux context. A SELinux context, sometimes referred to as an SELinux label, is an identifier which abstracts away the system-level details and focuses on the security properties of the entity. Not only does this provide a consistent way of referencing objects in the SELinux policy, but it also removes any ambiguity that can be found in other identification methods. For example, a file can have multiple valid path names on a system that makes use of bind mounts.
The SELinux policy uses these contexts in a series of rules which define how processes can interact with each other and the various system resources. By default, the policy does not allow any interaction unless a rule explicitly grants access.
Remember that SELinux policy rules are checked after DAC rules. SELinux policy rules are not used if DAC rules deny access first, which means that no SELinux denial is logged if the traditional DAC rules prevent the access.
SELinux contexts have several fields: user, role, type, and security level. The SELinux type information is perhaps the most important when it comes to the SELinux policy, as the most common policy rule which defines the allowed interactions between processes and system resources uses SELinux types and not the full SELinux context. SELinux types end with _t
. For example, the type name for the web server is httpd_t
. The type context for files and directories normally found in /var/www/html/
is httpd_sys_content_t
. The type contexts for files and directories normally found in /tmp
and /var/tmp/
is tmp_t
. The type context for web server ports is http_port_t
.
There is a policy rule that permits Apache (the web server process running as httpd_t
) to access files and directories with a context normally found in /var/www/html/
and other web server directories (httpd_sys_content_t
). There is no allow rule in the policy for files normally found in /tmp
and /var/tmp/
, so access is not permitted. With SELinux, even if Apache is compromised, and a malicious script gains access, it is still not able to access the /tmp
directory.
Figure 1.1. An example how can SELinux help to run Apache and MariaDB in a secure way.
As the previous scheme shows, SELinux allows the Apache process running as httpd_t
to access the /var/www/html/
directory and it denies the same process to access the /data/mysql/
directory because there is no allow rule for the httpd_t
and mysqld_db_t
type contexts. On the other hand, the MariaDB process running as mysqld_t
is able to access the /data/mysql/
directory and SELinux also correctly denies the process with the mysqld_t
type to access the /var/www/html/
directory labeled as httpd_sys_content_t
.
Additional resources
-
selinux(8)
man page and man pages listed by theapropos selinux
command. -
Man pages listed by the
man -k _selinux
command when theselinux-policy-doc
package is installed. - The SELinux Coloring Book helps you to better understand SELinux basic concepts.
- SELinux Wiki FAQ
1.2. Benefits of running SELinux
SELinux provides the following benefits:
- All processes and files are labeled. SELinux policy rules define how processes interact with files, as well as how processes interact with each other. Access is only allowed if an SELinux policy rule exists that specifically allows it.
- SELinux provides fine-grained access control. Stepping beyond traditional UNIX permissions that are controlled at user discretion and based on Linux user and group IDs, SELinux access decisions are based on all available information, such as an SELinux user, role, type, and, optionally, a security level.
- SELinux policy is administratively-defined and enforced system-wide.
- SELinux can mitigate privilege escalation attacks. Processes run in domains, and are therefore separated from each other. SELinux policy rules define how processes access files and other processes. If a process is compromised, the attacker only has access to the normal functions of that process, and to files the process has been configured to have access to. For example, if the Apache HTTP Server is compromised, an attacker cannot use that process to read files in user home directories, unless a specific SELinux policy rule was added or configured to allow such access.
- SELinux can enforce data confidentiality and integrity, and can protect processes from untrusted inputs.
SELinux is designed to enhance existing security solutions, not replace antivirus software, secure passwords, firewalls, or other security systems. Even when running SELinux, it is important to continue to follow good security practices, such as keeping software up-to-date, using hard-to-guess passwords, and firewalls.
1.3. SELinux examples
The following examples demonstrate how SELinux increases security:
- The default action is deny. If an SELinux policy rule does not exist to allow access, such as for a process opening a file, access is denied.
-
SELinux can confine Linux users. A number of confined SELinux users exist in the SELinux policy. Linux users can be mapped to confined SELinux users to take advantage of the security rules and mechanisms applied to them. For example, mapping a Linux user to the SELinux
user_u
user, results in a Linux user that is not able to run unless configured otherwise set user ID (setuid) applications, such assudo
andsu
. - Increased process and data separation. The concept of SELinux domains allows defining which processes can access certain files and directories. For example, when running SELinux, unless otherwise configured, an attacker cannot compromise a Samba server, and then use that Samba server as an attack vector to read and write to files used by other processes, such as MariaDB databases.
-
SELinux helps mitigate the damage made by configuration mistakes. Domain Name System (DNS) servers often replicate information between each other in a zone transfer. Attackers can use zone transfers to update DNS servers with false information. When running the Berkeley Internet Name Domain (BIND) as a DNS server in RHEL, even if an administrator forgets to limit which servers can perform a zone transfer, the default SELinux policy prevent updates for zone files [1] that use zone transfers, by the BIND
named
daemon itself, and by other processes. -
Without SELinux, an attacker can misuse a vulnerability to path traversal on an Apache web server and access files and directories stored on the file system by using special elements such as
../
. If an attacker attempts an attack on a server running with SELinux in enforcing mode, SELinux denies access to files that thehttpd
process must not access. SELinux cannot block this type of attack completely but it effectively mitigates it. -
SELinux in enforcing mode successfully prevents exploitation of kernel NULL pointer dereference operators on non-SMAP platforms (CVE-2019-9213). Attackers use a vulnerability in the
mmap
function, which does not check mapping of a null page, for placing arbitrary code on this page. -
The
deny_ptrace
SELinux boolean and SELinux in enforcing mode protect systems from the PTRACE_TRACEME vulnerability (CVE-2019-13272). Such configuration prevents scenarios when an attacker can getroot
privileges. -
The
nfs_export_all_rw
andnfs_export_all_ro
SELinux booleans provide an easy-to-use tool to prevent misconfigurations of Network File System (NFS) such as accidental sharing/home
directories.
Additional resources
- SELinux as a security pillar of an operating system - Real-world benefits and examples Knowledgebase article
- SELinux hardening with Ansible Knowledgebase article
- selinux-playbooks Github repository with Ansible playbooks for SELinux hardening
1.4. SELinux architecture and packages
SELinux is a Linux Security Module (LSM) that is built into the Linux kernel. The SELinux subsystem in the kernel is driven by a security policy which is controlled by the administrator and loaded at boot. All security-relevant, kernel-level access operations on the system are intercepted by SELinux and examined in the context of the loaded security policy. If the loaded policy allows the operation, it continues. Otherwise, the operation is blocked and the process receives an error.
SELinux decisions, such as allowing or disallowing access, are cached. This cache is known as the Access Vector Cache (AVC). When using these cached decisions, SELinux policy rules need to be checked less, which increases performance. Remember that SELinux policy rules have no effect if DAC rules deny access first. Raw audit messages are logged to the /var/log/audit/audit.log
and they start with the type=AVC
string.
In RHEL 8, system services are controlled by the systemd
daemon; systemd
starts and stops all services, and users and processes communicate with systemd
using the systemctl
utility. The systemd
daemon can consult the SELinux policy and check the label of the calling process and the label of the unit file that the caller tries to manage, and then ask SELinux whether or not the caller is allowed the access. This approach strengthens access control to critical system capabilities, which include starting and stopping system services.
The systemd
daemon also works as an SELinux Access Manager. It retrieves the label of the process running systemctl
or the process that sent a D-Bus
message to systemd
. The daemon then looks up the label of the unit file that the process wanted to configure. Finally, systemd
can retrieve information from the kernel if the SELinux policy allows the specific access between the process label and the unit file label. This means a compromised application that needs to interact with systemd
for a specific service can now be confined by SELinux. Policy writers can also use these fine-grained controls to confine administrators.
If a process is sending a D-Bus
message to another process and if the SELinux policy does not allow the D-Bus
communication of these two processes, then the system prints a USER_AVC
denial message, and the D-Bus communication times out. Note that the D-Bus communication between two processes works bidirectionally.
To avoid incorrect SELinux labeling and subsequent problems, ensure that you start services using a systemctl start
command.
RHEL 8 provides the following packages for working with SELinux:
-
policies:
selinux-policy-targeted
,selinux-policy-mls
-
tools:
policycoreutils
,policycoreutils-gui
,libselinux-utils
,policycoreutils-python-utils
,setools-console
,checkpolicy
1.5. SELinux states and modes
SELinux can run in one of three modes: enforcing, permissive, or disabled.
- Enforcing mode is the default, and recommended, mode of operation; in enforcing mode SELinux operates normally, enforcing the loaded security policy on the entire system.
- In permissive mode, the system acts as if SELinux is enforcing the loaded security policy, including labeling objects and emitting access denial entries in the logs, but it does not actually deny any operations. While not recommended for production systems, permissive mode can be helpful for SELinux policy development and debugging.
- Disabled mode is strongly discouraged; not only does the system avoid enforcing the SELinux policy, it also avoids labeling any persistent objects such as files, making it difficult to enable SELinux in the future.
Use the setenforce
utility to change between enforcing and permissive mode. Changes made with setenforce
do not persist across reboots. To change to enforcing mode, enter the setenforce 1
command as the Linux root user. To change to permissive mode, enter the setenforce 0
command. Use the getenforce
utility to view the current SELinux mode:
# getenforce
Enforcing
# setenforce 0 # getenforce Permissive
# setenforce 1 # getenforce Enforcing
In Red Hat Enterprise Linux, you can set individual domains to permissive mode while the system runs in enforcing mode. For example, to make the httpd_t domain permissive:
# semanage permissive -a httpd_t
Note that permissive domains are a powerful tool that can compromise security of your system. Red Hat recommends to use permissive domains with caution, for example, when debugging a specific scenario.