Performing single-step analysis

Until now, we’ve covered a few methods of analyzing SELinux policies through command-line utilities such as seinfo and sesearch. These utilities can assist users in performing single-step analyses: they either provide immediate information about an SELinux object (which is mainly what seinfo is about) or are capable of querying direct SELinux rules (which is the scope of sesearch).

Not all capabilities of the seinfo and sesearch utilities have been discussed yet though, so let’s see what other tricks these commands have up their sleeves.

Using different SELinux policy files

Many SELinux analysis tools, including seinfo and sesearch, can access both the currently loaded SELinux policy and a specified SELinux policy file. The latter allows developers to query SELinux policies of systems they do not have direct access to, for which direct access is cumbersome (such as mobile devices), or that have been used in previous situations (backups) and are no longer active.

For instance, to analyze a policy file called policy.sepolicy-2, the following seinfo command can be used:

$ seinfo ./policy.sepolicy-2
Statistics for policy file: ./policy.sepolicy-2
Policy Version: 30 (MLS enabled)
Target Policy: selinux
Handle unknown classes: deny
 Classes: 63 Permissions: 286
 Sensitivities: 1 Categories: 1024
 Types: 1858 Attributes: 28
 Users: 1 Roles: 2
 Booleans: 0 Cond. Expr.: 0
 Allow: 108120 Neverallow: 0
 Auditallow: 24 Dontaudit: 553
 Type_trans: 639 Type_change: 0
 Type_member: 0 Range_trans: 0
 Role allow: 0 Role_trans: 0
 Constraints: 0 Validatetrans: 0
 MLS Constrain: 59 MLS Val. Tran: 0
 Permissives: 0 Polcap: 2
 Defaults: 0 Typebounds: 0
 Allowxperm: 185 Neverallowxperm: 0
 Auditallowxperm: 0 Dontauditxperm: 0
 Initial SIDs: 27 Fs_use: 16
 Genfscon: 83 Portcon: 0
 Netifcon: 0 Nodecon: 0

When the command is not explicitly told to parse a given policy file, it will try to query the current active policy through the /sys/fs/selinux/policy pseudo-file.

Displaying policy object information

The main purpose of the seinfo application is to display SELinux object information. This information is presented on a per-object basis. Various SELinux object types are supported, ranging from the well-known types, attributes, roles, and users, to the more specialized fs_use_* declarations or genfscon statements.

A complete list of supported object types (and their resulting seinfo options) can be found on the seinfo manual page, or through the direct help:

$ seinfo --help

Regardless of the object type that the user is interested in, seinfo has three main modus operandi:

  • In the first mode, it lists the objects of a given type. For this, only the option has to be passed on, without additional information. For instance, to list all object classes available in the policy, use the following command:
$ seinfo --class
  • In the second mode, it can confirm (or deny) the presence of an object instance. To accomplish this, add the instance name to the command. For instance, to validate if the memprotect class is available in the policy, use the following command:
$ seinfo --class memprotect
Classes: 1
 memprotect

Sadly, regardless of whether the instance is available or not, the return code of the application is the same, so scripts cannot use this without additional statements to verify whether the instance exists. Instead, they will need to check the output of the command (which will state that zero instances exist that match the name).

  • The third mode displays expanded information about a selected instance. Although not all information objects support an expanded set, most of the common ones do. The expanded information generally shows a list of (different) instances related to the initial query:
$ seinfo --class memprotect -x
Classes: 1
 class memprotect
{
 mmap_zero
}

