Split Capabilities: Making Capabilities Scale

Mark S. Miller markm@caplet.com
Sun, 09 Jul 2000 11:17:51 -0700


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