Notes on SElinux: initial concepts

Here are some of my notes on using SElinux (Security Enhanced linux) in fedora. By default in fedora (including and above core 4) SElinux is installed and a targeted policy is active. The targeted policy is where the default (non-SElinux) linux security is followed, but a few targeted programs have limits imposed on what they can do (I'll talk more about the targeted policy in later notes). There is a lot of terminology in the SElinux world, and this can make some of the quite intuitive concepts much less intuitive. SElinux can be a very useful security tool, and it is worth looking at what it can do.


SElinux uses a Mandatory Access Control (MAC) mechanism that is designed to only allow a program the access to files and resources that it needs to do its job. Compare this with the traditional linux/unix approach of Discretionary Access Control (DAC) in which a program has all the privileges and access of the user that ran it. To see the difference consider the example:

Suppose I have a process running that fetches my email from a email server and dumps it into a file. If this program has a security flaw and can be compromised, under the traditional linux security the person who compromised it potentially has all the access and abilities of the user who ran that program (i.e. me!). Under SElinux, this process could be confined to only being able to read its configuration file and write the email messages to a specific destination file. A compromise under this situation would only allow the person the ability to read the configuration file and append junk to the email file.

The terms subject and object are often used to talk about the division between the process and the files and resources it uses. A process will usually be the subject, but there can be many types of objects. To name just a few, objects include; files, directories, network connections, system devices:

Subjects and objects

SElinux sits along side traditional linux security (DAC). For example, if you don't have read access to some file then the traditional linux DAC system prevents access and SElinux won't even be consulted. When SElinux is used to make a security decision it simply compares "the process needing to do something" with "the object it wants to do it with" and after consulting a large matrix based on lots of rules it then comes up with a set of permissions or actions which limit what the process is allowed to do with the object. That is the essence of SElinux.

Of course, how this takes place is a little more involved (the devil is in the details). The key to SElinux is the security context. All processes have a security context and all objects, like files, devices etc., also have a security context. Note, to distinguish between process and object contexts, contexts for processes are called domains and contexts for objects are called "file contexts", but they are essentially the same. Generally, contexts are stored with the subject or object (in the kernel for processes and as extended file attributes for most objects). A context is made up from a number of parts (which we will look at below), but the key one is called a type. Basically, when a process is compared with an object, it is their types that are compared and used to lookup what that process is allowed to do with that object. SElinux is based on the Type Enforcement™ security model.

In SElinux there are two types of security decisions to be made:

  1. Transition decisions - when a new process is started or new object created, what are the security contexts they are given?
  2. Access decisions - what access does a process have to an object (or even another process)?

As introduced above, both of these decisions are made on the basis of the contexts of the subjects and objects involved. The security context is composed from 3 or 4 parts, each part separated by a colon ":". A typical context may look like:


In this example context, there are 3 parts. The parts that make up a context are:

  • Users The first component represents a user or "identity". This is not necessarily a real user, rather a definition of what types of things this identity can do. Real users are mapped to these SElinux identities and it is possible to create a specific SElinux identity that maps directly to a single linux user (this is in fact done for root). Basically, an identity is a collection of roles (see below). By convention names of identities end in "_u" except where there is a one to one mapping (e.g. "root").
  • Roles The second component is important for processes (all files have the filler role of object_r). Roles are used to group what sort of things the process can do when it has that role. In particular, it is a way of grouping security types (below). By convention names of roles end in "_r".
  • Types This third component is the key to getting to grips with SElinux, as I mentioned above. Ultimately, things can be reduced to what process types have access to what object/resource types. By convention names of types end in "_t".
  • MLS SElinux has been extended to be able to implement Multilevel Security (MLS) policies. This fourth component is used when this type of policy is in operation. I will add more notes on MLS and MCS later.

Lets consider the first type of security decision - the transition decision. Suppose you want to run a web browser. You type in your bash shell the command "firefox" (or click the firefox icon if your a "point and click" type of person). SElinux must make the decision of what security context the browser process gets when it runs. This can be important, as your browser could be isolated so that it can only do a limited number of things (limiting what malicious java/javascript can do, for example). SElinux chooses the context for the new process based on the context of the running process from which the new process was started (bash, or the desktop session) and the context of the program file (the firefox binary). The decision is made by taking these two context types and looking up a large matrix based on a set of rules to decide on the new type for your browser process.

Similarly, a transition decision for an object (e.g. the creation of a new file) is also based on two contexts; the context of the process creating the new object, and the context of a related object (e.g. the parent directory).

The access decision is probably more intuitive. The decision is simply whether a process is given access to an object. Like the transition decision, there are two contexts involved in making this decision; the process context and the object context. In addition to these, there is also information about the object involved, such as what sort of things can be done with the type of object - this information is called the object class. For each class of object there is a list of permissions a process can be granted for this type of object. For example, in the "file" object class there are 20 "permissions" or types of things a process can do (including; read, get attributes, append, set attributes, write, etc.). Compare this with traditional linux security (DAC) where the possibilities are divided into three (read, write and execute). SElinux allows much more fine grained control over what processes can do.

When a process is trying to interact with an object, the "type" from the context of the process and the "type" from the object context are looked up in a large matrix that was built from the policy rules. A list is generated that contains a YES or NO for every permission in the object class belonging to this object. This list is called an access vector and it specifies what this process is and is not allowed to do with this object. This access vector is then used to grant or deny access:

Type Enforcement

In SElinux there are three possibilities for the outcome of decisions:

  • allowed
  • audit allow - allow but log that this took place
  • audit deny - deny and log that this took place

Roles and Users

We have introduced above the main engine of SElinux, that of Type Enforcement. But types are only one component of the context. There are also user and role components.

SElinux maintains its own user identities onto which normal linux user identities are mapped. In SElinux it is possible to build identities with a much finer grained set of abilities. However, in the targeted policy of fedora, all users, except the super user, are mapped to a single SElinux identity leaving the traditional linux user/security model dominant when it comes to user identities.

To simplify the management of the Type Enforcement security model, SElinux has an additional layer called Role Based Access Control (RBAC). A role provides a higher level of abstraction from individual types and allows convenient groupings of all the files and programs involved in some high-level task. A user can be authorised to act in certain roles, where these roles intuitively encompass all the types and permissions needed for the specific job. In the default targeted policy of fedora, this abstraction is not really used and all processes run in the system_r role.

Roles make more sense for processes rather than objects (i.e. a process takes on a role to do a task). As SElinux has the same form of security contexts for objects as for processes, most objects are simply given the role called object_r.

Seeing is believing

The ls command has a number of extended options for SElinux (see the man page for ls). The -Z option is a quick way of looking at the security context that belongs to files:

#ls -Z /usr/bin/bzip2 -rwxr-xr-x root root system_u:object_r:bin_t /usr/bin/bzip2

Here we see that the executable bzip2 file has a security context with an identity of system_u, the standard file role of object_r and the type of bin_t.

There is a similar -Z option for the ps command that shows the security context for processes:

#ps auxZ | grep bzip2 user_u:system_r:unconfined_t domenico ... bzip2 presto.ogg

Here the linux user "domenico" is running the bzip2 command, and the process has the security context identity user_u which is the default identity for non-privileged people, the role of system_r and the type of unconfined_t.