Gentoo Logo

Disclaimer : This document is not valid and is not maintained anymore.

[ << ] [ < ] [ Home ] [ > ] [ >> ]

2. SELinux Concepts


2.a. Introduction

SELinux Concepts

Since SELinux is a MAC system, you should already figure out that managing SELinux-based permissions and rights might be a bit more challenging than managing the discretionary access control rights generally used on a Linux system. What is more is that SELinux works on top of the DAC system everybody is used from Linux. As a system administrator, you will need to be acquainted with some of the concepts and structures that SELinux has put in place in order to manage the access on the SELinux system.

Describing those concepts is the purpose of this particular chapter. We will give examples on the various concepts from a SELinux enabled Gentoo Hardened system. However, do not fear if the use of particular commands is not explained sufficiently. They are currently meant as examples (their output is more important) and will be discussed further in this document.

SELinux Policies

Within Gentoo (and other distributions as well), SELinux is supported through several policy levels. These are, in climbing order of complexity (meaning they can offer more security, but are harder to manage):

  1. targeted is a policy where network-facing services (daemons) are confined (the processes can only execute those actions that are defined in the policy), but other applications are running what is called unconfined, meaning that there are little to no restrictions for those processes.
  2. strict is a policy where all processes are confined. There are no unconfined domains. In other distributions, this is still considered the targeted policy but without the unconfined domain definition.
  3. multi-category security is a policy where the (confined) domains can be categorized (split up), allowing for multiple processes running in different instances of a confined domain
  4. multi-level security is a policy where rules exist regarding the sensitivity of domains and resources. This allows for a "proper" information flow policy (make sure that sensitive data isn't leaked to less privileged domains). Conceptually, one can understand this best if one considers sensitivity levels of Public, Internal, Confidential, Strictly Confidential, etc.

When using Gentoo Hardened, all these policies are available. However, development focuses mainly on strict and mcs. The targeted policy is assumed to work if strict works whereas we know that the mls policy is currently not fit yet for production use.

Note: To clear up some confusion, especially when trying to seek support outside Gentoo: our "strict" implementation is not what was "strict" up to the year 2008. The old meaning of strict involved a different implementation of the policy.

2.b. Security Contexts

Users, Roles, Domains, Sensitivities and Categories

One of the first concepts you will need to be acquainted with is the concept of a security context. This is a state given to a resource that uniquely identifies which grants (permissions) are applicable to the resource. This context is extremely important for SELinux as it is the definition on which it bases its permissions (grants or denials). When a resource has no security context assigned, SELinux will try to give it a default security context which - in the spirit of lowest privilege - has little permissions to perform any actions.

Within SELinux, such a security context is displayed using three to five definitions, depending on the type of policy you are running:

This is the SELinux user (which is not the same as the Linux/Unix technical user) assigned to the resource
This is the SELinux role in which the resource currently works
This is the type assigned to the resource and is the key to SELinux' enforcement rules
This is a level given to a resource informing the system about the sensitivity of this resource. A sensitivity is something akin to Public, Internal, Restricted, Confidential, Strictly Confidential, ... Sensitivity levels are only supported in MLS policies.
This is a specific instantiation of a resource. It allows segregation of resources even if they are of the same type. More about categories later - categories are supported in MLS and MCS policies.

More information on these particular definitions is given throughout the remainder of this chapter.

As an example let's take a look at the security context of a logged on user:

Code Listing 2.1: Getting the security context of a logged on user

~$ id -Z

In this case, the user is identified as the SELinux user staff_u, currently in the staff_r role and assigned to the staff_t type. The actions the user is allowed to do are based upon this security context. Also, you notice that only three identifiers are shown. This is because the example is taken on a strict (or targeted) policy system. The next example gives the same result, but on an MCS policy system.

Code Listing 2.2: Getting the security context of a logged on user on an MCS policy system

~$ id -Z

Here, the user is running with sensitivity level of s0 (which, in an MCS policy system, is the only available sensitivity) and with a category set of c0 up to and including c1023. However, note that in an MCS policy system categories are optional, so you might just see an output of staff_u:staff_r:staff_t:s0.

Access Control Policy

As mentioned before, these security contexts are used as the base for the permission rules. What SELinux does is check the security context of the source (for instance a process) and the destination (for instance a file that that process wants to read). It then checks if the requested operation (read) is allowed between those two contexts. Keep in mind though that SELinux works on top of the standard permission system used by Linux. If a process is not able to read a file to begin with, SELinux is not even consulted.

Now, where the security context defines the state of a resource, we have not spoken about the resources themselves. Within SELinux, the resource types are defined as object classes. Common examples are file or dir, but SELinux also manages classes such as filesystem, tcp_socket, process, sem (semaphores) and more.

On each object class, a set of permissions is declared which are possible against a resource within this object class. For instance, the process object class supports at least the following permissions:

Code Listing 2.3: Supported permissions against a 'process' resource

~# ls /selinux/class/process/perms
dyntransition  getcap      rlimitinh     setpgid        siginh
execheap       getpgid     setcap        setrlimit      sigkill
execmem        getsched    setcurrent    setsched       signal
execstack      getsession  setexec       setsockcreate  signull
fork           noatsecure  setfscreate   share          sigstop
getattr        ptrace      setkeycreate  sigchld        transition

The most common SELinux access control rule (allow) is described as follows:

Code Listing 2.4: SELinux allow statement

      +-+-+  +-+--+ +-+-+ +---+---+
        |      |      |       `- Permission to be granted (like "write")
	|      |      `- Class on which permission is given (like "file")
	|      `- Resource (label) on which permission is valid (like "portage_conf_t")
	`- Actor (domain) which gets the privilege (like "sysadm_t")

Let's take a look at a small example to explain the permission rules and how SELinux uses them. The example user is in the staff_u:staff_r:staff_t context and wants to write to its own home directory. As we can expect, this should be allowed. Don't worry about the commands here, we'll discuss them more properly further in this document.

Code Listing 2.5: Seeing if a user can write to its own home directory

(Show the security context for the users' home directory)
~$ ls -dZ ${HOME}
staff_u:object_r:user_home_dir_t  /home/swift

(Find the allow-rule which allows the staff_t type to write into a 
 directory with the user_home_dir_t type)
~$ sesearch -s staff_t -t user_home_dir_t -c dir -p write -A
Found 1 semantic av rules:
  allow staff_t user_home_dir_t : dir { ioctl read write create ... };

As expected, the security context of the user (to be more specific, the domain in which it resides) has write access to the domain of the target's directories. The notion of domain is frequently used in SELinux documentation and refers to the type assigned to a process. BTW, as files do not have roles, they are given the default object_r role by SELinux.

Now take a look at the following example. Our user, who is inside the portage group, wants to write to the /var/tmp/portage directory:

Code Listing 2.6: Seeing if a user can write to the /var/tmp/portage directory

~$ id -a
uid=1001(swift) gid=100(users) groups=100(users),...,250(portage),...
~$ ls -ldZ /var/tmp/portage
drwxrwxr-x. 3 portage portage  system_u:object_r:portage_tmp_t 4096 Dec  6 21:08 /var/tmp/portage

From the standard Linux permissions, the user has write access. But does SELinux also grant it?

Code Listing 2.7: Trying to write into /var/tmp/portage

~$ sesearch -s staff_t -t portage_tmp_t -c dir -p write -A
(Notice that there is no output given here)
~$ touch /var/tmp/portage/foo
touch: cannot touch '/var/tmp/portage/foo': Permission denied

As SELinux could not find a rule that allows the staff_t domain to write to any directory labeled with the portage_tmp_t type, the permission was denied.

2.c. Type Enforcements / Domain Types

Types and Domains

To explain how the permission rules work and how this is enforced through the security contexts, let's start from the last definition in the context (the type) and work our way forward through the roles and users.

  • A SELinux type is a particular label assigned to a resource. The passwd command for instance is labeled with the passwd_exec_t type.
  • A SELinux domain is the security state of a process and identifies the rights and permissions it has. It is most often referred to by its type declaration. For instance, for a running passwd command, its domain is passwd_t.

The rules that identify the allowed actions for a domain have been described earlier. Again:

Code Listing 3.1: Standard SELinux policy rules

allow <src_domain> <dst_type> : <class> { permission [ permission [ ... ] ] } ;

An example for the passwd_t domain would be the permissions granted between the passwd_t domain and the shadow_t type (used by the /etc/shadow file).

Code Listing 3.2: Grants between passwd_t and shadow_t

allow passwd_t shadow_t : file { ioctl read write create ... } ;

This permission syntax is very powerful, but also difficult. To have a secure system where normal behavior is allowed, you need to seriously fine-tune these rules for each and every application (and thus domain) that your system wants to host. Giving too broad permissions to a domain on a particular type might result in unauthorized activity being granted. Giving too few permissions might result in loss of efficiency or even effectiveness.

To support easier grant rules, SELinux allows grouping of types using type attributes. For instance, the attribute exec_type bundles all types that are assigned to executable files (such as bin_t, ssh_exec_t, ...), whereas the file_type attribute bundles all types that are assigned to regular files. Although this can simplify rule management, it makes it easier to grant too many permissions.

Domain Transitions

So far for types, domain definitions and their permissions. We have stated before that permissions are based on the domain in which a process resides. But how does a process become part of the domain? You might think that this happens by default (starting the passwd command would automatically bring the process in the passwd_t domain), but this is in fact a combination of three specific privileges that need to be granted:

  1. The current domain must be allowed to transition to a domain
  2. The target domain should have an entry point, which is an executable that is allowed to start in the domain
  3. The source domain should have execute rights on (the domain of) that executable

Important: Not being allowed to transition does not mean that you cannot execute the binary. The binary can still be executed, but will not run inside the target domain. Instead, it will inherit the domain of the executor and hence the rights and permissions of this domain.

Through these rules, the security administrator of a system can more specifically control who and under which conditions particular actions can be taken.

2.d. Roles and Rights

The Role of a Role

The previously discussed domains and domain rules is quite powerful. However, this is not where SELinux stops. After all, you want to be able to deny access towards particular domains from unauthorized users. One requirement is of course not to allow transitions from the user domain to that restricted domain, but how can you enforce one set of users to be allowed and another to be denied?

Enter the roles. By using roles, you can tell SELinux which domains are allowed for a role and which aren't. An example would be the ifconfig_t domain. This domain has the rights to change the networking interface definitions - not something you want to allow your users. And in fact, if you would verify, SELinux does not allow the user role user_r to be assigned with the ifconfig_t domain.

Code Listing 4.1: ifconfig_t domain and user_r versus sysadm_r

~$ seinfo -ruser_r -x
    Dominated Roles:
~$ seinfo -rsysadm_r -x
    Dominated Roles:

Important: Again, not being able to be associated with a domain does not mean that the user_r role cannot execute the ifconfig binary. It can, but it will execute the binary within its own domain (user_t) and as such will not have the rights to manipulate the networking interface (but will still be able to read the interface information albeit with limited output).

Roles are often used in access control systems to group permissions to a single functional set (the role) which can then be assigned to individuals (accounts). For instance, such access control systems create roles for accountants, operators, managers, ... and grant the appropriate privileges to these roles. Then, their users are assigned one (or sometimes multiple) roles and the users inherit the permissions assigned to these roles.

With SELinux, the idea remains the same (use roles to functionally differentiate privileges) but is implemented differently: roles are assigned target domains in which a role is allowed to "be in". The permissions remain assigned to the domains.

Role Transitions

Users (and processes) have the ability to switch roles. This is allowed by SELinux, but of course only when the switch itself is granted. By default, the SELinux policy used by Gentoo Hardened offers five roles on a SELinux system:

The object_r role is the only role by default available through SELinux. It is usually only assigned to resources where roles have no benefit or value (such as files and directories).
The system_r role is used for highly privileged system services. The system_r role is allowed to switch to any other "default" role. No role exception sysadm_r can switch to the system_r role.
The sysadm_r role is used for system administration activities. The sysadm_r role is allowed to switch to any other "default" role. Only the system_r and staff_r roles are allowed to switch to the sysadm_r role.
The staff_r role is used for system operators who might have the rights to perform system administration tasks. The staff_r role is only allowed to switch to the sysadm_r role. Only sysadm_r and system_r can switch to the staff_r role.
The user_r role is used for standard, unprivileged users. It is not allowed to transition towards any other role; only sysadm_r and system_r roles are allowed to switch to the user_r role.

Note: A "default" role is any of user_r, staff_r, sysadm_r or system_r. If you create additional roles yourself, they are not part of the "default" roles.

Using these definitions, a user inside the user_r role will never be able to execute ifconfig within the ifconfig_t domain. The use of the word never here is important: not even if the user is able to become root using sudo or any other command will he be able to run the ifconfig command in the ifconfig_t domain because, even after running sudo, he is still inside the user_r role.

SELinux Users

A SELinux user is not the same as the Linux user. Whereas standard Linux user accounts can be switched using commands such as su or sudo, a SELinux user can not be changed. Even when you successfully execute sudo, your SELinux user will remain the same.

When you look at a SELinux powered system, you might notice that that system doesn't use many SELinux users. For instance, Gentoo Hardened's default setup defines the users root, user_u, staff_u, sysadm_u and system_u and some systems never introduce any other SELinux user. But if that is the case, is the above advantage of SELinux users (once a user is logged on, he cannot change his SELinux user) the only one?

Well, no. SELinux users are also used to categorize accounts which have the permission to use a particular role.

Code Listing 4.2: SELinux users and their associated roles

~# semanage user -l
SELinux User    SELinux Roles

root            staff_r sysadm_r
staff_u         staff_r sysadm_r
sysadm_u        sysadm_r
system_u        system_r
user_u          user_r

Standard Linux users are mapped to these SELinux users:

Code Listing 4.3: Linux users and their SELinux user mappings

~# semanage login -l
Login Name          SELinux User

__default__         user_u
root                root
swift               staff_u

In this example, only logins of the Linux user swift (through staff_u) and root (through the root SELinux user) will be able to eventually run inside the sysadm_r role. All other Linux accounts will be by default mapped to the user_u user (and this user_r role).

This is only applicable for interactive logins. Processes that are launched through an init script or otherwise do not automatically become part of the SELinux user user_u: depending on the security context of whatever process is starting them, they can become anything. Of course, if the security context of the process that is starting them is user_u:user_r:user_t then they will not be able to transform into anything other than user_u:user_r:* with * a domain supported by the user_r role.

SELinux users are also used to implement User Based Access Control or UBAC. This SELinux functionality allows for domains to be SELinux user aware: a process running in the context of a particular SELinux user can then - for instance - only work with files of the same SELinux user. This offers a finer grained access method, because that process might run within a domain which has write access to the domain of the file, but can still not write to the file because the SELinux users' differ.

At this moment, Gentoo Hardened SELinux' supports both policies with and without UBAC, although we strongly recommend to use UBAC. This is controlled through the ubac USE flag.

2.e. Multi Level Security / Multi Category Security


Next to the type enforcement feature, SELinux also offers MLS and MCS support. This allows administrators to define a hierarchical confidentiality policy. For instance, you can ensure that a user or process within a certain security domain and level can write to files with the same level (or higher), or read files with the same level (or lower), but not write files to a lower level. This allows administrators to implement some sort of public/internal/confidential/strictly confidential hierarchical security level for files.

Although implementation of MLS is possible with the type enforcement rules we have previously explained, it would lead to an unmanageable collection of types and permissions. The MLS implementation simplifies this.

Multi-Level Security

The most flexible - but also most challenging to manage - method offered by SELinux is MLS, or Multi-Level Security. When using this policy type, security administrators can assign sensitivity labels to resources and define which domains (and which sensitivity levels) are able to read/write to which level. A level is always given as a range, showing the lowest and highest level that a particular domain is running in.

Next to the sensitivity level, MLS supports categories on a per-level basis. These categories allow the security administrator to make different, possibly independent "containers" for sensitive resources. To give an example, the administrator can support the levels Public up to Strictly Confidential, and categories of "Finance", "Risk Analysis", "Acquisitions", "IT Systems", ...

With such categories, one can then allow one role to have access to all sensitivity levels for a particular category (say "IT Systems") but still only have access to the Public and Internal documents of all other categories.

Multi-Category Security

The MCS or Multi-Category Security policy is a subset of the MLS policy. It supports the various categories, but without using the multiple security levels for the resources.

The use of MCS has become popular because it is far less difficult to manage while still retaining some of the flexibilities offered by the MLS policy. Where MLS is more chosen for business purposes (and as such has some influence on the organization of the business), MCS is often used for multitenancy architectures. In a multi-tenant architecture, systems are running processes for various clients simultaneously. Categorisation allows for separation of privileges across these processes without introducing multiple domains (which would require the development of new policies for each new client that a system wants to serve).

2.f. Reference Policy

About refpolicy

As described previously, SELinux uses type enforcement to describe the state of your system. This is done by giving each resource on your system (be it a process, a network port, a file or directory) a specific type and describe the rules how types can work with each other.

Managing such a policy is not easy. Unlike some other MAC systems, which rely on a learning mode and do not use domain definitions (they rather keep track of which commands a process is allowed to execute), a proper SELinux definition requires lots (thousands and thousands) of permission lines.

To ensure that no duplicate effort is made, and to help distributions like Gentoo, Fedora, RedHat, Debian, ... with their SELinux integration efforts, a project is launched called The Reference Policy.

This project, managed by Tresys, is used by almost all SELinux supporting distributions, including Gentoo Hardened, Fedora, RedHat Enterprise Linux, Debian, Ubuntu and more. This implementation not only offers the modular policies that users are looking for, but also enhances the SELinux experience with additional development tools that make it easier to work with the SELinux policies on your system. Updates in the reference policy eventually make it in all supported distributions. The same goes for Gentoo Hardened, which aims to use a policy as close as possible to the reference policy, and submits its own patches to the reference policy as well, which benefits the entire community.

Reference Policy API

One major advantage of the reference policy is its API. To help policy writers, the reference policy uses a macro language which generates the necessary allow (and other) rules. This macro language makes it a lot easier to add rights to particular domains. You can find the API documented online, but if you have USE="doc" set, it will be stored on your system as well the moment you install and configure SELinux.

Modular Approach

Another feature of the reference policy is its use of modules. If you would build all rules in a single policy (a binary file readable by the Linux kernel, allowing it to interpret and enforce SELinux rules), the file would quickly become too huge and inefficient.

Instead, the reference policy defines the rules in what it calls modules, which define one domain (like portage_t) or more (if they are all tightly related) and the rights and privileges that that domain would need in order to function properly. Any right that the domain needs with respect to another domain needs to be defined through that domains' interfaces (see earlier), forcing the modules to be specific and manageable.

Code Listing 6.1: Example overview of installed SELinux modules

# semodule -l
alsa    1.11.0
apache  2.3.0
audioentropy    1.6.0
dbus    1.15.0
dmidecode       1.4.0

By using a modular approach, one only needs to load the base policy (kernel layer as well as other, core definitions) and the modules related to his system. You can then safely ignore the other modules. This improves performance (smaller policy, which also causes rebuilds to be a lot less painful) and manageability (properly defined boundaries for policy rules).

Tunables and Conditionals

But wait, there's more. The reference policy also supports booleans. Those are flags that a security administrator can enable or disable to change the active policy. Properly defined booleans allow security administrators to fine-tune the policy for their system.

Code Listing 6.2: Overview of available booleans

# getsebool -a
allow_execheap --> off
allow_execmem --> off
allow_execmod --> off
allow_execstack --> off
allow_gssd_read_tmp --> on
allow_httpd_anon_write --> off

Booleans are an important part to make a generic reference policy which is still usable for the majority of SELinux users. Although they have specific requirements (such as allowing ptrace, or disallowing execmem) they can still use the same reference policy and only need to toggle the booleans they need.

Policy Files and Versions

The SELinux policy infrastructure that is used (i.e. the capabilities and functionalities that it offers) isn't in its first version. Currently, SELinux deployments use a binary version of 24 or 26 (depending on the kernel version used).

Code Listing 6.3: Getting the binary policy version

# sestatus
SELinux status:                 enabled
SELinuxfs mount:                /selinux
Current mode:                   enforcing
Mode from config file:          enforcing
Policy version:                 24
Policy from config file:        strict

Every time functionalities or capabilities are added which require changes to the internal structure of the compiled policy, this version is incremented. The following is an overview of the policy versions' history, basically translated from the security/selinux/include/security.h file in the Linux kernel.

Version 12
"Old API" for SELinux, which is now deprecated
Version 15
"New API" for SELinux, merged in Linux kernel 2.6.0 (until 2.6.5)
Version 16
Conditional policy extensions added (2.6.5)
Version 17
IPV6 support added (2.6.6 - 2.6.7)
Version 18
Fine-grained netlink socket support added (2.6.8 - 2.6.11)
Version 19
Enhanced multi-level security (2.6.12 - 2.6.13)
Version 20
Access vector table size optimizations (2.6.14 - 2.6.18)
Version 21
Object classes in range transitions (2.6.19 - 2.6.24)
Version 22
Policy capabilities (features) (2.6.25)
Version 23
Per-domain permissive mode (2.6.26 - 2.6.27)
Version 24
Explicit hierarchy (type bounds) (2.6.28 - 2.6.38)
Version 25
Filename based transition support (2.6.39)
Version 26
Role transition support for non-process classes (3.0)
Version 27
Support flexible inheritance of user and role for newly created objects (3.5)
Version 28
Support flexible inheritance of type for newly created objects (3.5)
Version 29
Support constraint naming (3.13)

2.g. Next Steps

What Next

It might be difficult to understand now, but the concepts are important because, if something fails on your system when SELinux is enabled, but it doesn't fail when SELinux is disabled, then you will need to dive into the security contexts, rules, types and domain transitions to find out why.

The next chapter in line will give you some background resource information (online resources, books, FAQs, etc.) After that, we'll dive into the installation and configuration of SELinux on your Gentoo Hardened system. Then, we'll configure and tune the SELinux policy to our needs.

[ << ] [ < ] [ Home ] [ > ] [ >> ]


View all

Page updated April 9, 2014

Summary: To be able to properly work with SELinux, it is vital that you understand a few of its concepts like domains, domain transitions and file contexts. Without a basic understanding of these aspects, it will be difficult to understand how SELinux policies work and how to troubleshoot if things go wrong.

Chris PeBenito

Sven Vermeulen

Chris Richards

Donate to support our development efforts.

Copyright 2001-2014 Gentoo Foundation, Inc. Questions, Comments? Contact us.