Mon, 31 Mar 2003 12:51:03 -0500
> I understand how class ZipFile could exercise authority in a
> rexec-based world, if the zipfile module was trusted code. But I
> thought that a capability view of the world doesn't distinguish
> between trusted and untrusted code. I guess I need to understand
> better what kind of "barriers" the capability way of life *does* use.
I think you are on track with regard to the deeper question you are grappling
with. Almost all dangerous things come ultimately from C code. (I can think of
one danger that can come from pure Python code: it can provide an illicit
communications channel between other objects.)
So in the "separate policy language" way of life, access to the ZipFile class
gives you the ability to open files anywhere in the filesystem. The ZipFile
class therefore has the "dangerous" flag set, and when you run code that you
think might misuse this feature, you set the "can't use dangerous things" flag
on that code.
In the capability way of life, it is still the case that access to the ZipFile
class gives you the ability to open files anywhere in the system! (That is: I'm
assuming for now that we implement capabilities without re-writing every
dangerous class in the Library.) In this scheme, there are no flags, and when
you run code that you think might misuse this feature, you simply don't give
that code a reference to the ZipFile class. (Also, we have to arrange that it
can't acquire a reference by "import zipfile".)
So far the two approaches have the same effect, and the difference, for better
or for worse, is that the policy of "this code can't use ZipFile" is encoded in
Python reference-management code in the latter and encoded in a pair of flags in
Now, we might want to allow certain code to use something else dangerous (such
as the socket module) while simultaneously disallowing it from using ZipFile.
As we add N more dangerous modules, and M more objects of untrusted code that we
want to control, we have an N*M access control matrix to configure which code
can use which modules. (In an access control matrix, rows are "subjects" --
things that can exercise authority and columns are "resources" -- things that
might require authority when used.)
In a system where designation is not unified with authority, you tell this
untrusted code "I want you to do this action X.", and then you also have to go
update the policy specification to say that the code in question is allowed to
do the action X. This "say it twice if you really mean it" overhead puts a
practical limit on how fine-grained your policies can be, and it adds a source
of accidents that lead to security holes.
So now with a large or fine-grained access control matrix, we see the "unify
designation and authority" maxim really shines, and really matches well with
the Zen of Python.
But there is still another advantage that capabilities offer over other access
control systems. With normal access control (and an extremely diligent and
patient programmer and user) you can in theory achieve the Principle of Least
Privilege -- that the untrusted code runs with the minimal set of authorities
necessary to do its job. However, this is implemented by creating a new
"principal" -- a new row in the access control matrix, setting the access
control bits in each element of that row, and preventing any other code from
setting the bits in that row.
Now, observe that only maximally trusted code -- with "root" authority -- is
allowed to make these kinds of updates to the access control matrix. This means
that all code is divided into two kinds: the kind that can impose
Least-Privilege on code that it invokes (this code has root authority), and the
kind that can be constrained by Least-Privilege when it is invoked (this code
With capabilities there is no such distinction. All code can be constrained to
have access to only the privileges that it requires, and at the same time all
code can constrain other code that it invokes.
This feature, which I call "Higher-Order Principle of Least Privilege" [*]
enables new applications.
For example, using first-order Least-Privilege a web browser which runs
cap-Python "caplets" could extend selective privileges to the caplets, such as
permission to read a certain file, while withholding others, such as permission
to write to that file, or permission to send the contents of the file to a
In addition, if cap-Python supports Higher-Order Least-Privilege, those caplets
could themselves use other caplets ("web services"?) without unnecessarily
exposing their privileges to those sub-caplets.
One could imagine, for example, a web browser written in cap-Python, which runs
inside the first web browser (e.g. Mozilla with a cap-Python plug-in), and uses
cap-Python caplets to extend its (the cap-Python web browser's) functionality.
If people already had the cap-Python plug-in installed in their local Mozilla,
then simply visiting the "cap-python-browser.com" site would be sufficient to
launch the cap-Python web browser.
Of course, this could lead straight to a fully functional desktop, making good
on Marc Andreesen's old threat to turn the browser into the operating system and
the operating system into the device driver.
This would be effectively the "virtualization" of access control. I regard it
as a kind of holy Grail for internet computing.
[*] I call it that because it is the application of the Principle of Least
Privilege to the implementation of the Principle of Least Privilege. One should
be able to impose least-privilege constraints on the code one uses without
requiring full root privileges oneself!
^-- under re-construction: some new stuff, some broken links