Gentoo Logo

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

Gentoo SELinux Handbook

Content:

  • Introduction to Gentoo/Hardened SELinux
    In this part we cover what SELinux is and how it is positioned within the Gentoo/Hardened project.
    1. Enhancing Linux Security
      Security is more than enabling a certain framework or installing a different Linux kernel. It is a way of working / administrating your Gentoo Linux system. We cover a few (generic) best practices, and then elaborate on what Mandatory Access Control is and how SELinux fills in this gap.
    2. SELinux Concepts
      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.
    3. SELinux Resources
      To get more acquainted with SELinux, many resources exist on the Internet. In this chapter we give a quick overview of the various resources as well as places where you can get more help when you are fighting with SELinux.
  • Using Gentoo/Hardened SELinux
    With the theoretic stuff behind us, let us start by installing Gentoo/Hardened with a SELinux kernel as well as the SELinux tools.
    1. Gentoo SELinux Installation / Conversion
      To set up SELinux within Gentoo/Hardened, you first need to install Gentoo with the correct Hardened profile (or convert to the Hardened profile) and then update your system to become a SELinux-managed system. This chapter will guide you through this process.
    2. Configuring SELinux For Your Needs
      With SELinux now "installed" and enabled (although in permissive mode), we now configure it to suit your particular needs. After all, SELinux is a Mandatory Access Control system where you, as security administrator, define what is allowed and what not.
    3. SELinux Commands
      Let's take a step back and get to know a few more commands. We covered most of them in the previous section, but we will now dive a bit deeper in its syntax, features and potential pitfalls.
    4. Permissive, Unconfined, Disabled or What Not...
      Your system can be in many SELinux states. In this chapter, we help you switch between the various states / policies.
    5. Modifying the Gentoo Hardened SELinux Policy
      Gentoo Hardened offers a default policy, but this might not allow what you want (or allows too much). In this chapter we tell you how you can tweak Gentoo's policy, or even run your own.
    6. Troubleshooting SELinux
      Everything made by a human can and will fail. In this chapter we will try to keep track of all potential issues you might come across and how to resolve them.
    7. Change History
      As documentation evolves with the technology, this handbook too sees its fair share of changes. To allow users, who are already on SELinux, to verify if there are any changes they need to be aware off, this chapter lists the changes in chronological order.

A. Introduction to Gentoo/Hardened SELinux

1. Enhancing Linux Security

1.a. Introduction

A Warm Welcome

Welcome to the Gentoo SELinux handbook. In this resource, we will bring you up to speed with Gentoo Hardened's implementation of SELinux and the policies involved. Part of this exercise is to help you understand why SELinux was brought to life and which concept is behind the development of the SELinux patches. We will cover the SELinux concepts, the reference policy that Gentoo Hardened uses and elaborate on how to work with the various SELinux tools.

The purpose of this book is not to explain SELinux itself in great detail. There are many references available on the Internet and in the better bookstores that help you with the SELinux topic. Instead, we will focus on SELinux integration within Gentoo Hardened. Of course, we will give a quick introduction to SELinux to allow you to understand how it works, what it is and help you identify which actions you will need to take in order to properly secure your system using the SELinux tools.

1.b. Securing Linux

Security In General

Security is often seen as a vague concept. What is security in general? How do you measure security? What is the benefit and how do you make sure you do not put too much effort in securing your system?

Well, security zealots will tell you that there is no such thing as too much security. If properly implemented, security does not restrict functionality or performance. It does not give you too much overhead in order to do your tasks. But implementing security properly is a different and time-consuming task. That is also why you often hear that security is as good as its administrator.

So, how can you look at security? A good practice on security is to define your security goals. List what you want to achieve and why. By tracking the threats that you want to minimize, you build up a security model that is appropriate for your environment. Such threats can be very broad, such as "Ensure no-one is able to work around our security measures".

In case of a Linux system powered with SELinux, this would at least mean that you want to protect critical system files, such as kernel image(s) and boot loader configuration, passwords and the SELinux policy binary itself from being written by anyone or anything except trusted processes.

Access Control

A decent access control system (or group of systems) ensures that only authorized individuals or processes are granted access to the resources they are tring to work with.

Before one can implement an access control system, you first need to have proper authentication in place. If your authentication schemes are flawed, your access control system might not be able to differentiate legitimate users from malicious ones.

Authenticating users within Linux is often done through PAM (Pluggable Authentication Modules), a powerful mechanism to integrate multiple low-level authentication schemes into a high-level interface.

