7.3 Type-Enforcement Declarations

     

Type-enforcement (TE) declarations are of seven types:


attribute_def

Attribute declarations


type_def

Type declarations


typealias_def

Type alias declarations


bool_def

Boolean declarations


transition_def

Transition declarations


te_avtab_def

TE access vector table declarations


cond_stmt_def

Conditional statement declarations

7.3.1 Type Declarations

The SELinux policy language requires that all type names be explicitly defined. In the simplest possible form, a type declaration merely defines a name as a type. For instance, the type declaration:

 type ping_t; 

would mark ping_t as the name of a type. Type declarations need not precede all statements that refer to the types they define; you can place type declarations any place within a TE file.

Optionally, a type declaration may define one or more aliases for the type name. Any alias associated with a type can be freely used in place of the primary name of the type. A type declaration can also optionally associate one or more attributes with the type name.

Figure 7-1 shows the syntax of a type declaration. As an example, the ping.te file contains two type declarations:

 type ping_t, domain, privlog; type ping_exec_t, file_type, sysadmfile, exec_type; 

The first declaration identifies ping_t as a type name, and associates the attributes domain and privlog with the type name, marking the type as a domain that communicates with the system log process. The second declaration identifies ping_exec_t as a type name, and associates the attributes file_type , sysadmfile , and exec_type with the type name, marking the type as one used to identify executable files accessible by system administrators.

Figure 7-1. Type declaration (type_def)
figs/selx_0701.gif

To better understand how type attributes work with types, consider the definition of the syslogd domain, which contains the following declarations:

 allow privlog devlog_t:sock_file { ioctl read getattr lock write append }; allow privlog syslogd_t:unix_dgram_socket sendto; allow privlog syslogd_t:unix_stream_socket connectto; allow privlog devlog_t:lnk_file read; 

Notice how the type attribute privlog is used in these declarations in the same way that an actual type name might be used. Type attributes differ from types in that type attributes generally appear in multiple domains, whereas each type generally appears only in a single domain. You can think of a type attribute as simply an abbreviation standing for a set of access vector rules. You can associate these access vector rules with a type simply by binding the type attribute with the type, just as the domain and privlog type attributes are bound to the ping_t type.

The four allow declarations given earlier specify the range of permissible operations associated with the privlog type attribute, specifically :

  • Perform various read and write operations on socket files having type devlog_t .

  • Send data to datagram and stream sockets having type syslogd_t .

  • Read files and symbolic links having type devlog_t .

As you'd likely guess, the types devlog_t and syslogd_t are used to label system log files, system log FIFOs, and the sockets used to communicate with the syslog process.

The meanings of type attributes such as domain and privlog are not hardcoded in SELinux. Instead, the meaning of a type attribute is determined by policy statements. Consequently, the administrator of an SELinux system can create new type attributes or modify the meaning of type attributes that appear in sample policies. If the administrator of an SELinux system has added or modified many type attributes, it may be difficult to determine their meanings, as doing so would involve reading all the policy declarations related to each customized type attribute.

Fortunately, the set of type attributes defined in sample policies is rich, and system administrators generally do not need, or choose, to extend or modify it substantially. And most domain attributes have names that suggest their meaning. Appendix E, explained in the upcoming section titled "Attribute Declarations," summarizes the meanings of principal SELinux type attributes.


7.3.2 Type-Alias Declarations

As explained in the preceding section, a type declaration can optionally bind one or more aliases to a type name. However, it's more common to use a special type-alias declaration to establish such a binding. Figure 7-2 shows the syntax of type-alias declarations.

Figure 7-2. Type-alias declaration (typealias_def)
figs/selx_0702.gif

Many M4 macros generate type alias declarations. However, a few TE files contain explicit type-alias declarations. For instance, the cups.te file contains the follow type-alias declaration:

 typealias cupsd_etc_t alias etc_cupsd_t; 

This declaration defines etc_cupsd_t as an alias for the type name cupsd_etc_t , allowing the two names to be used interchangeably.

