A Taste of Computer Security© Amit Singh. All Rights Reserved. Written in June 2004
Access Control is an internal (to an operating system) protection mechanism. One form of access control is seen in CPU instructions that may only be executed in supervisor mode, which usually amounts to within the kernel. The division of virtual memory into kernel and user parts is also a form of access control.
Access control plays an important role at the administrative level too. The well-aged Access Matrix model is basis for several access control mechanisms. In this model, you have:
- Objects: resources (for example, hardware devices, data files, etc.) that need access control (that is, must be accessed in a protected fashion)
- Subjects: active entities (for example, user processes) that access objects
- Rights: operations (such as enable, disable, read, write, execute, etc.) on objects are represented by access rights
It is useful to point out the concept of a protection domain, which may be thought of as a collection of access rights that subjects inside the domain enjoy. In a typical operating system, the kernel is in its own protection domain. Each user (each user's processes, to be precise) is in a separate domain. For a given user, each of his processes are in separate domains too. Carrying this further, you will realize that within a program, different subroutines may be in different domains. An important thing to note is that domains may overlap with, or even entirely contain, other domains.
The model could be visualized as a matrix M where each row i represents an object i, each column j represents a subject j, and matrix element M[i, j] contains a set of rights. Note that M[i, j] could be empty. In a real-life operating system, such a matrix would have a large number of rows and columns, but would be sparse, thereby rendering a global table (explicitly as a two-dimensional data structure) would be inefficient.
Two popular implementation approaches are Access Lists and Capability Lists.
An access list enumerates who all may access a particular object. Thus, you need to know the identities of all subjects. The Unix file permission scheme is an example. Note that in the context of Unix file permissions, "others" is a wildcard (catch-all) for subjects whose identity is not known (they may not even exist yet). Access lists are more effective when it's easy to put subjects in groups.
A capability list enumerates each object along with the operations allowed on it. This is a ticket-based scheme, where the possession of a capability (an unforgeable ticket) by a subject allows access to the object. In this scheme, it is extremely critical to protect the capability list, as capabilities must not propagate without proper authentication. Note that capabilities are finer grained than access list entries, and often can replace the Unix all-or-nothing super-user model. For example, rather than making the
ping command setuid root, it is more secure to have a capability representing raw access to the network, and providing only that to
DAC and MAC
The terms Discretionary and Mandatory are frequently used in the context of access control.
A discretionary access control (DAC) scheme is, well, at the discretion of the user. An object's owner (who is usually also the object's creator) has discretionary authority over who else may access that object. In other words, access rights are administered by the owner. Examples include Unix file permissions and a username/password system. Note that with DAC, the system cannot tell the real owner apart from anybody else. Moreover, if an access attempt fails, you may get any number of chances to retry.
Mandatory access control (MAC) involves aspects that the user cannot control (or is not usually allowed to control). A Utopian (or Draconian, if you so wish) MAC system would be one that uses your DNA. Another example is that of a hardware address that cannot be changed by a user. Under MAC, objects are tagged with labels representing the sensitivity of the information contained within. MAC restricts access to objects based on their sensitivity. Subjects needs formal clearance (authorization) to access objects.
As an example, on Trusted Solaris, MAC relies on sensitivity labels attached to objects. The MAC policy compares a user's current sensitivity label to that of the object being accessed. The user is denied access unless certain MAC checks are passed. It's mandatory as the labeling of information happens automatically, and ordinary users cannot change labels. In contrast, DAC uses file permissions and optional access control lists (ACLs) to restrict information based on the user's ID (uid) or his group ID (gid). It's discretionary as a file's owner can change its permissions at his discretion.
Domain and Type Enforcement (DTE) [Badger et al, 1995] is an access control mechanism based on the principle of least privilege. Thus, only those access rights that are absolutely necessary are granted to a program. DTE is enforced in the kernel, but is configurable, and is meant to be used as a tool for implementing MACs.
In DTE, subjects are grouped into domains, while objects are grouped into types. Access rules specify which domains have access to which types. Execution of certain programs may cause transitions between domains. An important feature of DTE is a high-level language, DTEL, that allows specification of security policies. A sample policy is shown below:
/* Sample DTE Policy */
type unix_t /* normal UNIX files, programs, etc. */
type movie_t /* movie footage */
#define DEFAULT (/bin/zsh), (/bin/sh), (/bin/csh), (rxd->unix_t)
domain editor_d = DEFAULT, (rwd->movie_t);
domain system_d = (/etc/init), (rwxd->unix_t), (auto->login_d);
domain login_d = (/bin/login), (rwxd->unix_t), (exec->movie_d);
initial_domain system_d; /* system starts in this domain */
assign -r unix_t /;
assign -r movie_t /projects/movies;
The above specification means that the first process (
/etc/init) starts in the
system_d domain. All processes inherit this domain, except
/bin/login, which runs in its own domain, which has the authority to create the user domain
Flask and SELinux
The National Security Agency (NSA) and Secure Computing Corporation (SSC) collaborated to design a generalization of type enforcement as a flexible access control mechanism. Originally implemented for microkernel-based systems (such as Mach), the architecture was enhanced as the University of Utah joined in to to integrate it into the Fluke research operating system. Later ported (in part) to Utah's OSKit, Flask was most recently implemented for Linux, resulting in Security-Enhanced Linux (SELinux).
Flexibility in such an architecture was important for it to be acceptable for mainstream operating systems. SELinux includes mandatory access controls on a variety of objects: processes (operations such as execute, fork, ptrace, change scheduling policy, send certain signals, ...), files (create, get/set attributes, inherit across execve, receive via IPC), filesystems (mount, remount, unmount, associate), TCP and Unix domain sockets, network interfaces, IPC objects, procfs, devpts, and so on.
Similar to DTE, the security policy configuration in SELinux uses a high-level language for specification. Type enforcement can be combined with Role-Based Access Control (RBAC), wherein each process has an associated role. System processes run in the
system_r role, while user may have roles such as
user_r. A role is only allowed to enter a specified set of domains. Domain transitions may occur, for example, to a more restricted domain when the user runs an application that should be run with a subset of the user's privileges.
Linux Security Modules
Linux Security Modules (LSM) [Cowan et al, 2002] is a general purpose access control framework for the Linux kernel that allows various access control modules to be implemented as loadable kernel modules. Some existing access control implementations have been ported to this framework, such as:
- POSIX.1e capabilities
- Domain and Type Enforcement
- SubDomain (least-privilege confinement)
The LSM interface mediates access to internal kernel objects by using hooks in the kernel code just before the access. Most LSM hooks are restrictive, but permissive hooks are supported. Examples of kernel objects include process structures, superblocks, inodes, open files, network devices, network buffers, sockets, skbuffs, ipc message queues, semaphores, and shared memory, and so on. Opaque security fields are used to associate security information with these objects.
Linux Intrusion Detection System (LIDS) is an enhancement for the Linux kernel that implements, among other things, mandatory access control.