Project:SELinux/CodingStyle

From Gentoo Wiki
Jump to: navigation, search

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:

CODE Gentoo-specific change in the policy
# 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:

  1. Boolean declarations (using the gen_bool block, for base policy)
  2. Tunable declarations (using the gen_tunable blocks, for modular policy)
  3. Attribute declarations
  4. Type declarations

Introduce sufficient documentation for each declaration, like so:

CODE Example documentation for declarations
## <desc>
## 

## Enable support for NFS in foo ##

## </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:

CODE Comment block for a new local policy
########################################
#
# foo_t policy
#

The order inside the policy rules is as follows:

  1. Self rules, starting with the *capability* and *process* object classes
  2. Rules applicable to the objects owned by the module itself, sorted by object type alphabetically
  3. Calls to the kernel layer module, first the kernel module itself and then in alphabetical order
  4. Calls to the system layer module, in alphabetical order
  5. Calls to all other modules, in alphabetical order
  6. Build option blocks (using ifdef())
  7. Conditional policy blocks (using if())
  8. Tunable policy blocks (using tunable_policy())
  9. 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:

CODE Using in-line documentation for tunables
## <desc>
##   

## Some information about this boolean. ##

## </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 support
    • foo_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 the foo_t domain
    • foo_enable_homedirs enables home directory support in the foo_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 module
    • httpd_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 the user_home_content attribute
    • foo_manage_user_home to allow the domain to manage all classes of the user_home_t type
    • foo_read_user_home_files to allow the domain to read user_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 ports
    • foo_can_network_connect_http to enable the foo domain to connect to the HTTP ports
    • foo_plugin_can_relabel to enable the foo_plugin_t domain to relabel files

Attributes

In case of client- and server domains,

  • attribute names should follow the modulename_server and modulename_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 types
    • java_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 assign postfix_domain
    • java_domain_template to assign java_domain
  • if not through templates (i.e. no types are generated) then use interface names like so:
    • postfix_domain_type to assign postfix_domain
    • java_domain_type to assign java_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

Note
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:

  1. Templates
  2. Domain related interfaces
    1. Role interfaces
    2. Run interfaces
    3. Domain transition interfaces
    4. Execution interfaces
  3. Transformation interfaces (which assign attributes to types), sorted alphabetically by primary object type or attribute
  4. Access interfaces
    1. Alphabetically by primary object type or attribute, then
    2. Increasing in access level (getattr, search, setattr, list, read, append, write, rw, create, filetrans, rename, delete, manage, relabelto, relabelfrom, relabel), then
    3. Access interface before dontaudit (if a _dontaudit_ interface is added)
  5. Admin interfaces
    1. If multiple components are used, order alphabetically by component, with the "master" admin interface last
  6. Unconfined interface

Templates

Templates should always end with _template in the name.

Domain related interfaces

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
CODE Example run 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:

FILE example.ifAssigning an attribute
#########################################
## <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:

FILE example.ifAssigning an attribute
#########################################
## <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 the user_home_content attribute
  • pulseaudio_client_type() assigns the pulseaudio_client attribute
  • pulseaudio_client_privs() assigns the necessary privileges that a PulseAudio client would need.
Note
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:

CODE Naming convention for single type access interfaces
<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 definitions
  • object 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 read icecast_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 is device_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 name
      • files_manage_all_non_security_files
      • If no class is provided, the name is plural (due to the "all")
  • class is an optional class which limits the applicability of the interface to the given class, and is always plural (hence ending with "s")
Note
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:

CODE Naming convention for transition access interfaces
<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 transition is the transition type to work on
    • in case of a file transition, it is filetrans
  • the targettype is the type to assign after transition. Its naming convention is similar as the one for object in the single access interface.

Organization of code in .fc files

The organization in the .fc files is as follows:

  1. Alphabetically by path, then
  2. Increasing in depth, then
  3. First regular expressions, and then exact matches