Authorizing access to resources however is often done through a simple permission scheme. Most resources are not hidden by default, although patches and updates exist (such as those offered by Gentoo Hardened's kernel sources with grSecurity patches which includes support for this kind of measures). File-system wise, you can hide the existence of files by ensuring the directory in which the file resides is not readable nor "executable" by unauthorized accounts.

This default permission scheme has major drawbacks. It does not allow you to define very flexible authorizations (it only allows permissions on three levels: owner, group-owner and everybody else) and is limited to read/write/execute rights (although a few additional attributes are supported nowadays as well).

Another drawback is that the permission scheme is discretionary, meaning that users and processes are able to change the security policy in place.

For the majority of uses, this permission scheme is sufficient and has proven to offer a decent method for managing access authorizations. But the drawbacks have shown to be a major hole in the Linux' offering.

1.c. Mandatory Access Control

Enter SELinux

If the above mentioned discretionary access control, abbreviated to DAC, is not sufficient (and if you are keen on security, you will not find it sufficient), you need a Mandatory Access Control, or MAC system.

When using a MAC system, activities that a process wants to perform on another resource need to be explicitly allowed. It offers a higher granularity on permissions as well as resources. They often support not only files, but also sockets, ports, memory segments, queues, processes, kernel services, system calls, devices, file systems and more. The granularity of activities supported is also quite large. For files, this can be append, create, execute, write, link, ioctl, get- and setattr, read, rename, lock, ... whereas for sockets this might be append, bind, connect, create, write, sendto, accept, ... Also, when using a MAC system, no user or process can manipulate the security policy itself: what the security administrator has defined cannot be overturned.

This is where SELinux comes to play. SELinux is a Linux kernel feature which implements, amongst other things, a MAC system for controlling and governing access to various resources. It uses a deny-by-default permission scheme, so any access that a process wants to perform needs to be explicitly granted.

SELinux also allows you to put a finer-grained permission model on top of the traditional DAC system (which is still in use when using SELinux - in other words, if the traditional system does not allow certain activities, it will not be allowed even if there are SELinux policies granting the permission).

What is SELinux

To support this finer-grained permission model, you would think that changes are needed to the Linux kernel. Yet thanks to the Linux kernel LSM interface (Linux Security Modules), support for SELinux was easily added and since the 2.6 kernel series, SELinux has been integrated in the mainstream kernel release. But supporting SELinux and using SELinux are very different topics.

In order to properly identify resources, SELinux needs to assign labels to these resources. When the resources are in-memory, this is mostly supported by the Linux kernel itself, but for persistent resources such as files, these labels need to be placed somewhere. SELinux has chosen to use a file's extended attributes (which is stored on the file system itself). The advantage here is that a label remains on the file even if the file is renamed. A disadvantage of this approach is that the file system must support extended attributes, which not all file systems do (or have activated).

SELinux also uses roles to govern resource access. A user that does not have access to the system administration role should never be allowed to execute any system administration activities even if he is able to escalate its privileges (say through a set-uid application). To support roles, SELinux requires changes to the authentication services (PAM) and needs to store role definitions and authorizations somewhere.

Next to the kernel support and labels assigned to the resources and support within the authorization system, SELinux also requires particular tools to support the SELinux features. Examples are administrative tools to view and manipulate labels, privilege management tools (like sudo), system services (like SysVInit) etc. This is reflected in a set of patches against these (and more) tools which are not always part of the applications' main source code.

Gentoo Hardened and SELinux

What Gentoo Hardened offers is SELinux integrated in the distribution. When you select SELinux support, Gentoo Hardened will apply the necessary patches against the applications and help you (re)label your files and other resources to become SELinux-manageable. Gentoo Hardened also integrates SELinux support inside Portage, allowing for newly installed files to be automatically labeled and to use a SELinux-supporting sandbox environment for safe package building.

Next to the pure technological support, we hope that you will also find the necessary supporting documents, guides, experience and on-line support for using SELinux within Gentoo. Never hesitate to come and say hi on the #gentoo-hardened chat channel in the Freenode IRC network or on our mailing lists.

If you believe that SELinux is the right thing for you and you want to try it out using Gentoo Hardened, please read on. The next chapter will inform you how SELinux security is "designed" and how it is conceptually structured. Further chapters will then help you with the authorization language and the "base" policies that most distributions start from, and finally help you install, run and manage a SELinux hardened Gentoo system.

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:

user
This is the SELinux user (which is not the same as the Linux/Unix technical user) assigned to the resource
role
This is the SELinux role in which the resource currently works
type
This is the type assigned to the resource and is the key to SELinux' enforcement rules
sensitivity
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.
category
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
staff_u:staff_r:staff_t

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
staff_u:staff_r:staff_t:s0-s0:c0.c1023

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

allow ACTOR  TARGET:CLASS PRIVILEGE;
      +-+-+  +-+--+ +-+-+ +---+---+
        |      |      |       `- 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
  user_r
    Dominated Roles:
      user_r
    Types:
      ...
~$ seinfo -rsysadm_r -x
  sysadm_r
    Dominated Roles:
      sysadm_r
    Types:
      ...
      ifconfig_t
      ...

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:

object_r
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).
system_r
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.
sysadm_r
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.
staff_r
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.
user_r
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

Introduction

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.

3. SELinux Resources

3.a. Background

Introduction to SELinux

3.b. SELinux Policy

Policy Related References

3.c. Books

Paper Books

  • SELinux by Example: Using Security Enhanced Linux, Frank Mayer, Karl MacMillan, and David Caplan, Prentice Hall, 2006; ISBN 0131963694
  • SELinux: NSA's Open Source Security Enhanced Linux, Bill McCarty, O'Reilly Media, 2004; ISBN 0596007167

3.d. Gentoo Specific Resources

Gentoo Hardened

The following resources are specific towards Gentoo Hardened's SELinux implementation.

B. Using Gentoo/Hardened SELinux

1. Gentoo SELinux Installation / Conversion

1.a. Installing Gentoo (Hardened)

Introduction

Getting a SELinux-powered Gentoo installation doesn't require weird actions. What you need to do is install Gentoo Linux with the correct profile, correct kernel configuration and some file system relabelling. We seriously recommend to use SELinux together with other hardening improvements (such as PaX / grSecurity).

This chapter will describe the steps to install Gentoo with SELinux. We assume that you have an existing Gentoo Linux system which you want to convert to Gentoo with SELinux. If this is not the case, you should still read on: you can install Gentoo with SELinux immediately if you make the correct decisions during the installation process, based on the information in this chapter.

Performing a Standard Installation

Install Gentoo Linux according to the Gentoo Handbook installation instructions. We recommend the use of the hardened stage 3 tarballs and hardened-sources kernel instead of the standard ones, but standard stage installations are also supported for SELinux. Perform a full installation to the point that you have booted your system into a (primitive) Gentoo base installation.

Switching to Python 2

For now, the SELinux management utilities are not all compatible with Python 3 so we recommend to switch to Python 2 until the packages are updated and fixed.

Code Listing 1.1: Switching to python 2

~# emerge '<=dev-lang/python-3.0'
~# eselect python list
Available Python interpreters:
  [1]   python2.7
  [2]   python3.1 *

~# eselect python set 1
~# source /etc/profile

Choosing a SELinux policy type

Gentoo supports four policy types within SELinux: strict, targeted, mcs and mls.

The differentiation between strict and targeted is based upon the unconfined domain. When loaded, the processes on your system that are not specifically confined within a particular policy module will be part of the unconfined domains whose purpose is to allow most activities by default (rather than deny by default). As a result, processes that run inside unconfined domains have no restrictions apart from those already enforced by standard Linux security. Although running without the unconfined domains is considered more secure, it will also be more challenging for the administrator to make sure the system still functions properly as there are no policy modules for each and every application "out there".

Next to targeted and strict, you can opt for mcs to allow categorization of the process domains. This is useful on multi-tenant systems such as web servers, virtualization hosts, ... where multiple processes will be running, most of them in the same security domain, but in different categories. Note though that to take advantage of the additional category support, either the applications themselves (such as the web server or hypervisor tools) need to configure the SELinux categories (so they need to support SELinux) or you will need to script around to start the individual instances with separate categories. Otherwise, mcs is just the same as targeted or strict.

Finally, you can also select mls to differentiate security domains on a sensitivity level. However, MLS is currently still considered experimental in Gentoo and as such not recommended.

In case of mcs or mls, you will need to use the unconfined USE flag to enable or disable unconfined domains in these policy types. The strict (no unconfined domains) type does not honor the USE flag, and the targeted (unconfined domains) type requires the USE flag set.

When you have made your choice between the SELinux policy types, save this in your /etc/portage/make.conf file as well. That way, Portage will only install the policy modules for that SELinux type. By default, the SELinux profiles enable strict and targeted (with strict being the default active type).

Code Listing 1.2: Setting the policy type in make.conf

~# nano /etc/portage/make.conf
POLICY_TYPES="strict"

Setting the filesystem contexts

If your /tmp location is a tmpfs-mounted file system, then you need to tell the kernel that the root context of this location is tmp_t instead of tmpfs_t. Many SELinux policy objects (including various server-level policies) assume that /tmp is tmp_t.

To configure the /tmp mount, edit your /etc/fstab:

Code Listing 1.3: Update /etc/fstab for /tmp

# For a "targeted" or "strict" policy type:
tmpfs  /tmp  tmpfs  defaults,noexec,nosuid,rootcontext=system_u:object_r:tmp_t  0 0

# For an "mls" or "mcs" policy type:
tmpfs  /tmp  tmpfs  defaults,noexec,nosuid,rootcontext=system_u:object_r:tmp_t:s0  0 0

Next, set the next line in your /etc/fstab to configure the context for the /run location:

Code Listing 1.4: Update /etc/fstab for /run

# For a "targeted" or "strict" policy type:
tmpfs  /run   tmpfs  mode=0755,nosuid,nodev,rootcontext=system_u:object_r:var_run_t  0 0

# For an "mls" or "mcs" policy type:
tmpfs  /run   tmpfs  mode=0755,nosuid,nodev,rootcontext=system_u:object_r:var_run_t:s0  0 0

Change the Gentoo Profile

Now that you have a running Gentoo Linux installation, switch the Gentoo profile to the right SELinux profile (for instance, hardened/linux/amd64/no-multilib/selinux). Note that the older profiles (like selinux/v2refpolicy/amd64/hardened) are not supported anymore.

Code Listing 1.5: Switching the Gentoo profile

~# eselect profile list
Available profile symlink targets:
  [1]   default/linux/amd64/10.0
  [2]   default/linux/amd64/10.0/selinux
  [3]   default/linux/amd64/10.0/desktop
  [4]   default/linux/amd64/10.0/desktop/gnome
  [5]   default/linux/amd64/10.0/desktop/kde
  [6]   default/linux/amd64/10.0/developer
  [7]   default/linux/amd64/10.0/no-multilib
  [8]   default/linux/amd64/10.0/server
  [9]   hardened/linux/amd64
  [10]  hardened/linux/amd64/selinux
  [11]  hardened/linux/amd64/no-multilib *
  [12]  hardened/linux/amd64/no-multilib/selinux

~# eselect profile set 12

Warning: Do not rebuild your system right now - wait until this is instructed by this document later. Rebuilding the system will pull in SELinux policies which could make your system unreachable if you reboot after it.

Note: Starting from the profile change, Portage will warn you after every installation that it was "Unable to set SELinux security labels". This is to be expected, because the tools and capabilities that Portage requires to set the security labels aren't available yet. This warning will vanish the moment the SELinux installation is completed.

Don't update your system yet - we will need to install a couple of packages in a particular order which Portage isn't aware of in the next couple of sections.

Update make.conf

Next, take a look at the following USE flags and decide if you want to enable or disable them.

USE flag Default Value Description
peer_perms Enabled The peer_perms capability controls the SELinux policy network peer controls. If set, the access control mechanisms that SELinux uses for network based labelling are consolidated. This setting is recommended as the policy is also updated to reflect this. If not set, the old mechanisms (NetLabel and Labeled IPsec) are used side by side.
open_perms Enabled The open_perms capability enables the SELinux permission "open" for files and file-related classes. Support for the "open" call was added a bit later than others so support was first made optional. However, the policies have matured sufficiently to have the open permission set.
ubac Enabled When disabled, the SELinux policy is built without user-based access control.
unconfined Disabled When set, policy builds (except for the "strict" policy) will include the unconfined module (thus allowing unconfined domains to exist on the system).

Make your choice and update the USE variable in /etc/portage/make.conf or in an appropriate /etc/portage/package.use location for the sec-policy/selinux-base package.

Manual System Changes

Warning: Most, if not all of the next few changes will be resolved through regular packages as soon as possible. However, these fixes have impact beyond the Gentoo Hardened installations. As such, these changes will be incorporated a bit slower than the SELinux-specific updates. For the time being, manually correcting these situations is sufficient (and a one-time operation).

The following changes might be necessary on your system, depending on the tools or configurations that apply.

  • Check if you have *.old files in /bin. If you do, either remove those or make them a copy of their counterpart so that they get their own security context. The .old files are hard links which mess up the file labelling. For instance, cp /bin/hostname /bin/hostname.old.

Installing a SELinux Kernel

Although the default Linux kernels offer SELinux support, we recommend the use of the sys-kernel/hardened-sources package.

Code Listing 1.6: Installing hardened-sources

(Only if you have not installed it previously of course)
~# emerge hardened-sources

Next, reconfigure the kernel with the appropriate security settings. This includes, but is not limited to

  • Support for extended attributes in the various file systems
  • Support system-call auditing
  • Support for SELinux

Below you can find a quick overview of the recommended settings.

Code Listing 1.7: Recommended settings for the Linux kernel configuration

Under "General setup"
[*] Prompt for development and/or incomplete code/drivers
[*] Auditing support
[*]   Enable system-call auditing support

Under "File systems"
(For each file system you use, make sure extended attribute support is enabled)
<*> Second extended fs support
[*]   Ext2 extended attributes
[ ]     Ext2 POSIX Access Control Lists
[*]     Ext2 Security Labels
[ ]   Ext2 execute in place support

<*> Ext3 journalling file system support
[ ]   Default to 'data=ordered' in ext3
[*]   Ext3 extended attributes
[ ]     Ext3 POSIX Access Control Lists
[*]     Ext3 Security Labels

<*> The Extended 4 (ext4) filesystem
[*]   Ext4 extended attributes
[ ]     Ext4 POSIX Access Control Lists
[*]     Ext4 Security Labels

<*> JFS filesystem support
[ ]   JFS POSIX Access Control Lists
[*]   JFS Security Labels
[ ]   JFS debugging
[ ]   JFS statistics

<*> XFS filesystem support
[ ]   XFS Quota support
[ ]   XFS POSIX ACL support
[ ]   XFS Realtime subvolume support (EXPERIMENTAL)
[ ]   XFS Debugging Support

<*> Btrfs filesystem (EXPERIMENTAL)
[ ]   Btrfs POSIX Access Control Lists

Under "Security options"
[*] Enable different security models
[*] Socket and Networking Security Hooks
[*] NSA SELinux Support
[ ]   NSA SELinux boot parameter
[ ]   NSA SELinux runtime disable
[*]   NSA SELinux Development Support
[ ]   NSA SELinux AVC Statistics
(1)   NSA SELinux checkreqprot default value
[ ]   NSA SELinux maximum supported policy format version
    Default security module (SELinux) --->

We recommend to use PaX as well. More information on PaX within Gentoo Hardened can be found in the Hardened Gentoo PaX Quickstart Guide.

Build and install the new Linux kernel and its modules.

Update fstab

Next, edit /etc/fstab and add the following line:

Code Listing 1.8: Enabling selinux-specific file system options

none   /selinux         selinuxfs    defaults    0 0

Also create this mount point

Code Listing 1.9: Creating the /selinux mountpoint

# mkdir /selinux

Reboot

With the above changes made, reboot your system. Assert yourself that you are now running a Linux kernel with SELinux enabled (the /selinux file system should be mounted). Don't worry - SELinux is at this point not activated.

1.b. Configure SELinux

Introduction

Next we will need to configure SELinux by installing the appropriate utilities, label our file system and configure the policy.

Install Policies and Utilities, Part One

First, install the sys-apps/checkpolicy and sys-apps/policycoreutils packages. Although these will be pulled in as dependencies of the SELinux policy packages themselves, we need to install these one time first - hence the -1 option.

Code Listing 2.1: Installing SELinux policy core utilities

~# emerge -1 checkpolicy policycoreutils

Next, we install the base SELinux policy package. This package provides the SELinux configuration file which we need to adjust prior to building all other SELinux packages.

Code Listing 2.2: Installing the SELinux base policy package

~# FEATURES="-selinux" emerge -1 selinux-base

Configure the SELinux Policy

Inside /etc/selinux/config you can now configure how SELinux is configured at boot time.

Code Listing 2.3: Editing the /etc/selinux/config file

# This file controls the state of SELinux on the system on boot.

# SELINUX can take one of these three values:
#       enforcing - SELinux security policy is enforced.
#       permissive - SELinux prints warnings instead of enforcing.
#       disabled - No SELinux policy is loaded.
SELINUX=permissive

# SELINUXTYPE can take one of these four values:
#       targeted - Only targeted network daemons are protected.
#       strict   - Full SELinux protection.
#       mls      - Full SELinux protection with Multi-Level Security
#       mcs      - Full SELinux protection with Multi-Category Security
#                  (mls, but only one sensitivity level)
SELINUXTYPE=strict

Within this configuration file, two variables can be set:

  • SELINUX sets how SELinux should behave:
    • enforcing will enable and enforce policies. This is where we want to go for, but you should probably start with permissive.
    • permissive will enable policies, but not enforce them. Any violation is reported but not denied. This is where you should start from as it will not impact your system yet allow you to get acquainted with SELinux - and validate the warnings to see if you can switch towards enforcing or not.
    • disabled will completely disable the policies. As this will not show any violations as well, it is not recommended.
  • SELINUXTYPE selects the SELinux policy type to load. Most development is done using the strict (as it provides full confinement) type, although the others are supported as well.

Make sure that the SELINUX variable is set to permissive right now. We will switch to enforcing later.

Install Policies and Utilities, Part Two

We can now continue with the installation of the SELinux policies. Rebuild the selinux-base package if you changed SELINUXTYPE to something else than strict, and then install the core SELinux policies through the sec-policy/selinux-base-policy package. This package contains the core SELinux policies needed to get your system up and running using SELinux. As Portage will try to label and reload policies (since the installation of sys-apps/policycoreutils) we need to temporarily disable SELinux support again (as Portage wouldn't be able to label anything as it doesn't understand it yet).

Code Listing 2.4: Installing the SELinux policy packages

~# FEATURES="-selinux" emerge -1 selinux-base
~# FEATURES="-selinux" emerge selinux-base-policy

Next, rebuild those packages affected by the profile change we did previously through a standard world update, taking into account USE-flag changes (as the new profile will change many default USE flags, including enabling the selinux USE flag). Don't forget to use etc-update or dispatch-conf afterwards as some changes to configuration files need to be made.

Code Listing 2.5: Update your Gentoo Linux system

~# emerge -uDN world

Next, install the additional SELinux tools that you might need in the future to debug or help with your SELinux installation. These packages are optional, but recommended.

Code Listing 2.6: Installing additional SELinux packages

~# emerge setools sepolgen checkpolicy

Finally, install the policy modules for those utilities you think you need policies for. In the near future, this will be done automatically for you (the packages will have an optional dependency on it, triggered by the selinux USE flag), but until that time, you will need to install them yourself.

Code Listing 2.7: Installing SELinux modules

~# emerge --search selinux-
[...]
(Select the modules you want to install)
~# emerge selinux-screen selinux-gnupg selinux-sudo selinux-ntp selinux-networkmanager ...

Reboot, and Label the File System

Important: Repeat these steps every time you have rebooted from a non-SELinux enabled kernel into a SELinux enabled kernel, as running with a non-SELinux enabled kernel will not update the security attributes of the files you create or manipulate during your day-to-day activities on your system.

First reboot your system so that the installed policies are loaded. Now we need to relabel your devices and openrc related files. This will apply the correct security contexts (labels) onto the necessary files.

Code Listing 2.8: Relabel /dev structure

~# mkdir /mnt/gentoo
~# mount -o bind / /mnt/gentoo

(Substitute the "strict" in the next command with "targeted" if that is your
SELINUXTYPE selection, and use "lib" instead of "lib64" if you have a 32-bit system)
~# setfiles -r /mnt/gentoo /etc/selinux/strict/contexts/files/file_contexts /mnt/gentoo/dev
~# setfiles -r /mnt/gentoo /etc/selinux/strict/contexts/files/file_contexts /mnt/gentoo/lib64
~# umount /mnt/gentoo

Next, if you have a swapfile rather than a swap partition, label it accordingly:

Code Listing 2.9: Labelling the swap file

~# semanage fcontext -a -t swapfile_t "/swapfile"
~# restorecon /swapfile

Now relabel your entire file system. The next command will apply the correct security context onto the files on your file system, based on the security context information provided by the SELinux policy modules installed.

Code Listing 2.10: Relabel the entire file system

~# rlpkg -a -r

If you ever have to install a SELinux policy module for a package after that that particular package is installed, you need to run rlpkg for that package to make sure that the security contexts for these files are set correctly. For instance, if you have installed sec-policy/selinux-screen after discovering that you have screen on your system:

Code Listing 2.11: Relabeling the files for a single package

(Make sure no screen sessions are running as their security contexts will not be adapted)
~# rlpkg -t screen

Enable the selinux_gentoo service

Gentoo provides an init script called selinux_gentoo which restores the contexts of dynamically created files and devices or pseudo file systems (/dev (optionally) and /sys) as those file systems cannot persist context changes across reboots.

The init script also supports booting in permissive mode first (for instance if you have a custom initramfs that fails to work in enforcing mode) and switch to enforcing mode later.

Enable the init script using rc-update add selinux_gentoo boot and update your boot loader configuration with the following boot options:

  • nosetenforce if you boot with enforcing=0 and do not want the init script to switch back to enforcing mode (if configured in /etc/selinux/config). If your /etc/selinux/config file is configured to boot in permissive mode, this init script will not change this behavior.
  • norestorecon if you do not want to restore the contexts of /dev.

Code Listing 2.12: Example GRUB configuration

# Boot in SELinux permissive and switch to enforcing later
# Requires /etc/selinux/config to have SELINUX=enforcing
title Gentoo Hardened/SELinux
root (hd0,0)
kernel /boot/kernel root=/dev/vg/root ... enforcing=0 ...

# Boot in SELinux permissive and stay in permissive, even if
# /etc/selinux:config has SELINUX=encorcing
title Gentoo Hardened/SELinux
root (hd0,0)
kernel /boot/kernel root=/dev/vg/root ... enforcing=0 nosetenforce ...

Reboot and Set SELinux Booleans

Reboot your system so that the newly applied file contexts are used. Log on and, if you have indeed installed Gentoo using the hardened sources (as we recommended), enable the SSP SELinux boolean, allowing every domain read access to the /dev/urandom device:

Code Listing 2.13: Enabling the global_ssp boolean

~# setsebool -P global_ssp on

Define the Administrator Accounts

If the SELINUXTYPE is set to strict, then we need to map the account(s) you use to manage your system (those that need access to Portage) to the staff_u SELinux user. If not, none of your accounts will be able to succesfully manage the system (except for root, but then you will need to login as root directly and not through sudo or su.) By default, users are mapped to the user_u SELinux user who doesn't have the appropriate rights (nor access to the appropriate roles) to manage a system. Accounts that are mapped to staff_u can, but might need to switch roles from staff_r to sysadm_r before they are granted the appropriate privileges.

Assuming that your account name is john:

Code Listing 2.14: Mapping the Linux account john to the SELinux user staff_u

~# semanage login -a -s staff_u john
~# restorecon -R -F /home/john

If you later log on as john and want to manage your system, you will probably need to switch your role. You can use newrole for this:

Code Listing 2.15: Switching roles

~$ id -Z
staff_u:staff_r:staff_t
~$ newrole -r sysadm_r
Password: (Enter your password)
~$ id -Z
staff_u:sysadm_r:sysadm_t

If you however use a targeted policy, then the user you work with will be of type unconfined_t and will already have the necessary privileges to perform system administrative tasks.

With that done, enjoy - your first steps into the SELinux world are now made.

Supporting Service Administration

By default, the Gentoo Hardened SELinux policies will allow the sysadm_t domain access to all services. However, some of these services have policies that allow them to be assigned to individual, non-root users. This requires the user to be granted the system_r role (meaning the user can, under certain circumstances, have his role change towards the system role).

It is therefor recommended to grant the system_r role to the administrative SELinux user you are going to use most. This most likely is the root and staff_u SELinux user.

Code Listing 2.16: Granting the system_r role to the staff and root user

# semanage user -m -R "staff_r sysadm_r system_r" root
# semanage user -m -R "staff_r sysadm_r system_r" staff_u

2. Configuring SELinux For Your Needs

2.a. Administering Users

Introduction

During the installation, we already covered how to map a Linux user to a SELinux user. In the example, we used a hypothetical user "john" and mapped him to the SELinux user "staff_u". If you are running a multi-user system, managing the right mappings is important. A user that is mapped to the SELinux user "user_u" will not get any additional rights. Even if you would give that user additional rights through commands such as sudo, the SELinux policy will not allow this user to do anything that is administration related.

For this reason, it is important to go over the SELinux user mappings and the Linux users on your system.

User Mappings

Run semanage login -l to show the current mappings between Linux logins and SELinux users.

Code Listing 1.1: Running semanage login -l

# semanage login -l

Login Name                SELinux User

__default__               user_u
root                      root
john                      staff_u
system_u                  system_u

The "user_u" SELinux user is for regular accounts. As such, the special __default__ mapping is defined by SELinux to denote every login that is not defined otherwise. This makes sure that a newly defined account does not get elevated privileges by default.

The next table gives an overview of the standard SELinux users available after an installation.

SELinux User Description
user_u Default regular SELinux user, which should be used by end-user accounts that are not going to administer any service(s) on the system
staff_u SELinux user for administrators. This user has the right to switch roles and as such gain elevated privileges
root SELinux user for the root account. It differs little from the staff_u account beyond being a different ID. This ensures that files protected by the user based access control for root cannot be handled by the staff_u (and other) users
sysadm_u SELinux user for system administration. By default, this account is not immediately used as this user immediately gets the administrative role (whereas staff_u and root still need to switch roles).
system_u SELinux user for system services. It should never be used for end users or administrators as it provides direct access to the system role (and privileges)
unconfined_u Used when the policy is targeted, this SELinux user has many privileges (it is essentially not limited in its actions, although it is still handled through SELinux - just through a "wide open" policy).

To map a user to a specific SELinux user, use semanage login -a:

Code Listing 1.2: Mapping a user 'sophie' to the staff_u user

# semanage login -a -s staff_u sophie

However, when you update such mapping, the files in that users' home directory will be owned by a wrong SELinux user. It is therefor important to relabel the files of that user:

Code Listing 1.3: Relabeling sophie's files

# restorecon -R -F /home/sophie

Additional SELinux Accounts

It is perfectly possible to create additional SELinux accounts, and then map the Linux logins to these new accounts. This can be necessary when you want a more thorough auditing (on end user level) or when you will be enhancing the policy with additional roles. Also, if you want to use the User Based Access Control feature, using different SELinux users is important to enforce the control on different users (if they all use the same SELinux user, then UBAC has little to no effect).

Managing the SELinux accounts is done through semanage user:

Code Listing 1.4: Creating a SELinux user

# semanage user -a -R "staff_r sysadm_r" sophie

Let's verify how the SELinux users are currently configured:

Code Listing 1.5: Checking the SELinux user identities

# semanage user -l
SELinux User    SELinux Roles

root            staff_r sysadm_r
sophie          staff_r sysadm_r
staff_u         staff_r sysadm_r
sysadm_u        sysadm_r
system_u        system_r
unconfined_u    unconfined_r
user_u          user_r

# semanage login -l
Login Name                SELinux User

__default__               user_u
root                      root
sophie                    staff_u
swift                     staff_u
system_u                  system_u

Now that a new SELinux user called "sophie" exists, we can now update the Linux user mapping for "sophie" towards the new SELinux user "sophie":

Code Listing 1.6: Updating the Linux user mapping

# semanage login -m -s sophie sophie
# semanage login -l
Login Name                SELinux User

__default__               user_u
root                      root
sophie                    sophie
swift                     staff_u
system_u                  system_u

Again, do not forget to relabel this users' files.

As you can see, managing SELinux users means defining the roles to which the user has access to. We already gave a high-level introduction to the default roles in SELinux Concepts, but as roles are important when using a Mandatory Access Control system, let's refresh our memory again:

SELinux Role Description
user_r Default end-user role. This role provides access to regular applications and activities, but does not allow any system or service administration beyond what is expected for a regular user.
staff_r Default administration role for day-to-day activities. This role has some additional privileges beyond what is offered through user_r, but is not a full system administrative role. It is meant for the non-administrative activities done by operators and administrators
sysadm_r System administration role. This role is highly privileged (since it also contains the privileges to update the policy) and should only be given to fully trusted administrators. It is almost never immediately granted to users (they first need to switch roles) except for direct root access (for instance through the console)
system_r System service role, which is used for the runtime services (processes). It is only granted to users when they get specific, limited administrative rights (for instance administration rights on a single daemon domain).
unconfined_r The unconfined role is used when the targeted policy is supported. This role is given to unconfined users (such as the SELinux unconfined_u user) which have very wide privileges (they almost run without constraints).

It should be noted that these roles are the default ones, but the security administrator - yes, that means you - can create additional roles and add particular privileges to it. We will discuss this later in this book as it means you'll need to update the Gentoo Hardened SELinux policy.

2.b. Reading Audit Logs

Introduction

When working with a SELinux-enabled system, you will eventually notice that things behave differently, but without giving any meaningful error message. Usually, when SELinux "denies" a particular access, it logs it into the audit log of the system, but for the application itself, it is perfectly possible that it just silently dies. If not, you're most likely to get a permission denied error message.

Initially, SELinux is running in permissive mode, which means that SELinux will log what it would deny, but still let it through. This mode is perfect for getting the system in shape without having too much problems keeping it running. Once you think your security settings are in order, then this mode can be switched from permissive to enforcing. We'll talk about these modes later.

First, let's take a look at the audit log and see what it is saying...

Audit Log Location(s)

The SELinux kernel code writes its denials (and sometimes even allowed but audited activities) into the audit log. If you are running on a Gentoo Hardened installation with the syslog-ng system logger, then the logger is already configured to place these audit lines in /var/log/avc.log. However, different system loggers or system logger configurations might put the entries in a different log location (such as /var/log/audit.log).

Below, you'll find the appropriate lines for the syslog-ng system logger configuration for writing the events in /var/log/avc.log.

Code Listing 2.1: syslog-ng.conf excerpt for SELinux AVC entries

# The following lines are only /part/ of the configuration file!
source kernsrc  { file("/proc/kmsg");       };
destination avc { file("/var/log/avc.log"); };
filter f_avc    { message(".*avc: .*");     };

log {
  source(kernsrc);
  filter(f_avc);
  destination(avc);
};

What is AVC?

As we mentioned, SELinux writes its entries in the audit log. These entries are called avc messages or avc log entries. The abbreviation AVC stands for Access Vector Cache and, like the name sais, is a caching system.

Using an access vector cache improves performance on dealing with (and enforcing) activities and privileges. Since SELinux offers a very detailed approach on privileges and permissions, it would become quite painful (performance-wise) if each call means that the SELinux code needs to look up the domain, the target resource label, the privilege and if it is allowed or not over and over again. Instead, SELinux uses the Access Vector Cache to store past requests/responses. It is the AVC subsystem that is responsible for checking accesses and (if necessary) logging it.

Reading an AVC Denial Message

Below you'll find a typical AVC denial message.

Code Listing 2.2: Example AVC denial message

Oct 15 13:04:54 hpl kernel: [963185.177043] type=1400 audit(1318676694.660:2472): 
  avc:  denied  { module_request } for  pid=14561 comm="firefox" kmod="net-pf-10"
  scontext=staff_u:staff_r:mozilla_t tcontext=system_u:system_r:kernel_t tclass=system

Let's analyze each part of this message one by one.

Code Listing 2.3: AVC denial: Timestamp and location information

Oct 15 13:04:54 hpl kernel: [963185.177043] type=1400 audit(1318676694.660:2472): 
  avc:  denied  { module_request } for  pid=14561 comm="firefox" kmod="net-pf-10"
  scontext=staff_u:staff_r:mozilla_t tcontext=system_u:system_r:kernel_t tclass=system

This first part of the message informs you when the message was written (Oct 15 13:04:54), on which host (hpl) and how many seconds since the system was booted (963185.177043).

Code Listing 2.4: AVC denial: source information

Oct 15 13:04:54 hpl kernel: [963185.177043] type=1400 audit(1318676694.660:2472): 
  avc:  denied  { module_request } for  pid=14561 comm="firefox" kmod="net-pf-10"
  scontext=staff_u:staff_r:mozilla_t tcontext=system_u:system_r:kernel_t tclass=system

Next is the source of the denial, i.e. what process is trying to do something. In this case, the process is firefox, with PID 14561, which is running in the source domain staff_u:staff_r:mozilla_t.

Code Listing 2.5: AVC denial: target resource

Oct 15 13:04:54 hpl kernel: [963185.177043] type=1400 audit(1318676694.660:2472): 
  avc:  denied  { module_request } for  pid=14561 comm="firefox" kmod="net-pf-10"
  scontext=staff_u:staff_r:mozilla_t tcontext=system_u:system_r:kernel_t tclass=system

The target of the activity is a kernel module (net-pf-10, which is the internal name given for IPv6), labeled system_u:system_r:kernel_t

Code Listing 2.6: AVC denial: denied action

Oct 15 13:04:54 hpl kernel: [963185.177043] type=1400 audit(1318676694.660:2472): 
  avc:  denied  { module_request } for  pid=14561 comm="firefox" kmod="net-pf-10"
  scontext=staff_u:staff_r:mozilla_t tcontext=system_u:system_r:kernel_t tclass=system

Finally, the action that is denied (module_request) and its class (system). These classes help you to identify what is denied, because a read on a file is different from a read on a directory.

For instance, in the following case, a process gorg with PID 13935 is trying to read a file called localtime with inode 130867 which resides on the device /dev/md3:

Code Listing 2.7: AVC denial example

Oct 15 14:40:30 hpl kernel: [968909.807802] type=1400 audit(1318682430.323:2614):
  avc:  denied  { read } for  pid=13935 comm="gorg" name="localtime" dev=md3 ino=130867
  scontext=staff_u:sysadm_r:gorg_t tcontext=system_u:object_r:locale_t tclass=file

In this case, it might be obvious that the file is /etc/localtime, but when that isn't the case, then you can find the following two commands useful:

Code Listing 2.8: Finding out the target resource based on inode and device

(Find out which device /dev/md3 is)
# mount | grep /dev/md3
/dev/md3 on / type ext4 (rw,seclabel,noatime,barrier=1,nodelalloc,data=journal)

(Find out what file has inode 130867)
# find / -xdev -inum 130867
/etc/localtime

Handling AVC denials

The major part of configuring SELinux is reading the denials, finding out what needs to be fixed (or ignored), fix it, and repeat the steps. Hopefully, the rest of this handbook will help you figure out what is causing a denial.

Denials can be cosmetic (an activity that is denied, but has no effect on the application's functional behaviour). If that is the case, the denial can be marked as dontaudit, meaning that the denial is not logged by default anymore. If you think that a denial is occurring but you do not see it in the logs, try disabling the dontaudit rules:

Code Listing 2.9: Disabling dontaudit

(The command can also be abbreviated to "semodule -DB")
# semodule --build --disable_dontaudit

In most cases though, denials need to be acted upon. Actions that might need to happen are:

  • relabeling the target resource (wrong labels might cause legitimate actions to be denied)
  • relabeling the source (process' binary file) as a wrong label might cause the application to run in the wrong domain
  • loading a necessary SELinux module, since the modules contain the rules to allow (and label) resources. Without the appropriate module loaded, you will notice denials since no other module gives the necessary grants (allow statements)
  • granting the right role to the user executing the application. We have covered users and their roles initially but we will go deeper into this subject later in the handbook.
  • adding your own SELinux policy statements, most likely because no SELinux policy module exists for the application you are trying to run

2.c. Using (File) Labels

Introduction

Within SELinux, access privileges are based on the label given on the originating part (called the domain) and its target resource. For instance, a process running in the passwd_t domain wants to read (= privilege) the file /etc/shadow which is labeled shadow_t (= the target resource). It comes to no surprise then that the majority of SELinux administration is (re)labeling the resources correctly (and ensuring their label stays correct).

Getting File Label(s)

There are many ways to relabel commands, and none of them are equal to another. But before we explain this in more detail, let's first take a look at a few file labels (and how you can query them).

In SELinux, labels are given on a file level through the file systems' ability to keep extended attributes. For SELinux, the attribute is called security.selinux and can be obtained through getfattr:

Code Listing 3.1: Getting a file's extended attribute for SELinux

$ getfattr -n security.selinux /etc/hosts
# file: etc/hosts
security.selinux="system_u:object_r:net_conf_t"

Of course, getting the file attribute this way is time consuming and not that flexible. For this purpose, most important applications (including coreutils) are made SELinux-aware. These applications mostly use the -Z option to display the SELinux context information. In case of files, this means the extended attribute content:

Code Listing 3.2: Getting the context of a file

$ ls -Z /etc/hosts
system_u:object_r:net_conf_t   /etc/hosts

Other commands exist that display the context as it should be, like matchpathcon. However, their purpose is to query the SELinux policy on your system to find out what the policy ought to be, not what it is:

Code Listing 3.3: Difference between context and matchpathcon result

$ ls -Z /etc/portage/make.conf
staff_u:object_r:etc_t    /etc/portage/make.conf
$ matchpathcon /etc/portage/make.conf
/etc/portage/make.conf            system_u:object_r:portage_conf_t

Setting File Label(s)

Now how can you manipulate file labels? Well, first of all: you will not be allowed to change the file labels of any possible file (not even if you are the owner of that file) unless the SELinux policy allows you to. These allow rules are made on two privilege types: which labels are you allowed to change (relabelfrom) and to which labels are you allowed to change (relabelto). You can query these rules through sesearch:

Code Listing 3.4: Querying the relabelto/relabelfrom types

# From which label on files (-c) is user_t (-s) allowed (-A) to relabel from (-p)?
$ sesearch -s user_t -c file -p relabelfrom -A
[...]
allow user_t mozilla_home_t : file { ... relabelfrom relabelto } ;

If you have the permission, then you can use chcon to change the context of a file:

Code Listing 3.5: Changing a file context

$ ls -Z strace.log
staff_u:object_r:user_home_t  strace.log
$ chcon -t mutt_home_t strace.log
$ ls -Z strace.log
staff_u:object_r:mutt_home_t  strace.log

If you do not hold the right privileges, you will get a descriptive error message:

Code Listing 3.6: Trying to change file context

$ chcon -t shadow_t strace.log
chcon: failed to change context of `strace.log' to `staff_u:object_r:shadow_t': Permission denied

Now, if you now think that chcon is all you need, you're wrong. The chcon command does nothing more than what it sais - change context. But when the system relabels files, these changes are gone. Relabeling files is often done to ensure that the file labels are correct (as in: the labels match what the SELinux policy sais they ought to be). The SELinux policy contains, for each policy module, the list of files, directories, sockets, ... and their appropriate file context (label).

We will look at SELinux policy modules later, but below you'll find an excerpt from such a definition, for the mozilla module:

Code Listing 3.7: Excerpt of the mozilla module file contexts

/usr/bin/firefox-bin                            -- gen_context(system_u:object_r:mozilla_exec_t,s0)
/usr/bin/mozilla-[0-9].*                        -- gen_context(system_u:object_r:mozilla_exec_t,s0)
/usr/bin/mozilla-bin-[0-9].*                    -- gen_context(system_u:object_r:mozilla_exec_t,s0)
/usr/lib(64)?/galeon/galeon                     -- gen_context(system_u:object_r:mozilla_exec_t,s0)
/usr/lib(64)?/netscape/.+/communicator/communicator-smotif\.real -- gen_context(system_u:object_r:mozilla_exec_t,s0)
/usr/lib(64)?/netscape/base-4/wrapper           -- gen_context(system_u:object_r:mozilla_exec_t,s0)
/usr/lib/[^/]*firefox[^/]*/plugin-container     -- gen_context(system_u:object_r:mozilla_plugin_exec_t,s0)
/usr/lib64/[^/]*firefox[^/]*/plugin-container   -- gen_context(system_u:object_r:mozilla_plugin_exec_t,s0)

To put the right label on a file, you can use the setfiles or restorecon commands. Since they are both the same command (but with a slightly different way of using) we'll only talk about restorecon for now - more information on the setfiles command can be found in its man page.

When you use restorecon, the application will query the SELinux policy to find out what the right label of the file should be. If it differs, it will change the label to the right setting. That means that you do not need to provide the label for a file in order for the command to work. Also, restorecon supports recursivity, so you do not need to relabel files one by one.

Code Listing 3.8: Using restorecon

$ ls -Z /etc/portage/make.conf
staff_u:object_r:etc_t            /etc/portage/make.conf
$ restorecon /etc/portage/make.conf
$ ls -Z /etc/portage/make.conf
system_u:object_r:portage_conf_t  /etc/portage/make.conf

Finally, Gentoo also provides a useful application: rlpkg. This script relabels the files of a Gentoo package (rlpkg <packagename>) or, given the right arguments, all files on the file system:

Code Listing 3.9: Using rlpkg

# Relabel the files of the firefox-bin package:
# rlpkg firefox

# Relabel all files on the file system:
# rlpkg -a -r

Overriding the SELinux Policy File Labels

You might not always agree with the label that the SELinux policy enforces on the files: you might have your files located elsewhere (a different location for your Portage tree is a nice example) or you need to label them differently in order for other applications to work. To not have to chcon these files over and over again, you can enhance the SELinux policy on your system with additional file context rules. These rules are used when you call restorecon as well and override the rules provided by the SELinux policy.

To add additional file context rules, you need to use the semanage command. This command is used to manage, manipulate and update the local SELinux policy on your system. In this particular case, we will use the semanage fcontext command:

Code Listing 3.10: Using semanage to add a file context rule

# Mark /mnt/gentoo/etc/portage/make.conf as a portage_conf_t type
# semanage fcontext -a -t portage_conf_t /mnt/gentoo/etc/portage/make.conf

# Mark /mnt/gentoo/usr/portage as portage_ebuild_t
# semanage fcontext -a -t portage_ebuild_t "/mnt/gentoo/usr/portage(/.*)?"

As you can see from the example, you can use wildcards. But beware about using wildcards: when a rule holds a wildcard, it has a lower priority than a rule without a wildcard. And the priority on rules with a wildcard is based on how "down" the string the first occurance of a wildcard is. For more information, please check out our FAQ on "How do I know which file context rule is used for a particular file?."

If you want to delete a file context definition, you use semanage fcontext -d:

Code Listing 3.11: Deleting a file context definition

# semanage fcontext -d -t portage_ebuild_t /mnt/gentoo/etc/portage/make.conf

Finally, to view all file context definitions (both user-set and SELinux policy provided), you can use semanage fcontext -l. To only see the locally set, add -C:

Code Listing 3.12: Viewing user-set file context enhancements

# semanage fcontext -C -l
SELinux fcontext                          type             Context
/opt/xxe/bin/.*\.jar                      all files        system_u:object_r:lib_t
/srv/virt/gentoo(/.*)?                    all files        system_u:object_r:qemu_image_t

Customizable types

Labels on files are not that hard to understand, but you might come into some surprises if you do not know that there are also customizable types.

A customizable type is a specific type which is not touched by the SELinux administration tools by default. If you want to relabel a file that currently holds a customizable type, you will need to force this through the commands (such as restorecon -F).

There are not that many customizable types by default. The list of types that SELinux considers as customizable are mentioned in the customizable_types file within the /etc/selinux/*/contexts location:

Code Listing 3.13: Listing the customizable types

# cat /etc/selinux/strict/contexts/customizable_types
mount_loopback_t
public_content_rw_t
public_content_t
swapfile_t
textrel_shlib_t

Such types exist because these types are used for files whose location is known not to be fixed (and as such, the SELinux policy cannot without a doubt know if the label on the files is correct or not). The public_content_t one, which is used for files that are readable by several services (like FTP, web server, ...), might give you a nice example for such a case.

If you look at the restorecon man page, it mentions both customizable types as well as the user section. The latter is for rules that are identified in the SELinux policy as being files for an end user, like the following definitions in the mozilla policy module:

Code Listing 3.14: User section definition within mozilla module

HOME_DIR/\.mozilla(/.*)?      gen_context(system_u:object_r:mozilla_home_t,s0)
HOME_DIR/\.netscape(/.*)?     gen_context(system_u:object_r:mozilla_home_t,s0)
HOME_DIR/\.phoenix(/.*)?      gen_context(system_u:object_r:mozilla_home_t,s0)

Although in the above example, forcing restorecon on the files is probably correct, there are examples where you do not want this. For instance, the firefox policy by default only allows the application to write to directories labeled mozilla_home_t. If you want to download something, this isn't possible (unless you download it into ~/.mozilla). The solution there is to label a directory (say ~/Downloads) as mozilla_home_t.

2.d. SELinux Policy and Booleans

Introduction

We have dealt with users and labels now, but there is still a third aspect that we haven't touched: the SELinux policy itself.

The SELinux policy as offered by Gentoo Hardened is a carefully tuned SELinux policy, based on the reference policy (a distribution-agnostic SELinux policy) with minor changes. Hopefully, you will not need to rewrite the policy to suit it for your needs, but changes are very likely to occur here and there.

Changing the SELinux Policy Behavior: Booleans

A common and user friendly way of tweaking the SELinux policy is through booleans. A SELinux boolean, also known as a conditional, changes how the SELinux policy behaves based on the setting that the user provides. To make this a bit more clear, let's look at a few booleans available:

Code Listing 4.1: Getting SELinux booleans

# getsebool -a | grep ^user
user_direct_mouse --> off
user_dmesg --> off
user_ping --> on
user_rw_noexattrfile --> off
user_tcp_server --> off
user_ttyfile_stat --> off

Although they might not say much on first sight, these booleans alter how the SELinux policy enforces user activity (hence the booleans starting with user_). For instance, user_ping is set to on, so a user is allowed to use ping. If it was set to off, the SELinux policy would not allow a user to execute ping.

Booleans can be toggled on or off using setsebool or togglesebool. With setsebool you need to give the value (on or off) whereas togglesebool switches the value.

Code Listing 4.2: Disallowing the use of ping by users

# setsebool user_ping off

By default, setsebool does not store the boolean values - after a reboot, the old values are used again. To persist such changes, you need to add the -P option:

Code Listing 4.3: Persistedly allow users to run dmesg

# setsebool -P user_dmesg on

Booleans allow administrators to tune the policy, and allow security administrators to write policies that are flexible enough for a more widespread use. In terms of Gentoo flexibility, these booleans might not be used enough (it would be nice to couple these booleans on USE flags, so that a server build with USE="ldap" gets the SELinux policy to use ldap, whereas USE="-ldap" disallows it). But still, the use of booleans is a popular method for making a more flexible SELinux policy.

Managing SELinux Policy Modules

In this last part, we'll cover SELinux policy modules. We mentioned before that the SELinux policy used by Gentoo Hardened is based on the reference policy, which offers a modular approach to SELinux policies. There is one base policy, which is mandatory on every system and is kept as small as possible. The rest are SELinux policy modules, usually providing the declarations, rules and file contexts for a single application (or type of applications).

With semodule -l you can see the list of SELinux policy modules loaded:

Code Listing 4.4: Listing the loaded SELinux modules

# semodule -l
alsa       1.11.0
apache     2.3.0
entropyd   1.6.0
dbus       1.15.0
dnsmasq    1.9.0
(...)

Within Gentoo Hardened, each module is provided by the package sec-policy/selinux-<modulename>. For instance, the first module encountered in the above example is provided by selinux-alsa:

Code Listing 4.5: The SELinux policy module package in Gentoo

$ emerge --search selinux-alsa
Searching...
[ Results for search key : selinux-alsa ]
[ Applications found : 1]

* sec-policy/selinux-alsa
    Latest version available: 2.20110726
    Latest version installed: 2.20110726
    Size of files: 574 kB
    Homepage:      http://www.gentoo.org/proj/en/hardened/selinux/
    Description:   SELinux policy for alsa
    License:       GPL-2

If you need a module that isn't installed on your system, this is considered a bug (packages that need it should depend on the SELinux policy package if the selinux USE flag is set). But once you install the package yourself, the module will be loaded automatically:

Code Listing 4.6: Installing a SELinux policy package

# emerge selinux-screen

If you want to remove a module from your system though, uninstalling the package will not suffice: the SELinux policy module itself is copied to the policy store earlier (as part of the installation process) and is not removed from this store by Portage. Instead, you will need to remove the module manually:

Code Listing 4.7: Uninstalling a SELinux policy module

# emerge -C selinux-screen
# semodule -r screen

2.e. Next steps

What to do now?

Up until now, your system has been running in permissive mode. You will need to enable enforcing before you are properly protected by SELinux. We will discuss how to switch to enforcing mode in Permissive, Unconfined, Disabled or What Not... but before that, you will need to consider a few things...

Initramfs users

If your system uses an initramfs to boot up, you will not be able to boot straight into enforcing mode (due to bug #397597). To work around this issue, you can create the following init script which will switch from a permissive mode into forcing mode reasonably fast within the boot process (and before the network is started):

Code Listing 5.1: Content of /etc/init.d/selinux_enforce

#!/sbin/runscript
# Copyright 1999-2012 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2
# $Header: /var/cvsroot/gentoo/xml/htdocs/proj/en/hardened/selinux/hb-using-configuring.xml,v 1.7 2013/08/10 17:11:03 swift Exp $

description="Switch into SELinux enforcing mode"

depend() {
	need sysfs
}

start() {
	if get_bootparam "norestorecon" ; then
		ewarn "Skipping restoring file contexts in /dev as requested"
	else
		ebegin "Restoring file contexts in /dev"
			restorecon -R /dev
		eend 0
	fi
	
	if get_bootparam "nosetenforce" ; then
		ewarn "Skipping switching to enforcing mode as requested by kernel cmdline"
	else
		. /etc/selinux/config
		CURRENTMODE=$(cat /sys/fs/selinux/enforce)

		if [ "${SELINUX}" = "enforcing" ] && [ "${CURRENTMODE}" = "0" ];
		then
			ebegin "Switching to enforcing mode"
			echo 1 > /sys/fs/selinux/enforce
			eend $?
		else
			ewarn "Not switching to enforcing mode, or enforcing mode already enabled"
		fi
	fi
}

Add the init script to the boot runlevel, and edit your boot loader configuration to always boot with enforcing=0 set. The init script will update the file contexts in /dev and then, if your system is configured to run in enforcing mode, switch to enforcing mode.

If you need to temporarily stay in permissive mode, you can add nosetenforce as boot parameter (after enforcing=0) which will skip the setenforce step).

Users of a graphical environment

If you boot into a graphical environment (using GDM, KDM or another graphical login manager) you will need to update the PAM configuration file(s) of the managers with the following:

Code Listing 5.2: Example update on LXDM PAM configuration file

# /etc/pam.d/lxdm
# [...]
session    required     pam_loginuid.so
session    optional     pam_gnome_keyring.so auto_start
session	   optional     pam_selinux.so

This will ensure that the security context in which you are logged on is set correctly. We will update the packages that place those PAM files accordingly, but it might take some time.

3. SELinux Commands

3.a. SELinux Information Commands

Introduction

You should currently have a SELinux enabled system (but running in permissive mode, so it will not enforce its policy rules). So before we introduce you to the world of SELinux and how you can add more rules to make sure your system remains functional when you switch to enforcing mode, we first give a quick overview of the various SELinux related commands.

We start off with state commands where you can get global information on SELinux state (is it running in enforcing mode or not, versions etc.)

Getting SELinux Status

The first command we will talk about is sestatus.

Code Listing 1.1: Running sestatus

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

The output of this command shows you that SELinux is enabled and is currently in the permissive mode. It also tells you that the system is configured to run in strict mode - so no unconfined_t domain here.

The sestatus command also has an extended output if you run it with the -v option. When this is done, the command returns the contexts of important processes and files:

Code Listing 1.2: Running sestatus -v

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

Process contexts:
Current context:                staff_u:sysadm_r:sysadm_t
Init context:                   system_u:system_r:init_t
/sbin/agetty                    system_u:system_r:getty_t
/usr/sbin/sshd                  system_u:system_r:sshd_t

File contexts:
Controlling term:               staff_u:object_r:user_devpts_t
/sbin/init                      system_u:object_r:init_exec_t
/sbin/agetty                    system_u:object_r:getty_exec_t
/bin/login                      system_u:object_r:login_exec_t
/sbin/rc                        system_u:object_r:rc_exec_t
/usr/sbin/sshd                  system_u:object_r:sshd_exec_t
/sbin/unix_chkpwd               system_u:object_r:chkpwd_exec_t
/etc/passwd                     system_u:object_r:etc_t
/etc/shadow                     system_u:object_r:shadow_t
/bin/sh                         system_u:object_r:bin_t -> system_u:object_r:shell_exec_t
/bin/bash                       system_u:object_r:shell_exec_t
/usr/bin/newrole                system_u:object_r:newrole_exec_t
/lib/libc.so.6                  system_u:object_r:lib_t -> system_u:object_r:lib_t
/lib/ld-linux.so.2              system_u:object_r:lib_t -> system_u:object_r:ld_so_t

Another general SELinux status command is getenforce, which allows you to quickly see if your SELinux is running in enforcing mode (SELinux policies are enforced), permissive (SELinux policies are checked and logged, but not enforced) or disabled (SELinux policy is not loaded and thus not checked).

Code Listing 1.3: Using the getenforce command

# getenforce
Enforcing

Getting SELinux Object Information

Next on the table is the seinfo command. This command allows you to query the running policy for all objects (types, roles, attributes, users, booleans ...) defined.

Common usages are:

  • checking if a specific domain is defined on your system (in case you're wondering if you need to load an additional SELinux policy module or not)
  • checking which domains a particular role can be in (in case you're wondering if your regular users are allowed by SELinux policies to even be transitioned towards a specific domain)
  • checking which attributes are assigned to a specific domain (or vice versa, which domains have a specific attribute set) as some SELinux policy rules work on attributes rather than domains

As an example, we query if the crontab_t domain is known, if the user_r role can use the contab_t domain and finally which domains have the cron_spool_type attribute set.

Code Listing 1.4: Using seinfo

# seinfo -tcrontab_t
  crontab_t
# seinfo -ruser_r -x
  user_r
    Dominated Roles:
      user_r
    Types:
      [...]
      crontab_t
      [...]
# seinfo -acron_spool_type -x
  cron_spool_type
    user_cron_spool_t
    system_cron_spool_t

Querying SELinux Policy Rules

A command which you will often use is sesearch. This command allows you to query the current policy allow rules and is a huge help when trying to find out if something is allowed (or why something isn't allowed).

The sesearch command is most often used with a source domain (-s), target domain (-t) or both, the class for which you want to query allow rules for (file, dir, socket, process ...) and the privilege you want to query for (read, write, open, transition, execute ...).

For instance, to find out which domains can write the files that have the shadow_t domain:

Code Listing 1.5: Querying allow rules with sesearch

# sesearch -t shadow_t -c file -p write -A
Found 8 semantic av rules:
  [...]
  allow portage_t shadow_t : file { ioctl read write ... };
  allow useradd_t shadow_t : file { ioctl read write ... };
  ...

You will notice that there are sometimes results based on attributes rather than domains:

Code Listing 1.6: Allow rule based on attribute

  allow portage_t file_type : file { ioctl read write ... };

In this case, the source domain (portage_t) is allowed to write to files whose domain have the file_type attribute set. If you get the feeling of these things, you'll wonder if the above rule is not a flagrant security issue as almost all domains for files have the file_type set. Yes and no - if we take a look at which domains have file write privileges to file_type domains, you'll notice that this is only portage:

Code Listing 1.7: Querying domains with file-write privileges to file_type domains

# sesearch -t file_type -c file -p write -A -d
Found 1 semantic av rules:
  allow portage_t file_type : file { ioctl read write ... };

Note that we had one command without the -d option and one with. When -d is given, the search will perform an exact search without resolving the attributes. When -d is not given, it will resolve the attribute. In the last command example, dropping -d would result in hundreds of allow rules: for each domain that has file_type set, the search tries to find rules that allow file-write access to that particular domain.

Another interesting functionality of the sesearch command is to show you the rules that are applicable depending on the state of a boolean. If you want to query on a particular boolean, use -b. If you want to see the logic that the policy uses, use -C (and yes, both can be combined).

As an example, we'll check what we allow (or deny) when the global_ssp boolean is set:

Code Listing 1.8: Checking the policy regarding the global_ssp boolean

# sesearch -b global_ssp -A -C -d
Found 2 semantic av rules:
ET allow domain device_t : dir { getattr search open } ; [ global_ssp ]
ET allow domain urandom_device_t : chr_file { ioctl read getattr lock open } ; [ global_ssp ]

The prefix you see shows two letters, relating to two important definitions:

  • Is the rule currently Enabled or Disabled?
  • Does the boolean need to be set to True or False to enable the rule?

Getting Security Context Information

During administrative tasks, and especially when you are checking if a SELinux denial could be made, it is important to find out what the security context is for a particular resource. Luckily, Gentoo Hardened - if properly installed - has already patched some tools to allow you to get this information using your standard tools.

To get the security context of a file, use ls -Z:

Code Listing 1.9: Getting a file security context

~$ ls -Z /etc/portage/make.conf
system_u:object_r:portage_conf_t /etc/portage/make.conf

To get the security context of a process, use ps -Z:

Code Listing 1.10: Getting a process security context

# ps -Z $(pidof init)
LABEL                             PID TTY      STAT   TIME COMMAND
system_u:system_r:init_t            1 ?        Ss     0:00 init [3]  

To get the security context of the current user, use id -Z:

Code Listing 1.11: Getting a user security context

~$ id -Z
staff_u:staff_r:staff_t

3.b. Managing SELinux

Introduction

Managing SELinux objects (booleans, users, ports, contexts ...) is most often done using semanage. As this application offers the interface towards various SELinux configurations, we dedicate an entire section on it, but will also cover the commands that offer similar functionality (and are sometimes easier to remember).

Booleans

We have already covered SELinux booleans earlier in this book as well as the getsebool and setsebool commands. With semanage you can too manage the booleans and, as an added bonus, listing the booleans will also show the description of the boolean (even though there is still work to be done in this area).

Code Listing 2.1: Listing the available SELinux booleans

# semanage boolean -l
SELinux boolean                 Description

allow_ptrace            -> off  allow_ptrace
rsync_export_all_ro     -> off  rsync_export_all_ro

Note: As you will notice, most descriptions are just the boolean name, but you will find more and more booleans with a better description as you get acquainted with - and install more - SELinux policy modules.

You can set a boolean with both setsebool and semanage:

Code Listing 2.2: Setting SELinux boolean values

# semanage boolean -m --on -F user_dmesg

SELinux Users and Logins

SELinux users and logins are different from Unix accounts. SELinux logins allow you to map a Unix account to a SELinux user:

Code Listing 2.3: Listing the SELinux logins

# semanage login -l
Login Name          SELinux User

__default__         user_u
root                root
swift               staff_u
system_u            system_u

The default behavior is that users are logged on as the user_u SELinux user. This SELinux user is a non-administrator user: it has no specific privileges and should be used for every account that never requires elevated privileges (so no su or sudo rights for anything).

The account you use to administer your system should be mapped to the staff_u SELinux user (or its own user with the appropriate roles). This can be accomplished as follows (example with the Unix account anna):

Code Listing 2.4: Letting 'anna' log on as 'staff_u'

# semanage login -a -s staff_u anna

Important: Make sure that whatever account you use to administer your system is mapped to the staff_u user, or has the ability to switch to the sysadm_r role. Portage only works from within the sysadm_r role.

As mentioned, SELinux users are configured to be able to join in on one or more roles. To list the available roles, you can use semanage user -l:

Code Listing 2.5: Listing login / role mappings

# semanage user -l
SELinux User        SELinux Roles

root                staff_r sysadm_r
staff_u             staff_r sysadm_r
[...]

Managing Ports

Even network ports (like port 22 for SSH) are 'protected' by SELinux. To get an overview of which domains are assigned to which ports (or port ranges) use semanage port -l.

Code Listing 2.6: Listing SELinux managed ports

# semanage port -l | grep '22$'
ssh_port_t             tcp     22

3.c. Using SELinux

Introduction

Up until now we've covered getting SELinux related information as well as managing SELinux settings. However, users on a SELinux hardened system will also need to know a few things about working with SELinux, including (but not limited to) roles and role transitions.

Switching Roles

As a type enforcement access control system, SELinux allows particular roles to be within a set of domains. If you are using a role which is not allowed within a particular domain, you will not be successful in using that domain and will be denied the actions assigned to that domain.

If your standard users are all SELinux user_u users (with the only supported role being user_r) then those users will never need to switch roles (nor are they allowed to). But users that are staff_u (or other users that have multiple roles) those users should be made clear how they switch between roles. We have already covered how to map such users to the correct SELinux user (see SELinux Users and Logins).

The command that accomplishes switching roles is called newrole. It's use is pretty straight forward.

Code Listing 3.1: Using newrole

~$ newrole -r sysadm_r
Password: (Enter the users' password)

When performing a role transition, SELinux will ask the user to re-authenticate through its users' password.

4. Permissive, Unconfined, Disabled or What Not...

4.a. SELinux States

Introduction

When SELinux is available, it will generally be in one of three states on your system: disabled, permissive or enforcing.

Disabled

When getenforce returns "Disabled", then SELinux is not running on your system. Even though it might be built in your kernel, it is definitely disabled. Your system will still run with regular discretionary access controls (the usual permission rules for standard Linux environments) but the mandatory access controls are not active.

When SELinux is disabled, it also means that files, directories, etc that are modified or created will not get the proper SELinux context assigned to them. When you later start your system with SELinux enabled (permissive or enforcing), issues will arise since the SELinux subsystem will not know which label the files have (it will default the label to one that is not accessible by most domains).

The best way to go forward in such case is to boot in permissive mode and then relabel the entire file system:

Code Listing 1.1: Relabeling the entire file system

# rlpkg -a -r

Permissive

When SELinux is enabled in permissive mode (getenforce returns "Permissive"), then SELinux is enabled and it has a policy loaded. Every access a process makes is checked against the policy rules and, if an access is not allowed, it will be logged (unless the denial is marked as dontaudit) but it will not be prohibited.

The permissive mode is perfect to get acquainted with SELinux and have the system made ready for future "enforcing" mode. While running in permissive mode, applications that are not SELinux aware will behave as if SELinux is not running. This is perfect to validate if a problem is caused by SELinux or not: if in permissive mode the problem still persists, then it is not caused by SELinux.

There is one caveat though: if the application is SELinux-aware (it knows that it can run in a SELinux environment and is able to make SELinux-specific calls) it might still react differently. Although this is often (but not always) a bad programming practice, some applications check if SELinux is enabled and base their functional flow on the results, regardless of the state being permissive or enforcing.

To find out if an application is SELinux aware, simply check if it is linked against libselinux (with ldd or scanelf - part of app-misc/pax-utils):

Code Listing 1.2: Checking if /bin/ls is SELinux-aware

# scanelf -n /bin/ls
 TYPE     NEEDED FILE
ET_DYN   libselinux.so.1,librt.so.1,libc.so.6   /bin/ls

Enforcing

If getenforce returns "Enforcing", then SELinux is loaded and will act based on the policy. When a process tries some activity that is not allowed by the policy, it will be logged (unless a dontaudit is set) and the activity will not go through. This is the only mode where you can truely say that SELinux is active, because it is only now that the policy is acted upon.

Switching States

Depending on your Linux kernel configuration, you can switch between states using one of the following methods. The kernel configuration however can be made so that some of these options are disabled (for instance, a fully hardened system will not allow disabling SELinux in any way).

Using the command setenforce:

Code Listing 1.3: Switching between enforcing and permissive

(Switching to permissive mode)
# setenforce 0

(Switching to enforcing mode)
# setenforce 1

Using the kernel boot option enforcing:

Code Listing 1.4: Switching between enforcing and permissive through boot options

(The following GRUB kernel line would boot in permissive mode)
kernel /kernel-2.6.39-hardened-r8 root=/dev/md3 rootflags=data=journal enforcing=0

Using the /etc/selinux/config SELINUX variable:

Code Listing 1.5: /etc/selinux/config SELINUX setting

# cat /etc/selinux/config
# This file controls the state of SELinux on the system on boot.

# SELINUX can take one of these three values:
#       enforcing - SELinux security policy is enforced.
#       permissive - SELinux prints warnings instead of enforcing.
#       disabled - No SELinux policy is loaded.
SELINUX=enforcing

# SELINUXTYPE can take one of these four values:
#       targeted - Only targeted network daemons are protected.
#       strict   - Full SELinux protection.
#       mls      - Full SELinux protection with Multi-Level Security
#       mcs      - Full SELinux protection with Multi-Category Security 
#                  (mls, but only one sensitivity level)
SELINUXTYPE=strict

When you want to switch from permissive to enforcing, it is recommended to do so in the order given above:

  1. First boot up in permissive mode, log on, verify that your context is correct (id -Z) and then switch to enforcing (setenforce 1). You can now test if your system is still working properly.
  2. Next, boot with enforcing=1 as kernel parameter (unless you boot with an initramfs, see earlier in this handbook). This way, your system will boot in enforcing mode, but if things go haywire, you can just reboot, leave out the option and be back in permissive mode
  3. Finally, edit /etc/selinux/config to persist this change.

Domain-permissive Mode

You can also opt to mark a single domain permissive while running the rest of the system in an enforcing state. For instance, to mark mplayer_t as a permissive domain (which means that SELinux does not enforce anything):

Code Listing 1.6: Marking mplayer_t as permissive

# semanage permissive -a mplayer_t

With the -d option, you can remove the permissive mark again.

4.b. SELinux Policy Types

Introduction

Next to the SELinux state, SELinux also offers different policy types. These types differentiate themselves in specific SELinux features that are enabled or disabled. Within Gentoo, three are supported (and a fourth is available): targeted, strict, mcs (and mls).

The type used on a system is declared in /etc/selinux/config:

Code Listing 2.1: The SELINUXTYPE information in /etc/selinux/config

# cat /etc/selinux/config
# This file controls the state of SELinux on the system on boot.

# SELINUX can take one of these three values:
#       enforcing - SELinux security policy is enforced.
#       permissive - SELinux prints warnings instead of enforcing.
#       disabled - No SELinux policy is loaded.
SELINUX=enforcing

# SELINUXTYPE can take one of these four values:
#       targeted - Only targeted network daemons are protected.
#       strict   - Full SELinux protection.
#       mls      - Full SELinux protection with Multi-Level Security
#       mcs      - Full SELinux protection with Multi-Category Security 
#                  (mls, but only one sensitivity level)
SELINUXTYPE=strict

strict (without unconfined domains)

The strict policy type is the policy type that was described in the earlier chapters, and coincidentally the type that is the easiest to understand. With the strict policy type, each and every application runs in a domain that has limited privileges. Although there are highly privileged domains, they are never truely unlimited in their privileges.

targeted (using unconfined domains)

The targeted policy type is similar to the strict one, with one major addition: support for unconfined domains. Applications (or users) that run in an unconfined domain are almost unlimited in their privileges. The unconfined domains are usually used for users and user applications, but also the init system and other domains are marked as "unconfined" domains.

The idea behind the targeted policy is that network-facing services are running in (confined) regular domains whereas the rest uses the standard discretionary access controls offered by Linux. These other domains are running as "unconfined".

mcs (using multiple categories)

The introduction of mls and mcs offers the ability for multi-tenancy: multiple instances of the same application should be able to run, but each instance should be confined with respect to the others (instead of all these processes running in the same domain and, hence, the same privileges).

A simple example is virtualization: a virtual guest which runs in the qemu_t domain needs write privileges on the image file that contains the guest operating system. However, if you run two guests, you do not want each guest to write to the other guests' file. With regular domains, you will need to provide this. With mcs, you can give each running instance a specific category (number) and only grant it write privileges to the guest file with the correct category (number).

mls (using multiple security levels)

The mls policy type is available but not yet supported by Gentoo Hardened. With this policy type, it is possible to give sensitivity levels on files and resources as well as domains. Sensitivity levels can best be expressed in terms of public, private, confidential or strictly confidential. With MLS, you can mark a file as one (or a set of) sensitivity level(s) and ensure that only domains with the right sensitivity level can access it.

Switching Types

It is not recommended to switch between types often. At best, you choose your policy type at install time and stick with it. But it is not impossible (nor that hard) to switch between types.

Make sure that your POLICY_TYPES variable in make.conf contains the target policy type already and that the SELinux policy packages have been built since. If that isn't the case, edit the POLICY_TYPES variable to include the target policy type, and rebuild all SELinux policy packages using emerge $(qlist -IC sec-policy).

Now switch your system to permissive mode using setenforce 0 or, if your system does not allow switching the mode, edit /etc/selinux/config to have the system boot in permissive mode. If you cannot use setenforce 0 then you need to reboot now so that the system is in permissive mode.

Next, edit /etc/selinux/config and change the SELINUXTYPE variable from the current policy type to the new one. This will tell SELinux to load the right policy at boot time.

Now go to the built policy modules in /usr/share/selinux because we need to load in the new policy (as you are currently still running with the old type). The next example shows how to do this if you come from a strict policy type and want to go to mcs:

Code Listing 2.2: Loading in the mcs policy

# cd /usr/share/selinux/mcs
# semodule -b base.pp -i $(ls *.pp | grep -v base.pp | grep -v unconfined.pp)

You are now running with the mcs policy loaded, but will have lots of denials if you do anything on the file system, because the files on your file system are not labeled correctly: the mcs policy type requires the labels to have a sensitivity label on them, which isn't the case if you use the strict policy. So let's relabel the entire file system, including those locations that might be hidden because other file systems are mounted on top of it.

Code Listing 2.3: Relabeling the entire file system

(Substitute "strict" with your SELINUXTYPE, and use "lib" instead of "lib64"
if you have a 32-bit system)
# rlpkg -a -r
# mount -o bind / /mnt/gentoo
# setfiles -r /mnt/gentoo /etc/selinux/strict/contexts/files/file_contexts /mnt/gentoo/dev
# setfiles -r /mnt/gentoo /etc/selinux/strict/contexts/files/file_contexts /mnt/gentoo/lib64
# umount /mnt/gentoo

Finally, edit /etc/fstab and update the rootcontext= parameters to include a sensitivity label as well (in case you switched towards mcs or mls) or not anymore (in case you switched to targeted or strict).

Code Listing 2.4: Changing /etc/fstab

# Example when switching from strict to mcs
tmpfs  /tmp  tmpfs  defaults,noexec,nosuid,rootcontext=system_u:object_r:tmp_t:s0  0 0

With all these steps now completed, reboot to ensure that everything is still working correctly (even the boot-up).

5. Modifying the Gentoo Hardened SELinux Policy

5.a. SELinux Policy Language

Introduction

By default, Gentoo provides a generic, yet tightly controlled policy which is deemed a good start policy for the majority of users. However, the purpose behind a Mandatory Access Control system is to put the security administrator in control. As such, a handbook on SELinux without information on how to write policies wouldn't be complete.

In this chapter, we'll talk a bit about the language behind SELinux policies and give some pointers on how to create your own policies, roles, etc.

Building a SELinux Module

First, before we go into the art of SELinux policy writing, let's first make a small SELinux module with a rule we can test, build the module and see if things work. Although these steps are fairly easy, they are important nonetheless. Modifying the SELinux policy as offered by Gentoo is best done through additional SELinux policy modules. Only when the core policy (the base policy) is not to your liking should you see on using a totally different policy.

Let's start with a skeleton for a policy module we'll call testmod. You should use simple names for the modules as the build infrastructure is quite sensitive to special constructs. Use only letters a-z and numbers, and never start a module name with a number.

Code Listing 1.1: Policy module skeleton

policy_module(testmod, 1.0.0)

Yes, that's it. But as you can see, it is fairly empty. So let's add a rule that allows a regular user (in the user_t domain) to read ebuild files (of type portage_ebuild_t).

Code Listing 1.2: Policy module testmod

policy_module(testmod, 1.0.0)

require {
  type user_t;
  type portage_ebuild_t;
  class file { read open getattr };
  class dir { read search open getattr };
}

allow user_t portage_ebuild_t:file { read open getattr };
allow user_t portage_ebuild_t:dir { read search open getattr };

As you can see, something as simple as allowing a user to read a file requires quite a few privileges. The directory privileges are needed to allow a user to navigate through the Portage tree structure whereas the file privileges are needed for a user to be able to access and open the ebuilds. Save this file as testmod.te.

To build the policy and convert it into the binary module that we can load into the SELinux policy store, we can use the Makefile available in /usr/share/selinux/strict/include (substitute strict with the SELinux policy type you are using).

Code Listing 1.3: Building a binary policy module

$ make -f /usr/share/selinux/strict/include/Makefile testmod.pp

The filename (testmod.pp) is the destination binary SELinux module name. The Makefile will automatically look for the testmod.te file you have in the working directory.

As a result, you should now have a file called testmod.pp. This module file can now be loaded in the SELinux policy store as follows:

Code Listing 1.4: Loading a binary module

# semodule -i /path/to/testmod.pp

Congratulations! You have now build your first SELinux policy module. If you want to disable it, remove it through semodule -r testmod.

This method of building a policy (using the Makefile and semodule) is something that you will need to do every time you want to update the SELinux policy on your system. The contents of the policy however does change as we will see in the rest of this document.

Getting the SELinux Policy Interfaces

To streamline policy development, the SELinux policy based on the reference policy uses interfaces to access privileges within a module. If you have built selinux-base-policy with USE="doc" then this information is available at /usr/share/doc/selinux-base-policy-<version>/html. It is recommended to have this information at hand, since most policy development/updates will be done through the interfaces offered by the policy.

If you are just interested, you can also find these interface definitions online. Mind you though, the online resource is only the reference policy and might differ a bit from the policy available within Gentoo.

Using Policy Interfaces

Using the policy interfaces allows you to update the policy with more readable functions. For instance, to allow the user_t domain to call and use Portage applications, the module could look like so:

Code Listing 1.5: Example policy to allow user_t to use portage

policy_module(testmod, 1.0.0)

require {
  type user_t;
  role user_r;
}

portage_run(user_t, user_r)

Of course, this makes the user_t domain much more privileged than the previously defined rules to read ebuild files: it allows the user to call portage, update the system, etc. Of course, the user still requires the proper regular Linux permissions (so he needs to be part of the portage group or become root). Needless to say, we do not recommend to grant this to a regular user ;-)

5.b. Full SELinux Policy Modules

Checking Out an Isolated Module

With the above in mind, we can now go one step further and investigate a full policy module, with both the type enforcement rules (.te file), file contexts (.fc) and interfaces (.if).

You should know that writing a module requires you to get intimate with the application. It isn't a matter of just hoping for the best: as a security administrator, you will be responsible for defining what accesses are allowed and which not. If you forget one, the application might break under the users' hands. But if you add too much, you might grant privileges that can be abused later on. And it will be a lot more difficult to track and remove privileges later as you will be hesitating if the privilege is needed or not.

In this section, we will not divulge in how to write one. We have an excellent Gentoo Hardened SELinux Development resource that guides you in that. However, we will look into such a full module to explain the other aspects of policy development.

Type Enforcement File

The .te file we wrote earlier is a type enforcement file. Its purpose is to define the access rules related to the module that you are building, but also - and more importantly - define new types (or even roles).

The example below is a snippet from a module for the skype application.

Code Listing 2.1: Snippet from skype.te

policy_module(skype, 1.0.0)

type skype_t;
type skype_exec_t;
application_domain(skype_t, skype_exec_t)

type skype_home_t;
userdom_user_home_content(skype_home_t)

manage_dirs_pattern(skype_t, skype_home_t, skype_home_t)
manage_files_pattern(skype_t, skype_home_t, skype_home_t)

In the above example, three new types are declared: skype_t (which will be used for the application), skype_exec_t (which is the label given to the application binary) and skype_home_t (which will be used for the users' ~/.Skype location). Also, the skype_t domain is given some privileges with respect to the skype_home_t label (manage directories and files).

File Context File

In the .fc file (which stands for file context file) the module's resources (files, directories, sockets, ...) are defined. Once the module is loaded, these rules are added so that file system relabeling will put the correct context on the files.

The example below is a snippet from the skype modules' file context file.

Code Listing 2.2: Snippet from skype.fc

HOME_DIR/\.Skype(/.*)?    gen_context(system_u:object_r:skype_home_t,s0)
/opt/skype/skype       -- gen_context(system_u:object_r:skype_exec_t,s0)
/usr/bin/skype         -- gen_context(system_u:object_r:skype_exec_t,s0)

The format of the file context file has the following syntax:

  1. The regular expression that matches the file(s) and directorie(s) affected by that line
  2. An optional identifier to differentiate the type of files (file, directory, socket, symbolic link, ...)
  3. A gen_context line that contains the context to assign to the file(s) and directorie(s)

Interface File

In the .if file (for interface file) interfaces are declared which can be used by other modules. It is through interfaces that a nicely defined policy can be built on top of other, existing policy modules.

One interface could be to allow users to call and execute an application. For instance, the following interface can be found in the skype module.

Code Listing 2.3: Snippet from skype.if

interface(`skype_role',`
        gen_require(`
                type skype_t, skype_exec_t, skype_tmpfs_t, skype_home_t;
        ')

        role $1 types skype_t;

        domtrans_pattern($2, skype_exec_t, skype_t)

        allow $2 skype_t:process { ptrace signal_perms };

        manage_dirs_pattern($2, skype_home_t, skype_home_t)
        manage_files_pattern($2, skype_home_t, skype_home_t)
        manage_lnk_files_pattern($2, skype_home_t, skype_home_t)

        relabel_dirs_pattern($2, skype_home_t, skype_home_t)
        relabel_files_pattern($2, skype_home_t, skype_home_t)
        relabel_lnk_files_pattern($2, skype_home_t, skype_home_t)

        ps_process_pattern($2, skype_t)
')

Through this skype_role, we can then allow users to call skype, as can be found in the unprivuser.te file (which defines the user_t domain):

Code Listing 2.4: Snippet from unprivuser.te to call skype

optional_policy(`
	skype_role(user_r, user_t)
')

The following table shows a few common interfaces that could be in use. We seriously recommend to look at the available interfaces when enhancing or creating your own modules - and be sure to pick the interface that adds just what you need, nothing more.

Templates
Suffix Example Description
_template virt_domain_template(prefix) Not really an interface, templates create additional domains based on the information given to them. This is usually done for fine-grained policy templates with a common (sub)set of privileges.
Transformations
Suffix Example Description
miscfiles_cert_type(resource) Transformation interfaces generally add specific attributes to resources or domains. Attributes "transform" the given resource into something more. In the given example, the miscfiles_cert_type(resource) assigns the cert_type attribute to the resource (and also marks it as a file). Interfaces, like miscfiles_read_all_certs work on these attributes.
Access interfaces
Suffix Example Description
_<access>_<resource> mta_getattr_spool(domain) Grant the specified domain access towards the shown resource. The resource usually defines the type too (like kudzu_getattr_exec_files: grant getattr on the kudzu_exec_t files) unless it is obvious from the name, or when the resource is a more specific term towards the domain. It can also include dontaudit (like mta_dontaudit_getattr_spool).
_exec dmesg_exec(domain) Grant one domain the right to execute the given domains' executable file (in the example, allow "domain" to execute dmesg_exec_t files), but without implying that the domains transition. In other words, dmesg gets executed but still confined by the privileges of the source domain.
_domtrans dmesg_domtrans(domain) Grant one domain execute and transition privileges towards the new domain. This interface is most commonly used to allow application domains to transition to another. In the given example, dmesg is ran with the privileges of the dmesg_t domain.
_run netutils_run(domain, role) Grant a given role and domain the rights to execute and transition towards the given domain. This is usually granted to (existing) user roles and domains and gives them the set of privileges needed to interact safely with the new (interactive) domain (such as terminal access).
_role xserver_role(role, domain) Allow the given role and domain the necessary permissions to transition and interact with the given domain. This interface is enhanced with the privileges to interact with the domain (and its underlying files) more thoroughly, and is usually assigned to newly created users or roles within the policy (rather than enhance existing user domains and roles).
_admin aide_admin(domain) Grant the given domain the rights to administer the target domains' environment. This usually involves privileges to manage and relabel all affiliated files, directories, sockets, etc.

5.c. Using audit2allow

Introduction

When reading online resources on SELinux, you will notice that there are many references to a tool called audit2allow. This tools' purpose is to read AVC denial messages from the audit log file and transform them into a policy module that you can load. The advantage is that it makes it a lot easier to write policies. The downside is that the output (unless you use the -R option) is not usable for the Makefile we used earlier to build modules.

Another disadvantage is that the tool does not intelligently cope with changes. It blindly accepts denials and treats them as if they need to be allowed, rather than investigate if no other context should be given to the file, etc.

Using audit2allow

Using audit2allow is pretty straightforward. You send it the denials you want to fix and store the result in a .te file. You then convert it into an intermediary format which can then be translated into a .pp file for final loading by semodule.

For instance, to catch all denials and transform them into allowed statements from firefox-related denials:

Code Listing 3.1: Generate a new policy using audit2allow

# grep firefox /var/log/avc.log | audit2allow -m firefoxmod > firefoxmod.te
# checkmodule -m -o firefoxmod.mod firefoxmod.te
# semodule_package -o firefoxmod.pp -m firefoxmod.mod
# semodule -i firefoxmod.pp

Keep the module name (given through the -m option) simple: only use characters ([a-z]) and numbers ([0-9]), and start the module name with a character.

5.d. Using selocal

Introduction

Sometimes we need to just make a small adjustement here, an addition there, all over time. If we use audit2allow, this would result in several separate modules over time - mypolicy1, mypolicy2, ... After a while, we do not know which rules are added where and for what reason.

To support this in the future, Gentoo is providing a tool that allows you to add in small rule sets over time, documenting the reasons why and simplifying the management of these rules.

Using selocal

With policycoreutils-2.1.13-r11 onwards, a new command called selocal is available. This command allows users to easily add in additional SELinux policy rules to the local policy without having go through the hassle of building and maintaining their own .te files. Instead, this command does that for you.

Rules that are added to the local policy (hence the name, selocal) can be accompanied with a small comment to allow users to describe why a change was added (or to refer to a bug id on Gentoo's bugzilla).

Code Listing 4.1: Adding a rule to the local policy

# selocal -a "rpcbind_stream_connect(sysadm_t)" -c "Be able to call exportfs (NFS)"
# selocal --build --load

With --list you can view the currently added local policy rules, and with --delete they can be removed from the local policy. When you want to have the changes take effect, run selocal --build --load to build the new local policy and load it in memory.

5.e. Creating Additional Roles

Create the Role and Domain

If you want to create additional roles on the system, you first need to create a SELinux module that creates that role, together with its main domain. Below is a very simple example for a database administration role, which we will offer through the sec-policy/selinux-dbadm package later:

Code Listing 5.1: Example dbadm_r and dbadm_t definition

policy_module(dbadm, 1.0.0)

#######################################
#
# Declarations
#

role dbadm_r;

# Create a user domain (dbadm_t) 
userdom_base_user_template(dbadm)

#######################################
#
# dbadm local policy
#

allow dbadm_t self:capability { dac_override dac_read_search sys_ptrace };

files_dontaudit_search_all_dirs(dbadm_t)
files_delete_generic_locks(dbadm_t)
files_list_var(dbadm_t)

selinux_get_enforce_mode(dbadm_t)

logging_send_syslog_msg(dbadm_t)

userdom_dontaudit_search_user_home_dirs(dbadm_t)

optional_policy(`
	# Grant the user admin rights on PostgreSQL (process-wise)
	postgresql_admin(dbadm_t, dbadm_r)
')

Build and load the module and verify that the role is now available:

Code Listing 5.2: Build and verify

# make -f /usr/share/selinux/strict/include/Makefile dbadm.pp
# semodule -i dbadm.pp
# seinfo -r | grep dbadm
  dbadm_r

Assign Users the Role

Next, assign users the role you just created. You can do this to existing SELinux users, but here we'll create an additional SELinux user for the role.

Code Listing 5.3: Grant a user the role

(Create a new SELinux user called dbadm_u and grant it the dbadm_r role)
# semanage user -a -R "staff_r dbadm_r system_r" dbadm_u

Next map the user(s) to this SELinux user.

Code Listing 5.4: Mapping a set of users to the dbadm_u user

# semanage login -a -s dbadm_u david
# semanage login -a -s dbadm_u laura

Also load in the following policy to support transitioning to the dbadm_r role for the staff_r role:

Code Listing 5.5: Allow transitioning to dbadm_r

dbadm_role_change(staff_r)

In the first semanage command, where we create the dbadm_u user, you might have noticed that we grant it the system_r role. This is because the user is granted the postgresql_admin role, allowing the user to manipulate the postgresql init script:

Code Listing 5.6: User restarting postgresql service

$ ls -Z /etc/init.d/postgresql
system_u:object_r:postgresql_initrc_exec_t    /etc/init.d/postgresql
$ sudo -r dbadm_r -t dbadm_t /etc/init.d/postgresql restart

Thanks to the SELinux support by sudo, you can also mention the role and type in the sudoers file:

Code Listing 5.7: Using the sudoers file for specific roles

david ALL=(ALL) ROLE="dbadm_r" TYPE="dbadm_t" NOPASSWD: /etc/init.d/postgresql [a-z]*

With this setting, the user can just run sudo /etc/init.d/postgresql restart.

By using sudo correctly, you can grant the user full administrative rights over a daemon (including editing files) with a much lower risk of the user elevating his rights to a more system-wide administrative role.

The idea behind this approach is that the user stays within its main domain (like staff_t) but is allowed to perform administrative actions through sudo which allow him to (temporarily) transition to the dbadm_r role.

6. Troubleshooting SELinux

6.a. Unable To Load SELinux Policy

Problem Description

If you notice that SELinux is not functioning at all, a quick run of sestatus should give you closure if SELinux is enabled and loaded or not. If you get the following output, no SELinux policy is loaded:

Code Listing 1.1: sestatus output

SELinux status:                disabled

If this is the case, read on in this section to find out how to troubleshoot and resolve this.

No Policy Installed

One potential reason would be that there is no policy to load to begin with. Take a look inside /usr/share/selinux/strict or /usr/share/selinux/targeted (depending on your configuration) and look for a file called base.pp. If no such file exists, you will need to install the base policy. This policy is offered by the sec-policy/selinux-base-policy package, but it is better to read up on the chapter regarding Gentoo SELinux Installation / Conversion as more important changes might be missing.

Policy Not Loaded

If the base.pp file exists in /usr/share/selinux/strict (or targeted/), take a look inside /etc/selinux/strict/policy. This location too should contain a base.pp policy module (when a SELinux policy is loaded, it is copied from the first location to the second).

If no base.pp file exists, install and load the policy:

Code Listing 1.2: Installing the base policy

~# semodule -n -B

This is a one-time operation - once installed and loaded, it will be reloaded upon every reboot.

Init Can Not Load the SELinux Policy

During system boot, the init process is responsible for loading and interacting with the SELinux policy in memory. If init does not support SELinux, you will get no SELinux support in your environment.

To verify if init supports SELinux, we need to check if it uses the libselinux.so shared object:

Code Listing 1.3: Checking if init supports SELinux

~# ldd /sbin/init
        linux-vdso.so.1 =>  (0x00006ace30e84000)
	( You should see something similar to the following line: )
        libselinux.so.1 => /lib/libselinux.so.1 (0x00006ace30a46000)
        libc.so.6 => /lib/libc.so.6 (0x00006ace306e9000)
        libdl.so.2 => /lib/libdl.so.2 (0x00006ace304e5000)
        /lib64/ld-linux-x86-64.so.2 (0x00006ace30c68000)

If this is not the case, make sure that emerge --info shows that the selinux USE flag is in place, and reinstall sys-apps/sysvinit. If the selinux USE flag is not in place, check your Gentoo profile and make sure it points to a selinux/v2refpolicy/... profile.

Policy Store is Corrupt

If you encounter problems during boot-up or semodule operations which fail with loading problems, but cannot be resolved with the above solution, then you might need to reinstall the policies after eliminating the corrupt store.

Code Listing 1.4: Recovering from store corruption

~# semodule -n -B
libsemanage.semanage_load_module: Error while reading from module file
/etc/selinux/targeted/modules/tmp/base.pp. (No such file or directory)

~# setenforce 0
~# mv /etc/selinux/targeted /etc/selinux/targeted.old
~# FEATURES="-selinux" emerge -1av $(qlist -IC sec-policy)
~# restorecon -R /etc/selinux

This will effectively disable the current, corrupted SELinux policy store and then use Portage to reinstall all SELinux policy packages that are installed on the system. When done, the file contexts of /etc/selinux are restored, after which you should be able to continue.

6.b. Unable to Log On

Problem Description

If you are unable to log on in a particular situation (remote, local, as root, as regular user, ...) there are a few possible problems which you might have hit. However, to resolve them you'll need to be able to log on to the system as sysadm_r in one way or the other.

If you can not log in as a sysadm_r user, disable SELinux (boot with enforcing=0) so that no SELinux enforcements are made. Changes that you make in permissive mode are equally effective as in enforcing mode.

Incorrect Context

In the majority of cases will you find that a security context is incorrect. Run sestatus -v and compare the Process contexts or File contexts that you see in the output with the next table.

Process Context If wrong context...
Init context system_u:system_r:init_t First, verify that init itself is correclty labeled. Check the output of the previously run sestatus -v command for the /sbin/init file and make sure that it is set to system_u:object_r:init_exec_t. If that is not the case, relabel sys-apps/sysvinit using rlpkg sysvinit. Also make the same checks as in the Unable To Load SELinux Policy section. Reboot your system and retry.
agetty context system_u:system_r:getty_t Make sure that the /sbin/agetty binary is labeled system_u:object_r:getty_exec_t. If not, relabel the sys-apps/util-linux package using rlpkg util-linux. Then restart all the agetty processes using pkill agetty (they will automatically respawn).
File Context If wrong context...
/bin/login system_u:object_r:login_exec_t The login binary is part of sys-apps/shadow. Run rlpkg shadow to relabel the files of that package and retry logging in.
/sbin/unix_chkpwd system_u:object_r:chkpwd_exec_t This binary is part of the sys-libs/pam package and is used by SSH when it is configured to use PAM for user authentication. Relabel the package using rlpkg pam and retry logging in.
/etc/passwd system_u:object_r:etc_t The /etc/passwd and /etc/shadow must be labeled correctly, otherwise PAM will not be able to authenticate any user. Relabel the files through restorecon /etc/passwd /etc/shadow and retry logging in.
/etc/shadow system_u:object_r:shadow_t
/bin/bash system_u:object_r:shell_exec_t The users' shell (in this case, bash) must be labeled correctly so the user can transition into the user domain when logging in. To do so, relabel the app-shells/bash package using rlpkg bash. Then, try logging in again.

6.c. Unable to Emerge Anything (OSError: [Errno 22] Invalid argument)

Problem Description

When trying to install software with Portage, you get a huge python stacktrace and finally the error message OSError: [Errno 22] Invalid argument:

Code Listing 3.1: Stacktrace dump when portage fails to install software

Traceback (most recent call last):
  File "/usr/bin/emerge", line 43, in <module>
    retval = emerge_main()
  File "/usr/lib64/portage/pym/_emerge/main.py", line 1906, in emerge_main
    myopts, myaction, myfiles, spinner)
  File "/usr/lib64/portage/pym/_emerge/actions.py", line 437, in action_build
    retval = mergetask.merge()
...
  File "/usr/lib64/portage/pym/portage/package/ebuild/doebuild.py", line 104, in _doebuild_spawn
    return spawn(cmd, settings, **kwargs)
  File "/usr/lib64/portage/pym/portage/package/ebuild/doebuild.py", line 1255, in spawn
    return spawn_func(mystring, env=mysettings.environ(), **keywords)
  File "/usr/lib64/portage/pym/portage/_selinux.py", line 105, in wrapper_func
    setexec(con)
  File "/usr/lib64/portage/pym/portage/_selinux.py", line 79, in setexec
    if selinux.setexeccon(ctx) < 0: 
OSError: [Errno 22] Invalid argument

Wrong Context

The above error comes when you launch portage (through emerge) while you are not in sysadm_t context. You can verify this with id -Z:

Code Listing 3.2: Checking current context

~# id -Z
system_u:system_r:local_login_t

As long as the context isn't sysadm_t, then Portage will break. This is because Portage wants to switch its execution context from portage_t to portage_sandbox_t but fails (it isn't in portage_t to begin with because the user who launched Portage isn't in sysadm_t).

Please check Unable to Log On above first. Also make sure that you can dispatch-conf or etc-update after installing SELinux so that /etc/pam.d/system-login is updated with the right pam_selinux.so calls.

Forcing Installation

If you need to force Portage to continue regardless (for instance, you were in the middle of a SELinux installation so cannot properly resolve such issues now), run the emerge command but with FEATURES="-selinux". This will effectively disable Portage' SELinux integration, but allows you to continue installing software.

Code Listing 3.3: Running emerge without selinux support

~# FEATURES="-selinux" emerge -u world

Make sure that you relabel the entire file system after using this approach! Portage will not label the files installed on the system correctly if you disable its SELinux support. To relabel the entire file system, use rlpkg -a -r.

7. Change History

7.a. Introduction

About this document

This document will give an overview of all SELinux documented changes made on particular dates and that might be important for users to follow up through.

Changes that only affect ~arch users will be documented below and moved up when they are stabilized. It is possible though that these changes will be "fixed" automatically and as such removed from this page.

7.b. Overview of Changes for Stable Users

2013/04/19 - Introducing selocal command

With policycoreutils-2.1.13-r11 onwards, a new command called selocal is available. This command allows users to easily add in additional SELinux policy rules to the local policy without having go through the hassle of building and maintaining their own .te files. Instead, this command does that for you.

Rules that are added to the local policy (hence the name, selocal) can be accompanied with a small comment to allow users to describe why a change was added (or to refer to a bug id on Gentoo's bugzilla).

Code Listing 2.1: Adding a rule to the local policy

# selocal -a "rpcbind_stream_connect(sysadm_t)" -c "Be able to call exportfs (NFS)"
# selocal --build --load

With --list you can view the currently added local policy rules, and with --delete they can be removed from the local policy. When you want to have the changes take effect, run selocal --build --load to build the new local policy and load it in memory.

2013/04/16 - Introduce selinux_gentoo init script

With policycoreutils-2.1.13-r8 and later, we now provide our own init script selinux_gentoo, which includes the necessary support for the initramfs users, but also resets the contexts of dynamically generated resources (on pseudo file systems) which are different from the default setting.

The first user here is /sys/devices/system/cpu/online which gets labeled cpu_online_t (from revision 13 of the SELinux policy, or when using live ebuilds for the policy).

The init script will by default also restore the contexts of all /dev devices (unless you boot with the norestorecon option) and will switch to enforcing mode if /etc/selinux/config has SELINUX=enforcing set but the user booted with enforcing=0 (unless you boot with nosetenforce option).

This means that users are now encouraged to add this init script to the boot runlevel:

Code Listing 2.2: Adding selinux_gentoo to the boot runlevel

# rc-update add selinux_gentoo boot

2012/12/04 - Introduce USE=unconfined

From selinux-base-2.20120725-r9 onwards, we will now also support a USE=unconfined setting. When enabled, it will configure your SELinux policy to support the unconfined domains. If your policy is targeted, this behavior will be implied, whereas the strict policy will not consider this USE flag at all (it will not activate unconfined domains on strict).

Supporting this USE flag allows us to differentiate unconfined domains versus regular ones when using the mls or mcs policy types. When set, the selinux-unconfined package will be built as well, and the module will be loaded, and the policy seusers file (which contains the default domain mappings for users) will be updated to use the unconfined_u SELinux user for root and other users.

2012/08/16 - Adding system_r role to admins

Since selinux-base-2.20120725-r3 and later, init scripts will now support the upstream "labeled" init script approach. This means that those services whose init script follows the <domain>_initrc_exec_t naming convention can now be assigned to specific users (allowing those to manage the services without the need to grant them system administration rights).

The downside of this approach is that the system administrator itself (who uses the sysadm_t domain) now also needs to be granted the right to manage those services. And granting this right means that the SELinux user (be it root or staff_u) needs to be granted the system_r role:

Code Listing 2.3: Granting system_r role

# semanage user -m -R "staff_r sysadm_r system_r" root
# semanage user -m -R "staff_r sysadm_r system_r" staff_u

2012/06/24 - Definition of /run in fstab

The /run location needs to be mounted with the var_run_t context. To do so, /etc/fstab needs to be modified as per the instructions in Setting the filesystem contexts.

2012/05/26 - Support of initramfs

Users who boot with an initramfs will need to boot in permissive mode first, and later on switch to enforcing mode. This can be done automatically using an init script, as documented at Initramfs users.

2012/05/26 - Support for graphical login managers

Users who boot into a graphical environment (such as through GDM) will need to edit their PAM configuration files accordingly to support SELinux security context settings. This is documented at Users of a graphical environment.

2012/05/18 - No more sandbox configuration needed

The previously documented editing of /etc/sandbox.conf to open write access to /sys/fs/selinux/context can be removed as the SELinux profile does this now automatically.

2012/04/29 - Edit of lvm-start/stop scripts no longer needed

When users install the newly stabilized 2.20120215 policies, the documented editing of /lib/rcscripts/addons/lvm-st*.sh is no longer needed.

2012/02/21 - /dev mount line in fstab no longer needed

The previously documented /dev mount line in /etc/fstab is no longer needed as util-linux-2.20.1-r1 has been marked stable (which contains the correct bug fix).

2011/12/10 - Deprecation of selinux/v2refpolicy/* profiles

The old SELinux profiles (starting with selinux/v2refpolicy) are not supported anymore. Users are strongly encouraged to switch to the new profiles (those ending with /selinux).

2011/07/22 - Introduction of MLS/MCS support

We now support MLS and MCS, right next to targeted and strict SELinux policy types. When using MLS or MCS, you will need to update the /tmp entry in your /etc/fstab to use rootcontext=system_u:object_r:tmp_t:s0 (note the trailing :s0).

7.c. Overview of Changes for ~Arch Users

2013/07/07 - Introduced support for mcstrans

When the SELinux policy is MLS-enabled (so it is MCS or MLS), then we have the option of managing categories. Categories allow us to "tag" resources and make sure that only processes that have the right category set assigned to them can read/manipulate the resources.

For SELinux, categories are numbers, starting from c0 (category zero) to whatever maximum is used in the policy:

Code Listing 3.1: Checking the maximum number of categories

$ seinfo | grep Categories
  Sensitivities:      1   Categories:       1024

For most administrators/humans though, this is not that efficient. To support more human readable formats, SELinux supports category translations (and even sensitivity translations). Inside a configuration file (setrans.conf in the main configuration directory, like /etc/selinux/mcs) administrators can enter common sensitivity sets and ranges. The chcat tool can then be used to list those:

Code Listing 3.2: Listing translated sensitivity ranges

# chcat -L
s0                             SystemLow
s0-s0:c0.c1023                 SystemLow-SystemHigh
s0:c0.c1023                    SystemHigh

To enable these translations, create the proper translation file (of which you can find numerous examples in /usr/share/doc/policycoreutils-*/mcstrans) and then start the mcstransd service.

Code Listing 3.3: Starting the mcstransd service

# rc-service mcstransd start

That's it - if we now look at contexts, we will see the translated ranges:

Code Listing 3.4: Listing contexts to see translated ranges

# ls -lZ seusers
-rw-r--r--. root root system_u:object_r:selinux_config_t:SystemLow seusers

Print

Page updated April 9, 2014

Summary: This is the Gentoo SELinux Handbook.

Chris PeBenito
Author

Sven Vermeulen
Author

Chris Richards
Author

Donate to support our development efforts.

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