Customizing the Policy

This section describes how to customize the policy. It discusses how to perform various common changes to the policy, from adding users and permissions to defining entirely new domains, types, and roles.

Adding Users

When a user is added to the system, the policy may need to be updated to recognize the user. As discussed in the Section called User Identity Model and the Section called User Declarations, it may be appropriate to simply map the new user to the generic user_u user identity if the new user only requires unprivileged access and does not need to be separated from other such users by the policy. In that case, no updates to the policy are required.

If the user must be recognized by the policy, then the administrator must add the user to the policy/users file, specifying the set of authorized roles for the user, and reload the policy via make load in the policy directory.

As an example, suppose that the administrator has added a user steve to the system who should be authorized for both the staff_r and sysadm_r roles. To update the policy, the administrator would add an entry to the policy/users file as shown below, and run make load to reload the policy:

user steve roles { staff_r sysadm_r };

Adding Permissions

After installing SELinux, the administrator may discover that additional permissions must be allowed in order for the system to function properly. It is advisable to run SELinux in permissive mode initially and to exercise the standard operations of the system in order to generate audit messages for all operations that would have been denied by the example policy. These messages can typically be found in the dmesg output or /var/log/messages with the prefix avc: denied. A couple of example audit messages that might be generated during the execution of system cron jobs are shown below:

avc:  denied  { rename } for  pid=26878 exe=/usr/sbin/logrotate 
      path=/var/log/messages.4 dev=03:02 ino=1345261
      scontext=system_u:system_r:system_crond_t 
      tcontext=system_u:object_r:var_log_t tclass=file
avc:  denied  { create } for  pid=26878 exe=/usr/sbin/logrotate 
      path=/var/log/messages dev=03:02 ino=1345261
      scontext=system_u:system_r:system_crond_t 
      tcontext=system_u:object_r:var_log_t tclass=file

The critical fields of each avc denied message are the list of permissions, the source security context (scontext), the target security context (tcontext), and the target security class (tclass). These example audit messages show that the system_crond_t domain is being denied permissions to rename and create files with the var_log_t type. The other fields in each audit message provide any information about the specific processes and objects that can be determined when the audit message is generated. These messages show that the process was running the logrotate program and was attempting to access files in the /var/log directory.

The audit messages should be carefully reviewed to determine whether the denied permission should be allowed via a TE allow rule (described in the Section called TE Access Vector Rules). The audit2allow script provides an example of how to automatically convert the audit messages to TE allow rules that grant the denied permissions, but these rules should be reviewed to ensure that they do not violate the desired security goals. Other options include placing the process into a different domain or placing the object into a different type, possibly requiring the definition of new domains and/or types. It is also sometimes desirable to continue denying the permission, but to disable auditing of the permission via a TE dontaudit rule.

In the case of the example audit messages, the denied permissions could be allowed by adding the following rule to the policy/domains/program/crond.te file:

allow system_crond_t var_log_t:file { rename create setattr unlink };
However, granting these permissions to the system_crond_t domain allows all system cron jobs to access these files. A better approach would be to define a separate domain for the logrotate program that has these permissions. This approach is discussed further in the Section called Creating a New Domain.

Not all permission denials can be solved simply through modifying the TE configuration. It may be necessary to modify the RBAC configuration (described in the Section called RBAC Statements) or the constraints configuration (described in the Section called Constraint Definitions) as well. In the example policy, these configurations are relevant for the process transition permission when the role or user identity changes and for the file create or relabel permissions when the user identity of the file differs from the process.

After updating the policy configuration to allow the denied permissions, the administrator must then build and load the new policy by running make load in the policy directory. The permissions should then be granted on subsequent operations. If the same denials persist, then it is likely that the permission is being denied by the RBAC or constraints configuration and that these configurations were not updated by the administrator.

Adding Programs to an Existing Domain

An administrator may wish to add a program to an existing domain that is already being used for related programs that require similar permissions. First, the administrator should locate an appropriate domain by examining the existing program domains under policy/domains/program and by examining how existing programs are associated with the executable types for those domains in policy/file_contexts/program. After selecting an appropriate domain, the administrator should verify that a domain transition is defined from the desired starting domain to the new domain. If not, then an appropriate domain_auto_trans rule should be added to the domain's .te file and the policy should be reloaded via make load.

The administrator must then relabel the program with the executable type for the domain. This relabeling can be performed either using chcon or by updating the file contexts configuration and using restorecon, as discussed in the Section called Applying the File Contexts Configuration. If a process is already running the program, the administrator must then restart the process in order to place it into the domain, typically using run_init for system processes.

As an example, suppose that an administrator wants to add a new filesystem administration utility to the system that requires similar permissions to the fsck program. Looking at the file contexts configuration, the administrator would see that fsck is labeled with the fsadm_exec_t type. Looking under the policy/domains/program directory, the administrator would find the fsadm.te file with the definitions for the corresponding fsadm_t domain. After verifying that this domain is appropriate for the new utility, the administrator can add an entry to policy/file_contexts/program/fsadm.fc for the new utility and run restorecon on the program or use chcon to manually set the context on the program.

Creating a New Domain

After installing SELinux or after installing a new software package, the administrator may discover that some system processes are left in the initrc_t domain in the output of ps -eZ. These system processes should either be disabled or placed into an appropriate domain. This may simply involve adding the program to an existing domain, as discussed in the Section called Adding Programs to an Existing Domain, or it may require creating a new domain. The administrator may also discover that new domains are needed to address denied permissions, as discussed in the Section called Adding Permissions, for system processes or user programs. New domains are also needed when new roles are defined.

