An SElinux module (3): interfaces

When creating the type enforcement rules for lighttpd (part 1) we used a lot of interfaces to other modules and policies. For example, we used the interface provided by the apache module to allow the lighttpd module access to all the same system web content (labelled with the type httpd_sys_content_t). This, and all the other interfaces we used, not only made this module easier to write but also make it robust to changes in any of the other modules.

Creating interfaces to the types and resources defined in this module allows other modules to interact with this one in a similar manner. There are a number of resources that this module has exclusive access to by virtue of specifically declared types (for example, the lighttpd configuration and log files). We will create interfaces to provide read access to these files for other modules, as we may need to grant access to certain modules at some point.

Creating an interface

The file lighttpd.if is the interface file we will create and use for the lighttpd module. A particular interface is defined as a macro which takes arguments and sets up appropriate type enforcement rules using these arguments. For each interface we also write a comment in XML form making the information about the interface machine readable. This is then used by various tools which can significantly aid policy creating and debugging.

The first interface, which we will use as an example, provides read access to the lighttpd log files. An interface is created using the macro called interface which itself takes two arguments. The first argument is the name of the interface and the second is the rules and policy that the interface provides and any dependencies it may have (i.e. what are the types this interface uses or depends on). Arguments to the new interface are accessed in a similar manner to shell scripts (i.e. the first argument is $1, the second is $2 etc.).

A good first step is to construct the rules for the interface. We define our interface so that the first argument is a domain type for which we are allowing access to the logs. Within our interface we can use other interfaces in exactly the same way as in the type enforcement file. A logging interface would allow this domain to search the log filespace which is a useful start to providing read access to the lighttpd logs:


Although this allows access to search the log directory (which has the type var_log_t) it does not provide access to search the lighttpd log sub-directory as it has the specific type of lighttpd_log_t. To allow searching of lighttpd log directories we add the rule:

allow $1 lighttpd_log_t:dir list_dir_perms;

which uses the macro list_dir_perms that contains the permissions for searching and listing a directory. Finally we need to provide read access to the actual log files (also labelled with the lighttpd_log_t type). Again we use a macro to do this for us (note this is not an interface to a particular module rather a convenience macro):


The first argument of this macro is the domain type being granted read access (here, contained in the $1 interface argument), the second and third arguments are the file type and the directory type which contains the file (here, both have the same lighttpd_log_t type).


Types that we explicitly use in this interface must be declared as a dependency, i.e. the interface wouldn't work without these types being defined. The only type we explicitly use in the rules created above is the lighttpd_log_t type. To declare it as an interface dependency we use the gen_require macro, which takes as an argument the declarations necessary for the interface to work:

gen_require(` type lighttpd_log_t; ')

Notice the use of open quotes ` and close quotes ' - this is an m4 language eccentricity. Putting the entire interface together we have:

interface(`lighttpd_read_log',` gen_require(` type lighttpd_log_t; ') logging_search_logs($1) allow $1 lighttpd_log_t:dir list_dir_perms; read_files_pattern($1,lighttpd_log_t,lighttpd_log_t) ')

XML comments

The final task is to create the XML comments for the interface. This is done by placing comments above the interface declaration itself and using XML tags such as <summary> and <param>. An example comment for this interface would be:

# <summary> # Allow the specified domain to read lighttpd log files. # </summary> # <param name="domain"> # <summary> # Domain allowed access. # </summary> # </param> # <rolecap/>

This completes the interface which provides read access to the lighttpd log files. In the example lighttpd.if source file there is also an interface providing read access to the lighttpd configuration files.

The next step

Although this completes the initial process of creating the lighttpd module, the next step is to compile, install and debug the module in a working system.