SELinux

Introduction

Security Enhanced Linux is NSA's open source version of a better Linux. The work on SELinux has taken many years (some aspects of the implementation look a bit old-style) but it is an interesting approach towards better host based security.

The following is a discussion of the book on SELinux by Bill Mccarty and concentrates on the concepts behind SELinux and the specific implementation of it.

The root of the problem: Discretionary access control

In an operating system using discretionary access control (and most modern small- to midrange systems do) a user starts a program and transfers all her rights to this program. On the resources they own, users can perform arbitrary changes of security settings.

In those systems the identity used to run a program or a service is therefore extremely important. There is no concept of restricting authority because it is unclear what a program might do with a users rights.

In other words: the fundamental principle of security, the policy of least authority (or privilege) is violated by those systems and they provide a playground for viruses and trojan horses. It is important to understand that this is a built-in feature of such systems.

Attacks on discretionary systems often follow a stair pattern: after gaining entry into a program running with a relatively powerless identity the attacker works her way up by then attacking other programs. Why can she do this? Because the first program that she has taken over is not limited in its actions. It is only limited in with respect to the authority it can use with those actions.

Of course, network available services running with high privileges (identity) or complex setuid programs are even more dangerous.

Ways to control authority.

One way to prevent a program from doing wrong would be to restrict the authority it gets from its identity. If a user would only hand over a partial set of her rights to the program the program itself could do less harm. Still, it could use the existing rights for illegal actions. Capability based systems use the approach of transfering only the rights needed for an operation to a program. But to prevent the abuse of even those rights they typically follow a programming style that tries to restrict resource access to objects which the program got from the user directly - so called call inversion pattern.

Another way to prevent right abuse by programs would be to restrict the actions of the program. Say by defining a policy which describes which resources a program can access in which way. This puts a program into a sandbox like structure which it cannot leave no matter how powerful the users identity otherwise is. SELinux follows this approach.

All access control needs to create restrictions and by doing so faces the problem of the granularity of restrictions. Restricting access on class base (e.g. allow socket access) is different from restricting access on instance level (port 80 or socket number 4711). While we would certainly always prefer instance level based restrictions we will not be able to do so in all cases due to the complexity of configuration.

SELinux core concepts

  1. Programs execute in sandboxes called domains

  2. Resources (objects) live in protection domains called types

  3. Policies describe the ways those resources can be used through access vectors and transition rules

  4. Each process or object has an associated security descriptor which consists of identity, role and domain.

  5. At runtime when a process wants access to an object the security descriptors of both are matched and compared and access is only allowed when the policies allow it.

  6. All access rules are kept in policy files and there are tens of thousands of access rules.

  7. Roles define which domains a user can enter. They do not provide access by themselves.

  8. A user can have several roles but only one active role at any time. No role merging is done. The system itself knows only four roles (system, staff, sysadm, user) and few installations add more roles.

User roles and transitions

A surprising side-effect of protection domains described by security policies shows when the "su" utility is used: No more extra login with the root credentials is needed. Why? Because a) the users identity is already known - why should one change IDENTITY to perform a different function? This not only violates the principle of accountability (always know WHO is doing something) but also makes the root credentials less secure. In traditional systems the root credentials are needed because the system does not know that user X has the right to run "su". And b) on a SELinux system a policy exists that allows user X the transition to the role "sysadm" - which is known by the system.

There is a tiny issue with not using live credentials in this case: what if the user left the desktop and somebody else is typing in "su"? But even in this case we do not want the root credentials being entered. All we want is a liveness check on the users identity and we would then ask her to repeat initial authentication.

Another intersting case it the question of the "system" role which is reserved for running system services. Some systems allow sysadm or staff users to transition to the system role automatically so they can start system services automatically.

Roles and Granularity of Protection

Another surprise in SELinux is the few number of roles that exist. Systems based on discretionary access control typically need to create more and more roles to distinguish access rights. Once this gets too cumbersome for users those systems perform role merging - they build the final set of access rights by merging the rights from all roles a user has.

When this merging becomes a pain users are put into various group thereby inheriting various rights and roles.

Associating the users with the right roles and groups is extremely critical because a programs rights to perform actions is directly related to the rights resulting from role and group membership.

Instance level access control is typically provided directly by code.

