This article is part of the TechXchange: Cybersecurity
The profound growth in Internet-connected devices has heightened the need for secure systems, beyond the traditional bounds of enterprise IT gateways and servers. Embedded devices from wearables to automobiles, consumer devices, factories, and much more are being connected to the Internet at astounding rates. Billions of consumer and industrial devices are now connected, with trillions more to come.
Recent high-profile attacks on major corporate and government computer systems have heightened the public awareness of computer system security. These highly publicized cyber attacks compromised the personal information of millions of consumers, resulting in the reissue of millions of credit cards whose numbers had been stolen by the cyber criminals behind these attacks. Software vulnerabilities with names like “Heartbleed” and “Shellshock” became familiar terms even outside of computer circles. For these and other reasons, building secure Internet connected devices has never been more important.
SELinux Background
SELinux is a framework and set of tools originally developed by the United States NSA that is used to harden Linux systems against potential threats. These threats can include deliberate attacks, misuse, and software vulnerabilities including viruses and malware. SELinux was originally integrated into the mainline Linux kernel over a decade ago, in the early days of the Linux 2.6 kernel. While no framework can protect against certain software bugs, SELinux has the potential to make a system much more robust and far less vulnerable to external threats including viruses and malware. SELinux is an important tool in the arsenal of security analysts, and is used as a key component of an overall system security strategy.
Traditional UNIX and current Linux systems rely on a security model called Discretionary Access Control. In the DAC model, access to system resources is based on the identity of the (user) processes and to the groups to which that user belongs. It is characterized by a set of users and groups, to which each process and file system object belongs, together with file system attributes that include read, write and execute in three categories for every file system object. The categories are user, group, and other.
This file type includes high resolution graphics and schematics when applicable.
For example, a file called logo.png might belong to user chris and group tools. The file’s attributes could be user:read-write, group:read, other:none. This configuration would allow user “chris” to have read-write access to the file, any user in group “tools” would have read access, while any other non-root users on the system not in group “Tools” would be denied access. This is the traditional DAC access model.
Figure 1 illustrates these concepts in simplified form. In the figure we define two users and three file system objects. User Sue belongs to groups “finance” and “mktg”, while user Bob belongs to the “admin” group. File A is owned by Sue and is in the finance group. File B is owned by the root user, and is in the admin group. File C is owned by Bob and is in the mktg group.
Figure 1 depicts the access rights for each user on each file, together with the attributes for each file. Notice that each user has read/write access to files that they respectively own, but only Bob in the admin group has any access to the file owned by root, because he is a member of the admin group, and File B is also.
By contrast, SELinux enabled systems are built around a security model called Mandatory Access Control. MAC-based systems extend the security architecture beyond users, groups and file permissions. SELinux uses the Linux Security Modules (LSM) framework of the Linux kernel to extend the security capabilities of stock Linux systems. The fundamental model for SELinux MAC involves a subject (process), attempting to perform an action (read, write, allocate memory, etc) on an object (system resource). In security circles, this architecture is often referred to as a subject-access-object model.
Discretionary and mandatory access control systems differ in a fundamental way. The best way to understand the difference is the following: In a simple Linux system using only the usual DAC access mechanisms, a user can make his own decisions and specify the access permissions for the resources that he owns. In other words, the access permissions for his own resources are at his own discretion. In a MAC system, access permissions for every resource on the system, independent of ownership, is centrally controlled by a system-wide security policy. MAC security policy overlays DAC, but does not eliminate it. That is, assuming the global SELinux policy allows user Sue read access file A, Sue still must have traditional DAC read permissions to read file A. In SELinux, all actions by subjects on objects must be explicitly granted by the SELinux policy.
This explanation might sound complicated but the fundamental concepts are not difficult. Let’s assume that a subject (often a process acting on behalf of a user) wishes to open a file on a specific file system. A rule must be created that instructs SELinux to allow that specific process to exercise open and read/write permissions for that particular file. Of course, this example is overly simplistic, but describes the conceptual behavior.
âSELinux uses a global set of labels that must first be attached to each subject and object in the system. When a Linux system is initially configured for SELinux, or when the SELinux policy is changed, a special system process traverses the entire file system and applies (or relabels, as it’s called in the SELinux vocabulary) every file in the file system according to templates supplied with the SELinux framework. SELinux prevents access to any system resource that is not labeled. For example, if a USB drive is inserted on an SELinux system in enforcing mode, the files on that USB drive are unreadable by any user on the system, including the root user, unless the system policy has specific rules to allow such access.
A central database contains a set of rules that explicitly defines the access rights to a specified object for any given action by a subject. This set of rules associates the labels from subjects and objects to grant access rights based on these labels. Collectively the set of access rules is referred to as the system policy. Several policies can exist on the same system. A global SELinux configuration file selects which policy is to be used during the uptime of a Linux system. Many Linux distributions support several policies. Some embedded Linux distributions ship with a minimum policy, which provides an initial framework that allows the embedded developer complete control and customization of the system’s behavior.
SELinux is architected such that the mechanism for governing access control is entirely separate from the policy that is used to enforce a given security model. The kernel is responsible solely for enforcement control, and makes no policy decisions as to whether the requested action is allowable or not. A policy rule either allows a particular action by a subject on an object, or it does not. The kernel knows nothing of this policy, and acts only to allow or deny actions based on the rules generated by the policy. Furthermore, when SELinux is set to enforcing mode, access is denied by default unless a rule specifically grants access to a given resource by a specific subject.
Enabling SELinux
SELinux must be enabled on a Linux system before it can be used. The Linux kernel must be compiled with support for the SELinux security infrastructure. Several kernel configuration parameters enable SELinux and set this as the default security model. See CONFIG_SECURITY_SELINUX* in the Linux kernel configuration menu for details. Detailed information on compiling the kernel with these configuration parameters is beyond the scope of this article.
Many Linux distributions, including embedded Linux distributions come with options to easily enable SELinux. If you are working with one of these commercial Linux distributions, you should find documentation on how to enable the kernel for SELinux within the documentation that accompanies your distribution.
Once the kernel has been compiled for SELinux support it must be enabled. SELinux has three modes.
Disabled–The infrastructure is present and operational, but has been effectively turned off.
Permissive–SELinux is enabled and fully functional, but by default allows all actions. Actions are logged for use in creating custom rules.
Enforcing–SELinux is working and preventing unauthorized actions.
When SELinux is running in disabled mode, it does nothing. SELinux policy rules are not enforced, and audit logging is completely disabled. Permissive mode is useful for development and debug of SELinux policy. In Permissive mode, SELinux allows all accesses, but logs each access using a syntax that can easily be converted into a rule or set of rules that will allow the access. An SELinux utility called audit2allow can actually create a rule from a log entry, making system configuration much easier for those new to SELinux. Enforcing mode should be obvious – SELinux is enabled and actively protecting the system resources from unauthorized access outside of those allowed by the policy.
By default, when SELinux has been enabled in the kernel, it will be enabled after system boot. A global configuration file determines its operational mode at boot time. This file has different names and locations depending on the Linux distribution in use, but a common path for most distributions is on /etc/selinux/config. This global configuration file selects two runtime parameters for SELinux. The first is the mode enumerated in the list above. The second is the policy to use by default. The format of the configuration file is quite simple:
SELINUX=enforcing
SELINUXTYPE=default
These entries in the SELinux global configuration file instruct SELinux to enter the enforcing mode and use the policy called default. Many Linux distributions ship with several example policies, or have them available for download. Others may include standard and mls, or multi-level security. It is important to understand that these are template policies, provided for the users convenience, and are almost never used unmodified in a production system. It is up to the system designer or administrator to modify and extend these policies for a specific product application.
Policy names can vary depending on the Linux distribution in use. Some common policy names and their descriptions follows:
minimum–Simple entry-level policy that provides for a small number of protected domains for applications such as http server, ftp server, etc. Most processes in a minimal policy will run unconstrained.
standard–Typical policy often used for desktop applications.
mls–Supports a multi-level, heirarchical policy for highly critical systems such as those used in military and government applications.
refpolicy–This is the SELinux reference policy published on github that can be used for a variety of systems and makes a good starting point for building a comprehensive customized policy, and in many distributions, is the base for the standard policy. It has its roots in the original NSA example policy.
One can easily discover whether SELinux is enabled and operational. Simply use the getenforce command from the Linux command line:
root@pluto:# getenforce
Enforcing
This trivial command reports that SELinux has been configured and enabled with the enforcing mode as described above. Another useful command is used to examine the state of an SELinux-enabled system. sestatus issued without parameters, will list some pertinent information about the SELinux installation, including its current status (the same information as reported by the getenforce command as shown above) as well as the current mode, policy name and version and other relevant data.
root@pluto:~# sestatus
SELinux status: enabled
SELinuxfs mount: /sys/fs/selinux
SELinux root directory: /etc/selinux
Loaded policy name: minimum
Current mode: permissive
Mode from config file: enforcing
Policy MLS status: enabled
Policy deny_unknown status: allowed
Max kernel policy version: 28
SELinux Security Context
In a traditional Linux system, users are typically associated with humans that interact with the system. In SELinux, a user is not generally associated with a specific human (user account) as it often is in traditional Linux systems, but more often represents a class of users. For example, a typical SELinux embedded system configured with a minimal policy might have 6 users by default: sysadmin, system, root, staff, user and unconfined. In typical SELinux syntax, these user classes would be named system_u, user_u, etc. However, there is nothing in SELinux that enforces this naming style – it has become convention in the design and management of SELinux policy to decorate the label with an underscore and letter representing one of user (u), role (r) or type (t).
A role is used in SELinux systems to control which domains a user is allowed to occupy. Roles in a typical embedded Linux system configured with a minimal policy might include staff_r, user_r, object_r, sysadm_r, system_r and unconfined_r. Notice again the convention of decorating the role name with an underscore ‘r’.
In SELinux, all subjects and objects are associated with a type which taken together governs the access permissions for specific users. The combination of user:role:type is called the security context. (Additional fields called sensitivity and category exist to support multi-level security policies, but these are often unused where MLS is not required.) Figure 4 illustrates the format of an SELinux context. Notice that the Sensitivity and Category fields are in parenthesis, indicating that they are optional and often unused or set to default values.
In SELinux-enabled systems, common Linux utilities have been enhanced to show the security context as an aid to troubleshooting access permissions and designing new security modules for custom applications. For example, most relevant utilities will honor the –Z switch to show SELinux security context output. For example, using the ls command with the –Z switch yields this:
root@pluto:~# ls -Z /lib | head -n 5
system_u:object_r:lib_t:s0 depmod.d
system_u:object_r:lib_t:s0 firmware
system_u:object_r:lib_t:s0 ld-linux-armhf.so.3
system_u:object_r:lib_t:s0 ld-linux.so.3
system_u:object_r:lib_t:s0 libacl.so.1
These objects found in the /lib directory have a user of system_u, role of object_r, and type of lib_t.
In order to implement security context, SELinux applies labels to every file system object and controlled resource in the system. SELinux enabled systems perform this file system labeling upon first boot, or when the policy is changed. You can also manually relabel the file system. When you first enable an SELinux system, you may notice a reboot directly after startup while SELinux performs the file system relabeling operation. When a system is enabled with SELinux, the supported file systems make use of extended attributes designed to hold the security context information.
SELinux Policy Types
One of the criticisms of SELinux is that it is very complex and a custom security policy is very difficult to design, configure and manage. Indeed, the reference policies that come with most distributions have thousands of rules. The minimum policy used as the basis of this article, which originates from the Yocto Project contains just short of four thousand allow rules. SELinux running on a complex multi-user server might contain tens of thousands to even one hundred thousand or more allow rules.
If you were to examine the source code for an SELinux reference policy, it would resemble the source tree of a relatively complex software project. It has a build infrastructure, configuration files, and multiple subdirectories of policy source. The reference policy is built in a fashion similar to a complex software package. The source tree is configured, followed by a build step, and then a package step. Once built, the result (a set of binary policy objects) can be installed on a system as a reference policy. The reference policy is maintained as a source tree on github at github.com/TresysTechnology/refpolicy.
SELinux access rules are constructed based on a security context, consisting of the triplet user:role:type. In order for a process to access a system object, they must be in the same domain. Consider the domain as synonymous with the type field of the context. Access rules allow the process to transition to the domain of an object, while other rules allow the process to access specific resources based on user and sometimes role.
The typical approach to customizing a SELinux system is to add to a default policy in a modular fashion. SELinux supports the concept of a policy module to contain changes required for a specific application or set of applications.
The semodule utility is used to list, add, remove, enable, disable, or upgrade SELinux policy modules. In order to give a custom application permission to run on the system, a module can be added specifying the rules required for that application.
SELinux systems contain a search utility to view the configured rules. The sesearch utility provides the system developer with the ability to search through the policy for specific rules, or to print them all. The secon utility displays the security context for a specified object.
A typical SELinux rule might look like this:
allow user_t user_home_t:file { create read write unlink};
This example rule, taken from the excellent SELinux wiki at selinuxproject.org, allows any process labeled with type user_t to create, read, write or delete any files labeled with type user_home_t.
Summary
SELinux can be used as one element of an overall security architecture. When enabled, a global policy defines what operations a subject (usually a process) can perform on objects (usually files and other system resources). This is referred to as Mandatory Access Control. Simply stated, unless the policy explicitly states “program A is allowed to perform action X” then it will not be allowed. SELinux can partition applications or groups of applications to their own domain, effectively isolating them from the rest of the system. A properly designed security policy will significantly limit the damage in case a software vulnerability or malicious attacker gains access to an application.
It is important to understand that while many SELinux-enabled distributions come with default policies, these are virtually never used without modification in production systems. Some level of design, implementation and most importantly, validation is required before a system can be deployed confidently. While some may criticize SELinux as being difficult to master and configure, it is little different from learning any new programming language or operating system. A learning curve is to be expected—but the protection provided by SELinux for Internet connected devices far outweighs the development overhead.
Read more articles at the TechXchange: Cybersecurity
This file type includes high resolution graphics and schematics when applicable.