Distinguishing between policies
The most common SELinux policy store names are strict
, targeted
, mcs
, and mls
. None of the names assigned to policy stores are fixed, though, so it is a matter of convention. Hence, it is recommended to consult the distribution documentation to verify what the proper name of the policy should be. Still, the name often provides some information about the SELinux options that are enabled through the policy.
Supporting MLS
One of the options that can be enabled is MLS support. If it is disabled, then the SELinux context will not have a fourth field with sensitivity information in it, making the contexts of processes and files look as follows:
staff_u:sysadm_r:sysadm_t
To check whether or not MLS is enabled, it is sufficient to see if the context, indeed, doesn't contain such a fourth field, but it can also be acquired from the Policy MLS status
line in the output of sestatus
:
# sestatus | grep MLS
Policy MLS Status: disabled
Another method would be to look into the pseudo file, /sys/fs/selinux/mls
. A value of 0
means disabled, whereas a value of 1
means enabled:
# cat /sys/fs/selinux/mls
0
Policy stores that have MLS enabled are generally targeted
, mcs
, and mls
, whereas strict
generally has MLS disabled.
Dealing with unknown permissions
Permissions (such as read, open, and lock) are defined both in the Linux kernel and in the policy itself. However, sometimes, newer Linux kernels support permissions that the current policy does not yet understand.
Take the block_suspend
permission (to be able to block system suspension) as an example. If the Linux kernel supports (and checks) this permission but the loaded SELinux policy does not understand that permission yet, then SELinux has to decide how it should deal with the permission. SELinux can be configured to do one of the following actions:
allow
: Assume everything that is not understood is alloweddeny
: Assume no one is allowed to perform this actionreject
: Stop and halt the system
This is configured through the deny_unknown
value. To see the state for unknown permissions, look for the Policy deny_unknown status
line in sestatus
:
# sestatus | grep deny_unknown
Policy deny_unknown status: denied
Administrators can set this for themselves in the /etc/selinux/semanage.conf
file through the handle-unknown
variable (with allow
, deny
, or reject
).
RHEL by default allows unknown permissions, whereas Gentoo by default denies them.
Supporting unconfined domains
A SELinux policy can be very strict, limiting applications as close as possible to their actual behavior, but it can also be very liberal in what applications are allowed to do. One of the concepts available in many SELinux policies is the idea of unconfined domains. When enabled, it means that certain SELinux domains (process contexts) are allowed to do almost anything they want (of course, within the boundaries of the regular Linux DAC permissions, which still hold) and only a select number of domains are truly confined (restricted) in their actions.
Unconfined domains have been brought forward to allow SELinux to be active on desktops and servers where administrators do not want to fully restrict the entire system, but only a few of the applications running on it. Generally, these implementations focus on constraining network-facing services (such as web servers and database management systems) while allowing end users and administrators to roam around unrestricted.
With other MAC systems, such as AppArmor, unconfinement is inherently part of the design of the system as they only restrict actions for well-defined applications or users. However, SELinux was designed to be a full mandatory access control system and thus needs to provide access control rules even for those applications that shouldn't need any. By marking these applications as unconfined, almost no additional restrictions are imposed by SELinux.
We can see whether or not unconfined domains are enabled on the system through seinfo
, which we use to query the policy for the unconfined_t
SELinux type. On a system where unconfined domains are supported, this type will be available:
# seinfo -tunconfined_t
unconfined_t
For a system where unconfined domains are not supported, the type will not be part of the policy:
# seinfo -tunconfined_t
ERROR: could not find datum for type unconfined_t
Most distributions that enable unconfined domains call their policy targeted
, but this is just a convention that is not always followed. Hence, it is always best to consult the policy using seinfo
. RHEL enables unconfined domains, whereas with Gentoo, this is a configurable setting through the unconfined USE
flag.
Limiting cross-user sharing
When UBAC is enabled, certain SELinux types will be protected by additional constraints. This will ensure that one SELinux user cannot access files (or other specific resources) of another user, even when those users are sharing their data through the regular Linux permissions. UBAC provides some additional control over information flow between resources, but it is far from perfect. In essence, it is made to isolate SELinux users from one another.
Note
A constraint in SELinux is an access control rule that uses all parts of a context to make its decision. Unlike type enforcement rules, which are purely based on the type, constraints can take the SELinux user, SELinux role, or sensitivity label into account. Constraints are generally developed once and left untouched, otherwise--most policy writers will not touch constraints during their development efforts.
Many Linux distributions, including RHEL, disable UBAC. Gentoo allows users to select whether or not they want UBAC through the Gentoo ubac USE
flag (which is enabled by default).
Incrementing policy versions
While checking the output of sestatus
, we see that there is also a notion of policy versions:
# sestatus | grep version
Max kernel policy version: 28
This version has nothing to do with the versioning of policy rules but with the SELinux features that the currently running kernel supports. In the preceding output, 28
is the highest policy version the kernel supports. Every time a new feature is added to SELinux, the version number is increased. The policy file itself (which contains all the SELinux rules loaded at boot time by the system) can be found in /etc/selinux/targeted/policy
(where targeted
refers to the policy store used, so if the system uses a policy store named strict
, then the path would be /etc/selinux/strict/policy
).
If multiple policy files exist, we can use the output of seinfo
to find out which policy file is used:
# seinfo
Statistics for policy file: /etc/selinux/targeted/policy/policy.30
Policy Version & Type: v.30 (binary, mls)
...
The next table provides the current list of policy feature enhancements and the Linux kernel version in which that feature is introduced. Many of the features are only of concern to the policy developers, but knowing the evolution of the features gives us a good idea about the evolution of SELinux:
Version |
Linux kernel |
Description |
12 |
The "old API" for SELinux, now deprecated. | |
15 |
2.6.0 |
Introduced the new API for SELinux. |
16 |
2.6.5 |
Added support for conditional policy extensions. |
17 |
2.6.6 |
Added support for IPv6. |
18 |
2.6.8 |
Added support for fine-grained netlink socket permissions. |
19 |
2.6.12 |
Added support for MLS. |
20 |
2.6.14 |
Reduced the size of the access vector table. |
21 |
2.6.19 |
Added support for MLS range transitions. |
22 |
2.6.25 |
Introduced policy capabilities. |
23 |
2.6.26 |
Added support for per-domain permissive mode. |
24 |
2.6.28 |
Added support for explicit hierarchy (type bounds). |
25 |
2.6.39 |
Added support for filename-based transitions. |
26 |
3.0 |
Added support for role transitions for non-process classes.
Added support for role attributes. |
27 |
3.5 |
Added support for flexible inheritance of user and role for newly-created objects. |
28 |
3.5 |
Added support for flexible inheritance of type for newly-created objects. |
29 |
3.14 |
Added support for attributes within SELinux constraints. |
30 |
4.3 |
Added support for extended permissions and implemented first on IOCTL controls.
Enhanced SELinux XEN support. |
History of SELinux feature evolution
By default, when a SELinux policy is built, the highest supported version as defined by the Linux kernel and libsepol
(the library responsible for building the SELinux policy binary) is used. Administrators can force a version to be lower using the policy-version
parameter in /etc/selinux/semanage.conf
.
Different policy content
Besides the policy capabilities described above, the main difference between policies (and distributions) is the policy content itself. We already covered that most distributions base their policy on the reference policy project. But although that project is considered the master for most distributions, each distribution has its own deviation from the main policy set.
Many distributions make extensive additions to the policy without directly passing the policies to the upstream reference policy project. There are several possible reasons why this is not directly done:
- The policy enhancements or additions are still immature: Red Hat initially starts with policies being active but permissive, meaning the policies are not enforced. Instead, SELinux logs what it would have prevented and, based on those logs, the policies are then enhanced. This means that a policy is only ready after a few releases.
- The policy enhancements or additions are too specific to the distribution: If a policy set is not reusable for other distributions, then some distributions will opt to keep those policies to themselves as the act of pushing changes to upstream projects takes quite some effort.
- The policy enhancements or additions haven't followed the upstream rules and guidelines: The reference policy has a set of guidelines that policies need to adhere to. If a policy set does not comply with these rules, then it will not be accepted.
- The policy enhancements or additions are not implementing the same security model as the reference policy project wants: As SELinux is a very extensive mandatory access control system, it is possible to write completely different policies.
- The distribution does not have the time or resources to push changes upstream.
This means that SELinux policies between distributions (and even releases of the same distribution) can, content-wise, be quite different. Gentoo for instance aims to follow the reference policy project closely, with changes being merged within a matter of weeks.