To create a new domain, the administrator should first create a new .te file under the policy/domains directory and populate it with appropriate TE declarations and rules. As an example, the creation of the policy/domains/program/logrotate.te file for the logrotate program will be discussed. The need for a separate domain for the logrotate program was introduced in the Section called Adding Permissions. The domain definition begins by declaring the domain and its executable type using type declaration rules (described in the Section called Type Declarations), as shown below:

type logrotate_t, domain, privowner;
type logrotate_exec_t, file_type, sysadmfile, exec_type;
To grant the new domain a basic set of starting permissions, the general_domain_access macro (described in Table 6 in the Section called TE Access Vector Rules in the Section called TE Access Vector Rules) can be used as shown below:
general_domain_access(logrotate_t)
For least privilege purposes, it may be desirable to instead individually define specific rules tailored for the new domain.

If the program is known to create files in shared directories, e.g. /tmp files, then the administrator can declare types for these files and file type transition rules (described in the Section called TE Transition Rules). An example type declaration and file type transition rule for temporary files created by logrotate is shown below:

type logrotate_tmp_t, file_type, sysadmfile, tmpfile;
file_type_auto_trans(logrotate_t, tmp_t, logrotate_tmp_t)
More concisely, this same set of rules could be expressed using the tmp_domain macro. Likewise, if the program is known to require certain permissions, then these permissions can be allowed by the administrator. Since the administrator knows that the program requires permissions to the /var/log files, the following rules might be initially specified:
allow logrotate_t var_log_t:dir rw_dir_perms;
allow logrotate_t var_log_t:file create_file_perms;
To cause the domain to be entered automatically from system cron jobs and from administrator shells when logrotate is executed, domain transition rules (described in the Section called TE Transition Rules) should be added for the appropriate domains. These rules can either be placed in the new domain's .te file or in the files for the source domains. Typically, if the source domain transitions to many different domains (e.g. every daemon or many programs), it is preferable to place the rule in the target domain to ease adding new domains and provide better encapsulation. Examples of these rules are shown below:
domain_auto_trans(system_crond_t, logrotate_exec_t, logrotate_t)
domain_auto_trans(sysadm_t, logrotate_exec_t, logrotate_t)
The first rule along with some related allow rules that are typically needed for system cron jobs can be more concisely written using the system_crond_entry macro.

After providing a minimal definition of the domain and transitions into the domain, the administrator should authorize roles for the domain. Role declarations (described in the Section called Role Declarations and Dominance) can be placed either in the domain's .te file or in the policy/rbac file. The former approach is preferable in order to encapsulate the domain's definition. Role declarations for the logrotate_t domain are shown below:

role system_r types logrotate_t;
role sysadm_r types logrotate_t;

The updated policy configuration can then be compiled and loaded by running make load in the policy directory. The administrator should then add the program to the file contexts configuration and run restorecon on the program or run chcon to manually set the context. A policy/file_contexts/program/logrotate.fc configuration file for logrotate is shown below:

/usr/sbin/logrotate		system_u:object_r:logrotate_exec_t

The administrator can then try running the program in its new domain to discover whether additional permissions are required. If the program is to be run as a system process, the administrator should use run_init to start it. If additional permissions are required, then the steps in the Section called Adding Permissions can be followed to complete the domain.

Creating a New Type

New types can be created to provide distinct protection for specific objects. An administrator may also discover that new types are needed to address denied permissions, as discussed in the Section called Adding Permissions. To create a new type, the administrator should first add a type declaration (described in the Section called Type Declarations) to the TE configuration. If the type is associated with a particular domain, then the declaration should be placed in the domain's .te file. If the type is a general type, then the declaration can be placed in one of the files under policy/types.

If automatic transitions to this type are desired, then the administrator should define type transition (described in the Section called TE Transition Rules) rules for the appropriate domains. The administrator should add appropriate TE allow rules to the TE configuration to permit authorized domains to access the type. The administrator can then build and reload the policy via make load. After updating the policy, the administrator can then apply the type to a file by updating the file contexts configuration and running restorecon on the file or by using chcon.

As an example, consider the /dev/initctl named pipe, which is used to interact with the init process. The initctl_t type was defined for this file in the policy/domains/program/init.te file, as shown below:

type initctl_t, file_type, sysadmfile;
Since this file is created at runtime, a file type transition rule must be specified to ensure that it is always created with this type. The file type transition rule for this type is:
file_type_auto_trans(init_t, device_t, initctl_t)
Two other domains need to access this object: the domain for the /etc/rc.d scripts and the domain for the system administrator. Hence, the following TE allow rules are added to the policy/domains/program/initrc.te and policy/domains/admin.te files:
allow initrc_t initctl_t:fifo_file rw_file_perms;
allow sysadm_t initctl_t:fifo_file rw_file_perms;
The policy can then be reloaded via make load. The administrator would then add the following entry to policy/file_contexts/program/init.fc and apply restorecon to the file:
/dev/initctl			system_u:object_r:initctl_t

Creating a New Role

New roles can be created to provide separation among users beyond the simple division between ordinary users and administrators. To add a new role, the administrator should use the full_user_role macro to instantiate a role and a set of domain definitions for the initial login domain for the role and for programs run from the role. To allow transitions between the new role and other roles, the role_tty_type_change macro in domains/user.te may be used. Appropriate users should be authorized for the new role in policy/users. The policy can then be reloaded via make load.

After updating the policy, the administrator should add an entry for the role to the /etc/selinux/(strict|targeted)/contexts/default_type application configuration file.