Guido wrote:
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 the former. 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 doesn't). 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 remote computer. 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. Regards, Zooko [*] 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! http://zooko.com/ ^-- under re-construction: some new stuff, some broken links