Defining file contexts through patterns
SELinux policy modules can contain file context definitions through their .fc
files. In these files, path expressions are used to point to the various locations that should match a particular file context, and class identifiers are used to differentiate file context definitions based on the file class (directories, regular files, symbolic links, and more).
In this recipe, we'll create a mylogging
SELinux module, which defines additional path specifications for logging-related contexts. We will use direct file paths as well as regular expressions, and take a look at the various class identifiers.
How to do it…
To define a file context through an SELinux policy module, use the following approach:
- With
matchpathcon
, we can check what is the context that the SELinux tools would reset the resource to:~# matchpathcon /service/log /service/log system_u:object_r:default_t
- Create the
mylogging.te
file in which we mention the types that are going to be used in the definition. It is a best practice to handle types that are not defined by the SELinux module itself through a different SELinux module. In this example though, we also declarevar_t
to keep the example simple:policy_module(mylogging, 0.2) gen_require(` type var_t; type var_log_t; type auditd_log_t; ')
- Next, create the
mylogging.fc
file in which we declare the path expressions and their associated file context:/service(/.*)? gen_context(system_u:object_r:var_t,s0) /service/log(/.*)? gen_context(system_u:object_r:var_log_t,s0) /service/log/audit(/.*)? gen_context(system_u:object_r:auditd_log_t,s0) /lxc/.*/log -d gen_context(system_u:object_r:var_log_t,s0) /var/opt/oracle/listener\.log -- gen_context(system_u:object_r:var_log_t,s0)
- Now, build the policy module and load it:
~$ make mylogging.pp ~$ semodule –i mylogging.pp
- With
matchpathcon
, we can now verify whether the context known to the SELinux tools is the correct one:~# matchpathcon /service/log /service/log system_u:object_r:var_log_t
How it works…
An SELinux policy module contains everything SELinux needs to properly handle a set of policy rules. This includes the rules themselves (which are declared in a .te
file) with optional interface declarations (in the .if
files), which define interfaces that other policies can call in order to generate specific SELinux rules. The third and final part of an SELinux policy module is the related file contexts file —hence the .fc
file suffix.
Note
Context declarations in a .fc
file do not automatically enforce and set these contexts. These are merely definitions used by the SELinux utilities and libraries when a relabeling operation occurs.
This contexts file contains, per line:
- A path expression to which an absolute file path should match
- An optional class identifier to discern contexts (files, directories, sockets, symbolic links, and so on)
- The context to be assigned to this path
Each part of the context definition is whitespace delimited:
<path> [<class identifier>] <context>
The lines can be ordered to the policy developers' liking. Most developers order paths in an alphabetical order with grouping based on the top-level directory.
Path expressions
The regular expression support in the SELinux tools and libraries is based on Perl-Compatible Regular Expressions (PCRE).
Of all possible expressions, the simplest expression to use is the one without globbing, such as the following code:
/var/opt/oracle/listener\.log
An important part of this is the escape of the period—if we don't escape the period, then the PCRE support would treat the period as any character matching not only a listener.log
file, but also listener_log
or listenerslog
.
A very common expression is the one that matches a particular directory and all subdirectories and files inside, which is represented in the following example:
/service(/.*)?
This ensures that there is always a context definition for a file or directory within.
The order of processing
Given the exhaustive list of path expressions that a regular system has, a file path can match multiple rules, so which one will the SELinux utilities use?
Basically, the SELinux utilities follow the principle of most specific first. Given two lines A and B, this is checked in the following order, where the first match wins:
- If line A has a regular expression in it and B doesn't, then B is more specific.
- If the number of characters before the first regular expression in line A is less than the number of characters before the first regular expression in line B, then B is more specific.
- If the number of characters in line A is less than the number of characters in line B, then line B is more specific.
- If line A does not specify an SELinux type (so that the context part of it is
<<none>>
) and line B does, then line B is more specific.
The SELinux utilities will load in the definitions given through the files available at /etc/selinux/mcs/contexts/files/
, but will give preference to the ones in file_contexts.local
(and then file_contexts.homedirs
) as those are the definitions made by the system administrator locally. However, if a local definition uses a regular expression and a policy-provided definition doesn't, then the policy-provided definition is still used. This is the only exception to the preference rules between the various context files.
The SELinux utilities provide a tool called findcon
(part of the setools
or setools-console
package) that can be used to analyze this ordering, which shows the matching patterns within a single (!) context definition file and orders them from least specific to most specific:
~$ findcon /etc/selinux/mcs/contexts/files/file_contexts -p /var/log/aide /.* system_u:object_r:default_t:s0 /var/.* system_u:object_r:var_t:s0 /var/log/.* system_u:object_r:var_log_t:s0 /var/log/aide(/.*)? system_u:object_r:aide_log_t:s0
If only the actual context definition is needed (and not the full set of matching expressions with the precedence order as findcon
shows), then matchpathcon
can be used instead:
~# matchpathcon /var/log/aide /var/log/aide system_u:object_r:aide_log_t:s0
Class identifiers
The second part of the context definition is an optional part—a class identifier. Through a class identifier, developers can tell the SELinux utilities that a context definition is only applicable if the path expression matches a particular file class. If the class identifier is omitted, then any class matches.
If a class identifier is shown, then one (per line) of the following identifiers can be used:
- The '
--
' identifier is used for regular files - The '
-d
' identifier is used for directories - The '
-l
' identifier is used for symbolic links - The '
-b
' identifier is used for block devices - The '
-c
' identifier is used for character devices - The '
-p
' identifier is used for FIFO files - The '
-s
' identifier is used for sockets
Context declaration
The final part of a context definition is the context itself that is to be assigned to all matching resources. It is generated through the gen_context
macro, as follows:
gen_context(system_u:object_r:var_t,s0)
The gen_context
macro is used to differentiate context definitions based on policy features. If the target policy does not support MLS, then only the first argument (system_u:object_r:var_t
, in the example) is used. If the policy supports MLS but only a single sensitivity (s0
), then :s0
is appended to the context. Otherwise, the second argument (coincidentally also s0
in the example) is appended (with a colon in front).
Generally, contexts only differ on the SELinux type. The SELinux owner and SELinux role of the resource usually remain system_u
and object_r
respectively.
A special value for the context is <<none>>
, like in the following definition:
/proc -d <<none>>
This tells the SELinux utilities that they should never try to set the context of this resource. Whenever an administrator triggers a filesystem relabeling operation, these specific locations will not have their label changed (regardless of their current label). This does not mean that an existing context should be removed!
There's more...
In the recipe, we covered how to define labels in great detail. If many changes are made, it makes sense to force a relabel on the entire system. On Red Hat systems, this can be accomplished by creating a flag file and rebooting the system:
~# touch /.autorelabel ~# reboot
On Gentoo systems, the entire system can be relabeled using the rlpkg
command:
~# rlpkg -a -r
On Red Hat systems, the command to relabel the system is called fixfiles
:
~# fixfiles relabel
This is also needed if a system has been (temporarily) booted without SELinux support or with SELinux disabled as files will be created that have no file context. When an SELinux-enabled system is booted again, it will mark those files as unlabeled_t
, which is a type that most domains have no access to (SELinux-wise).