Wednesday, January 6, 2010

7.3 Type-Enforcement Declarations











 < Day Day Up > 







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)







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)







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)









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)







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)







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)











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)







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.

















     < Day Day Up > 



    No comments: