[Python-Dev] In defense of Capabilities [was: doc for new restricted execution design for Python]

Talin talin at acm.org
Fri Jul 7 08:12:31 CEST 2006


Brett Cannon wrote:
> On 7/5/06, Talin <talin at acm.org> wrote:
>> Transitioning from the checked to the unchecked state could only be done
>> via C code. So the 'file' wrapper, for example, would switch over to the
>> unchecked interpreter before calling the actual methods of 'file'. That
>> C wrapper might also check the current permission state to see what
>> operations were legal.
> 
> So add the proper checks in Python/ceval.c:call_function() to check for 
> this
> flag on every object passed in that is called?

Right. I also realized that you would need to add code that propagates 
the checked bit from the class to any instances of the class. So 
whenever you call a class to create an object, if the class has the 
checked bit, the instance will have it set as well.

>> So essentially, what I propose is to define a simple security primitive
>> - which essentially comes down to checking a single bit - and use that
>> as a basis to create more complex and subtle security mechanisms.
> 
> Right, but it does require that the proper verification function be turned
> on so that the permission bit on 'file' is checked.  It kind of seems like
> 'rexec' and its f_restricted flag it set on execution frames, except you 
> are
> adding an object-level flag as well.
> 
> Either way, the trick is not fouling up switching between the two checking
> functions.
> 
> -Brett

I wasn't aware of how rexec worked, but that seems correct to me.

Given a 'restricted' flag on a stack frame, and one on the object as 
well, then the code for checking for permission violations is nothing 
more than:

    if (object.restricted && exec_frame.restricted)
        raise SecurityException

In particular, there's no need to call a function to check a "permission 
level" or "access rights" or anything of the sort - all that stuff is 
implemented at a higher level.

By making the check very simple, it can also be made very fast. And by 
making it fast, we can afford to call it a lot - for every operation in 
fact.

And if we can call it for every operation, then we don't have to spend 
time hunting down all of the possible loopholes and ways in which 'file' 
or other restricted objects might be accessed.

Originally I had thought to simply add a check like the above into the 
interpreter. However, that would mean that *all* code, whether 
restricted or not, would have to pay the (slight) performance penalty of 
checking that flag. So instead, I thought it might be more efficient to 
have two different code paths, one with the check and one without. But 
all this is based on profound ignorance of the interpreter - there might 
be a hundred other, better ways to do this without having to create two 
versions of ceval.

Another interesting think about the check bit idea is that you can set 
it on any kind of object. For example, you could set it on individual 
methods of a class rather than the class as a whole. However, that's 
probably needlessly elaborate, since fine-grained access control will be 
much more elegantly achieved via trusted wrappers.

-- Talin


More information about the Python-Dev mailing list