7.3.3 Attribute Declarations

A type attribute is a name that is bound to one or more types and used to define a set of types sharing some property. For instance, a type attribute can be used to designate the types (domains) that are allowed to read the system log file.

Because type attributes can appear in allow declarations just as though they were types, permissions can be granted by referring either to types or type attributes. An allow declaration containing a type attribute refers to all types associated with the type attribute. Thus, type attributes make it convenient to specify policies that apply to multiple types. The relationship between types and attributes is a many-to-many relationship; an indefinite number of types can be associated with an attribute, and an indefinite number of attributes can be associated with a type.

Type attributes are defined in the file attrib.te . Appendix E summarizes the type attributes defined in the Fedora Core 2 implementation of SELinux.

Figure 7-3 shows the syntax of an attribute declaration, the SELinux policy statement that defines a type attribute. As you can see, the syntax is quite simple. A typical declaration is:

 attrib admin; 

This declaration identifies admin as an attribute. Appendix E explains that this attribute is used to identify administrator domain ”domains that should be available only to system administrators.

Figure 7-3. Attribute declaration (attribute_def)
figs/selx_0703.gif

Recall that the term domain refers to a type associated with a process.


7.3.4 TE Access-Vector Declarations

The permissions enforced by the SELinux security engine are held in kernel data space in an object known as the TE access matrix. As explained in Chapter 2, the TE access matrix includes four distinct access components , called vectors:


allow

Operations that are allowed but are not logged


auditallow

Operations that are allowed and are logged when they occur


auditdeny

Operations that are denied and are logged when they are attempted


dontaudit

Operations that are denied, but are not logged when they are attempted

Each TE access vector contains TE access-vector rules. A TE access-vector rule specifies permissible operations ”based on a source type, a target type, and a security object class. Whenever an operation is attempted, the SELinux security engine searches the access vectors for a rule matching the source type, target type, and object class of the operation. If a matching rule is found, the access vector containing the rule determines the action taken by SELinux. For instance, if the matching rule resides in the allow access vector, the operation is allowed. However, if the matching rule resides in another access vector, or no matching rule exists, the operation is denied.

Figure 7-4 shows the syntax of access-vector rules. Notice that the diagram shows what seems to be a fifth type of access-vector rule, represented by the neverallow rule type. The neverallow rule defines constraints that the SELinux policy must observe. The policy compiler checks for violations of these constraints, and if it finds any violations, it terminates without producing a binary policy file. You can add or subtract neverallow rules from the SELinux policy. However, they're intended as a safety feature that prevents you from generating a grossly insecure policy, so it's generally best not to disturb them.

Figure 7-4. TE access vector rule declaration (te_avtab_def)
figs/selx_0704.gif

Each of the five forms of access vector rules contains four terms:

  • The source type or types; this is generally the type associated with the process attempting to perform an operation.

  • The target type or types; this is generally the type associated with the object that the process is attempting to manipulate.

  • The object class or classes to which the rule applies.

  • The permissions that the rule establishes.

The syntax of each of these terms is represented by the replaceable text names , which was explained in Chapter 6 and represented in Figure 6-13.

Here's a sample allow declaration associated with the ping_t domain:

 allow ping_t ping_exec_t:file { read getattr lock execute ioctl }; 

The rule created by this declaration allows processes running in the ping_t domain to perform any of five operations ( read , getattr , lock , execute , and ioctl ) on files labeled as belonging to the ping_exec_t domain.

If you check the ping.te file, you won't find this declaration there. Many access-vector declarations, including this one, are created by expansion of M4 macros, such as the domain_auto_trans macro explained later in this section.


The standard SELinux security policy includes fewer than six auditallow declarations. Here's a sample declaration:

 auditallow kernel_t security_t:security load_policy; 

Recall that auditallow rules don't actually enable any operations. Therefore, this rule is supplemented by an allow rule such as:

 allow kernel_t security_t:security load_policy; 

