Creating a capabilities-based restricted execution system

Serge Orlov sombDELETE at pobox.ru
Sat Jan 3 15:21:05 EST 2004


"Sean R. Lynch" <seanl at chaosring.org> wrote in message news:LmmdnUn4seDeGWuiXTWc-w at speakeasy.net...
> I've been playing around with Zope's RestrictedPython, and I think I'm
> on the way to making the modifications necessary to create a
> capabilities-based restricted execution system. The idea is to strip out
> any part of RestrictedPython that's not necessary for doing capabilities
> and do all security using just capabilities.
>
> The basic idea behind capabilities is that you don't give any piece of
> code you don't trust a reference to something you don't want it to have
> access to. You use proxies instead (E calls them "facets").

"Don't give" sounds good in theory but fails in practice. You can't prevent
leakage 100%, so any security system _must_ help programmer to keep
trusted data away from untrusted code. Do you know that rexec failed
exactly because it didn't help to prevent leakage?

>
> In order to be able to allow untrusted code to create proxy objects, I
> needed to be able to store a reference to the proxied object in a
> private attribute.
>
> To create private attributes, I'm using "name mangling," where names
> beginning with X_ within a class definition get changed to
> _<uuid>_<name>, where the UUID is the same for that class. The UUIDs
> don't need to be secure because it's not actually possible to create
> your own name starting with an underscore in RestrictedPython; they just
> need to be unique across all compiler invocations.

This is a problem: you declare private attributes whereas you should be
declaring public attributes and consider all other attributes private. Otherwise
you don't help prevent leakage. What about doing it this way:

obj.attr means xgetattr(obj,acc_tuple) where acc_tuple = ('attr',UUID)
and xgetattr is
def xgetattr(obj,acc_tuple):
  if not has_key(obj.__accdict__,acc_tuple):
    raise AccessException
  return getattr(obj,acc_tuple[0])

__accdict__ is populated at the time class or its subclasses are created.
If an object without __accdict__ is passed to untrusted code it will
just fail. If new attributes are introduced but not declared in __accdict__
they are also unreachable by default.

>
> The nice thing about using this name mangling is that it's only done at
> compile time and doesn't affect runtime performance. An interesting side
> effect is that code defined on a class can access private attributes on
> all descendants of that class, but only ones that are defined by other
> code on that class, so this isn't a security issue.
>
> I was thinking I needed read-only attributes to be able to avoid
> untrusted code's being able to sabotage the revoke method on a proxy
> object, but I'm thinking that just keeping around a reference to the
> revoke method in the original code may be enough.
>
> Does anyone think I'm going in completely the wrong direction here? Am I
> missing anything obvious?

It depends on what type of security do you want. Did you think about DOS
and covert channels? If you don't care about that, yeah, you don't miss
anything obvious. <wink> you should worry whether you miss something
non-obvious.

By the way, did you think about str.encode? Or you are not worried about
bugs in zlib too?

-- Serge.





More information about the Python-list mailing list