On 7/5/06, Talin <[EMAIL PROTECTED]> wrote:
Brett Cannon wrote:
> On 7/5/06, Michael Chermside <[EMAIL PROTECTED]> wrote:
>> If you were using capabilities, you would need to ensure that
>> restricted interpreters could only get the file object that they
>> were given. But then _all_ of these fancy versions of the
>> restrictions would be immediately supported: it would be up to the
>> users to create secure wrappers implementing the specific
>> restrictions desired.
>
> I agree.  I would prefer this way of doing it.  But as I have said, making
> sure that 'file' does not get out into the wild is tough.

I seem to recall someone mentioned earlier in this discussion the notion
of somehow throwing an exception when sandboxed code attempts to push a
file reference onto the interpreter stack.

That was AMK.

I'm not an expert in these matters, so perhaps what I am going to say
will make no sense, but here goes:

What if there were two copies of the evaluator function. One copy would
be a slightly slower 'checked' function, that would test all objects for
a 'check' bit. Any attempt to evaluate a reference to an object with a
check bit set would throw an exception.

The other eval function would be the 'unchecked' version that would run
at full speed, just like it does today.

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?

Note that whenever a C function sets the interpreter state to
'unchecked', that fact is saved on the stack, so that when the function
returns, the previous state is restored. The function for setting the
interpreter state is something like PyCall_Unchecked( ... ), which
restores the interpreter state back to where it was.

Transitioning from unchecked to checked is trickier. Specifically, you
don't want to ever run sandboxed code in the unchecked state - this is a
problem for generators, callbacks, and so on. I can think of two
approaches to handling this:

First approach is to mark all sandboxed code with a bit indicating the
code is untrusted. Any attempt to call or otherwise invoke a function
that has this bit set would throw the interpreter into the 'checked'
state. (Note that transitioning the other way is *not* automatic - i.e.
calling trusted code does not automatically transition to unchecked state.)

The approach is good because it means that if you have intermediary code
between the wrapper and the sandboxed code, the interpreter still does
the right thing - it sets the interpreter into checked state.

One problem is how to restore the 'unchecked' state when a function call
returns. Probably you would have to build this into the code that does
the state transition.

If marking the sandboxed code isn't feasible, then you'd have to have
the wrapper objects wrap all of the callbacks with code that goes to
checked state before calling the callbacks. This means finding all the
possible holes - however, I suspect that there are far fewer such holes
than trying to hide all possible 'file' methods. However, one advantage
of doing this is that restoring the 'unchecked' state after the call
returns is fairly straightforward.

The advantage of the this whole approach is that once you set the
'check' bit on 'file', it doesn't matter whether 'file' gets loose or
not - you can't do anything with it without throwing an exception.
Moreover, it also doesn't matter what code path you go through to access
it. Only C code that flips the interpreter into unchecked state can call
methods on 'file' without blowing up.

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
_______________________________________________
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com

Reply via email to