Access Control has been part of operating system security since its inception. It can be broadly defined as selective restriction to access a resource. For example, in Linux, this selection is done on the basis of users who may not be able to access files owned by each other which works on the basis of Discretionary Access Control (DAC). DAC is the basic level access control which relies on Linux permissions. Here, each file has a set of permissions for all users of the file. It allows the owner and the root user to change these permissions. The three available permissions are read, write and execute, which can be applied to 3 groups of users. The owner (of the file), the group (which the file belongs to) and others (all other users except for the owner and the members of the group). The access of these different users on the file is controlled by the permissions set on the file.

ls command with -l option outputs the permission string associated with a file. For example an example output to the command may look like:

The permission string representation for the file bar.csv is -rwxrwr–. These strings can be interpreted as triplets ignoring the first letter which is ‘d’ when the file (in the linux context) is a directory and a -’ otherwise.  The first triplet here belongs to the owner, the second one to the group and the third one to others. In this case the first triplet for the owner is rwx which means the owner has read, write and execute permissions. The second triplet is rw which means the group only has read and write permissions and the third triplet is rpointing to only the read permission for all other users. Here is the wiki link for more on DAC.

At first look DAC seems to be at the top of its game. But there are areas in access control that DAC cannot cover. For example, a mail client which can compose, read or delete emails can change the permission of a mail file to world readable which is strictly undesired.The mail file should only be allowed to be read by the owner. In this case there is no way to restrict the client (using DAC alone) from doing what it is not supposed to do. This is where the need for an additional layer of security comes in. This is provided by Mandatory access control or MAC.

MAC  is completely different and is not something that replaces DAC. MAC is one of the ways to enhance what is already offered by DAC. It allows the system to define which processes can access which files. Objects include anything that is maintained as files by Linux OS which includes directories, sockets, devices, etc.

MAC is not included in most of the linux distributions including Ubuntu. Android was the first Linux distribution to use MAC for commercial purpose in the form of SELinux which is just one of the many implementations of MAC. Other implementations include RSBACAppArmor, Oracle Label Security, etc. Discussing all the different types of MAC would be out of the scope of this article and thus the discussion would be limited to SELinux.

What is SELinux?

SELinux is an implementation of MAC and is based on type enforcement. SELinux works on the principle of default denial. That means of all the access available for a process or a user, only those that are explicitly specified are allowed and everything else is denied. Taking the earlier example of the mail client, MAC can be used to restrict the mail client from changing the permission of the file by simply NOT specifying that permission for the mail client (default deny, remember?). On the other hand it can be given permission to read or write the file. Such a fine grained control is not available in DAC.

In the context of SELinux, processes are referred to as subjects and files are referred to as objects. Object roles are another concept which acts as a filter to allow only certain type of subjects to access a particular object. In addition to role, every subject and object is assigned a type which uniquely identifies the subject or the object. The ls command with -Z option outputs a label for all the subjects (files) in the current directory that gives type and role information about the subjects. For objects (processes), ps command  with Z option would work in a similar way. These labels are called context in SELinux. Contexts are represented by labels of the format:

User refers to an SELinux user associated with the context. Each linux user has at least one SELinux user associated with it. ‘u’ is used if no user is associated with a particular context. Role refers to the SELinux role and type refers to SELinux type. ‘r’ is used if no role is associated with the context. The user, role and type of a context controls the access associated with it. Level is only used in multi layer security (MLS) systems which is again out of the scope of discussion of this article. The default value is ‘s0’.

For example, in an SELinux enforcing system, running ls -Z in the command line outputs something like:

 

Here both u:object_r:device:s0 and u:object_r:rootfs:s0 are labels representing the context for objects corresponding to the objects associated with dev and etc directories respectively. Similarly for processes ps -Z outputs:

Here u:r:init:s0 and u:r:kernel:s0 are the labels for init and kthreadd daemon processes respectively.

These labels are a way to implement rules in SELinux. In layman terms rules are like permissions which allow a subject to access an object. In SELinux these are called policies and are used by the developers for fine grained access control. The concept of policies, being a separate topic, will be discussed in a future article. For the purpose of this article consider policies as permission statements. For example

This can be broadly understood as – allow a particular subject to carry out operations that require the specified permissions on an object.

Now that the concept of SELinux is slowly becoming clear, an introduction to one of the implementations would make sense. For the purpose of this article we can take up the SELinux implementation used in Android.

Implementation in Android

Till Android 4.3, applications were isolated from each other using linux UIDs. That means every application ran as a separate user thus sandboxing them. Starting from Android 4.3 SELinux is used to further define the boundaries of the application sandbox. In the 5.0 Lollipop release, Android has moved to full enforcing mode.

There are 3 different modes SELinux can run in Android:

  1. Enforcing: SELinux policy is enforced. SELinux denies access based on SELinux policy rules.
  2. Permissive: SELinux policy is not enforced. SELinux does not deny access, but denials are logged for actions that would have been denied if running in enforcing mode.
  3. Disabled: SELinux is disabled. This mode is not of our interest as its not support in Android (The system goes into bootloop if it is enabled).

Breaking down the SELinux context labels, android uses the same label format discussed in the SELinux section. For the user attribute android uses the default user i.e ‘u’. For the roles attribute, the default value ‘r’ is used for subjects (or processes) as subjects do not have a specific role and ‘object_r’ for objects(or files). The ‘object_r’ notation remains constant with all the objects in Android and is not very extensively used for policy implementations. The type attribute is the one that affects the implementation of the policies. It varies with processes or the files it is associated with. The level attribute is always ‘s0’ as Android does not implement multi layer security (MLS).

A file context label for example in android would look like:

The label corresponds to the dev folder in the root directory. Being a directory (a linux file), the role is ‘object_r’, it uses the default user ‘u’ and the type specified is ‘device’ which is associated with the types that can use this file. Each of these contexts follow the rule of default-deny in android. For every access a subject needs a policy stating the same has to be defined. If there is no policy, the kernel will outright deny the access. The policies written for each of these access are then compiled into a non-human readable file. This file with the name ‘sepolicy’ would be read by Android from the root directory of the boot image as the system boots up.

Though SELinux implementation in Android is still in development, it provides the developer with a pretty good tool for fine grained access. Now that the concepts are clear the only thing that remains is writing policies. A future article on that would be posted in a short while.