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__.
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.