<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE sections SYSTEM "/dtd/book.dtd">

<!-- The content of this document is licensed under the CC-BY-SA license -->
<!-- See http://creativecommons.org/licenses/by-sa/1.0 -->

<!-- $Header: /var/cvsroot/gentoo/xml/htdocs/proj/en/hardened/selinux/hb-using-states.xml,v 1.6 2012/06/14 18:09:51 swift Exp $ -->

<sections>
<version>3</version>
<date>2012-06-14</date>

<section>
<title>SELinux States</title>
<subsection>
<title>Introduction</title>
<body>

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

</body>
</subsection>
<subsection>
<title>Disabled</title>
<body>

<p>
When <c>getenforce</c> 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.
</p>

<p>
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).
</p>

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

<pre caption="Relabeling the entire file system">
# <i>rlpkg -a -r</i>
</pre>

</body>
</subsection>
<subsection>
<title>Permissive</title>
<body>

<p>
When SELinux is enabled in permissive mode (<c>getenforce</c> 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 <e>not</e> be prohibited.
</p>

<p>
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 <e>that are not SELinux aware</e> 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.
</p>

<p>
There is one caveat though: if the application is <e>SELinux-aware</e> (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.
</p>

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

<pre caption="Checking if /bin/ls is SELinux-aware">
# <i>scanelf -n /bin/ls</i>
 TYPE     NEEDED FILE
ET_DYN   libselinux.so.1,librt.so.1,libc.so.6   /bin/ls
</pre>

</body>
</subsection>
<subsection>
<title>Enforcing</title>
<body>

<p>
If <c>getenforce</c> 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.
</p>

</body>
</subsection>
<subsection>
<title>Switching States</title>
<body>

<p>
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).
</p>

<p>
Using the command <c>setenforce</c>:
</p>

<pre caption="Switching between enforcing and permissive">
<comment>(Switching to permissive mode)</comment>
# <i>setenforce 0</i>

<comment>(Switching to enforcing mode)</comment>
# <i>setenforce 1</i>
</pre>

<p>
Using the kernel boot option <c>enforcing</c>:
</p>

<pre caption="Switching between enforcing and permissive through boot options">
<comment>(The following GRUB kernel line would boot in permissive mode)</comment>
kernel /kernel-2.6.39-hardened-r8 root=/dev/md3 rootflags=data=journal <i>enforcing=0</i>
</pre>

<p>
Using the <path>/etc/selinux/config</path> <c>SELINUX</c> variable:
</p>

<pre caption="/etc/selinux/config SELINUX setting">
# <i>cat /etc/selinux/config</i>
# 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.
<i>SELINUX=enforcing</i>

# 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
</pre>

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

<ol>
  <li>
    First boot up in permissive mode, log on, verify that your context is
    correct (<c>id -Z</c>) and then switch to enforcing (<c>setenforce 1</c>).
    You can now test if your system is still working properly.
  </li>
  <li>
    Next, boot with <c>enforcing=1</c> 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
  </li>
  <li>
    Finally, edit <path>/etc/selinux/config</path> to persist this change.
  </li>
</ol>

</body>
</subsection>
<subsection>
<title>Domain-permissive Mode</title>
<body>

<p>
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):
</p>

<pre caption="Marking mplayer_t as permissive">
# <i>semanage permissive -a mplayer_t</i>
</pre>

<p>
With the <c>-d</c> option, you can remove the permissive mark again.
</p>

</body>
</subsection>
</section>

<section>
<title>SELinux Policy Types</title>
<subsection>
<title>Introduction</title>
<body>

<p>
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):
<c>targeted</c>, <c>strict</c>, <c>mcs</c> (and <c>mls</c>).
</p>

<p>
The type used on a system is declared in <path>/etc/selinux/config</path>:
</p>

<pre caption="The SELINUXTYPE information in /etc/selinux/config">
# <i>cat /etc/selinux/config</i>
# 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)
<i>SELINUXTYPE=strict</i>
</pre>

</body>
</subsection>
<subsection>
<title>strict (without unconfined domains)</title>
<body>

<p>
The <c>strict</c> 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.
</p>

</body>
</subsection>
<subsection>
<title>targeted (using unconfined domains)</title>
<body>

<p>
The <c>targeted</c> 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.
</p>

<p>
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".
</p>

</body>
</subsection>
<subsection>
<title>mcs (using multiple categories)</title>
<body>

<p>
The introduction of <c>mls</c> and <c>mcs</c> offers the ability for
<e>multi-tenancy</e>: 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).
</p>

<p>
A simple example is virtualization: a virtual guest which runs in the
<c>qemu_t</c> 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 <c>mcs</c>, 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).
</p>

</body>
</subsection>
<subsection>
<title>mls (using multiple security levels)</title>
<body>

<p>
The <c>mls</c> 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 <e>public</e>, <e>private</e>, <e>confidential</e> or <e>strictly
confidential</e>. 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.
</p>

</body>
</subsection>
<subsection>
<title>Switching Types</title>
<body>

<p>
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.
</p>

<p>
First, you need to edit <path>/etc/selinux/config</path> so that it both
switches the policy type as well as put the mode in <e>permissive</e>. This is
necessary, since at your next reboot, many labels might (or will) be incorrect.
</p>

<p>
Next, edit <path>/etc/fstab</path> and make sure that the domains you use there
are updated accordingly. For instance, the line for <path>/tmp</path>:
</p>

<pre caption="Changing /etc/fstab">
<comment># Example when switching from strict to mcs</comment>
tmpfs  /tmp  tmpfs  defaults,noexec,nosuid,rootcontext=system_u:object_r:tmp_t<i>:c0</i>  0 0
</pre>

<p>
When this is done, reboot your system. Log on as root, and relabel your entire
file system using <c>rlpkg -a -r</c>. Finally, reboot again and then validate if
your context (such as when logged on as a user) is correct again. Once you are
confident that the domains and contexts are correct, switch the SELinux policy
mode back to "enforcing".
</p>

</body>
</subsection>
</section>

</sections>
