SELinux as a security pillar of an operating system - Real-world benefits and examples

Updated -

The number of vulnerabilities is growing every day. Some vulnerabilities moderate, while others have a critical impact that can lead to escalating privileges or code execution. In the case of critical vulnerabilities, it is necessary to react immediately and patch the system.

The problem is zero-day attacks when patches are not yet available, or the developers do not even know about the vulnerability, but the attackers are already exploiting it. Security technologies based on the Mandatory Access Control (MAC) concept such as Security Enhanced Linux (SELinux) can prevent these attacks.

SELinux is a process-isolation technology to mitigate attacks that use privilege escalations. Various operating systems use SELinux to determine access defined by the SELinux policy, and what is not specifically allowed is denied. In the SELinux policy, all subjects and objects have defined special security labels called SELinux contexts. The system uses SELinux contexts to decide whether to grant or deny access. If a process wants to access files, SELinux policy rules must allow it.

Apache web server directory traversal

Due to a vulnerability to path traversal on an Apache web server, an attacker can access files and directories stored on the file system by using special elements such as ../.

In the following examples, sequences of dots and slashes encoded with %2F traverse the directory and then access the /home/niki/secret.txt file:

http://192.168.0.53/?page=..%2F..%2F..%2F..%2F..%2F..%2F..%2Fhome%2Fniki%2Fsecret.txt

The secret.txt file has the following permissions:

-rw-r--r--. 1 root root unconfined_u:object_r:home_root_t:s0    secret.txt

The SELinux context for files in the home directory is home_root_t.

When SELinux is disabled or in permissive mode, you can display the content of a private file, for example:

$ curl -s  http://192.168.0.53/?page=..%2F..%2F..%2F..%2F
..%2F..%2F..%2Fhome%2Fniki%2Fsecret.txt
 ...
This is my private file.
...

If the server that contains the /home/niki/ directory is running with SELinux in enforcing mode, for example, RHEL in the default configuration, an attacker cannot access the file by using the directory-traversal vulnerability:

$ curl -s  http://192.168.0.53/?page=..%2F..%2F..%2F..%2F
..%2F..%2F..%2Fhome%2Fniki%2Fsecret.txt

On the server side, after the attacker attempted to access the file, a few SELinux denials occurred. These denials alert the user that the Apache process wants to open, get attributes, and read the /home/niki/secret.txt file.

SELinux Alert Browser - directory traversal example

This is because the Apache process does not have defined access to the home directory in the SELinux policy. However, for example, an Apache process with the httpd_t context can open or read files with the passwd_file_tcontext defined for the /etc/passwd file. This means that SELinux cannot block this type of attack completely but it can mitigate it.

NULL pointer dereferences vulnerability

In the case of the NULL pointer dereferences vulnerability (CVE-2019-9213), the default SELinux configuration was successful against exploitation of kernel NULL pointer dereferences on non-SMAP (Supervisor Mode Access Prevention) platforms. Attackers could use a vulnerability in the mmap function, which lacked a check of mapping a null page, for placing arbitrary code on this page.

The proof of concept in Issue 1792 on bugs.chromium.org shows the vulnerability of exploitation of kernel NULL pointer dereferences. In the first case, SELinux is in permissive mode and the vulnerability can be successfully exploited:

$ getenforce
Permissive
$ ./null_map
400000000 -00011000 rw -p 00000000  00:00 
data at NULL: 0x706f2064696c6156

In the following case, SELinux is running in enforcing mode and the default configuration:

$ getenforce
Enforcing
$ ./null_map
400000000 -00011000 rw -p 00000000  00:00 
Segmentation  fault (core dumped)

This attack vector fails because SELinux provides memory protection "security check on mmap operations to see if the user is attempting to mmap to a low area of the address space." as you can see in the following SELinux alert, where an attempt to access mmap_zero is logged:

SELinux Alert Browser - null_map example

Privilege escalation through ptrace_traceme

Many examples of exploited proofs-of-concept show the importance of SELinux technology and its successful mitigation or blocking of exploited vulnerabilities. However, the default SELinux configuration is less strict than it could be because otherwise users might face more problems and consider disabling SELinux. But more usability means less security.

The privilege escalation through ptrace_traceme (CVE-2019-13272) vulnerability provides an example, in which an attacker can achieve privilege escalation to root even though SELinux is running in enforced mode, but the correct SELinux configuration can prevent such attacks.

The National Institute of Standards and Technology (NIST) website describes this vulnerability as follows: "In the Linux kernel before 5.1.17, ptrace_link in kernel/ptrace.c mishandles the recording of the credentials of a process that wants to create a ptrace relationship, which allows local users to obtain root access by leveraging certain scenarios with a parent-child process relationship, where a parent drops privileges and calls execve (potentially allowing control by an attacker)."