The supported types that seinfo can query are the following:

  • With --attribute (-a), seinfo shows all currently known SELinux attributes in the policy. When expanded, it shows the types associated with a given attribute.
  • With --bool (-b), seinfo shows all currently known SELinux booleans in the policy. When expanded, it shows the current value of the boolean.
  • With --class (-c), seinfo shows the supported SELinux classes. When expanded, it shows the permissions supported by that class.
  • With --role (-r), seinfo shows the SELinux roles supported in the policy. When expanded, it shows the domains allowed for that role.
  • With --type (-t), seinfo shows the SELinux types in the policy. When expanded, it shows the aliases that the type has, as well as the attributes.
  • With --user (-u), seinfo shows the SELinux users (not the Linux users or logins) known by the policy. When expanded, it shows the roles and sensitivity range associated with the SELinux user.
  • With --category, seinfo shows the currently supported categories. When expanded, it shows the sensitivities for which the category is associated (only in MLS policies).
  • With --common, seinfo shows the common permission sets. These are sets inherited by different classes. When expanded, it shows the permissions part of that set.
  • With --constrain, seinfo shows the current constraints. There is no expanded information for this query.
  • With --default, seinfo shows the default_* rules within the policy. One of these rules, for instance, is the default sensitivity range for a class (default_range). There is no expanded information for this query.
  • With --fs_use, seinfo shows the fs_use_* rules within the SELinux policy. One of these rules is to allocate a security context for filesystems that support extended attributes (fs_use_xattr). There is no expanded information for this query.
  • With --genfscon, seinfo shows the context allocations for filesystems that do not support extended attributes. There is no expanded information for this query.
  • With --initialsid, seinfo shows all the initial Security Identifiers (SID). These are all the classes that have predefined contexts set. When expanded, it shows the context associated with the SID.
  • With --netifcon, seinfo shows the contexts currently associated with the network interfaces. This is only applicable when labeled networking is active. There is no expanded information for this query.
  • With --nodecon, seinfo shows the contexts currently associated with the node definitions (hosts). This is only applicable when labeled networking is active. There is no expanded information for this query.
  • With --permissive, seinfo shows which types are currently marked as permissive domains. There is no expanded information for this query.
  • With --polcap, seinfo shows the policy capabilities (that is, in-policy settings that define the SELinux subsystem behavior, such as support for SCTP through the extended_socket_class policy capability). When expanded, it shows the actual policy capability statements in the policy.
  • With --portcon, seinfo shows the current port mappings and their associated contexts (which is also interpreted by semanage port -l). There is no expanded information for this query.
  • With --sensitivity, seinfo shows the currently supported sensitivity levels. When expanded, it shows the actual policy statements to declare the sensitivities.
  • With --typebounds, seinfo shows the type bounds (SELinux types or domains bounded by a parent domain). There is no expanded information for this query.
  • With --validatetrans, seinfo shows the transition constraints active in the policy (these are constraints that limit when a file transition is allowed). This is not used in most Linux distributions. There is no expanded information for this query.

The seinfo command also has an --all option that shows all possible information it can get from a policy file. However, this does not include the expanded information.

Understanding sesearch

Where seinfo displays information about SELinux objects, sesearch is used to query SELinux rules and behavior information between a source and a target resource.

We have been using sesearch to query standard allow rules (type enforcement-related access controls) as well as the impact of SELinux booleans on these allow rules. The sesearch application allows us to not just query rules based on the rule type, but also filter based on additional parameters. Let’s see which parameters can be used for sesearch filters:

  • The most common queries are to filter out the rules that match a given source expression using --source (-s) and/or target expression using --target (-t):
$ sesearch -A -s mount_t -t unconfined_t

The sesearch application can also deal with indirect source or target information. For instance, when querying information related to the svirt_sandbox_domain attribute, it will also display rules of all types that have this attribute assigned. We can selectively disable this behavior using -ds (for source) and -dt (for target):

$ sesearch -A -s svirt_sandbox_domain -ds
  • With the --class (-c) argument, we can search for only those rules affecting a specified resource class (such as filedirtcp_socket, and so forth—the list of all possible classes can be obtained using seinfo --class):
$ sesearch -A -s svirt_sandbox_domain -c file
  • If we are interested in only a particular action (or permission), we can use the --perm (-p) argument. This is particularly useful when we encounter a denial for a certain action (say, write) and want to see which domains are allowed to perform this action, as it might indicate that we are examining the wrong source domain. We can list multiple permissions, in which case sesearch will display the rules that have at least one permission in them:
$ sesearch -A -s staff_t -c file -p write

