zondag 28 juni 2009

Policy module source

In this article i will try to explain a bit more about the policy module source files.

A policy module source has three files. The first file is a Type Enforcement file. These files have the .te extension. The second file is a interface file. These files have a .if extension. The third file is called a file context file. This file has a .fc extension.

Type enforcement source policy file.

This file has policy and declarations that a personal or local to the policy module. Policy that is used by the (personal) types that are declared in this module.

Interface source policy file.

This file has policy and declarations that are shared with other types.

File context source policy file.

This file has personal file contexts for the personal types that are (usually) declared in the Type Enforcement file.

Some background information:

Example of a AVC denial:

avc: denied { read write } for pid=1864 comm="tor" path="/dev/console" dev=tmpfs ino=496 scontext=system_u:system_r:tor_t:s0 tcontext=system_u:object_r:console_device_t:s0 tclass=chr_file

Example of the AVC denial when processed by audit2allow:

allow tor_t console_device_t:chr_file { read write };

Example of the AVC denial processed by audit2allow -R:


The AVC denial has a lot of information about details of a denied rule in the Access Vector Cache. The basic audit2allow command translates this AVC denial into human readable policy language. The
audit2allow -R command goes looking for any available shared policy that may be available for us to use.

In this example the
tor_t domain wants to read and write to /dev/console which is a character device file that has type console_device_t. Tor interacts with terminal.

To make policy manageable and to keep the footprint of policy as small as possible the concept of shared policy is used. There is no need for duplicate policy. There should be a single point where a certain access is defined. This point is defined in the interface file of the target.

In this example
term_use_console is shared policy that is hosted by the module that declared(owns) type console_device_t. Interfaces (shared policy) are usually prefixed by the name of the module that own the type of the target.

tor_t domain tries to read and write to console_device_t which is a type that is declared in the terminal.te source policy file. The terminal.if interface file hosts policy to interact with this type properly: term_use_console. term is the abbreviation for terminal which is the name of the module that hosts the console_device_t file.

The type
console_device_t is declared here -- it is a declaration the is personal to the terminal policy module (terminal.te):

http://oss.tresys.com/projects/refpolicy/browser/trunk/policy/modules/kernel/terminal.te (line 21)

The interface
term_use_console is defined here -- it is policy that is shared (hosted) by the terminal policy module (terminal.if):

(line 219 to line 237)

The terminal module own the
console_device_t type and shares all policy other types need to be able to interact with this type. If something changes in the way that interaction is done with this type then the terminal.if is a central point to modify policy for this. Other types simple call this shared policy and changes automatically get synchronized.

Shared policy usually have a commented header which explains the purpose of the interface and the parameters it expects when it is called.

For term_use_console the description is:

Read from and write to the console

And the parameter it expects is:

Domain allowed access.

If the tor_t domain wants to read and write to the terminal a device file with type
console_device_t then it can simple call the shared policy that is hosted in the terminal.if file, which is the file that shares policy and declaration with regard to types and domains that are personal to the terminal policy module.

Look at interfaces like BASH functions. You can source a external file that has BASH functions and then call any functions that are provided by the sources functions file.

The purpose of the commented headers is that it is easy to reference and call the interfaces. The source policy can be converted to html if you run "
make html" in the source root.

An example of this is hosted here:


The specific term_use_console interface is specified here:


Below the commented header for the term_use_console interface the actual shared policy can be found. This policy often has calls to shared policy for types that are external to the module. In this case the term_use_console as a interface call to
dev_list_all_dev_nodes($1) Which is shared policy that is hosted by the devices module (interfaces defined in device.if).

$1 is a variable of the parameter is expects. Look up the interface name here: http://oss.tresys.com/docs/refpolicy/api/kernel_devices.html and see what parameter is expects: Domain allowed to list device nodes.

If a domain type
tor_t wants to list device nodes then simple call dev_list_all_dev_nodes(tor_t)

$1, $2, $3 etc are variables that replace parameter 1, parameter 2, parameter 3 etc.

Another rule in the term_use_console interface in terminal.if is:

allow $1 console_device_t:chr_file rw_chr_file_perms;

If term_use_console(tor_t) is defined than the rule is translated:

allow tor_t console_device_t:chr_file rw_chr_file_perms;

Which basically allows the
tor_t domain type read and write access to character files with type console_device_t.

The last thing to mention about the term_use_console interface and interfaces in general is the
gen_require() blocks that can be seen.

Since type
console_device_t is declared in terminal.te and since term_use_console is called by tor_t domain in the tor.te source policy file, the tor_t files has to borrow the console_device_t type which is external to the tor.te file.

gen_require() and require{} block basically source types that are declared in other modules. After the types are sourced they can be used in personal policy.

another example:

If you encounter a AVC denial than consider that the target type (tcontext type) usually hosts policy to facilitate the access that the source type (scontext type) in the AVC denial needs. Run the AVC denial through audit2allow to hav it translated to raw policy language. Run the AVC denial through audit2allow -R to have it look for any shared policy that facilitates the access that is required.

Of course you can also do this yourself:

avc: denied { read } for pid=1842 comm="smartd" name="config" dev=dm-1 ino=39859 scontext=system_u:system_r:fsdaemon_t:s0 tcontext=system_u:object_r:selinux_config_t:s0 tclass=file

The smartd executable that runs in the
fsdaemon_t domain wants to read a file with name config and with type selinux_config_t.

allow fsdaemon_t selinux_config_t:file read;

The module that has declared
selinux_config_t should also provide shared policy that facilitates the access fsdaemon_t domain needs.

I would expect that type
selinux_config_t would be declared in selinux.te since types and interfaces are often prefixed by the name of the module that owns it. In this case it is not so straight forward. A little peruse of the policy shows that this type is declared in the selinuxutil.te file.

So shared policy related to this type should be in the selinuxutil.if file. On line 595 in the selinuxutil.if interface file here:


This interface called
seutil_read_config can be called by fsdaemon_t if we wish to give that domain this permissions.


However policy decisions are usually not that simple to make. A better idea may be to use this interface on line 575:


File context files define file contexts of types that are declared in the policy module. Have a look at some of the many examples Type Enforcement, Interface and File contexts files available in Tresys Reference policy.

Geen opmerkingen:

Een reactie plaatsen