[Python-Dev] Re: Capabilities - published interfaces
Luke Kenneth Casson Leighton
lkcl at lkcl.net
Sat Dec 20 07:19:42 EST 2003
capabilities: the means to make code disappear.
thing is that there is a lot of code.
some of the boundaries have already been highlighted where
the "Capabilities" have not sufficiently been restricted.
object.__class__ is a good example.
Access to __class__
the obvious solution to fix that particular problem is to
turn the access to __class__ around.
the problem is that by creating objects, as many __class__es
are created as there are objects. considering restricting
access to all of those __class__es is totally daunting and
... but look at it closely: they're all the same function name,
so it's not necessarily the individual __class__es that could
be restricted but the method by which __class__ is accessed.
if you "feed" access to __class__ via a single function, you have
a bottleneck again which can be replaced.
so, the proposal is simple: create an __builtin__ function called
__get_class__ through which access to __class__ is made.
it takes, as a first argument, the class itself.
obj.__class__ is redirected to it (__builtin__.__get_class__(obj))
to maintain code compatibility.
then it becomes possible to over-ride the __get_class__ function and
to "vet" it in a restricted execution mode.
again, it's worth reiterating here that if it wasn't for the fact
that python is run "initiated" in "unrestricted" mode and "jumps down"
to "restricted" execution, this wouldn't be a problem.
the reason for that is because if you ran python initiated in a
file-restricted mode from startup, no unrestricted file objects with
write permission would be created, such that there would be zero risk
of anyone _getting_ an unrestricted file object, through which the
file.__class__.__new__(file.__class__, ....) method could be called.
anyway. if that is not practical (for whatever reason), then you leave
it alone, and consider the function __new__ instead, which i believe
is the _real_ reason why access to __class__ is considered bad.
again, turning it round by creating a function __builtin__.__new__()
is a way forward because that function can be restricted.
Access to __builtins__ and __globals__ from the stack.
i don't know if this is the case, but it's worth mentioning, as
background, to avoid potential confusion.
there's the concept of globals, locals and there's __builtins__
in the python language.
in the _implementation_ of the python language, there are c-variables
which may be global, may be local: possible conceptual confusion between
the implementation and the language need to be avoided!
my question is:
_is_ it possible to make a function call in python
such that that function's "view" of what the globals,
locals and __builtins__ are are COMPLETELY different
from what the CALLER of that function's view of globals,
locals and __builtins__?
in other words, is globals() global in the python implementation,
or is globals() copied on the function-call stack frame in the
python implementation? [or other]
what i am getting at is that it needs to be possible, if capabilities
are to work, to be able to make a transition in the python
language from a full-featured mode in one function call into a
totally restricted mode in another function call, and to be able
to come back again.
_without_ the entry into the restricted mode having any damaging
consequences on the full-featured mode.
i note, for example, in the rexec.py code, that only self.locals
is modified in the runcode() example RestrictedConsole class.
why is only self.locals['__builtins__'] restricted, not self.globals?
am i missing something here?
surely the globals should be modified too?
what happens if self.globals is reassigned?
Access to interfaces
one of the things that is strangely lacking in python is the ability
to restrict access to python objects, a la public, protected and
private from c++.
perl users find this to be utterly incomprehensible and reprehensible,
especially the bits where conventions are obeyed - and followed! - about
putting underscores in front of function names.
from a restricted execution perspective, this is not really okay.
what i propose is that two additional per-class functions (or lists)
be added (two more functions later) which can ONLY be called from
__init__: they are called __set_public_interface__() and
these functions take, as arguments, a list - or simpler yet,
two variables are added which can only be initialised in __init__:
__public_interface__ and __protected_interface__.
basically they consist of lists of functions that can be accessed
publicly and by inheriting classes respectively.
the reason for not specifying a list of private functions is because
it then becomes necessary to explicitly search through that list
excluding things from external access, which is not the way
"Capabilities" are done.
if the lists are None, there are no restrictions.
if the lists are empty, no functions are accessible - which is
what i also propose is that it be possible to make a copy of a
class and then _remove_ items from these two lists.
it must _not_ be possible to either add to or to replace the list
items or the lists themselves.
there's quite a lot here.
i hope you find it useful.
More information about the Python-Dev