SELinux Concepts - but for humans

14 Feb 2017
This is your SELinux dictionary!

In our previous guide we looked at how to setup modern ngnix configuration without disabling SELinux. In this post, we're going to look at a few more terms and concepts that SELinux uses, so that we can later do more advanced SELinux tricks.

SELinux is about labels

This is the core part of SELinux: labels. Everything from ports to files are all labeled a SELinux label. We can use the -Z flag on most command line utilities to view the label:

$ ls -lhZ
  dr-xr-xr-x.   6 root root system_u:object_r:boot_t:s0       5.0K Jan 27 08:41 boot/
  drwxr-xr-x.  22 root root system_u:object_r:device_t:s0     4.1K Feb  6 14:01 dev/
  drwxr-xr-x.   1 root root system_u:object_r:etc_t:s0        5.5K Feb  6 14:01 etc/
  drwxr-xr-x.   1 root root system_u:object_r:home_root_t:s0    48 Jul 14  2016 home/
  dr-xr-x---.   1 root root system_u:object_r:admin_home_t:s0  354 Jan 30 19:37 root/
  drwxrwxrwt.  14 root root system_u:object_r:tmp_t:s0         300 Feb  6 14:38 tmp/
  drwxr-xr-x.   1 root root system_u:object_r:usr_t:s0         174 Nov 16 20:58 usr/

$ ps -eZ
  LABEL                             PID TTY          TIME CMD
  system_u:system_r:init_t:s0         1 ?        00:00:05 systemd
  system_u:system_r:kernel_t:s0       2 ?        00:00:00 kthreadd
  system_u:system_r:syslogd_t:s0    655 ?        00:00:05 systemd-journal
  system_u:system_r:policykit_t:s0 1155 ?        00:00:36 polkitd

$ netstat -Z
  Active Internet connections (w/o servers)
  Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name     Security Context
  tcp        0      0 vogon-constructor:48378 ec2-54-172-133-71:https ESTABLISHED 6146/firefox         fined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
  tcp        1      0 vogon-constructor:52280 www0.libre.fm:http      CLOSE_WAIT  23503/rhythmbox      fined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023

Labels are purely cosmetic. On their own, they don't mean anything. But they all policies to target the thing (process/port/file).

Analogy time

Let's pretend that a SELinux label is a class on a HTML element. You add a class to an element:

<!-- SELinux HTML :) -->
<div process="/run/systemd/journal/" class="system_u object_r syslogd_var_run_t s0"></div>
<div process="/usr/bin/systemd-journald" class="system_u system_r syslogd_t s0"></div>
allow-file-access: /run/systemd/log/;

Once we have our SE-HTML, we could write a selinux policy (which is like the CSS in this analogy):

.syslogd_t {
  allow-file-rw-access: syslog_var_run_t;
}

Just a disclaimer, the syntax for SELinux policies is not this pretty. We'll be covering that in the next post in the series, so make sure to subscribe:

Dissecting a label

Here's a label from systemd-journal:

system_u:system_r:syslogd_t:s0

Labels can look very confusing. But they are really quite simple. We just break it into 4 parts:

  • system_u - the user (hence the _u)
  • system_r - the role (hence the _r)
  • syslogd_t - the type (hence the _t). This is the most important part - it tells SELinux to use the policy for syslog_t processes - which usually contains the bulk of the enforcement rules
  • s0 - the MLS security code. By default, SELinux doesn't use MLS, so this is meaningless (see the section below for more)

As you can see, the only important part of this label is the type (something_t). That is a common pattern in SELinux labels. For example, her is the label for /etc/systemd/system/default.​target:

unconfined_u:object_r:systemd_unit_file_t:s0

  • unconfined_u - see below
  • object_r - common for many configuration files, meaningless to us
  • systemd_unit_file_t - this is a systemd unit file. There is probably a policy that targets this type, allowing systemd to read unit files
  • s0 - the MLS security code. By default, SELinux doesn't use MLS, so this is meaningless

So it is easy: just read the typename_t section and you are good!

Unconfined

On your server, there are probably many things running as either unconfined_u, unconfined_r or unconfined_t. We saw that above with the systemd unit file.

The unconfined_X labels are reserved labels that have no policy attached. And with SELinux, no policy means there is no restriction. So if you don't want something to be policed, use unconfined. Unconfined doesn't override any other policies; so something with unconfined_u and systemd_unit_file_t will still be restricted per systemd_unit_file_t policy.

Unconfined is the default for many processes on the desktop for that exact reason. I am typing now from gnome-terminal running unconfined and inside vim, unconfined again. You often don't want to restrict what desktop users can do, hence the user of unconfined.

What is "Targeted Enforcement"?

Above we touched on the MLS codes. This is a very interesting part of SELinux.

SELinux comes with 2 modes; targeted (the default on every distro) and MLS (Multi-Level Security). Targeted policies mean that things are un-restricted by default, and only restricted if a policy is written for them (when they are targeted).

With MLS, everything is restricted by default. MLS is used by three letter agencies, such as the NSA (SELinux's initial developer). RedHat has a small section on MLS in their docs, if you are interested. MLS also uses the s0 part of the label to specify the security classification of the file.

Labeling files

With normal unix permissions, files permissions are set at file creation time. This means that every app has to think about what the correct permissions for files are.

In SELinux, things are labeled based on their characteristics. Ports are labeled based on their port number. Processes are labeled based on their executable path. And files are similar; they are labeled based on their path.

We can see the list of path labeling rules by running:

$ sudo semanage fcontext --list
  SELinux fcontext                                   type               Context

  /                                                  directory          system_u:object_r:root_t:s0
  /.*                                                all files          system_u:object_r:default_t:s0
  /bin                                               all files          system_u:object_r:bin_t:s0
  /bin/.*                                            all files          system_u:object_r:bin_t:s0
  /bin/alsaunmute                                    regular file       system_u:object_r:alsa_exec_t:s0
  /bin/bash                                          regular file       system_u:object_r:shell_exec_t:s0
  /bin/bash2                                         regular file       system_u:object_r:shell_exec_t:s0
  /bin/d?ash                                         regular file       system_u:object_r:shell_exec_t:s0
  /bin/dbus-daemon                                   regular file       system_u:object_r:dbusd_exec_t:s0
  /bin/dmesg                                         regular file       system_u:object_r:dmesg_exec_t:s0
  /bin/fish                                          regular file       system_u:object_r:shell_exec_t:s0
  /bin/hostname                                      regular file       system_u:object_r:hostname_exec_t:s0
  ...

As you can see, it is just a simple map from path regex to label. We how to add a new rule to this fcontext map in our previous guide. Adding custom fcontexts is a very important part of SELinux policy development and usage.

Conclusion

SELinux is conceptually simple: we label some things, then apply policies to them. Hopefully this post helps you understand how SELinux works on a 1000-foot level. If not, make sure to check Red Hat's SELinux coloring book for a different explanation. Make sure to subscribe as we continue our journey to secure a normal web-app server with a custom SELinux policy!