In a normal capability based system the possession of a capability confers on its possessor an unrestricted right to access the object identified in a capability in the ways defined by the access rights contained in the capability. (In SPEEDOS restrictions on the access to an object for which a capability is held can be achieved, for example through the use of attribute types with bracket routines.)
Not quite so well defined are the metarights associated with capabilities, i.e. how capabilities themselves can be accessed and used. In this note we describe the rights and restrictions associated with capabilities themselves. Capabilities are stored in protected segments and can only be accessed indirectly using Kernel instructions. The four main instruction kinds provided for this purpose are as follows:
The free movement of capabilities can lead to security problems. For example the owner O of a file F might pass a copy of a capability to another user U1, but may not wish to allow U1 to make another copy which can be transferred to other users.
Restrictions on the movement of capabilities are therefore necessary. For this purpose a capability contains a set of metarights (permissions) which can be unset when a capability is moved, in a similar manner to restriction of semantic access rights, confinement permissions, etc. The following table lists the metarights currently planned for SPEEDOS and the effect of unsetting these metarights (i.e. confining the use of the capability):
| Confinement Mode | Effect on Capability if Unset |
| Permit Move | can only be used to make an inter-module call |
| Permit Normal | cannot be use to make calls but only
|
| Permit Duplicates | when moved the original capability is invalidated |
| Permit Distribution | can be moved only if the owner of process and of file data are identical (but see Permit Transfer) |
| Permit Transfer | can be moved to another user. After move if Permit Transfer is unset then Permit Distribution is also unset by kernel. |
None of these metarights affect a user's right to execute a read_capability instruction, i.e. a module can always gain read access to the content of its capabilities.
If this metaright is unset, a capability can be used only to make an inter-module call. The intention behind this strong restriction is to allow a capability to be passed as a parameter from one module to another with the assurance that the called module cannot make a copy of the capability, but use it only to make an inter-module call. (After the caller returns, the parameter segment, including the capability, is deleted.) This is a mechanism which makes the capability revocation problem easier to solve.
By unsetting this metaright a capability is temporarily changed from "normal" mode into a restricted "directory" mode. The purpose of a directory module is to store capabilities for users. For some implementations of directory module code any user module can function as a directory the temptation may exist to take advantage of the capabilities which it receives to access the associated modules or to make copies of the capabilities. When a capability is in directory mode these dangers are prevented, in that the capability cannot
In effect it can only be moved
The problem with directory mode is that one has to be able to set this correctly when placing a capability in a directory and it has to be possible for the capability to revert to normal mode when it is passed back from the directory to a user module. Transferring to directory mode is achieved by unsetting permit_normal in the copy capability when it is moved to a parameteer segment for the call to the directory. Reverting to normal mode is achieved automatically when case 3 above occurs, i.e. the Kernel resets a capability back to normal mode in a return parameter segment after it has been transferred from a file segment.
Normally a move operation is implemented in SPEEDOS as a copy operation (with restrictions in the new copy but not in the original capability). However, a user may wish to ensure that a capability which he passes on to another process or module cannot be duplicated (i.e. only one instance of this capability may exist). For example when passing a capability to a spooler this ensures that the spooler cannot make and hold onto a secret copy. To achieve this he unsets permit_duplicates. In this case each move operationis a destructive move and the source capability is invalidated.
If this metaright is unset, a capability may not be moved or copied from a segment in an address space of one user to a segment of an address space owned by another user. The capability can be freely copied (if permit_duplicates is set) and moved between any segments/address spaces owned by the owner of the address space in which the capability is already stored.
The intention of unsetting permit_distributionis to ensure that a capability passed to another user cannot be further distributed by that user to third parties. This creates a dilemma. Information can only be passed in SPEEDOS between segments/address spaces owned by different users via persistent data segments, not via parameter segments (as the latter are effectively stack segments of the calling user). So how can a user, operating in his own environment, unset permit_distributionis and still pass the capability to the intended user? The solution requires another permission, which is now described:
This metaright is relevant only in association with permit_distribution. (In other words , if permit_distribution is set, permit_transfer is always ignored.) If permit_distribution is unset but at the same time permit_transfer is set, the rules of permit_distribution are ignored (for this one move operation) but as soon as the rules of permit_distribution are violated once, then permit_transfer is automatically unset by the Kernel. In other words a user wishing to restrict distribution of a capability unsets permit_distribution but leaves permit_transfer set. This allows the distribution operation to take place, but the no further distribution operations can take place.
A module can be deleted only by presenting the owner capability as a parameter to the Kernel's deletion routine.
As the unique identifiers of modules (which appear in module capabilities) are never reused, a capability for a deleted module is automatically invalid, i.e. the Kernel establishes that the module no longer exists when a capability is used as an inter-module call operand and aborts the call. Whenever the Kernel detects that a module identifier is invalid, it unsets a valid bit in the corresponding capability.
© 1999 J. L. Keedy. Comments and corrections welcome to keedy@informatik.uni-ulm.de.