[Python-Dev] Capabilities

Paul Prescod paul@prescod.net
Sun, 30 Mar 2003 13:59:26 -0800


Ka-Ping Yee wrote:
> On Sun, 30 Mar 2003, Paul Prescod wrote:
> 
>>It wouldn't have hurt for you to describe how the code achieves security
>>by using lexical closure namespaces instead of dictionary-backed
>>namespaces. ;)
> 
> Sorry.  :)  I assumed it would be clear.

It probably is for those following the thread more closely.

> That immutability isn't required in order to prevent filesystem access.

Okay, now I see that that's what you meant about "__dict__". You were 
talking about the object's. namespace in general, not the magical 
attribute named __dict__.

>...
>>del x.__class__.__setattr__
> 
> Sneaky.  :)   

I would have complimented you on the elegance of this proposal but I 
thought it might just be a translation of E's object construct. To 
whatever extent you innovated in creating it, congratulations, it's very 
cool.

 >  ....In restricted mode you wouldn't be able to do that.

I'm not clear (because I've been following the thread with half my 
brain, over quite a few days) whether you are making or have made some 
specific proposal. I guess you are proposing a restricted mode that 
would make this example actually secure as opposed to almost secure. Are 
you also proposing any changes to the syntax?

Also, is restricted mode an interpreter mode or is it scoped by module? 
I can't see how it would work as an interpreter mode because too much 
library code depends on introspectability and hackability of Python objects.

>>I can't see in
>>this model how to implement what C++ calls a "friend" class.
> 
> I haven't tried an example that requires that yet, but two classes
> could communicate through access to a shared object if they wanted to.

This doesn't actually simulate "friend" but that's probably because 
friend makes no sense in a capability system.

It occurs to me after further thought that there are two orthogonal 
problems. First is privacy for the sake of software engineering. Python 
has always rejected that and I'm glad it has (although it makes advocacy 
harder). This sort of privacy just gets in your way when you're trying 
to coerce code into doing what you want when it wasn't designed to. 
Languages like C++ make it really hard to hack when you need to, but 
they don't really prevent you from doing it if you are determined 
enough, so you have the worst of both worlds.

Second, is safety for the sake of security. IF you have chosen the 
capabilities model of security, THEN "friend" perhaps doesn't make 
sense. You either have a capability reference or you don't. The code's 
compile-time class or package is irrelevant. Allowing classes (as 
opposed to objects) to declare each other friends probably only opens up 
security holes.

But if you want to have an example of something like this for the record 
books, perhaps you could implement an iterator over a data structure 
with the caveat that we'd like to implement the iterator and data 
structure in separate files (because sometimes the implementation of 
each could be large and complicated). I think it works like this:

The Data structure is one capability class. The iterator is another. The 
application asks the data structure to create an iterator. The data 
structure creates one and passes some subset of its internal state to 
the new object. It probably could not (and anyway should not) pass a 
pointer to the opaque closure that is its external representation. So 
instead it passes in whatever state variables the iterator is likely to 
be interested in.

If you did want to emulate class-based "friendship" (can't think of why, 
off the top of my head) you could do so like this:

    def tellMeYourSecrets(myfriend):
       if instanceof(myfriend, MyFriendClass):
           return my_namespace()
       else:
           raise SecurityViolation, "Bug off"


The example in Stroustrop is where you want a vector class to be able to 
directly read the internals of a matrix class rather than go through 
inefficient method calls. But in a capabilities universe, even matrices 
can't, in general, see the internals of other matrices. I guess they'd 
have to use the trick above if that was really necessary.

>>If this technique became widespread, Python's restrictions on assigning
>>to lexically inherited variables would probably become annoying.
> 
> 
> The Namespace offers a possible workaround. 

Yes, but why workaround rather than fix? Is there a deep reason Python 
objects can't write to intermediate namespaces? Is it just a little bit 
of extra safety against accidentally overwriting something? This is 
probably overkill in the case of intermediate scopes. And if not, there 
could be a keyword which is like global but for intermediate scopes.

> ...
> It would be cool if you could suggest little "security challenges"
> to work through.  Given specific scenarios requiring things like
> mutability or friend classes, i think trying to implement them in
> this style could be very instructive.

Unfortunately, most of the examples I can come up with seem to be hacks, 
workarounds and optimizations. It isn't surprising that sometimes you 
lose some efficiency or simplicity when working in a secure system.

It makes me wonder about whether E might be less fun, efficient and 
productive than Python because security is embedded so deeply within it? 
(just a speculation...I don't know E) A Python that could go back in 
forth from secure mode to insecure mode might be a nice compromise.

  Paul Prescod