[Python-Dev] Capabilities (we already got one)
Phillip J. Eby
pje@telecommunity.com
Tue, 01 Apr 2003 13:01:54 -0500
>However, you don't use the same technique to control access to Python
*modules*
>such as the zipfile module, because the "import zipfile" statement will
give the
>current scope access to the zipfile module even if nobody has granted such
>access to the current scope.
>...
>So your solution to this, to prevent code from grabbing privileges willy
nilly
>via "import" and builtins, is rexec, which creates a scope in which code
>executes (now called a "workspace"), and allows you to control which
builtins
>and modules are available for code executing in that "workspace".
Almost. I think you may be confusing module *code* and module
*objects*. Guido pointed this out earlier.
A Python module object is populated by executing a body of *code* against
the module *object* dictionary. The module object dictionary contains a
'__builtins__' entry that gives it its "base" capabilities.
Module *objects* possess capabilities, which are in their dictionary or
reachable from it. *Code* doesn't possess capabilities except to constants
used in the code. So access to *code* only grants you capabilities to the
code and its constants.
So, in order to provide a capability-safe environment, you need only
provide a custom __import__ which uses a different 'sys.modules' that is
specific to that environment. At that point, a "workspace" consists of an
object graph rooted in the supplied '__builtins__', locals(), globals(),
and initially executing code.
We can then see that the standard Python environment is in fact a
capability system, wherein everything is reachable from everything else.
The "holes" in this capability system, then, are:
1. introspective abilities that allow "breaking out" of the workspace (such
as the ability to 'sys._getframe()' or examine tracebacks to "reach up" to
higher-level stack frames)
2. the structuring of the library in ways that equate creating an instance
of a class with an "unsafe" capability. (E.g., creating instances of
'file()') coupled with instance->class introspection
3. Lack of true "privacy" for objects. (Proxies are a useful way to
address this issue, because they allow more than one "capability" to exist
for the same object.)