Book Image

SELinux System Administration

By : Sven Vermeulen
Book Image

SELinux System Administration

By: Sven Vermeulen

Overview of this book

NSA Security-Enhanced Linux (SELinux) is a set of patches and added utilities to the Linux kernel to incorporate a strong, flexible, mandatory access control architecture into the major subsystems of the kernel. With its fine-grained yet flexible approach, it is no wonder Linux distributions are firing up SELinux as a default security measure. SELinux System Administration covers the majority of SELinux features through a mix of real-life scenarios, descriptions, and examples. Everything an administrator needs to further tune SELinux to suit their needs are present in this book. This book touches on various SELinux topics, guiding you through the configuration of SELinux contexts, definitions, and the assignment of SELinux roles, and finishes up with policy enhancements. All of SELinux's configuration handles, be they conditional policies, constraints, policy types, or audit capabilities, are covered in this book with genuine examples that administrators might come across. By the end, SELinux System Administration will have taught you how to configure your Linux system to be more secure, powered by a formidable mandatory access control.
Table of Contents (13 chapters)

Everything gets a label


In natural language, the term "context" can be used in a sentence for example, "it depends on the context". Well, with SELinux, it does depend on the context! The context of a process is what identifies the process to SELinux. SELinux has no notion of Linux process ownership and frankly doesn't care how the process is called, which process ID it has and under which account the process runs. All it wants to know is what the context is of that process. Let's look at an example context: the context of the current user (try it out yourself if you are on a SELinux enabled system):

$ id -Z
unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023

The id command, which returns information about the current user, with the -Z switch (a commonly agreed switch for displaying SELinux information) shows us the context of the current user (actually the context of the id process itself when it was executing). As we can see, the context is a string representation, and looks like it has five fields (it doesn't, it has four fields. The last field just happens to contain a ':').

SELinux developers decided to use contexts (strings) instead of real process metadata as well as contexts on resources (often called labels) for its access controls. This is different to MAC systems such as AppArmor which use the path of the binary (and thus the process name) and the paths of the resources to handle permission checks. The decision to make SELinux a label-based mandatory access control was taken for various reasons, which are as follows:

  • Using paths might be easier for administrators, but this doesn't allow to keep the context information close to the resource. If a file or directory is moved, remounted, or a process has a different namespace view on the files, the access controls might behave differently. With contexts, this information is retained and the system keeps controlling the resource properly.

  • Contexts reveal the context of the process very well. The same binary application can be launched in different contexts depending on how it got started. The context value (for example, the one shown in the id -Z output earlier on) is exactly what the administrator needs. With it, he knows what the rights are of each of the running instances, but he can also deduce from it how the process might have been launched.

  • Contexts also make abstraction of the object itself. We are talking now about processes and files, but this is also applicable to less tangible resources, for example: pipes (inter-process communication) or database objects. Path-based identification only works as long as you can write a path.

As an example, consider the following two sentences:

  • Allow the httpd processes to bind to the TCP port 80

  • Allow the processes labeled with "httpd_t" to bind to TCP ports labeled with "http_port_t"

In the first example, we cannot easily reuse this policy when the web server process isn't using the httpd binary (perhaps because it was renamed, or it isn't Apache but another web server), or when we want to have HTTP access on a different port. With the labeled approach, the binary can be called "apache2" or "MyWebServer.py"; as long as the process is labeled httpd_t then the policy applies. The same with the port definition, you can label port 8080 with http_port_t and thus allow the web servers to bind to that port as well.

The context fields

To come to a context, SELinux uses at least three, and sometimes four values. Let us look at the context of the Apache web server as an example:

$ ps -eZ | grep httpd
system_u:system_r:httpd_t:s0  511  ?   00:00:00 httpd

As we can see, the process is assigned a context which is made up of the following fields:

  • system_u - represents the SELinux user

  • system_r - represents the SELinux role

  • httpd_t - represents the SELinux type (also known as domain in case of a process)

  • s0 - represents the sensitivity

The roles can be depicted as follows:

Structure of a SELinux context, using the id -Z output as an example

When we work with SELinux, contexts are all that we need. In the majority of cases, it is the third field (called the domain or type) that is most important as the majority of SELinux policy rules (over 99 percent) consists of rules related to the interaction between two types (without mentioning roles, users, or sensitivities).

SELinux types

As mentioned, SELinux is a label-based access control mechanism. In most SELinux literature, this is fine-tuned to say that SELinux is a type enforcement mandatory access control system. This is because the type of a process (called the domain) defines the fine-grained access controls of that process with respect to itself or other types (which can be processes, files, sockets, network interfaces, and more). When some access attempts are denied, the fine-grained access controls on the type level are most likely to blame.

With type enforcement, SELinux is able to control what an application is allowed to do based on how it got executed in the first place: a web server that is launched interactively by a user will run with a different type than a web server executed through the init system, even though the process binary and path are the same. The web server launched from the init system is most likely trusted (and thus allowed to do whatever web servers are supposed to do), whereas a user launched web server is less likely to be of "normal behavior" and as such will have different privileges.