The allow rule authorizes processes running in the kernel_t domain (that is, kernel processes) to perform the load_policy operation on security objects labeled with the security_t domain. More plainly, the allow rule allows the kernel to load an SELinux policy. The auditallow rule causes every such operation to be logged when it is performed. Thus, the system log contains a record of these important events.

The standard SELinux security policy does not include even one instance of an auditdeny rule. Since the default action of SELinux is to forbid unauthorized operations and make a log entry documenting the action, auditdeny rules are not generally needed. However, so that you can see how auditdeny rules work, here's a hypothetical auditdeny rule declaration:

 auditdeny user_t security_t:security load_policy; 

The rule created by this declaration forbids processes running in the user_t domain from performing the load_policy operation on security objects labeled with the security_t domain.

Here's a sample declaration of a dontaudit rule:

 dontaudit ping_t var_t:dir search; 

The rule created by this declaration suppresses log entries when processes in the ping_t domain attempt to search a directory labeled with the var_t domain, and are prohibited by the SELinux security engine from doing so.

It's somewhat common for programs to attempt operations on security-sensitive objects, even though they don't need to do so. The dontaudit rule enables you to suppress such operations and avoid cluttering the log with a flood of routine entries associated with them.


As explained, the neverallow rule type enforces constraints on the SELinux security policy itself. It helps ensure the integrity of the policy, which might be inadvertently weakened by well-intentioned but erroneous changes. Operations forbidden by a neverallow constraint are prohibited even if a conflicting allow rule exists within the SELinux security policy .

Here's a hypothetical neverallow constraint declaration:

 neverallow domain file_type:process transition; 

The constraint created by this declaration would prevent a process having the domain attribute from transitioning to a type having the file_type attribute. The constraint would prevent an errant policy modification that allowed a process to be treated as a file, which might compromise system security.

7.3.4.1 Special notations for types, classes, and permissions

The hypothetical neverallow constraint just given is effective but incomplete. Ideally, we'd prohibit transitions from a domain type to any non- domain type, not just every type marked as a file_type . A special notation associated with the replaceable text names enables us to do so:

 neverallow domain ~domain:process transition; 

The constraint associated with this declaration forbids a process having the domain type attribute from transitioning to a type not having that attribute. For instance, the constraint prevents a malicious user from causing a process to transition to a file or another nondomain object.

Notice that the target type is specified as ~domain . This notation, known as complementation , provides a convenient means of referring to types that do not possess a specified attribute. In this case, the declaration refers to types that do not have the domain attribute. If complementation were not available, we'd find it cumbersome to write a constraint such as this, since the constraint would have to refer explicitly to every type that is not a domain. Many such types might exist. Moreover, having added a new nondomain type to the policy, we might neglect to modify the constraint appropriately. So complementation provides an important convenience.

Another convenient notation is known as subtraction . Here's an example of a constraint declaration that employs subtraction:

 neverallow { domain -admin -anaconda_t -firstboot_t -unconfined_t -kernel_t           -load_policy_t } security_t:security load_policy; 

The constraint created by this declaration prevents any domain other than those listed with minus signs ( admin , anaconda , firstboot_t , unconfined_t , kernel_t , and load_policy_t ) from performing the load_policy operation on a security object having type security_t .

Occasionally, it's necessary to refer to all types, classes, or permissions. The asterisk (*) can be used to do so, as in the following constraint declaration:

 neverallow domain file_type:process *; 

The constraint created by this declaration prohibits any type having the domain attribute from performing any operation on processes having the file_type attribute.

Here's a somewhat more interesting example that includes two instances of the asterisk operator:

 neverallow ~{ domain unlabeled_t } *:process *; 

The constraint created by this declaration prevents types other than those having attributes domain or unlabeled_t from performing any operation on processes having any type.

Another special notation enables us to create rules where the target type is the same as the source type. Here's an example:

 neverallow {domain -admin -insmod_t -kernel_t -anaconda_t -firstboot_t -unconfined_t }  self:capability sys_module; 

