Types, Permissions, and Constraints in SELinux

Posted on the 11 June 2021 by Satish Kumar @satish_kumar86

Now that we know more about types (for processes, files, and other resources), let’s explore how these are used in the SELinux policy in more detail.

Understanding type attributes

We have discussed the sesearch application already and how it can be used to query the current SELinux policy. Let’s look at a specific process transition:

$ sesearch -s initrc_t -t httpd_t -c process -p transition -A
allow initrc_domain daemon:process transition;

Even though we asked for the rules related to theinitrc_tsource domain and thehttpd_ttarget, we get a rule back for theinitrc_domainsource domain and thedaemontarget. Whatsesearchdid here was show us how the SELinux policy allows the requested permission, but throughattributesassigned to theinitrc_tandhttpd_ttypes.

Type attributesin SELinuxare used to group multiple types and assign privileges to those groups rather than having to assign the privileges to each type individually. Forinitrc_domain, the following types are all tagged with this attribute, as can be seen through theseinfoapplication:

$ seinfo -a initrc_domain -x
Type Attributes: 1
  attribute initrc_domain;

As wecan see, theinitrc_ttype is indeed one of the types tagged withinitrc_domain. Similarly, thedaemonattribute is assigned to several types (several hundred, even). So, the single allow rule mentioned earlier consolidates more than a thousand rules into one.

Attributes are increasingly used in the policy as a way of consolidating and simplifying policy development. Withseinfo -a, you can get an overview of all the attributes supported in the current policy.

Querying domain permissions

The most common rules in SELinux are the allow rules, informing the SELinux subsystem what permissions a domain has. allow rules use the following syntax:

allow <source> <destination> : <class> <permissions>;

The<source>field is almost always a domain, whereas the<destination>field can be any type.

The<class>field allows us to differentiate privileges based on the resource, whether it is for a regular file, a directory, a TCP socket, a capability, and so on. A full overview of all supported classes can be obtained fromseinfo -c. Each class has a set of permissions assigned to it that SELinux can control. For instance, thesemclass (used for semaphore access) has the following permissions associated with it:

$ seinfo -c sem -x
Classes: 1
  class sem
inherits ipc

The reference to ipc in the output informs us that the class inherits permission from the common ipc class, which we can query as follows:

$ seinfo --common=ipc -x
Commons: 1

In the <permissions> field, most rules will bundle a set of permissions using curly brackets:

allow user_t etc_t : file { ioctl read getattr lock execute execute_no_trans open };

This syntaxallows policy developers to make very fine-grained permission controls. We can use thesesearchcommand to query these rules. The more options are given to thesesearchcommand, the finer-grained our search parameters become. For instance,sesearch -Awould give us all allow rules currently in place. Adding a source (-s) filters the output to only show the allow rules for this domain. Adding a destination or target (-t) filters the output even more. Other options that can be used to filter through allow rules withsesearchare the class (-c) and permission (-p) options.

As you might have guessed by now,sesearchis an extremely versatile command for queryingthe active policy, showing us the SELinux policy rules that match the options given.

Learning about constraints

Theallowstatements in SELinux, however, only focus on type-related permissions. Sometimesthough, we need to restrict certain actions based on the user or role information. SELinux supports this through constraints.

Constraintsin SELinuxare rules applied against a class and a set of its permissions that must be true for SELinux to further allow the request. Consider the following constraint on process transitions:

constrain process
  { transition dyntransition noatsecure siginh rlimitinh }
    u1 == u2 or
      t1 == can_change_process_identity and
      t2 == process_user_target
    ) or (
      t1 == cron_source_domain and
        t2 == cron_job_domain or
        u2 == system_u
    ) or (
      t1 == can_system_change and
      u2 == system_u
    ) or (
      t1 == process_uncond_exempt

This constraint says that at least one of the following rules must be true if a transitiondyntransition, or any of the other three mentioned process permissions is invoked:

  • The SELinux user of the source (u1) and that of the target (u2) must be the same.
  • The SELinux type of the source (t1) must have thecan_change_process_identityattribute set, and the SELinux type of the target (t2) must have theprocess_user_targetattribute set.
  • The SELinux type of the source (t1) must have thecron_source_domainattribute set, and either the target type (t2) should havecron_job_domainas an attribute, or the target SELinux user (u2) should besystem_u.
  • The SELinux type of the source (t1) must have thecan_system_changeattribute set, and the SELinux user of the target (u2) must besystem_u.
  • The SELinux type of the source (t1) must have theprocess_uncond_exemptattribute set.

It is through constraints that UBAC is implemented as follows:

u1 == u2
or u1 == system_u
or u2 == system_u
or t1 != ubac_constrained_type
or t2 != ubac_constrained_type

You can list the currently enabled constraints using seinfo --constrain. Multiple constraints can be active for the same class and permission set. In that case, all the constraints need to be true for the permission to go through.

Back to Featured Articles on Logo Paperblog