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; ... |
To find how a rule is derived from a macro, follow this approach. Take a rule you are curious about:
allow httpd_t httpd_suexec_t:process transition; ... type_transition httpd_t httpd_suexec_exec_t:process httpd_suexec_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:
grep -R ":process transition" macros/* macros/core_macros.te:allow $1 $3:process transition; # match macros/global_macros.te:allow $1 self:process transition; |
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:
grep httpd_suexec domains/program/apache.te | grep httpd_t daemon_sub_domain(httpd_t, httpd_suexec) |
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:
define(`domain_auto_trans',` domain_trans($1,$2,$3) type_transition $1 $2:process $3; ') ... define(`domain_trans',` allow $1 $3:process transition; ... |
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; |