The rule created by this declaration applies to domains other than six specific domains ( admin , anaconda , firstboot_t , unconfined_t , kernel_t , and load_policy_t ). It prohibits these domains from performing the sys_module operation on capability objects labeled with domains other than the source domain.

These special notations can be used with allow rules as well as neverallow rules. For instance, consider the following rule:

 allow sysadm_t self:process ~{ ptrace setexec setfscreate setrlimit }; 

This rule lets processes within the sysadm_t domain perform any operation on processes running within that domain, with the exception of the operations listed: ptrace , setexec , setfscreate , and setrlimit .

Table 7-1 summarizes the special notations used to specify types, classes, and permissions.

Table 7-1. Special notations for specification of types, classes, and permissions

Notation

Description

 * 

All members

 ~ 

Complementation

 - 

Subtraction

 self 

Target type same as source type


In addition to special notations, macros can be used to specify types, classes, or permissions. Appendix C summarizes a set of such macros, defined in the file macros/core_macros.te .

It's not necessary to specify all authorized permissions in a single access-vector rule. SELinux combines permissions pertaining to the same source type, target type, and object class into a single access-vector rule that authorizes all specified operations.


7.3.4.2 Macros that specify and authorize transitions

Two main types of rules govern transitions:


Type-transition rules

Specify transitions that occur when a new object, such as a process or file, is created.


Access-vector rules

Authorize transitions.

Type-transition rules do not authorize the transitions they specify. That is, they specify the transition that would occur, but don't actually give permission for the transition to occur. An access-vector rule must authorize the transition, or it will not be allowed to occur. Therefore, type transition and access vector rules both must be specified for most transitions. To avoid the associated tedium, several M4 macros conveniently generate type transition and access vector rule declarations from a single line of policy source code. Generally, the most useful of these macros are:


domain_auto_trans

Specifies and authorizes a transition related to the execution of a program defined as a domain entry point.


file_type_auto_trans

Specifies and authorizes a transition related to file creation.

For instance, the ping.te file of the Fedora Core 2 SELinux implementation invokes the domain_auto_trans macro three times:

 domain_auto_trans(unpriv_userdomain, ping_exec_t, ping_t) domain_auto_trans(sysadm_t, ping_exec_t, ping_t) domain_auto_trans(initrc_t, ping_exec_t, ping_t) 

The first invocation is executed conditionally, as explained in the next section. The second and third invocations are executed unconditionally. Each invocation defines a transition from a domain ( unpriv_userdomain , sysadm_t , or initrc_t ) to the ping_t domain when a ping_exec_t executable is loaded. The transition is also authorized by an access vector rule. For instance, the third invocation expands to the following policy declarations:

 type_transition initrc_t ping_exec_t:process ping_t; allow initrc_t ping_t:process transition; 

Here's an example of a typical use of the file_type_auto_trans macro, occurring in the ftpd .te file of the Fedora Core 2 SELinux implementation:

 file_type_auto_trans(ftpd_t, var_log_t, xferlog_t, file) 

This macro invocation expands to the following policy declarations:

 type_transition ftpd_t var_log_t:file xferlog_t; allow ftpd_t var_log_t:dir rw_dir_perms; allow ftpd_t var_log_t:file create_file_perms; 

The file_type_auto_trans macro simplifies definition of the ftpd_t domain, by using a one-line macro invocation to specify that:

  • When an ftpd_t process creates a file in a directory having type var_log_t (such as /var/log ), the file should be given the type xferlog_t . Thus, the FTP logs /var/log/xferlog and /var/log/xferreport will be properly labeled when created.

  • Any ftpd_t process can read and write var_log_t directories (that is, perform any of the following operations associated with rw_dir_perms : read , getattr , lock , search , ioctl , add_name , remove_name , and write ).

  • Any ftpd_t process can create files within var_log_t directories (that is, perform any of the following operations associated with create_file_perms : create , ioctl , read , getattr , lock , write , setattr , append , link , unlink , and rename ).