With the -ep option, sesearch will only list the rules that have all permissions in them, rather than at least one.

  • We can also query only those rules influenced by an SELinux boolean using the --bool (-b) argument.

    If we use the -eb option, then all booleans listed on the command line must be matched, rather than at least one.

  • The sesearch application can also use regular expressions rather than actual values. This is not the default behavior, but can be activated with -rs (for the source type or role), -rt (for the target type or role), -rc (for the class), -rd (for the default type or role), and -rb (for the boolean):
$ sesearch -A -s staff_.*_t -c process -p transition -rs

As this provides insights into the most common SELinux behavior and access controls, let’s go through the various rules and the impact they have on the system.

Querying allow rules

The first set of rules are the allow rules, of which many subtypes exist. The standard allow rule defines which actions a source domain can successfully trigger toward or against a target type:

$ sesearch --allow -s guest_t -t cgroup_t -c dir
allow guest_usertype cgroup_t:dir { getattr ioctl lock open read search };
allow guest_usertype filesystem_type:dir { getattr open search };

There are a few similar rules that SELinux policies can define, and these can be queried similarly with sesearch as follows:

  • Using --auditallow, we can query which actions are allowed by SELinux but will still result in an audit event.
  • Using --dontaudit, we can query which actions will not trigger an audit event, even when the action is denied.
  • Using --neverallow, we can query which actions are forbidden from being declared within the policy. Such actions, when defined, will cause the system to refuse to load new SELinux policies if they violate the rule. It cannot be used to negate existing rules though, and neverallow rules that you attempt to add to the policy afterward will fail if the current policy already has deviations against this rule.

SELinux also supports extended permission rules. These rules are similar to regular allow rules but take an additional (number) parameter that further limits the applicability of the rule, and are used to provide fine-grained access control for device queries. These queries are generally handled by the ioctl() system call, but until its support for extended permissions, SELinux could only control whether a domain was allowed to use the ioctl() system call or not, rather than filtering on the explicit query through ioctl().

With extended permission rules, SELinux policy developers can specify which ioctl() queries are allowed and which ones aren’t. For instance, we can grant a domain the ability to get a hardware address (known as SIOCGIFHWADDR, which is defined with number 0x8927) as follows:

allowxperm <domain> <resource> : tcp_socket ioctl 0x8927;

Within sesearch, we can query these rules using --allowxperm. Like regular allow rules, we also have the --auditallowxperm--dontauditxperm, and --neverallowxperm options to cover the extended-permission-equivalent rules. These have the same impact on the query and also on the extended permission rules.

Querying type transition rules

A second set of rules are the type transition rules. Rather than informing the system which actions are allowed or not, type transitions influence the SELinux context of objects and resources through actions taken by the processes on the system. Type transition rules, for instance, define what context a newly written file receives when it is written by a particular domain within a directory that has a given SELinux type, or what domain a newly created process receives when it is executed from a given source domain:

$ sesearch -T -s guest_t -c process
type_transition guest_t abrt_helper_exec_t:process abrt_helper_t;
type_transition guest_t chfn_exec_t:process chfn_t;
...

In this output, we can see that when the guest domain successfully executes a binary labeled with abrt_helper_exec_t, its resulting process will be assigned the abrt_helper_t context.

These rules are queried and interpreted by various tools in the Investigating domain transitions section.

Querying other type rules

Alongside the allow rules and type transition rules, sesearch can also query two other type-related rules: type_change and type_member. These rules are meant for SELinux-aware applications and are not enforced by the in-kernel SELinux subsystem:

  • With type_change statements (which can be filtered in sesearch using the --type_change option), developers inform the SELinux-aware application that a target resource should be relabeled with a given type on behalf of the source domain.

    For instance, when systemd assigns a terminal to a user, it queries the SELinux policy for type_change statements for the user domain, given the current terminal’s SELinux type, and will return the following type_change statement:

type_change guest_t tty_device_t:chr_file user_tty_device_t;

As the device file itself already exists and is only reassigned to a user, no type transition itself is done. Instead, the type_change rule is interpreted by the SELinux-aware application that relabels the device file accordingly.

  • The type_member rule (which can be filtered in sesearch using the --type_member option) informs SELinux-aware applications that participate in setting up polyinstantiated locations about the target SELinux type of such directories. For instance, when the /tmp location (which is labeled with tmp_t) is polyinstantiated for a user, then the following rule is used to understand that the /tmp view for this user is to be labeled with user_tmp_t:
type_member guest_t tmp_t:dir user_tmp_t;

The PAM module responsible for addressing the polyinstantiation is SELinux-aware, and will use these rules to deduce what the target types must be for the created locations.

Alongside the type-related statements, sesearch can also handle role-related queries.

Querying role-related rules

SELinux also has rules related to role activities and transitions. With the sesearch application, we can query which SELinux roles are allowed to be accessed from other roles, and when a role transition (such as switching from a user role to the system role) is performed:

$ sesearch --role_allow -s dbadm_r;
allow dbadm_r sysadm_r;
$ sesearch --role_trans -s dbadm_r;
role_transition dbadm_r mysqld_initrc_exec_t:process system_r;
role_transition dbadm_r postgresql_initrc_exec_t:process system_r;

The distinction between the two is that the allowed access (using --role_allow) shows which roles can be accessed from a given role, but they do not dictate when the change is done. The role transitions (using --role_trans) show when the system attempts to automatically change a role (and to what role it would be changed) when executing a script or binary. Hence, they can be compared with the allow rules (which specify what is allowed) and type transitions (defining SELinux behavior).

Analyzing role transitions and role allow rules helps administrators deduce which roles are too powerful or could result in potential security issues. For instance, allowing the dbadm_r role to switch to the system_r role through the postgresql_initrc_exec_t type might allow that role to invoke actions outside its scope if it also has the rights to modify postgresql_initrc_exec_t resources:

$ sesearch -A -s dbadm_t -t postgresql_initrc_exec_t -c file;
allow dbadm_t postgresql_initrc_exec_t:file { execute execute_no_trans getattr ioctl map open read };

While directly modifying postgresql_initrc_exec_t files is thus not allowed, it is not enough to only look at the main user type. A decent analysis needs to include all types reachable by the dbadm_r role, which we will cover in the Investigating domain transitions and Analyzing information flow sections. These sections will use apol, so let’s first see what this application is all about.

Browsing with apol

An advanced tool to perform policy analysis is apol, which can be launched by just executing the command without any arguments. The tool is graphical in nature and allows analysts and administrators to perform a wide range of analytical actions against the SELinux policy.

Once started, the first action to take with apol is to load a target policy (either the currently active policy or a file copied over from a different system). This can be accomplished through the Open Policy button, or by navigating to File | Open Policy.

The tool will then display a generic overview of the loaded policy:

single step image01

Once it has been loaded, select New Analysis to initiate the policy analysis functions:

single step image02

A decent number of analysis methods are provided. Let’s select Types to browse through the available types, or select an attribute to find out which SELinux types are assigned to that attribute:

single step image03

Similarly, with the TE Rules analysis, we can perform the same analysis as we did with the sesearch application:

single step image04

The more advanced analysis methods are covered in the Investigating domain transitions and Analyzing information flow sections.

Using apol workspaces

Analyzing SELinux policies can take a while, especially when this involves multiple phases of analysis and fine-tuning. The apol tool allows you to save your current workspace to disk, so that you can later get back to the analysis from the point at which you saved it:

single step image05

Workspaces not only retain the settings of the queries so far, but also the notes you might add. Notes are an important feature within apol where you can write down thoughts and observations from the queries you’ve made. The notes are associated with the tabs you have open, allowing you to switch between different queries as needed.

Now that we know how the apol application works, let’s see how we can use it (and other tools) for more in-depth analyses.

Related Articles

How to add swap space on Ubuntu 21.04 Operating System

How to add swap space on Ubuntu 21.04 Operating System

The swap space is a unique space on the disk that is used by the system when Physical RAM is full. When a Linux machine runout the RAM it use swap space to move inactive pages from RAM. Swap space can be created into Linux system in two ways, one we can create a...

read more

Lorem ipsum dolor sit amet consectetur

0 Comments

Submit a Comment

Your email address will not be published. Required fields are marked *

five − 4 =