1.a. SELinux Types

A type is a security attribute given to objects such as files, and network ports, etc. The type of a process is commonly referred to as its domain. The SELinux policy is primarily composed of type enforcement rules, which describe how domains are allowed to interact with objects, and how domains are allowed to interact with other domains. A type is generally suffixed with a '_t', such as sysadm_t. This is the most important attribute for a process or object, as most policy decisions are based on the source and target types.

1.b. SELinux Roles

SELinux is type enforcement, so the SELinux role is not the same as those in a role-based access control system. Permissions are not given to roles. A role describes the set of types a user can use. For example, a system administrator that is using the system for regular user tasks should be in the staff_r role. If they need to administrate the system, then a role change to sysadm_r is required. In SELinux terms, the domains that a user can be in is determined by their role. If a role is not allowed to have a certain domain, a transition to that domain will be denied, even if the type enforcement rules allow the domain transition. A role is generally suffixed with a '_r', such as system_r.

1.c. SELinux Identities

What is a SELinux Identity?

The SELinux identity is similar to a Linux username. The change of identity should be limited to very specific cases, since the role-based access control relies on the SELinux identity. Therfore, in general, a user’s SELinux identity will not change during a session. The user ID in Linux can be changed by set(e)uid, making it inappropriate for a SELinux identity. If a user is given a SELinux identity, it must match the Linux username. Each SELinux identity is allowed a set of roles.

Configure SELinux Identity Mapping (2006.1+)

The SELinux policy has several generic SELinux identities that should be sufficient for all users. This mapping only needs to be configured on the strict policy. The identity mapping for the targeted policy need not be configured, as the default identity (user_u) is sufficient in all cases.

When a user logs in, the SELinux identity used is determined by this mapping.

SELinux Identity Roles Description
system_u system_r System (non-interactive) processes. Should not be used on users.
user_u user_r Generic unprivileged users. The default identity mapping.
staff_u staff_r, sysadm_r System administrators that also log in to do regular user activties.
sysadm_u sysadm_r System administrators that only log in to do administrative tasks. It is not suggested that this identity is used.
root staff_r, sysadm_r Special identity for root. Other users should use staff_u instead.

See the SELinux HOWTO for semanage syntax for configuring SELinux identity mappings.

Configuring SELinux Identities (pre 2006.1)

SELinux identities are contained in the users file in the policy directory. The syntax for the file is simple. For example, to allow the user pebenito the roles staff_r and sysadm_r, add to the end of the file something like:

Code Listing 1: Example user line

user pebenito roles { staff_r sysadm_r };

Then load the policy. There must also be a Linux username pebenito. If a user does not have a user line in the file, their identity will be user_u, and only be allowed the user_r role.

Important: Normal users that have identities should be allowed user_r, not staff_r. Administrators should be allowed staff_r and sysadm_r. All users must be allowed user_r or staff_r otherwise they will be unable to log in remotely.

When giving a user an identity their home directory and contents should also be appropriately labeled. The user's home directory will be labeled based on the first role listed for the user, in the users file. For the above example, the user pebenito will have his home directory labeled as staff_home_dir_t.

1.d. SELinux Contexts

Using the above three security models together is called a SELinux context. A context takes the form identity:role:type. The SELinux context is the most important value for determining access.

Object Contexts

A typical ls -Z may have an output similar to this:

Code Listing 2: Example ls -Z output

drwxr-xr-x  root     root     system_u:object_r:bin_t          bin
drwxr-xr-x  root     root     system_u:object_r:boot_t         boot
drwxr-xr-x  root     root     system_u:object_r:device_t       dev
drwxr-xr-x  root     root     system_u:object_r:etc_t          etc

The first three columns are the typical linux permissions, user and group. The fourth column is the file or directory's security context. Objects are given the generic object_r role. From the other two fields of the context, it can be seen that the files are in the system identity, and have four different types, bin_t, boot_t, device_t, and etc_t.

Process Contexts

A typical ps ax -Z may have an output similar to this:

Code Listing 3: Example ps ax -Z output

  PID CONTEXT                                  COMMAND
    1 system_u:system_r:init_t                 [init]
    2 system_u:system_r:kernel_t               [keventd]
    3 system_u:system_r:kernel_t               [ksoftirqd_CPU0]
    4 system_u:system_r:kernel_t               [kswapd]
    5 system_u:system_r:kernel_t               [bdflush]
    6 system_u:system_r:kernel_t               [kupdated]
  706 system_u:system_r:syslogd_t              [syslog-ng]
  712 system_u:system_r:httpd_t                [apache]
  791 system_u:system_r:sshd_t                 [sshd]
  814 system_u:system_r:crond_t                [cron]
  826 system_u:system_r:getty_t                [agetty]
  827 system_u:system_r:getty_t                [agetty]
  828 system_u:system_r:getty_t                [agetty]
  829 system_u:system_r:getty_t                [agetty]
  830 system_u:system_r:getty_t                [agetty]
  831 system_u:system_r:httpd_t                [apache]
  832 system_u:system_r:httpd_t                [apache]
  833 system_u:system_r:httpd_t                [apache]