Occasionally, it's convenient to specify, but not authorize, a transition because the transition is already authorized elsewhere in the policy file or in another policy file. The following macros do so:


domain_trans

Specifies, but does not authorize, a transition related to execution of a program defined as a domain entry point.


file_type_trans

Specifies, but does not authorize, a transition related to file creation.

7.3.5 Transition Declarations

A transition rule specifies the new domains for a process or the security contexts for a newly created object, such as a file. Each transition rule has two types: a source type and a target type. For a process, the source type is the current domain of the process, and the target type is the type of the executable file. For an object, the source type is the domain of the process creating the object, and the target type is the type of a related object. For instance, if the object is a file, the target type is the type of the file's parent directory.

Figure 7-5 shows the syntax of type transitions. The railroad diagram contains three instances of replaceable text, each having the syntax of the now-familiar replaceable text names , originally described in Chapter 6 and represented in Figure 6-13:

  • The source type or types

  • The target type or types

  • The object class or classes to which the transition rule applies

The diagram also includes the replaceable text new_type , which has the syntax of the familiar replaceable text identifier . The replaceable text new_type specifies the new type of the process or object.

Figure 7-5. Transition declarations (transition_def)
figs/selx_0705.gif

Here's a typical type transition rule pertaining to a process:

 type_transition sysadm_t ping_exec_t:process ping_t; 

This rule affects the behavior of processes in the sysadm_t domain that execute a program having type ping_exec_t . Executing such a program causes the process to attempt to transition to the ping_t domain. I write attempt to because SELinux does not authorize operations, including transitions, by default. So if the transition is to succeed, an access-vector rule must authorize it; otherwise , unless SELinux is operating in permissive mode, the SELinux security engine will prohibit the transition.

Here's a typical type-transition rule pertaining to a file:

 type_transition httpd_t var_log_t:file httpd_log_t; 

This rule affects the behavior of processes in the httpd_t domain that create a file having a parent directory of the var_log_t type. Such files are created with the httpd_log_t type, unless the appropriate access vector rule does not exist.

The replaceable text identifier is always associated with a single identifier, whereas the replaceable text names can be associated with multiple identifiers, as shown in Figure 6-13. Because the railroad diagram refers to three instances of names and one instance of identifier ”rather than four instances of identifier ”a transition declaration can refer to multiple source types, target types, or classes. Here's a typical rule that does so:

 type_transition httpd_t tmp_t:{ file lnk_file sock_file fifo_file } httpd_tmp_t; 

Like the preceding rule, this rule also affects the behavior or processes in the httpd_t domain. When such a process creates a file , lnk_file , sock_file , or fifo_file object having a parent object of type tmp_t , the new object receives the type http_tmp_t , unless the appropriate access vector rule does not exist.

Because several sets of class names are commonly used, the file macros/ core_macros.te defines eight convenient M4 macros, described in Table 7-2. Using the appropriate macro, the preceding type transition rule could be written more compactly as:

 type_transition httpd_t tmp_t:notdevfile_class_set httpd_tmp_t; 

Table 7-2. Class name M4 macros

Macro

Definition

Description

 devfile_class_set 

 { chr_file blk_file } 

Device file classes

 dgram_socket_class_set 

 { udp_socket unix_dgram_socket } 

Datagram socket classes

 dir_file_class_set 

 { dir file lnk_file sock_file fifo_file chr_file blk_file } 

Directory and file classes

 file_class_set 

 { file lnk_file sock_file     fifo_file chr_file blk_file } 

File classes except dir

 notdevfile_class_set 

 { file lnk_file sock_file     fifo_file } 

File classes except dir and device files ( chr_file , blk_file )

 socket_class_set 

 { tcp_socket udp_socket      rawip_socket netlink_socket packet_socket unix_stream_socket unix_dgram_socket } 

