[ << ]
[ < ]
[ Home ]
[ > ]
[ >> ]
2. SELinux Concepts
Content:
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):
-
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.
-
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.
-
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
-
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 |
~$ ls -dZ ${HOME}
staff_u:object_r:user_home_dir_t /home/swift
~$ 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
~$
~$ 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:
-
The current domain must be allowed to transition to a domain
-
The target domain should have an entry point, which is an executable
that is allowed to start in the domain
-
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)
2.g. Next Steps
What Next
It might be difficult to understand now, but the concepts are important because,
if something fails on your system when SELinux is enabled, but it doesn't fail
when SELinux is disabled, then you will need to dive into the security contexts,
rules, types and domain transitions to find out why.
The next chapter in line will give you some background resource information
(online resources, books, FAQs, etc.) After that, we'll dive into the
installation and configuration of SELinux on your Gentoo Hardened system. Then,
we'll configure and tune the SELinux policy to our needs.
[ << ]
[ < ]
[ Home ]
[ > ]
[ >> ]
The contents of this document, unless otherwise expressly stated, are licensed under the CC-BY-SA-2.5 license. The Gentoo Name and Logo Usage Guidelines apply.
|