23093 system_u:system_r:sshd_t                 [sshd]
23095 user_u:user_r:user_t                     [bash]
23124 system_u:system_r:sshd_t                 [sshd]
23126 user_u:user_r:user_t                     [bash]
23198 system_u:system_r:sshd_t                 [sshd]
23204 user_u:user_r:user_t                     [bash]
23274 system_u:system_r:sshd_t                 [sshd]
23275 pebenito:staff_r:staff_t                 [bash]
23290 pebenito:staff_r:staff_t                 ps ax -Z

In this example, the typical process information is displayed, in addition to the process's context. By inspection, all of the system's kernel processes and daemons run under the system_u identity, and system_r role. The individual domains depend on the program. There are a few users logged in over ssh, using the generic user_u identity. Finally there is a user with the identity pebenito logged in with the staff_r role, running in the staff_t domain.

1.e. SELinux Policy Files (pre 2006.1)

The SELinux policy usually resides in /etc/security/selinux/src/policy. It is comprised of several files and directories for generating the policy. For easing the creation of the policy, macros from the m4 text processor are used to reuse common rules. The policy files are processed by m4, and then the policy compiler checkpolicy verifies that there are no syntactic errors, and creates a binary policy file. The binary policy then can be loaded into a running SELinux kernel.

Makefile

The policy Makefile handles the compiling and installation of policy. It has one configurable option for controlling the policy version, and has four targets.

Command Description
make policy Compiles the current policy into the binary policy file.
make install Compiles and installs the current policy into the /etc/security/selinux/src directory.
make load Compile, install, and load the current policy into the current running kernel.
make relabel Relabels the filesystems using the file contexts in the policy.

assert.te

The rules in this file will be checked in the final phase of compilation. If a permission granted in the policy matches one of these assertions, the policy compiler will reject the policy. This can aid in ensuring certain accesses are never allowed.

attrib.te

A type attribute can be used to identify a set of types with a similar property. Each type can have any number of attributes, and each attribute can be associated with any number of types. Attributes are explicitly declared in this file, and can then be associated with particular types in type declarations. Attribute names can then be used throughout the configuration to express the set of types that are associated with the attribute.

constraints

This file defines additional constraints on permissions in the form of expressions that must be satisfied in order for specified permissions to be granted. These constraints are used to further refine the type enforcement tables and the role allow rules. Typically, these constraints are used to restrict changes in user identity or role to certain domains.

domains/

This directory contains the type enforcement rules. This directory contains the files admin.te, staff.te, and user.te, which contain the access vectors for the sysadm_r, staff_r, and user_r roles. The program/ directory consists of all of the active policies for various programs and daemons. The misc/ directory contains all other policy files.

file_contexts/

This directory contains the files that describe the security contexts for all files on persistent filesystems. It contains the file types.fc which has all of the security contexts for the general system. The directory program/ contains the security contexts for the daemons in the domains/program/ directory. These are one-to-one mapped; for example, the domains/program/syslogd.te policy file corresponds to the file_contexts/program/syslogd.fc security contexts file.

flask/

This directory contains contains configuration files independent of the policy. These files contain definitions corresponding to definitions in the kernel headers. These files should not be modified.

fs_use

This file describes the labelling behavior for files on various filesystem types. For example, ext3 uses persistent labelling, while tmpfs uses transitional security IDs. In general, this file should not need to be modified.

genfs_contexts

This file contains the security contexts for files in a filesystem that do not support persistent file labels, such as /proc.

initial_sid_contexts

This file contains the initial context for each security ID. In general, this file should not need to be modified.

macros/

This directory contains the m4 macros used to ease creation and maintenance of the policy. It contains the macro file admin_macros.te for describing administration domains, such as sysadm_t. The user_macros.te contains macros used in user domains such as user_t and staff_t. The global_macros.te contains macros used throughout the entire policy.

mls

This file contains the configuration for SELinux multi-level security. Multi-level Security is experimental, and is not supported by Gentoo.

net_contexts

This file defines the security contexts of network objects such as ports, interfaces, and nodes. This will need to be modified if daemons run on nonstandard ports.