Socket classes

 stream_socket_class_set 

 { tcp_socket unix_stream_socket } 

Stream socket classes

 unpriv_socket_class_set 

 { tcp_socket udp_socket unix_stream_socket unix_dgram_socket } 

Unprivileged socket classes except raw IP socket class


7.3.6 Boolean Declarations

The Fedora Core 2 implementation of SELinux introduced a new feature: Boolean declarations. A Boolean is a true-false value that can be tested by policy statements. As explained in Chapter 4, the setbool command can set the value of a Boolean. Booleans make it possible to tailor dynamically the behavior of an SELinux policy.

Figure 7-6 shows the syntax of a Boolean declaration. The Fedora Core 2 SELinux policy defines one Boolean, user_ping :

 bool user_ping false; 

This Boolean controls nonprivileged user access to the ping and traceroute commands. This control is implemented by conditional declarations included in the ping.te and traceroute.te files, as explained in the next section.

Figure 7-6. Boolean declaration (bool_def)
figs/selx_0706.gif

7.3.7 Conditional Declarations

The declarations explained so far in this chapter have been unconditional declarations. Recent implementations of SELinux, such as that included in Fedora Core 2, also support conditional declarations. A simple conditional declaration has two parts :

  • A Boolean expression that is evaluated when the security engine makes policy decisions.

  • A declaration that takes effect only if the Boolean expression evaluates true. The declaration is referred to as a subdeclaration, because it occurs inside the conditional declaration.

A more sophisticated conditional declaration includes a Boolean expression and two alternative subdeclarations. Depending on the result of dynamically evaluating the Boolean expression, the declaration has the force of either of the two subdeclarations.

Figure 7-7 shows the syntax of a conditional declaration. As the figure shows, the syntax of the associated conditional expression ( cond_expr ) is rich. The subdeclaration or subdeclarations have a familiar form, that of either a type transition or access-vector declaration of the following kinds:

  • allow

  • auditallow

  • auditdeny

  • dontaudit

Although the railroad diagram in Figure 7-7 indicates that a subdeclaration can be an auditdeny declaration, SELinux does not support such subdeclarations at the time of writing. However, you can express equivalent policies by using one or more other declaration types rather than an auditdeny .


Figure 7-7. Conditional statement declaration (cond_stmt_def)
figs/selx_0707.gif

The conditional expression within a conditional statement declaration can use any of six relational operators, summarized in Table 7-3.

Table 7-3. Relational operators

Symbol

Description

 && 

Logical AND

 == 

Logical equality

 ! 

Logical negation

 != 

Logical inequality

 

Logical OR

 ^ 

Logical exclusive OR


Here's a sample conditional statement declaration, taken from the ping.te file associated with the Fedora Core 2 implementation of SELinux:

 if (user_ping) {     domain_auto_trans(unpriv_userdomain, ping_exec_t, ping_t)     # allow access to the terminal     allow ping_t { ttyfile ptyfile }:chr_file rw_file_perms;     ifdef(`gnome-pty-helper.te', `allow ping_t gphdomain:fd use;') } 

The user_ping conditional expression refers to a policy Boolean that indicates whether nonprivileged users are authorized to use the ping and traceroute commands, as explained earlier in this chapter. Only if the Boolean has the value true do the subdeclarations have effect. The subdeclarations:

  • Authorize an automatic transition from a domain marked as an unpriv_userdomain to the ping_t domain upon execution of a ping_exec_t program.

  • Authorize the ping_t domain to access the user's TTY or PTY.

  • Invoke an M4 macro, ifdef , that conditionally allows the ping_t domain to use file descriptions passed by the Gnome PTY helper ( gphdomain ) domain.



SELinux. NSA's Open Source Security Enhanced Linux
Selinux: NSAs Open Source Security Enhanced Linux
ISBN: 0596007167
EAN: 2147483647
Year: 2003
Pages: 100
Authors: Bill McCarty

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net