Macros are used throughout programming, as they provide reusable pieces of
code that you can call one time and have explode into many meaningful
lines. SELinux uses the m4 macro language for writing
reusable policy rules. This makes policy writing and management easier.
In using macros, policy writers gain flexibility, modularity, shared
quality control, and central management for complex pieces of policy.
Macros do not exist in the policy.conf file, as that
file represents the exploded macro policy code. It is possible to work
backward in finding where a particular policy.conf
entry exists. If a daemon has a rule that you cannot find in the
associated TE file at
$SELINUX_SRC/domains/program/<foo>.te,
then it is likely to be found in the macros. This section first explains
the syntax and usage of a macro, then discusses the analysis method in
more detail.
You can find more resources about m4 from the manual
page man m4, installed documentation at
/usr/share/doc/m4-<version>,
and through the resources listed in Chapter 9 References. Some of the specific macros used in
the targeted policy are explained in Section 3.4 Common Macros in the Targeted Policy.
This usage example shows the first few lines from the Apache HTTP macro file,
$SELINUX_SRC/macros/program/apache_macros.te:
define(`apache_domain', `
#This type is for webpages
#
type httpd_$1_content_t, file_type, homedirfile, httpdcontent, \
sysadmfile;
ifelse($1, sys, `
typealias httpd_sys_content_t alias httpd_sysadm_content_t;
')
# This type is used for .htaccess files
#
type httpd_$1_htaccess_t, file_type, sysadmfile;
...
The define(`apache_domain',` is the
beginning of the macro definition. Inside the definition, the
$1 represents the parameter passed to the
macro. Look in $SELINUX_SRC/domains/program/apache.te,
which has the following invocation:
apache_domain(sys)
This single line then generates a large set of types and rules,
substituting the passed parameter sys for
every $1:
type httpd_$1_htaccess_t, file_type, sysadmfile; -> \
type httpd_sys_htaccess_t, file_type, sysadmfile;
type httpd_$1_script_exec_t, file_type, sysadmfile -> \
type httpd_sys_script_exec_t, file_type, sysadmfile
role system_r types httpd_$1_script_t; -> \
role system_r types httpd_sys_script_t;
...
The allow rule says, httpd_t is
permitted to start a child process that transitions to
httpd_suexec_t. The
type_transition rule defines two
things: the circumstances, that is, when the domain
httpd_t is executing a file of the type
httpd_suexec_exec_t
(/usr/sbin/suexec); and the child domain
transitioned to, httpd_suexec_t. The
allow rule then permits the defined
transition.
These rules are present only in
$SELINUX_SRC/policy.conf, so they must be derived from a
macro.
In those rules, the variable elements are the parent domain
(httpd_t), the child domain
(httpd_suexec_t), and the program type
(httpd_suexec_exec_t). These are
represented in the macro as $1,
$2, and so forth. Fortunately, the
search is made easier because the object class
(process) and permission
(transition) are never variables in an
SELinux macro. It is safe to search using the class and permission as a
query:
The return from core_macros.te fits the right
format. Here it is in the macro file, showing it to be part of the
domain_trans() macro:
# domain_trans(parent_domain, program_type, child_domain)
#
# Permissions for transitioning to a new domain.
#
define(`domain_trans',`
#
# Allow the process to transition to the new domain.
#
allow $1 $3:process transition;
In the macro call, the variables are domain_trans($1,
$2, $3), with $1 the
parent domain, $2 the program type, and
$3 the child domain.
However, a search through
$SELINUX_SRC/domains/program/apache.te and
$SELINUX_SRC/macros/programs/apache_macros.te does not
find a line such as domain_trans(httpd_t,
httpd_suexec_t, httpd_suexec_exec_t). This means
that domain_trans() is not called
directly by the Apache HTTP policy, so another macro must be involved.
Looking back at the rules you are curious about, the common name roots
that make up those rules are httpd_t
and httpd_suexec. Focusing your search
on those as variables turns up a macro call:
The parameter httpd_suexec does not
have either of the suffixes, _t or
_exec_t, because it obtains those from
the macro. The macro
daemon_sub_domain() is found in
$SELINUX_SRC/macros/global_macros.te. Notice the
_exec_t and
_t that are attached to the variable
inputs $1 and
$2:
# define a sub-domain, $1_t is the parent domain, $2 is the name
# of the sub-domain.
#
define(`daemon_sub_domain', `
...
domain_auto_trans($1, $2_exec_t, $2_t)
Recall that the variables fed into
daemon_sub_domain() were
httpd_t
($1) and
httpd_suexec
($2). When m4 runs,
it inputs the parameters in the order received, so
$1 becomes
httpd_t,
$2_exec_t becomes
httpd_suexec_exec_t, and
$2_t is
httpd_suexec_t. Notice that the macro
daemon_sub_domain actually calls
domain_auto_trans(), which is found in
core_macros.te and looks like this:
There you see the completion of the chain, as
domain_trans() is called, and the
parameters are fed in to create the rules you are looking for:
$1 = httpd_t (base input of httpd_t)
$2 = httpd_suexec_exec_t (base input of httpd_suexec)
$3 = httpd_suexec_t (base input of httpd_suexec)
apache.te # feeds 2 variables into
daemon_sub_domain(httpd_t, httpd_suexec)# which calls
domain_auto_trans($1, $2_exec_t, $2_t) # that associates new vars
#### $1 = $1, $2_exec_t = $2, $2_t = $3) # and feeds the vars into
domain_trans($1,$2,$3) # which has
type_transition $1 $2:process $3; # that expands into
type_transition httpd_t httpd_suexec_exec_t:process httpd_suexec_t
# and
# expands domain_trans()
allow $1 $3:process transition; # which expands into
allow httpd_t httpd_suexec_t:process transition;
# Here is a final association of variables to sources
allow $1 $3 :process transition;
allow httpd_t httpd_suexec_t:process transition;
type_transition $1 $2 :process $3;
type_transition httpd_t httpd_suexec_exec_t:process httpd_suexec_t;