SELinux much more resembles capability or label based systems with respect to roles: They (and a users identity) are much less important. Compute objects are real principals and by restricting their actions directly the question of a users identity are much less critical. (While still being important for punishment etc.)

SELinux Domains and Types

Domains and types form sandboxes for programs and objects. Creation, actions and transitions are important lifecycle steps for domains/types. Unfortunately the difference between both concepts are not clear. SELinux seems to make almost no difference at all.

A user enters a domain because the domain has an associated policy that lets users of a certain role enter the domain. In most cases entry happens through a special program (entry point) in this domain. From then on the domain policy controls actions and transitions.

In case objects are accessed or created, the object creation process is typically governed by the policies of the parent object (directory) and the domain policies.

Security Descriptors and IDs (SIDs)

A security descriptor is a triple consisting of "identity:role:type". Every process and every object (e.g. file) has an associated SID. File related SIDs are stored in extra areas of the filesystem which needs to be formatted at the beginning of an SELinux system install.

SELinx Objects and access methods

SELinux offers many different object types and a long vector of different access methods. Nowadays a more object oriented modelling approach would be used to describe the relations and properties but here SELinux shows a bit of its age.

SELinux Implementation of a policy

  1. General definitions

  2. Type enforcement and file context definitions

  3. Macros and processing, compilation

General Definitions

SELinux policies consist of a large number of files. Many of them contain policy parts which need no adjustment, e.g. basic rules, macro definitions, object classes and methods etc. Classes are e.g. blk_file (block device file), netif (network interface), file etc. There are probably more than onehundred possible operations (of course not for every class). Typical operations are getattr, create, write, unmount etc.

A special element are so called attributes which are collections of types and act as container definitions. SELinux Admins can introduce new attributes or change existing ones.

All in all the mechanism reminds one at the (in)famous imake program configuration system which required intimate knowledge on every installation.

Type Enforcement and File Context Definitions

File contexts define the security contexts of resources belonging to a domain. A program running within a domain (sandbox) is restricted to use those resources and the resources are at the same time protected from the program (or other programs)

from ping.fc:
/bin/ping/* -- system_u:object_r:ping_exec_t 

this line allows only ping_exec_t domain programs access to the files in the ping directory.

from ping.te:
role sysadm_r types ping_t;
allow ping_t etc_t:file {getattr read}

This line allows programs in ping_t domain to access file objects in the etc_t domain through the methods getattr and read. (Examples taken from Bill Mccarty)

Macros and Processing, Compilation

In good old unix style all the files that make up a system policy are concatenated and processed through the macro processor M4. This has the unfortunate effect that the individual policy files do not show the true content. The resulting large policy file is then processed, C code generated and the resulting binary policy is loaded into the kernel.

A change in police - e.g. adding a user - requires the whole process to be repeated.

Adding a new program

Adding a new program can mean creating a new domain. But even if this is not the case the process needed to get the new program running is quite interesting. It works basically like this: The SELinux security log is used to find all the "denied" access the program was not allowed to perform due to security policy reasons.

Step by step "allow" statements are added to the policy database (files) to give the program more rights. Sometimes a new domain should be created if the addition of a program to an existing domain would cause to many access privileges to be granted.

The whole process is not only cumbersome: it also shows an interesting software problem. Usually we are glad about interfaces which hide implementation details. Just think about distributed remote calls where a client only gets an interface and never knows what the server side will call to perform the request.

But with respect to security we need to know what a certain program will do during a request. Which resources will be accessed etc. Unfortunately this information is today not available once a program is ready for installation. But a mandatory access control system like SELinux needs exactly this type of information - and it should not be necessary to RUN a program to find the access right problems.

Conclusion

SELinux is not really hard to configure. It is just a lot of work and the current software development process does not really help here as we have seen. According to the book by Bill Mccarty SELinus also has many more concepts (capabilities, Network object protection etc.) which are not yet implemented everywhere.

Bill Mccarty's book btw. is recommended reading if you want to get started with SELinux. It does a good job to explain the concepts and I especially liked the chapters where a sample policy was developed. You will have to read it a couple of times though because SELinux is simply quite large and complex.

Does SELinux improve security? In a way yes: Domains certainly restrict program behavior. The question is: will ordinary desktop PCs use it one day? And here I doubt that the usability in SELinux is good enough to deal with average users. So I believe it will be used in special environments (firewalls, tcb machines etc.) but it wont show up as a solution for the desktop.