Previous section   Next section

15.4 Ring-Based Access Control

The Multics system [235, 788] generalizes the notion of a supervisor and user state with a protection mechanism called ring-based access control. To understand its simplicity and elegance, one must realize that files and memory are treated the same from the protection point of view. For example, a procedure may occupy a segment of the disk. When invoked, the segment is mapped into memory and executed. Data occupies other segments on disk, and when accessed, they are mapped into memory and accessed. In other words, there is no conceptual difference between a segment of memory and a segment on a disk.

Segments are of two kinds: data and procedure. A segment could have r (read) rights, w (write) rights, e (execute) rights, and a (append) rights associated with it. These rights are contained in access control lists, which constrain access on a per-user basis. So all procedures that user bishop executes would have the rights associated with that user, bishop.

In addition, the Multics system defines a sequence of protection rings (or rings, for short) numbered from 0 to 63.[1] The kernel resides in ring 0. The higher the ring number, the lower the privileges of the segments in that ring. We also say that "a procedure executes in ring r" because the ring is associated with the individual segment, not with the entire process.

[1] In fact, the system as implemented had eight rings ([788], p. 141).

Subject to the access constraints noted below, procedures can "cross" ring boundaries. In some cases, the crossing causes a "ring-crossing fault" that traps to the kernel. At that point, a mechanism called the Gatekeeper checks arguments and access and performs other functions that constrain ring crossings. In other cases, no ring-crossing fault is induced, and access is permitted if the access modes allow.

A gate is simply an entry point (like the "public" designators of object-oriented languages). Gates are specially declared within programs, and the compiler and linker generate special code to make these entry points available to other procedures.

Assume that a procedure executing in ring r wants to access a data segment. Associated with each data segment is a pair of ring numbers called an access bracket (a1, a2), with a1 a2. Assume that the data segment's permissions allow the desired access. The ring numbering adds an extra constraint:

Assume that the same procedure, again executing in ring r, wants to access a procedure segment. Each procedure segment has an access bracket, just like a data segment. A procedure segment may also have a call bracket (c1, c2), with c1 c2. By convention, when a call bracket is present, c1 = a2, leading to an alternative notation of (a1, a2, a3), where (a1, a2) is the access bracket and (a2, a3) is the call bracket (that is, c2 = a3). The rules for access differ slightly from those for accessing a data segment:

EXAMPLE: Assume that a data segment has the access bracket (2, 4) and heidi has rw rights over the segment. If heidi's procedure executes in ring 1, and tries to read the process, the read succeeds. If heidi's procedure executes in ring 3, any reads succeed and any writes fail. If heidi's procedure executes in ring 5, all accesses fail.

EXAMPLE: Assume that a procedure segment has the bracket (2, 4, 6)—that is, its access bracket is (2, 4) and its call bracket is (4, 6). heidi's procedure calls that procedure. If heidi's procedure executes in ring 1, a ring-crossing fault occurs, but the call succeeds (unless the Gatekeeper blocks the call). If heidi's procedure executes in ring 3, the call succeeds and no ring-crossing fault occurs. If heidi's procedure executes in ring 5 and calls the procedure segment through a valid gate, the call succeeds; otherwise, it fails. If heidi's procedure executes in ring 7, the call fails.

The reason for the brackets shows how practical details complicate ideal solutions. Conceptually, the access bracket should contain one ring. However, consider a procedure embodying a service routine (such as "access file"). Then procedures in other rings accessing that routine would cause a large number of ring crossings. The operating system would need to handle these crossings, increasing the overhead. But if the procedures were within the service routine's access bracket, no ring-crossing faults would occur. Hence, the access bracket minimizes operating system overhead in this context.

A similar situation arises with different classes of users. Suppose a service routine lies in ring a. Some users need to invoke this routine. Others are allowed to invoke it in specific ways—for example, to access some system resource in a particular manner. Still others should not invoke it at all. The access bracket handles the first and third sets of users, but the second set cannot be handled with an access bracket. However, with a call bracket, the second set can access the service routine and be forced to use predefined entry points (the gates). Hence, the need for call brackets.

Variants of the ring mechanism have been used by other systems. The VAX system of Digital Equipment Corporation, for example, provides four levels of privilege: user, monitor, executive, and kernel. Contrast this with the more traditional two levels (user and supervisor) and the influence of the rings of Multics is clear.


  Previous section   Next section
Top