have
implemented such systems. This section discusses general issues for
capabilities in Java, rather than specifics of the Electric
Communities or JavaSoft systems.
Dating back to the 1960's, hardware and software-based capability
systems have often been seen as a good way to structure a secure
operating system [19,34,44]. Fundamentally, a
capability is an unforgeable pointer to a controlled system
resource. To use a capability, a program must have been first
explicitly given that capability, either as part of its initialization
or as the result of calling another capability. Once a capability has
been given to a program, the program may then use the capability as
much as it wishes and (in some systems) may even pass the capability
to other programs. This leads to a basic property of capabilities:
any program which has a capability must have been
permitted to use it
.
In early machines, capabilities were stored in tagged memory. A user program could load, store, and execute capabilities, but only the kernel could create a capability [27]. In Java, a capability is simply a reference to an object. Java's type safety prevents object references from being forged. It likewise blocks access to methods or member variables which are not labeled public.
The current Java class libraries already use a capability-style interface to represent open files and network connections. However, static method calls are used to acquire these capabilities. In a more strongly capability-based system, all system resources (including the ability to open a file in the first place) would be represented by capabilities. In such a system, an applet's top-level class would be passed an array of capabilities when initialized. In a flexible security model, the system would evaluate its security policy before starting the applet, then pass it the capabilities for whatever resources it was allowed. If an applet is to be denied all file system access, for example, it need only not receive a file system capability. Alternately, a centralized ``broker'' could give capabilities upon request, as a function of the caller's identity.
Since a capability is just a reference to a Java object, the object can implement its own security policy by checking arguments before passing them to its private, internal methods. In fact, one capability could contain a reference to another capability inside itself. As long as both objects implement the same Java interface, the capabilities could be indistinguishable from one another.
For example, imagine we wish to provide access to a subset of the file system -- only files below a given subdirectory. One possible implementation is presented in figure 2. A SubFS represents a capability to access a subtree of the file system. Hidden inside each SubFS is a FileSystem capability; the SubFS prepends a fixed string to all pathnames before accessing the hidden FileSystem. Any code which already possesses a handle to a FileSystem can create a SubFS, which can then be passed to an untrusted subsystem. Note that a SubFS can also wrap another SubFS, since SubFS implements the same interface as FS.
Also note that with the current Java class libraries, a program wishing to open a file can directly construct its own FileInputStream. To prevent this, either FileInputStream must have non- public constructors, or the FileInputStream class must be hidden from programs. This restriction would also apply to other file-related Java classes, such as RandomAccessFile. While the Java language can support capabilities in a straightforward manner, the Java runtime libraries (and all code depending on them) would require significant changes.