rbac

In the past this file was a centralized place for declaring roles. The role declarations have since since been divided up into TE files. This file now only has the rule for allowing a role change from the sysadm_r role to the system_r role.

tmp/

This directory is used for holding intermediate files when compiling the policy. It can be safely removed, if needed.

tunable.te

This is the main configuration file of the policy.

types/

This directory contains files for declaring general types of the system which do not appear in the individual program policies.

users

This file describes the SELinux identities, and the roles they can enter.

1.f. SELinux Policy Files (2006.1+)

The SELinux policy source files are no longer installed onto the system. In the /usr/share/selinux/{strict,targeted} directory there are a collection of policy packages and headers for building local modules. The policy files are processed by m4, and then the policy compiler checkmodule verifies that there are no syntactic errors, and a policy module is created. Then a policy package is created with with the semodule_package program, using the policy module and the module file contexts. The policy packaged then can be loaded into a running SELinux kernel by inserting it into the module store.

*.pp

Policy packages for this policy. These must be inserted into the module store so they can be loaded into the policy. Inside the package there is a loadable policy module, and optionally a file context file.

include/

Policy headers for this policy.

1.g. Binary Policy Versions

When compiling the policy, the resultant binary policy is versioned. The first version that was merged into 2.6 was version 15. The version number is only incremented generally when new features are added that require changes to the structure of the compiled policy. For example, in 2.6.5, conditional policy extensions were added. This required the policy version to be incremented to version 16.

What Policy Version Does My Kernel Use?

The policy version of a running kernel can be determined by executing sestatus or policyvers. Current kernels can load the previous version policy for compatibility. For example a version 17 kernel can also load a version 16 policy. However, this compatibility code may be removed in the future.

Note: The policy management infrastructure (libsemanage) will automatically create and use the correct version policies. No extra steps need be taken. (2006.1+)

Compiling the Right Version Policy (pre 2006.1)

The only adjustment needed is in the policy Makefile. There is a line near the top that looks like this:

Code Listing 4: Makefile contents

POLICYCOMPAT = -c 15

Normally, checkpolicy will create a policy for the current version. The policy versions that checkpolicy can create can be determined by running checkpolicy -V. With the above option uncommented, a compatibility policy can be created. The above statement will create a version 15 policy; it can be changed to 16.

Policy Versions

The following table contains the policy versions in 2.6 kernels.

Version Description Kernel Versions
12 "Old API" SELinux (deprecated).
15 "New API" SELinux merged into 2.6. 2.6.0 - 2.6.4
16 Conditional policy extensions added. 2.6.5
17 IPV6 support added. 2.6.6 - 2.6.7
18 Fine-grained netlink socket support added. 2.6.8 - 2.6.11
19 Enhanced multi-level security. 2.6.12 - 2.6.13
20 Access vector table size optimizations. 2.6.14 - 2.6.18
21 Object classes in range transitions. 2.6.19 - current

1.h. Conditional Policy Extensions

The conditional policy extensions allow the enabling and disabling of policy rules at runtime, without loading a modified policy. Using policy booleans and expressions, policy rules can be conditionally applied.

Determine Boolean Values

The status of policy booleans in the current running policy can be determined two ways. The first is by using sestatus.

Code Listing 5: Example sestatus output

# sestatus
SELinux status:         enabled
SELinuxfs mount:        /selinux
Current mode:           enforcing
Policy version:         17
 
Policy booleans:
user_ping               inactive

The second is getsebool which is a simple tool that displays the status of policy booleans, and if a value change is pending.

Code Listing 6: Example getsebool command

# getsebool -a
user_ping --> active: 0 pending: 0

Changing Boolean Values

The value of a boolean can be toggled by using the togglesebool command. Multiple booleans can be specified on the command line. The new value of the boolean will be displayed.

Code Listing 7: Example togglesebool command

# togglesebool user_ping
user_ping: active

The value of a boolean can be set specifically by using the setsebool command.

Code Listing 8: Example setsebool command

# setsebool user_ping 0

To set the value of a boolean, and make it the devault value, use the -P option. (2006.1+)

Code Listing 9: Change default value (2006.1+)

# setsebool -P user_ping 1

1.i. Policy Kernel Messages

While a system is running, a program or user may attempt to do something that violates the security policy. If the system is enforcing the policy, the access will be denied, and there will be a message in the kernel log. If the system is not enforcing (permissive mode), the access will be allowed, but there will still be a kernel message.

AVC Messages

Most kernel messages from SELinux come from the access vector cache (AVC). Understanding denials is important to understand if an attack is happening, or if the program is requiring unexpected accesses. An example denial may look like this:

