Let’s switch our view of the SELinux policy from wide-angle to close-up and examine a simple component of an SELinux policy, to better understand how an SELinux policy operates. Recall that the SELinux type enforcement mechanism is based on domains. At any given time, a running process is associated with a domain that determines its permissions. The SELinux policy statements that establish a domain are generally grouped as two files:
The file context (FC)
file, which has the filename extension
.fc
, resides in the
file_contexts/program
subdirectory of the policy
source directory. The file specifies the security contexts of
directories and files associated with the domain.
The type enforcement (TE)
file, which has the filename
extension .te
, resides in the
domains/program
subdirectory of the policy
source directory. The file specifies the access vector rules and
transitions associated with the domain.
An SELinux policy contains many files other than FC and TE files. However, most of the work you do with an SELinux policy will involve the FC and TE files. Because FC and TE files are central to SELinux, understanding the function of these files takes you a long way toward understanding SELinux policies. So in this section, we’ll overview the FC and TE files. The following chapters will explain more fully the FC and TE files as well as the other files that comprise an SELinux policy.
The FC and TE files that establish a domain generally carry the name
of the principal program associated with the domain. For instance,
the files associated with the domain that regulates the behavior of
the Snort
intrusion detection application are named
snort.fc
and snort.te
.
Let’s begin by examining the
snort.fc
file.
The
snort.fc
file
specifies security contexts for
directories and files related to Snort:
# SNORT /usr/sbin/snort -- system_u:object_r:snort_exec_t /usr/local/bin/snort -- system_u:object_r:snort_exec_t /etc/snort(/.*)? system_u:object_r:snort_etc_t /var/log/snort(/.*)? system_u:object_r:snort_log_t
The first line in the file is a comment, as indicated by the hash mark (#) appearing in the first column. The remaining four lines have a simple structure consisting of three columns:
Directories and files having a path matching the regular expression are labeled according to the specifications in columns two and three.
The flags specify whether the regular expression matches directories, files, or either directories or files. The paired dashes specify that the regular expression can match only ordinary files.
The security context specifies the SELinux user, role, and type with which the directory or file is to be labeled.
For instance, the Snort executable resides in the file
/usr/sbin/snort
, a path matching the regular
expression appearing in the second line of the FC file. When the
make relabel command is executed in the policy
source directory, the file /usr/sbin/snort
will
be labeled with the security context
system_u:object_r:snort_exec_t
.
The regular expression appearing in the fourth line of the file includes several metacharacters:
/etc/snort(/.*)? system_u:object_r:snort_etc_t
The metacharacters have the same meaning they take on in the
vi
editor and other Linux programs that use
regular expressions. In particular, the parentheses indicate
grouping, and the question mark (?) indicates that the preceding item
or group is optional. The dot (.) can be replaced by any single
character, and the asterisk (*) indicates that the preceding item or
group can be repeated indefinitely. The slash (/) is not a
metacharacter; it matches the slashes that separate the parts of a
directory pathname. Therefore, the regular expression matches the
path /etc/snort
and the path of any file or
directory contained in /etc/snort
. Matching
files and directories will be labeled with the security context
system_u:object_r:snort_etc_t
.
Now, let’s examine the TE file:
#DESC Snort - Network sniffer # # Author: Shaun Savage <[email protected]> # Modified by Russell Coker <[email protected]> # X-Debian-Packages: snort-common # daemon_domain(snort) log_domain(snort) can_network(snort_t) type snort_etc_t, file_type, sysadmfile; # Create temporary files. tmp_domain(snort) # use iptable netlink allow snort_t self:netlink_socket create_socket_perms; allow snort_t self:packet_socket create_socket_perms; allow snort_t self:capability { setgid setuid net_admin net_raw }; r_dir_file(snort_t, snort_etc_t) allow snort_t etc_t:file { getattr read }; allow snort_t etc_t:lnk_file read; allow snort_t self:unix_dgram_socket create_socket_perms; allow snort_t self:unix_stream_socket create_socket_perms; # for start script allow initrc_t snort_etc_t:file read;
As you can see, the TE file is somewhat more complex than the FC file. In particular, whereas the FC file contains only one sort of noncomment line, this TE file contains several:
Defines a type.
Define an access vector rule.
Lines beginning with other identifiers, such as
daemon_domain
and can_network
,
are macro invocations.
The line:
type snort_etc_t, file_type, sysadmfile;
defines snort_etc_t
as a type. The attributes
file_type
and sysadmfile
mark
this type as pertaining to file objects that can be accessed and
modified by users associated with the sysadm_r
(system administrator) role. Many such attributes are defined in the
attrib.te
file. If you look back to the FC
file,
you’ll see that the /etc/snort
directory and its contents are labeled with the type
snort_etc_t
.
Lines beginning with the keyword
allow
specify access vector rules authorizing
operations on various object types. For instance, the line:
allow snort_t etc_t:file { getattr read };
specifies that processes running in the snort_t
domain can read and get the attributes of files labeled with the
etc_t
type. Notice the use of curly braces, { and
}, to enclose the list.
Similarly, the line:
allow initrc_t snort_etc_t:file read;
specifies that processes running in the initrc_t
domain can read files labeled with the snort_etc_t
type. As it happens, the init
process, which
controls SysV daemons, runs in the initirc_t
domain. Thus, the init
process can read the
contents of the /etc/snort
directory tree, which
contains the Snort configuration files init
must
consult to start Snort with the user-specified options.
Notice that allow
lines are the most common sort
of line in the TE file. Recall that SELinux prohibits all operations
not explicitly authorized. So, a typical domain contains
several—perhaps many—allow
lines that
specify operations for which the domain is authorized.
Not all access vector rules specify authorized access. For instance,
as explained in Chapter 7,
auditdeny
and dontaudit
rules
specify prohibited operations. However, the
snort.te
file includes only
allow
rules.
In addition to type
and allow
lines, the TE file contains a variety of other noncomment lines.
These are
macro invocations—statements that
are expanded by the M4 macro processor into zero or more SELinux
policy statements. If you administer a system running Sendmail,
you’re likely already familiar with M4, because
Sendmail uses it to establish its configuration in much the same way
as SELinux does. If you aren’t familiar with macro
definitions and invocations, you can think of a macro definition as a
script and a macro invocation as a command invoking the script.
Let’s consider a simple example.
The file
macros/global_macros.te
defines many SELinux macros. Among them is the definition of the
can_network
macro,
which is invoked on line 11 of the snort.te
file
(comment lines omitted for simplicity):
define(`can_network',` allow $1 self:udp_socket create_socket_perms; allow $1 self:tcp_socket create_stream_socket_perms; allow $1 netif_type:netif { tcp_send udp_send rawip_send }; allow $1 netif_type:netif { tcp_recv udp_recv rawip_recv }; allow $1 node_type:node { tcp_send udp_send rawip_send }; allow $1 node_type:node { tcp_recv udp_recv rawip_recv }; allow $1 port_type:{ tcp_socket udp_socket } { send_msg recv_msg }; allow $1 mount_t:udp_socket rw_socket_perms; allow $1 node_type: { tcp_socket udp_socket } node_bind; allow $1 net_conf_t:file r_file_perms; ')dnl end can_network definition
When a macro is invoked, the invocation can supply the macro with
arguments. Consider line 11 of snort.te
:
can_network(snort_t)
This invocation of the can_network
macro supplies
the argument snort_t
. When the macro is
interpreted, its invocation is replaced with the lines from its
definition. However, the symbol $1
appearing
within the definition is replaced by the first supplied argument, the
symbol $2
is replaced by the second supplied
argument, and so on. In the macro invocation, notice that the left
parenthesis immediately follows can_network
, the
name of the macro. M4 requires that no space appear between the name
of a macro and the parenthesis that begins the
macro’s argument list.
In the case of the snort.te
file, the invocation
of can_network
provides one argument,
snort_t
. This argument replaces the symbol
$1
appearing in the macro definition. The result
is that the following lines replace the macro invocation within the
snort.te
file:
allow snort_t self:udp_socket create_socket_perms; allow snort_t self:tcp_socket create_stream_socket_perms; allow snort_t netif_type:netif { tcp_send udp_send rawip_send }; allow snort_t netif_type:netif { tcp_recv udp_recv rawip_recv }; allow snort_t node_type:node { tcp_send udp_send rawip_send }; allow snort_t node_type:node { tcp_recv udp_recv rawip_recv }; allow snort_t port_type:{ tcp_socket udp_socket } { send_msg recv_msg }; allow snort_t mount_t:udp_socket rw_socket_perms; allow snort_t node_type: { tcp_socket udp_socket } node_bind; allow snort_t net_conf_t:file r_file_perms;
These allow
lines authorize a variety of
network-related operations.
The point of using macros is that they make policies more concise and therefore easier to read and understand. They also help prevent inconsistencies that may lead to policy errors. The section of this chapter titled “The macros Subdirectory” summarizes many of the standard macros defined for use in SELinux policies.
As shown in Figure 5-3, the M4 macro processor is
invoked prior to the creation of the policy.conf
file, so that file contains no macro invocations. Thus, the SELinux
policy compiler does not actually process
any macro invocations.