Project:SELinux/CodingStyle
Our coding-style is based on the reference project StyleGuide.
Organization of code in .te files
When a policy module is adapted by Gentoo, but is available in the reference policy, then all changes made for Gentoo specifically (and not yet upstreamed) must be put at the end of the file, inside a ifdef(`distro_gentoo',...)
block.
- This is necessary so that the main file can be easily updated with upstream changes (no patch collisions).
- The coding style for the main document, and the large
ifdef(`distro_gentoo',...)
block at the end, are the same. Treat them as two separate files. - The only exception to this rule are Gentoo-specific code blocks that are upstreamed (which follow the same convention as other
ifdef()
blocks).
When changes must be made inline (for instance to remove interface calls we do not want) comment out the interface calls and add a comment right above it startin with "Gentoo:", like so:
# Gentoo: We reduce the privileges of the mozilla module and move these into tunable blocks
# files_exec_usr_files(mozilla_plugin_t)
files_list_mnt(mozilla_plugin_t)
files_read_config_files(mozilla_plugin_t)
General organization
The type enforcement rules should have the following organization.
First, the declarations are provided. These are, in order:
- Boolean declarations (using the
gen_bool
block, for base policy) - Tunable declarations (using the
gen_tunable
blocks, for modular policy) - Attribute declarations
- Type declarations
Introduce sufficient documentation for each declaration, like so:
## <desc>
## <p>
## Enable support for NFS in foo
## </p>
## </desc>
gen_tunable(foo_use_nfs, false)
# Assigned to domains which act as foo clients and are granted
# the set of privileges necessary to interact with foo
attribute foo_client;
# Assigned to the foo configuration files (*.conf), not for keys
type foo_conf_t;
files_type(foo_conf_t)
Next, the local policy rules are provided:
- first the "main" domain
- then in blocks ordered alphabetically by the domain (but ignoring unconfined domains)
Each block must be prepended with a comment like so:
########################################
#
# foo_t policy
#
The order inside the policy rules is as follows:
- Self rules, starting with the *capability* and *process* object classes
- Rules applicable to the objects owned by the module itself, sorted by object type alphabetically
- Calls to the kernel layer module, first the kernel module itself and then in alphabetical order
- Calls to the system layer module, in alphabetical order
- Calls to all other modules, in alphabetical order
- Build option blocks (using
ifdef()
) - Conditional policy blocks (using
if()
) - Tunable policy blocks (using
tunable_policy()
) - Optional policy blocks (using
optional_policy()
)
Finally, unconfined access rules are added, following the same structure as the local policy rules.
Tunables
Tunables must be documented with the in-line documentation system, like so:
## <desc>
## <p>
## Some information about this boolean.
## </p>
## </desc>
gen_tunable(modulename_enable_something, false)
Always start a boolean with the module name itself.
Please try to use boolean names that match the following use cases, if possible:
- Support for particular system-provided services (video support, audio support, but also NFS support or Kerberos support) use
_use_
in the name, like so:foo_use_nfs
to enable NFS supportfoo_use_video
to enable video support
- Support for application-provided services (i.e. from within the application managed by the domain) uses
_enable_
in the name, like so:foo_enable_ftp_server
enables the FTP server support for thefoo_t
domainfoo_enable_homedirs
enables home directory support in thefoo_t
domain
- Support for a specific implementation (usually in functionality-oriented policies) follows the
module_implementation
convention, like so:cron_fcron
enables fcron-specific privileges in the cron modulehttpd_hiawatha
enables hiawatha-specific privileges in the apache module
- Access rights by the domains follows the interface naming if applicable and understandable by end users:
foo_manage_all_user_home_content
to allow the domain to manage all types associated with theuser_home_content
attributefoo_manage_user_home
to allow the domain to manage all classes of theuser_home_t
typefoo_read_user_home_files
to allow the domain to readuser_home_t
files
- Access rights which are grouped functionally have multiple access interface calls and cannot be named after them easily. For these, use the
_can_
prefix with a functionally related suffix, like so:foo_can_network_connect
to enable the foo domain to connect to all portsfoo_can_network_connect_http
to enable the foo domain to connect to the HTTP portsfoo_plugin_can_relabel
to enable thefoo_plugin_t
domain to relabel files
Attributes
In case of client- and server domains,
- attribute names should follow the
modulename_server
andmodulename_client
naming conventions, like so:pulseaudio_client
is for domains that (always) are PulseAudio clients
- the interface to assign the attribute is called
modulename_(server|client)_type
, like so:pulseaudio_client_type(foo_t)
- if applicable, the interface to assign privileges is called
modulename_(server|client)_privs
, like so:pulseaudio_client_privs(pulseaudio_client)
In case of server membership domains (i.e. logical grouping of types related to a specific domain),
- use the
_domain
suffix, like so:postfix_domain
for all postfix related domain typesjava_domain
for all java related domain types
- if templates are used to assign the attribute, always end the template with
_template
, like so:postfix_domain_template
to assignpostfix_domain
java_domain_template
to assignjava_domain
- if not through templates (i.e. no types are generated) then use interface names like so:
postfix_domain_type
to assignpostfix_domain
java_domain_type
to assignjava_domain
In case of object type bundling, try to use functionally coherent naming.
- try not to use the
_type
suffix as that is used for the interfaces assigning the type
Type declarations
Types should be named functionally, starting with the module name, and ending with the _t
suffix.
The following table shows proper naming for these types.
Type | Functional type | Naming suffix | Transformation interface | Example | More information |
---|---|---|---|---|---|
Client | Executable | _exec_t
|
userdom_user_application_domain (end user, UBAC constraints apply) or application_domain (end user)
|
java_exec_t
|
|
Client | User configuration | _home_t
|
userdom_user_home_content (end user, UBAC constraints apply)
|
java_home_t
|
Files in HOME_DIR/.java/ |
Generic | Shared memory | _tmpfs_t
|
userdom_user_tmpfs_file (end user, UBAC constraints apply) or files_tmpfs_file
|
java_tmpfs_t
|
Usually files in /dev/shm. Also used for X11 applications |
Generic | Temporary files | _tmp_t
|
userdom_user_tmp_file (end user, UBAC constraints apply) or files_tmp_file
|
jabberd_tmp_t
|
Files in /tmp or /var/tmp |
Server | Cached data | _cache_t
|
files_type
|
squid_cache_t
|
|
Server | Configuration files | _conf_t
|
files_config_file
|
zebra_conf_t
|
For configuration files, usually in /etc. See also the Configuration supporting files (_etc_t )
|
Server | Configuration supporting files | _etc_t
|
files_config_file
|
postfix_etc_t
|
Although conf and etc are used with the same purpose, the idea is that etc files do not constitute configuration files, but supporting files. The audit.rules.stop.pre file supports the configuration, whereas audit.rules is a configuration file.However, distinction should only be made if there are different access patterns involved (or certain threats that can be mitigated with it). Otherwise this would only be more overhead. |
Server | Init scripts | _initrc_exec_t
|
init_script_file
|
jabberd_initrc_exec_t
|
Files in /etc/init.d |
Server | Lock files | _lock_t
|
files_lock_file
|
jabberd_lock_t
|
Files in /var/lock or /run/lock |
Server | Log files | _log_t
|
logging_log_file
|
jabberd_log_t
|
Files in /var/log |
Server | Run-time variable data | _var_run_t
|
files_pid_file
|
jabberd_var_run_t
|
Files in /var/run or /run |
Server | Variable state information | _var_lib_t
|
files_type
|
jabberd_var_lib_t
|
Files in /var/lib |
Organization of code in .if files
Our coding style has a few changes with respect to the upstream project, notably the inclusion of the Domain related interfaces and a larger set of privileges in the Access interfaces.
Interface files should be organized as follows:
- Templates
- Domain related interfaces
- Role interfaces
- Run interfaces
- Domain transition interfaces
- Execution interfaces
- Transformation interfaces (which assign attributes to types), sorted alphabetically by primary object type or attribute
- Access interfaces
- Alphabetically by primary object type or attribute, then
- Increasing in access level (getattr, search, setattr, list, read, append, write, rw, create, filetrans, rename, delete, manage, relabelto, relabelfrom, relabel), then
- Access interface before dontaudit (if a
_dontaudit_
interface is added)
- Admin interfaces
- If multiple components are used, order alphabetically by component, with the "master" admin interface last
- Unconfined interface
Templates
Templates should always end with _template
in the name.
A role interface is meant to be assigned to user domains and contain all the necessary privileges to work with and interact with a specific type.
- The first argument must be the role, and the second argument the userdomain type.
A run interface is meant to be assigned to other domains (which can be user domains) and contains only the necessary privileges to execute and transition to the domain (including role privileges).
- The first argument must be the domain type, and the second argument the role.
- The interface must call the
_domtrans
interface
##########################################
## <summary>
## Execute racoon and allow the specified role the domain.
## </summary>
## <param name="domain">
## <summary>
## Domain allowed to transition.
## </summary>
## </param>
## <param name="role">
## <summary>
## Role allowed access.
## </summary>
## </param>
#
interface(`ipsec_run_racoon',`
gen_require(`
type racoon_t;
')
ipsec_domtrans_racoon($1)
role $2 types racoon_t;
')
Transformation interfaces
Transformation interfaces generally assign an attribute or a set of privileges to a type.
First the transformation interface that assigns an attribute is listed. This interface is named after the attribute that it assigns, with the _type
suffix:
#########################################
## <summary>
## Assigns the example_domain attribute
## </summary>
## <param name="domain">
## <summary>
## Domain to be assigned the example_domain attribute
## </summary>
## </param>
#
interface(`example_domain_type',`
gen_require(`
attribute example_domain;
')
typeattribute $1 example_domain;
')
Next, the transformation interface that grants all necessary privileges associated with the attribute is mentioned, using the _privs
suffix:
#########################################
## <summary>
## All privileges associated with the example domains
## </summary>
## <param name="domain">
## <summary>
## Domain to be granted the privileges
## </summary>
## </param>
#
interface(`example_domain_privs',`
gen_require(`
...
')
...
')
Examples are:
userdom_user_home_content_type()
assigns theuser_home_content
attributepulseaudio_client_type()
assigns thepulseaudio_client
attributepulseaudio_client_privs()
assigns the necessary privileges that a PulseAudio client would need.
The use of a
*_privs
interface is specific to Gentoo and is meant to allow granting privileges through booleans.Access interfaces
Access interfaces assign privileges to a domain to interact with one or more resources.
Single type access interface
The single type access interface is named like so:
<modulename>[_dontaudit]_<privilegeset>_<object>[_<class>s]
In this, the
modulename
is the name of the module.dontaudit
is the optional modifier (which should be placed below the one without_dontaudit_
in it) to support not auditing denials related to the access interface.privilegeset
is the set of privileges, and should be the name as is used in the_pattern
and_perms
definitionsobject
is the target for the access privilege- If it is a regular type which starts with the module name, then it is the type name stripped of the module name and without
_t
:icecast_read_log
to readicecast_log_t
- If it is a regular type which does not start with the module name, "only" contains the module name or is ambiguous with other prefixed types, then it starts with
generic_
followed by the type name without_t
:dev_read_generic_files
(no object mentioned otherwise, as the object isdevice_t
)
- If it is an attribute, the name starts with
all_
, is stripped of the module name (if applicable) and is then followed by the attribute namefiles_manage_all_non_security_files
- If no class is provided, the name is plural (due to the "all")
- If it is a regular type which starts with the module name, then it is the type name stripped of the module name and without
class
is an optional class which limits the applicability of the interface to the given class, and is always plural (hence ending with "s")
Historically, the policy is filled with interface names that use a slightly different naming. For instance,
files_search_pids
to grant search access through the var_run_t
. In the above naming convention, this would become files_search_var_run
. There is also a pidfile
attribute and a files_manage_all_pids
to manage all types associated with that attribute. This duality and non-standardization of naming convention is still apparent in the policy and will likely not be updated.Transition access interface
The transition access interface is named like so:
<modulename>_<parenttype>_<transition>
<modulename>_<parenttype>_<transition>_<targettype>
In this, the
- the
parenttype
is the type of the parent resource from which a transition is defined.- In case of a filetransition, it is the type of the directory in which the file would be created
- The naming convention is similar as the one for
object
in the single access interface. The "is ambiguous" part here applies. For instance,cron_generic_log_filetrans_log
means that it is the "generic log type" (i.e.var_log_t
) and not the module log type (cron_log_t
) that is the parent.
- The naming convention is similar as the one for
- In case of a filetransition, it is the type of the directory in which the file would be created
- the
transition
is the transition type to work on- in case of a file transition, it is
filetrans
- in case of a file transition, it is
- the
targettype
is the type to assign after transition. Its naming convention is similar as the one forobject
in the single access interface.
Organization of code in .fc files
The organization in the .fc files is as follows:
- Alphabetically by path, then
- Increasing in depth, then
- First regular expressions, and then exact matches