Split Capabilities: Making Capabilities Scale

Karp, Alan alan_karp@hp.com
Wed, 12 Jul 2000 09:22:37 -0700


I agree entirely that least privilege is the only intelligent policy, and
e-speak encourages it.  It is unfortunate that our users demand the
familiar, insecure approach.  This fact doesn't prevent a careful user from
doing things safely.

Look at the various ways that "cp" could be provided.

1. "cp" is a method in a file system service that owns the disk.  The file
system must be trusted to perform its operations correctly.  The client
sends the request

% cp foo.txt bar.txt

providing his personal names for the two files associated with the labels
"foo.txt" and "bar.txt", along with names of key rings containing the access
rights to be applied.  The service receives the request and knows what
access rights the client has.  The request fails unless these rights include
read on foo.txt and write on bar.txt.  The default behavior, as demanded by
our users, is all the access rights of the client, even though we can
construct a key ring with exactly the minimum set of rights needed for the
operation.  

By the way, the names foo.txt and bar.txt may have no relation at all to the
actual name of the files on the disk.  This feature allows the file system
to move files around as needed without invalidating names provided by
clients.  It also means that the file system does not need to understand the
name syntax used by the client.  Further, there are no attacks based on
guessing names of someone else's files or names on the disk.

2. "cp" is a method in a service that does not own the disk.  In this case,
the client must transfer rights to the service.  In e-speak Developer
Release (DR) 3.0 (the new name for Beta 3.0), SPKI attribute certificates
are delegated.  In e-speak Beta 2.2, a new key ring is created with exactly
the rights being granted.  The request to the service now includes a name
bound to this key ring.  The service now has names bound only to the files
named by the client and a key ring with exactly the privileges needed.  It
can now submit the request to the "real" file system service.  Note that in
e-speak Beta 2.2 we can revoke the delegated privilege by simply destroying
the key ring.  We can even revoke the name bindings.  (If you really want to
know, I'll tell you.)

A service constructed this way is subject to fewer attacks than a real file
system.  If constructed properly, it will remove all the bindings associated
with a given request as soon as the command has been processed.  This "outer
scope provides no authority ...", as you put it. Thus, even an attack that
gets the service to execute an arbitrary piece of code can't get the service
to do something that the client could not have done.  In other words, we've
simplified the code needed to prevent the deputy from being confused.

3. "cp" is a program running client's process using child processes of the
client.  In this case, one child reads one file and another writes the
other.  One child can be given read privilege, and the other, write access.
This approach reduces the chance that a write would occur even if the read
fails.  Delegation of authority can be done exactly as in case 2.

Note that in the latter two cases, a careless user might forward a key ring
with more than the minimum authorities required to do the job.  However, two
features of e-speak provide some protection for such a user.  Firstly, all
the user need do is destroy this key ring to revoke all the granted
privileges.  Secondly, the service only has name bindings for files provided
by the client.  Since names are meaningless outside a client's name space,
there is no way for the service to affect other files even while holding
privileges to them.  Thus, a careless user is at more risk than a careful
one, but we've reduced the number of things that he needs to get right.

Now, let's get back to grepping a large number of files.  There is no way to
escape the fact that the process doing the grep needs read permission on
each file.  I could, of course, grant the child the permissions one at a
time as it needed to open the files, but I bet the performance would be
pretty bad, and I'd need to be sure to revoke one before giving out the
next.  Instead, in e-speak Beta 2.2, I'd construct a key ring with the
key(s) granting read permission to these files and pass a name binding for
it to the child.  I'd also give the child access to the part of my name
space containing bindings for the files to be searched.

_________________________
Alan Karp
Decision Technology Department
Hewlett-Packard Laboratories MS 1U-2
1501 Page Mill Road
Palo Alto, CA 94304
(650) 857-3967, fax (650) 857-6278


> -----Original Message-----
> From: Mark S. Miller [mailto:markm@caplet.com]
> Sent: Sunday, July 09, 2000 11:18 AM
> To: Karp, Alan
> Cc: 'Jonathan S. Shapiro'; e-lang@eros-os.org
> Subject: RE: Split Capabilities: Making Capabilities Scale
> 
> 
> 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
>