At 11:11 AM 7/6/00 , Karp, Alan wrote:
> > As an aside, I'ld argue that it is *rarely* the case that
> > users may wish to
> > share objects in bulk, and *never* the case that correctly
> > designed programs
> > should do so. Up to a point, the fact that capabilities means
> > that they
> > reinforce good design practices.
>
>Actually, I think the situation is quite common. Many times when I fork a
>process, I'd like the child process to have a substantial fraction of my
>privileges. Not every time, but many timmes. For example, a word processor
>I spawn will need access to fonts. A build will need access to source and
>object files and the required executables. Each of these requires transfer
>of a potentially large number of capabilities.
This is a defining issue of conventional capability style: The principle of least authority. For non-legacy-oriented code, we believe the child process (or whatever) should be given access to exactly those capabilities plausibly needed for it to carry out its duties. A great example (from Dean Tribble) is the difference between a file copy routine written in the Unix style vs the capability style. In the Unix style, we understand
% cp foo.txt bar.txt
to be passing the strings "foo.txt" and "bar.txt" to the program designated by "cp". The shell evaluates (sort of) the name "cp" to a program, but it does not evaluate the arguments to files. Instead, it leaves it to the cp program to do so. Therefore, the cp program needs access to the invoker's entire accessible file system merely in order to look up these two names! Any such system is begging for trojan horse viruses.
By contrast, the corresponding E command line
? cp ( <file:foo.txt> readOnly, <file:bar.txt> )
gives the "cp" function access only to the File objects that the two arguments evaluate to. It would not have access to anything else. To understand the authority needed to issue this command line, we need to expand the URI syntactic sugar:
? cp ( file__uriGetter get("foo.txt") readOnly, file__uriGetter get("bar.txt"))
The outer scope for interactive commands or top-level *.e scripts (the E equivalent of "main") contains powerful capabilities (like file__uriGetter) that provide all the authority of their process. Under legacy OSes, this is normally also all the authority of their "user". This is a dangerous environment, and the E programmer should do very little in this scope other than to invoke other services (like the above hypothetical "cp") with well chosen narrow authorities derived from these broad authorities. I take it this dangerous scope corresponds to the E-speak root name frame or the KeyKOS root login directory?
Invokable services (like "cp") are defined in *.emaker files, whose outer scope provides no authority whatsoever to effect the world outside of itself, other than to use computational resources. (Note: this claim has yet to be fully implemented.)
An E user that's sloppy about the principle of least authority might leave out the "readOnly" above, in which case everything would still work if "cp" operates correctly. If "cp" is buggy or malicious, the extra damage would be limited to modifications to the file named "foo.txt", rather than, as in the Unix case, all files modifiable by this user. Why is this safety so free of notational cost? Because we have to designate to cp what files we're interested in anyway. As long as these designations are evaluated in the invoking context rather than the invoked context, as is the case in any lexically scoped programming language, we're most of the way there.
From what I've read, E-speak has a similar perspective on names. So perhaps it can dispense with granting authority en-masse to child processes?
Cheers,
--MarkM