[Python-Dev] Re: rexec.py unuseable
Luke Kenneth Casson Leighton
lkcl at lkcl.net
Tue Dec 16 11:16:03 EST 2003
On Tue, Dec 16, 2003 at 07:13:21AM -0800, Michael Chermside wrote:
> I (Michael) wrote:
> [Speaking of how to provide restricted execution in Python]
> > Actually, I rather prefer the approach that has been mentioned before
> > of trying to use capabilities.
> > See, for instance, the threads on
> > Capabilities found here:
> > http://mail.python.org/pipermail/python-dev/2003-March/thread.html#33854
> Luke replied:
> > capabilities, acls, schmapabilities, same thiiing :)
> No... they're not. Read the thread I mentioned above, or read this,
> and some of the other documentation for the language E:
no offense intended: i'll read that later, i'm running out of time.
without going into too many definitions, consider what i am advocating
to be _like_ an access control list but instead to be a capabilities
control list, instead.
a "capabilities list", where it's a list ordered on a
per-caller-function-name basis [with a special wildcard function name
called "absolutely everything"]
> Later Luke writes:
> > btw yes you're right, it's better off called "capabilities"
> > but the name CCLs - capability control lists - is a bit of
> > a mouthful :)
> Again, I mean something different, NOT CCLs, but capabilities.
anyone have a one-para summary of the difference between
capabilities and access control lists?
even if it's "access control lists are lists of capabilities"
which i don't know if that's true.
access control lists are typically made on a per-user basis,
but what i am recommending in _this_ case is that a "user"
be considered to be a *function*.
so maybe i _do_ mean access control list and should stick to my
guns, here :)
is the difference between capabilities and access control lists
simply that capabilities lists restrict caller-function rights
and access control lists restrict user rights?
> Hmm... how about a quick summary from me (but I'm not an expert).
> Suppose that had some code which had an object representing a
> directory, with a method "open(filename, mode='r')" that opened
> files in the directory. Given this object, you could imagine
> constructing new objects with more limited capabilities. For
> instance, you might create a readOnlyDirectory object which had
> a method "open(filename)" that didn't allow specifying the mode
> as anything but 'r'. Or you might open a file and then pass a
> file object with "read()", "write()", "seek()", and other such
> methods, which would only access that file.
[i'll have to read this in more depth later, i'm out of time, sorry]
> So _IF_ the only way to access files were through this object (and
> that's a BIG if), then you could imagine a world where HAVING and
> object was equivalent to being able to do something. If a bit of
> code had access to a read-only-file object then it could read that
> file, but couldn't write to it, or do anything else with the file
> system unless it ALSO had access to some OTHER objects. That's
> capabilities... and it would work for most kinds of restricted
> resources, not just the file system. The key idea is that HAVING
> a pointer to the object is equivalent to having the permission to
> USE that object, and whatever it provides access to.
[again, i'll have to read this in more depth later, i'm out of time,
> There are several ways to "escape" out of this system. One way is
> to access some global ability... for instance, you might use the
> "open()" function from __builtins__.
i would expect __builtins__.open() to have _its_ own mmm...
capabilities list, and _if_ that list contained a permission
for the restricted function to "execute" it, then _yes_ it
would be allowed, but otherwise no, definitely not.
therefore, the author of the [new] rexec.py module should simply
be a matter of creating the right ACLs, and applying them.
in the case of __builtins__ it could be a matter of just applying
a capabilities list of one item:
[("all functions and modules", DENY, "write, apply-to-sub-objects")]
and that would be _it_!
all functions in __builtins__ would be dealt with, and restricted!
of course, i don't believe it will be _quite_ that simple, but it
> For capabilities to work in
> Python access to "dangerous" globals would need to be restricted.
simple: apply a capabilities list that denies dangerous actions, on
all such "dangerous" globals.
one important "permission" is "change acl" of course, which must be "DENIED"!
> Another way is to just create an object out of nowhere, or forge
> a pointer to an object. Fortunately, in Python these are already
> impossible... pure Python code cannot forge references or create
> objects without access to the type or class. (C extensions can
> do anything and are unsafe.)
that is why i mentioned about "create object" permissions
if there is a permission/capability whereby the capabilities list of
a parent object is "inherited" when a create object action is carried
out, the problem you describe is alleviated.
_at_ object create time (and object create itself could be a separate
permission / capability, granted on a per-function and per-module
basis like everything else), the capabilities are examined.
what happens is that _if_ the "inherit capabilities" flag is set,
then the newly created object receives a COPY of the parent object's
ta-da, problem solved.
this is a _normal_ bog-standard approach that is used in the windows
nt security model, and has been for over twenty years, now, and if
you count the VAX/VMS history as well, a lot longer than twenty years.
> Another way is to access the more powerful object that "empowers"
> a less powerful one... perhaps using the (supposed to be private)
> _directory field in the readOnlyfile object. So capabilities in
> Python are impossible without some sort of private data for
> objects (this is not a particularly onerous requirement). Yet
> *another* approach would be to use introspection... for instance,
> in Python today, given any file object, the class itself ("file")
> can be obtained via introspection, and then used to create other
> file objects. Using capabilities in Python would require that
> "restricted" objects have some more limited form of introspection...
> perhaps one could only obtain a "fake" class object which had
> a __equals__ method that simulated being the real class, but
> which had no __init__ so it couldn't be used to create new
i don't quite follow, even after reading the capabilities thread,
what introspection is.
but let me try to clarify so you can correct me if necessary:
introspection is the ability to go via the __XXXXX__ functions
etc. including the __class__ stuff, yes?
well, if i follow you correctly, you simply put a capabilities
list on all those things, or you put one on the entire object.
or better yet, you put an "inherited" one on the class, such that
_any_ object created will receive restricted capabilities.
> At any rate, you get the idea. Capabilities are possible in Python
> only if some sort of "restricted mode" is created, which restricts
> access to some built-in abilities and which creates "restricted"
> objects with some private data and limited introspection.
> But IF
> you had these things (and they're NOT trivial), then capabilities
> may be a conceptually more elegant approach than ACLs, lleading to
> more elegant programs.
i believe that if you understand what i am suggesting, and i
hope that filling in some examples above, i believe that what
i am suggesting covers your concerns.
the capabilities lists that i am recommending can be applied
on a per-function and per-object basis and can be inherited.
in this way, useful restrictions can be made to achieve the
... i didn't say, however, that it wouldn't require quite a lot
of thought about _which_ functions to apply restricted capabilities
starting, of course, with the "nothing goes" one, and repeatedly
attempting to run code.
More information about the Python-Dev