In the following example, after running the ./ptrace_traceme_root script available on https://github.com/bcoles/kernel-exploits with SELinux in enforcing mode and the default configuration, the user niki gains root access:

[niki@localhost cve-2019-13272]$ id
uid=1001(niki) gid=1001(niki) groups=1001(niki),10(wheel)
context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023

[niki@localhost cve-2019-13272]$ getsebool deny_ptrace
deny_ptrace --> off

[niki@localhost cve-2019-13272]$ ./ptrace_traceme_root
Linux 4.10 < 5.1.17 PTRACE_TRACEME local root (CVE-2019-13272)
[.] Checking environment ...
[~] Done, looks good
[.] Searching for known helpers ...
[~] Found known helper: /usr/libexec/gsd-wacom-led-helper
[.] Using helper: /usr/libexec/gsd-wacom-led-helper
[.] Spawning suid process (/usr/bin/pkexec) ...
[.] Tracing midpid ...
[~] Attached to midpid

[root@localhost cve-2019-13272]# id
uid=0(root) gid=0(root) groups=0(root),10(wheel)
context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023

If you use the same script on the same system, but you enable the deny_ptrace SELinux boolean before you run the script, the user niki cannot gain root access:

[niki@localhost cve-2019-13272]$ id
uid=1001(niki) gid=1001(niki) groups=1001(niki),10(wheel)
context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023

[niki@localhost cve-2019-13272]$ getsebool deny_ptrace
deny_ptrace --> on

[niki@localhost cve-2019-13272]$ ./ptrace_traceme_root
Linux 4.10 < 5.1.17 PTRACE_TRACEME local root (CVE-2019-13272)
[.] Checking environment ...
[!] Warning: SELinux deny_ptrace is enabled
[~] Done, looks good
[.] Searching for known helpers ...
[~] Found known helper: /usr/libexec/gsd-wacom-led-helper
[.] Using helper: /usr/libexec/gsd-wacom-led-helper
[.] Spawning suid process (/usr/bin/pkexec) ...
[-] Error: ptrace(PTRACE_TRACEME, 0, NULL, NULL)
[.] Tracing midpid ...
[-] Error: ptrace(PTRACE_ATTACH, midpid, 0, NULL)

[niki@localhost cve-2019-13272]$ id
uid=1001(niki) gid=1001(niki) groups=1001(niki),10(wheel)
context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c10

Also confining users prevents such types of attacks. In the following example, the deny_ptrace SELinux boolean is disabled, but the Linux user niki is confined to the SELinux user staff_u:

[niki@localhost cve-2019-13272]$ id
uid=1001(niki) gid=1001(niki) groups=1001(niki),10(wheel)
context=staff_u:staff_r:staff_t:s0

[niki@localhost cve-2019-13272]$ getsebool deny_ptrace
deny_ptrace --> off

[niki@localhost cve-2019-13272]$ ./ptrace_traceme_root
Linux 4.10 < 5.1.17 PTRACE_TRACEME local root (CVE-2019-13272)
[.] Checking environment ...
[~] Done, looks good
[.] Searching for known helpers ...
[~] Found known helper: /usr/libexec/gsd-wacom-led-helper
[.] Using helper: /usr/libexec/gsd-wacom-led-helper
[.] Spawning suid process (/usr/bin/pkexec) ...
Error becoming real+effective uid 1001 and gid 1001: Operation not permitted

[niki@localhost cve-2019-13272]$ id
uid=1001(niki) gid=1001(niki) groups=1001(niki),10(wheel)
context=staff_u:staff_r:staff_t:s

The SELinux policy prevents bypassing file read, write, and execute permission checks for Linux users mapped to theguest_u, staff_u, user_u, and xguest_u SELinux users.

Misconfigured NFS

A Network File System (NFS) allows remote hosts to mount file systems over a network and interact with those file systems as though they are mounted locally. Attackers can misuse exploits on a misconfigured NFS and, for example, gain root access. The default configuration of SELinux enables SELinux booleans nfs_export_all_rw and nfs_export_all_ro that do not restrict what content users can share. Therefore, SELinux does not prevent such dangerous cases as sharing /home directories.

You can turn these booleans off:

# semanage boolean -m --off nfs_export_all_rw
# semanage boolean -m --off nfs_export_all_ro

To share files with SELinux enabled, set the public_content_t context on the files that you want to share by using the semanage and restorecon commands:

# semanage fcontext -a -t public_content_t /path/to/shared/file
# restorecon -v /path/to/shared/file

The disabled booleans and setting the correct context to shared files help protect NFS servers and deny clients from accessing files that you want to keep secret.

Conclusion

The previous examples show the importance of SELinux technology and efficient mitigation or blocking of exploited vulnerabilities. You can make your systems even more secure, if you apply the described hardening tips on the default SELinux configuration.