Some tentative terminology. An ‘object’ is composed of ‘behavior’ and ‘state’. The behavior is typically a RO reference (capability) to some ordinary program and we say that the object ‘obeys’ the program. The state of an object is whatever mutable data is convenient for the object’s program to remember what it is doing and should do.
While capabilities may be composed of bits, the holder of a capability is not allowed to see the bits. In Linux the file descriptor is a small integer known to the holder, but it is merely an index into a table, kept by the kernel for each particular process. The entry is there much like a capability and I will call that table the C-list of the process. The kernel does not allow the process to either read or write this C-list.
Even if the bits in the capability were known to the holder he could not use them as a capability. In Linux the bits must occupy an entry in the table whose index is known to the holder. (Either of these two rules may be relaxed but some security patterns are possible only if both are enforced. Indeed the same capability may comprise different bits at different times, or different bits for different holders. If you enforce neither rule you do not have a capability system.)
There is some sort of messaging between objects and these messages can include capabilities. After an object receives such a message, that object holds the capability (in its C-list) at an index it specifies, at least if it reads the message expecting a capability. Such messaging generally includes the familiar call and return pattens where both call and return involve a message.
There are in capability platforms a few sorts of primitive objects. Here is a list of sorts generally included:
There must be within the system a way for an object to create new non-primitive objects whose behavior and initial state it defines. Upon such creation the creator gains sole the capability to call the new object.
For each of these sorts of object there is a capability. To extract information from, or to effect such an object (change its state) it is necessary to hold a capability to that object. Thus Linux fails to be a capability system.
A fundamental attribute of a capability system is that each action that relies on a capability must explicitly designate that capability in the program obeyed by the object that causes that action. In Linux the read system call explicitly designates the descriptor and thus the capability. In Linux the open system call does not conform to this pattern because whether or not the open happens depends on the permissions bits in the directory and also on the user id. Typically a capability system, in it foundations, has no concept of user.
A ramification of these rules is that many ‘files’ appear in no file directory. Programmers and administrators are likely to have a private directory of capabilities so that they need not remember indexes into C-lists. The directory is an ordinary object with a C-list.
A common capability pattern, almost a requirement, is that behavior may be shared between objects that cannot share data, except by capabilities they hold.
A common capability pattern is a primitive means to ascertain whether some object is of some defined behavior. See branding in Keykos. There are other solutions. At least the creator of objects should be able to recognize an object that he created, when a capability to that object is sent to the creator.
Some platforms supply quantified resources, such as space and time via capabilities. Mission critical applications either need this (to limit others) or need exclusive access to the platform.
Another observation is that connection begets connection; message may convey capabilities. More importantly: Only connection begets connection.