Code Listing 10: Example AVC Message

avc:  denied  { read write } for  pid=3392 exe=/bin/mount dev=03:03 ino=65554
scontext=pebenito:sysadm_r:mount_t tcontext=system_u:object_r:tmp_t tclass=file

While most AVC messages are denials, occasionally there might be an audit message for an access that was granted:

Code Listing 11: Example AVC Message 2

avc:  granted  { load_policy } for  pid=3385 exe=/usr/sbin/load_policy
scontext=pebenito:sysadm_r:load_policy_t tcontext=system_u:object_r:security_t tclass=security

In this case, the ability to load the policy was granted. This is a critical security event, and thus is always audited. Another event that is always audited is switching between enforcing and permissive modes.

SELinux will supress logging of denials if many are received in a short amount of time. However, This does not always imply there is an attack in progress. A program may be doing something that could cause many denials in a short time, such as doing a stat() on device nodes in /dev. To protect from filling up the system logs, SELinux has rate limiting for its messages:

Code Listing 12: Example AVC Message 3

AVC: 12 messages suppressed.

The policy would have to be modified to not audit these accesses if they are normal program behavior, but still need to be denied.

Other kernel messages

Code Listing 13: inode_doinit_with_dentry

inode_doinit_with_dentry:  context_to_sid(system_u:object_r:bar_t) returned 22 for dev=hda3 ino=517610

This means that the file on /dev/hda3 with inode number 517610 has the context system_u:object_r:bar_t, which is invalid. Objects with an invalid context are treated as if they had the system_u:object_r:unlabeled_t context.

1.j. Dissecting a Denial

Denials contain varying amounts of information, depending on the access type.

Code Listing 14: Example Denials

avc:  denied  { lock } for  pid=28341 exe=/sbin/agetty path=/var/log/wtmp dev=03:03 ino=475406
scontext=system_u:system_r:getty_t tcontext=system_u:object_r:var_log_t tclass=file

avc:  denied  { create } for  pid=20909 exe=/bin/ls scontext=pebenito:sysadm_r:mkinitrd_t
tcontext=pebenito:sysadm_r:mkinitrd_t tclass=unix_stream_socket

avc:  denied  { setuid } for  pid=3170 exe=/usr/bin/ntpd capability=7
scontext=system_u:system_r:ntpd_t tcontext=system_u:system_r:ntpd_t tclass=capability

The most common denial relates to access of files. For better understanding, the first denial message will be broken down:

Component Description
avc: denied SELinux has denied this access.
{ lock } The attempted access is a lock.
pid=28341 The process ID performing this access is 28341.
exec=/sbin/agetty The full path and name of the process's executable is /sbin/agetty.
path=/var/log/wtmp The path and name of the target object is /var/log/wtmp. Note: a complete path is not always available.
dev=03:03 The target object resides on device 03:03 (major:minor number). On 2.6 kernels this may resolve to a name, hda3 in this example.
ino=475406 The inode number of the target object is 475406.
scontext=system_u:system_r:getty_t The context of the program is system_u:system_r:getty_t.
tcontext=system_u:object_r:var_log_t The context of the target object is system_u:object_r:var_log_t.
tclass=file The target object is a normal file.

Not all AVC messages will have all of these fields, as shown in the other two denials. The fields vary depending on the target object's class. However, the most important fields: access type, source and target contexts, and the target object's class will always be in an AVC message.

Understanding the Denial

Denials can be very confusing since they can be triggered for several reasons. The key to understanding what is happening is to know the behavior of the program, and to correctly interpret the denial message. The target is not limited to files; it could also be related to network sockets, interprocess communications, or others.

In the above example, the agetty is denied locking of a file. The file's type is var_log_t, therefore it is implied that the target file is in /var/log. With the extra information from the path= field in the denial message, it is confirmed to be the file /var/log/wtmp. If path information was unavailable, this could be further confirmed by searching for the inode. Wtmp is a file that has information about users currently logged in, and agetty handles logins on ttys. It can be concluded that this is an expected access of agetty, for updating wtmp. However, why is this access being denied? Is there a flaw in the policy by not allowing agetty to update wtmp? It turns out that wtmp has the incorrect context. It should be system_u:object_r:wtmp_t, rather than system_u:object_r:var_log_t.

If this access was not understood, an administrator might mistakenly allow getty_t read/write access to var_log_t files, which would be incorrect, since agetty only needs to modify /var/log/wtmp. This underscores how critical keeping file contexts consistent is.

1.k. References

U.S. National Security Agency, SELinux Policy README