For instance, look at the following dbus-daemon processes:

# ps -eZ | grep dbus-daemon
system_u:system_r:system_dbusd_t 4531 ?        00:00:00 dbus-daemon
staff_u:staff_r:staff_dbusd_t    5266 ?        00:00:00 dbus-daemon

In the preceding example, one dbus-daemon process is the system D-Bus daemon running with the aptly named system_dbusd_t type, whereas another one is running with the staff_dbusd_t type assigned to it. Even though their binaries are completely the same, they both serve a different purpose on the system and as such have a different type assigned. SELinux then uses this type to govern the actions allowed by the process towards other types, including how system_dbusd_t can interact with staff_dbusd_t.

SELinux types are by convention suffixed with "_t", although this is not mandatory.

SELinux roles

SELinux roles - the second part of a SELinux context, enable SELinux to support role-based access controls. Although type enforcement is the most used (and known) part of SELinux, role-based access control is vital in order to keep a system secure, especially from malicious user attempts. SELinux roles are used to define which types a user processes can be in. As such, SELinux roles help define what a user can and cannot do.

On most SELinux enabled systems, the following roles are made available to be assigned to users. By convention, SELinux roles are defined with an "_r" suffix. Some of the roles and their descriptions are as follows:

user_r

This role is meant for restricted users, the user_r SELinux role is only allowed to have processes with types specific to end-user applications. Privileged types, for instance, those used to switch Linux user are not allowed for this role.

staff_r

This role is meant for non-critical operator tasks, the SELinux staff_r role is generally restricted to the same applications as the restricted user, but is also allowed to (a very few) more privileged types. It is the default role for operators to be in (so as to keep those users in the "least privileged" role as long as possible).

sysadm_r

This role is meant for system administration tasks, the sysadm_r SELinux role is very privileged, allowing for various system administration tasks. However, certain end user application types might not be supported (especially if those types are used for potentially vulnerable or untrusted software) to try and keep the system free from infections.

system_r

This role is meant for daemons and background processes, the system_r SELinux role is quite privileged, supporting the various daemon and system process types. However, end user application types and other administrative types are not allowed in this role.

unconfined_r

This role is meant for end users, the unconfined_r role is allowed a limited number of types, but those types are very privileged as it is meant for running any application launched by a user in a more or less unconfined manner (not restricted by SELinux rules). This role as such is only available if the system administrator wants to protect certain processes (mostly daemons) while keeping the rest of the system operations almost untouched by SELinux.

Other roles might be supported as well, such as guest_r and xguest_r (Fedora). It is wise to consult the distribution documentation for more information about the supported roles.

SELinux users

A SELinux user is different from a Linux user. Unlike the Linux user information which can change while the user is working on the system (through tools such as sudo or su), the SELinux policy will enforce that the SELinux user remains the same even when the Linux user itself has changed. Because of the immutable state of the SELinux user, specific access controls can be implemented to ensure that users cannot work around the (limited) set of permissions granted to them, even when they get privileged access. An example of such an access control is the UBAC (User Based Access Control) feature that some Linux distributions (optionally) enable, not allowing access to files of different SELinux users.

But the most important feature of SELinux users is that SELinux user definitions restrict which roles the (Linux) user is allowed to be in. Once a user is assigned a SELinux user, he cannot switch to a role that he isn't meant to be in. This is the role-based access control implementation of SELinux.

SELinux users are, by convention, defined with a "_u" suffix, although this is not mandatory. The SELinux users that most distributions have available are named after the role they represent, but instead of ending with "_r" they end with "_u". For instance, for the sysadm_r role, there is a sysadm_u SELinux user.

Sensitivity labels

Although not always present (some Linux distributions by default do not enable sensitivity labels), the sensitivity labels are needed for the MLS (Multi-Level Security) support within SELinux. Sensitivity labels allow classification of resources and restriction of access to those resources based on a security clearance. These labels consists of two parts: a confidentiality value (prefixed with "s") and a category value (prefixed with "c").

In many organizations and companies, documents are labeled internal, confidential, or strictly confidential. SELinux can assign processes a certain clearance level towards these resources. With MLS, SELinux can be configured to follow the Bell-LaPadula model, a security model that can be characterized by "no read up, no write down": based on a process' clearance level, that process cannot read anything with a higher confidentiality level nor write to (or communicate otherwise with) any resource with a lower confidentiality level. SELinux by itself, does not use the "internal", "confidential", and other labels. Instead, it uses numbers from 0 (lowest confidentiality) to whatever the system administrator wants to be as the highest value (this is configurable and set when the SELinux policy is built).

Categories allow for resources to be tagged with one or more categories on which access controls are also possible. The idea behind categories is to support multi-tenancy (for example, as systems hosting applications for multiple customers) within a Linux system, by having processes and resources belonging to one tenant to be assigned a particular category whereas the processes and resources of another tenant getting a different category. When a process does not have proper categories assigned, it cannot do anything with resources (or other processes) that have other categories assigned.

In that sense, categories can be seen as tags, allowing access to be granted only when the tags of the process and the target resource match.