Re: [Python-Dev] Security capabilities in Python
On Sat, 9 Apr 2005 00:13:40 -0500 (CDT), Ka-Ping Yee <[EMAIL PROTECTED]> wrote: >On Fri, 8 Apr 2005, Eyal Lotem wrote: > > I would like to experiment with security based on Python references as > > security capabilities. > > This is an interesting and worthwhile thought. Several people > (including myself) have talked about the possibility of doing > this in the past. I believe the two problems you mention can be > addressed without modifying the Python core. > > > * There is no way to create secure proxies because there are no > > private attributes. > > Attributes are not private, but local variables are. If you use > lexical scoping to restrict variable access (as one would in > Scheme, E, etc.) you can create secure proxies. See below. > > > * Lots of Python objects are reachable unnecessarily breaking the > > principle of least privelege (i.e: object.__subclasses__() etc.) > > True. However, Python's restricted execution mode prevents access > to these attributes, allowing you to enforce encapsulation. (At > least, that is part of the intent of restricted execution mode, > though currently we do not make official guarantees about it.) > Replacing __builtins__ activates restricted execution mode. > > Here is a simple facet function. > > def facet(target, allowed_attrs): > class Facet: > def __repr__(self): > return '' % (allowed_attrs, target) > def __getattr__(self, name): > if name in allowed_attrs: > return getattr(target, name) > raise NameError(name) > return Facet() > > def restrict(): > global __builtins__ > __builtins__ = __builtins__.__dict__.copy() > > # Here's an example. > > list = [1, 2, 3] > immutable_facet = facet(list, ['__getitem__', '__len__', '__iter__']) > > # Here's another example. > > class Counter: > def __init__(self): > self.n = 0 > > def increment(self): > self.n += 1 > > def value(self): > return self.n > > counter = Counter() > readonly_facet = facet(counter, ['value']) > > If i've done this correctly, it should be impossible to alter the > contents of the list or the counter, given only the immutable_facet > or the readonly_facet, after restrict() has been called. > > (Try it out and let me know if you can poke holes in it...) > > The upshot of all this is that i think you can do secure programming > in Python if you just use a different style. Unfortunately, this > style is incompatible with the way classes are usually written in > Python, which means you can't safely use much of the standard library, > but i believe the language itself is not fatally flawed. > Does using the gc module to bypass this security count? If so: [EMAIL PROTECTED]:~$ python -i facet.py >>> import gc >>> c = readonly_facet.__getattr__.func_closure[1] >>> r = gc.get_referents(c)[0] >>> r.n = 'hax0r3d' >>> readonly_facet.value() 'hax0r3d' >>> This is the easiest way of which I know to bypass the use of cells as a security mechanism. I believe there are other more involved (and fragile, probably) ways, though. Jp ___ Python-Dev mailing list [email protected] http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] Re: marshal / unmarshal
Terry Reedy wrote: > The particular issue here is not platform dependence as such but > within-platform usage dependence, as in the same code giving radically > different answers in a standard interactive console window and an idle > window, or when you run it the first time (from xx.py) versus subsequent > times (from xx.pyc) until you edit the file again. Yet, this *still* is a platform dependence. Python makes no guarantee that 1e1000 is a supported float literal on any platform, and indeed, on your platform, 1e1000 is not supported on your platform. Furthermore, Python makes no guarantee that it will report when an unsupported float-literal is found, so you just get different behaviour, by accident. This, in turn, is a violation of the principle "errors should never pass silently". Alas, nobody found the time to detect the error, yet. Just don't do that, then. Regards, Martin ___ Python-Dev mailing list [email protected] http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] Re: marshal / unmarshal
Martin> Yet, this *still* is a platform dependence. Python makes no
Martin> guarantee that 1e1000 is a supported float literal on any
Martin> platform, and indeed, on your platform, 1e1000 is not supported
Martin> on your platform.
Are float("inf") and float("nan") supported everywhere? I don't have ready
access to a Windows machine, but on the couple Linux and MacOS machines
at-hand they are. As a starting point can it be agreed on whether they
should be supported? (There is a unique IEEE-754 representation for both
values, right? Should we try and support any other floating point format?)
If so, the float("1e1") == float("inf") in all cases, right? If not,
then Python's lexer should be trained to know what out-of-range floats are
and complain when it encounters them. In either case, we should then know
how to fix marshal.loads (and probably pickle.loads).
That seems like it would be a start in the right direction.
Skip
___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe:
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
[Python-Dev] Re: Re: marshal / unmarshal
Skip Montanaro wrote:
> Are float("inf") and float("nan") supported everywhere?
nope.
>>> float("inf")
Traceback (most recent call last):
File "", line 1, in ?
ValueError: invalid literal for float(): inf
>>> float("nan")
Traceback (most recent call last):
File "", line 1, in ?
ValueError: invalid literal for float(): nan
>>> 1e1
1.#INF
>>> float("1.#INF")
Traceback (most recent call last):
File "", line 1, in ?
ValueError: invalid literal for float(): 1.#INF
> As a starting point can it be agreed on whether they should be supported?
that would be nice.
> In either case, we should then know how to fix marshal.loads (and probably
> pickle.loads).
pickle doesn't have the INF=>1.0 bug:
>>> import pickle
>>> pickle.loads(pickle.dumps(1e1))
...
ValueError: invalid literal for float(): 1.#INF
>>> import cPickle
>>> cPickle.loads(cPickle.dumps(1e1))
...
ValueError: could not convert string to float
>>> import marshal
>>> marshal.loads(marshal.dumps(1e1))
1.0
___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe:
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] Re: marshal / unmarshal
Skip Montanaro wrote:
> Martin> Yet, this *still* is a platform dependence. Python makes no
> Martin> guarantee that 1e1000 is a supported float literal on any
> Martin> platform, and indeed, on your platform, 1e1000 is not supported
> Martin> on your platform.
>
> Are float("inf") and float("nan") supported everywhere?
I would not expect that, but Tim will correct me if I'm wrong.
> As a starting point can it be agreed on whether they
> should be supported? (There is a unique IEEE-754 representation for both
> values, right?
Perhaps yes for inf, but I think maybe no for nan. There are multiple
IEEE-754 representations for NaN. However, I understand all NaN are
meant to compare unequal - even if they use the same representation.
> If so, the float("1e1") == float("inf") in all cases, right?
Currently, not necessarily: if a large-enough exponent is supported
(which might be the case with a IEEE "long double", dunno), 1e1
would be a regular value.
> That seems like it would be a start in the right direction.
Pieces of it would be a start in the right direction.
Regards,
Martin
___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe:
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
[Python-Dev] Re: Re: marshal / unmarshal
> pickle doesn't have the INF=>1.0 bug: > import pickle pickle.loads(pickle.dumps(1e1)) > ... > ValueError: invalid literal for float(): 1.#INF > import cPickle cPickle.loads(cPickle.dumps(1e1)) > ... > ValueError: could not convert string to float > import marshal marshal.loads(marshal.dumps(1e1)) > 1.0 should I check in a fix for this? the code in PyFloat_FromString contains lots of trickery to deal with more or less broken literals, and more or less broken C libraries. unfortunately, and unlike most other functions with similar names, PyFloat_FromString takes a Python object, not a char pointer. would it be a good idea to add a variant that takes a char*? if so, should PyFloat_FromString use the new function, or are we avoiding that kind of refactoring for speed reasons these days? any opinions? ___ Python-Dev mailing list [email protected] http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
[Python-Dev] Re: Security capabilities in Python
Ka-Ping wrote: > counter = Counter() > readonly_facet = facet(counter, ['value']) > > If i've done this correctly, it should be impossible to alter the > contents of the list or the counter, given only the immutable_facet > or the readonly_facet, after restrict() has been called. I'm probably missing something, but a straightforward reflection approach seems to work on my machine: >>> restrict() >>> readonly_facet = facet(counter, ['value']) >>> print readonly_facet.value() 0 >>> readonly_facet.value.im_self.n = "oops!" >>> print readonly_facet.value() oops! >>> class mycounter: ... def value(self): return "muhaha!" ... >>> readonly_facet.value.im_self.__class__ = mycounter >>> print readonly_facet.value() muhaha! ... >>> readonly_facet.value.im_func.func_globals["readonly_facet"] = myinstance ... and so on does that restrict() function really do the right thing, or is my python install broken? ___ Python-Dev mailing list [email protected] http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] Security capabilities in Python
Jp Calderone <[EMAIL PROTECTED]> writes: > Does using the gc module to bypass this security count? If so: > > [EMAIL PROTECTED]:~$ python -i facet.py > >>> import gc > >>> c = readonly_facet.__getattr__.func_closure[1] > >>> r = gc.get_referents(c)[0] > >>> r.n = 'hax0r3d' > >>> readonly_facet.value() > 'hax0r3d' > >>> > > This is the easiest way of which I know to bypass the use of cells > as a security mechanism. I believe there are other more involved > (and fragile, probably) ways, though. The funniest I know is part of PyPy: def extract_cell_content(c): """Get the value contained in a CPython 'cell', as read through the func_closure of a function object.""" # yuk! this is all I could come up with that works in Python 2.2 too class X(object): def __eq__(self, other): self.other = other x = X() x_cell, = (lambda: x).func_closure x_cell == c return x.other It would be unfortunate for PyPy (and IMHO, very un-pythonic) if this process became impossible. Cheers, mwh -- Java sucks. [...] Java on TV set top boxes will suck so hard it might well inhale people from off their sofa until their heads get wedged in the card slots. --- Jon Rabone, ucam.chat ___ Python-Dev mailing list [email protected] http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] threading (GilState) question
"Gregory P. Smith" <[EMAIL PROTECTED]> writes: >> > Under "Limitations and Exclusions" it specifically disowns >> > responsibility for worrying about whether Py_Initialize() and >> > PyEval_InitThreads() have been called: >> > >> [snip quote] >> >> This suggests that I should call PyEval_InitThreads() in >> initreadline(), which seems daft. > > fwiw, Modules/_bsddb.c does exactly that. Interesting. The problem with readline.c doing this is that it gets implicitly imported by the interpreter -- although only for interactive sessions. Maybe that's not that big a deal. I'd still prefer to change the functions (would updating the PEP be in order here? Obviously, I'd update the api documentation). Cheers, mwh -- It's relatively seldom that desire for sex is involved in technology procurement decisions. -- ESR at EuroPython 2002 ___ Python-Dev mailing list [email protected] http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] threading (GilState) question
On Apr 9, 2005, at 11:15 AM, Michael Hudson wrote: "Gregory P. Smith" <[EMAIL PROTECTED]> writes: Under "Limitations and Exclusions" it specifically disowns responsibility for worrying about whether Py_Initialize() and PyEval_InitThreads() have been called: [snip quote] This suggests that I should call PyEval_InitThreads() in initreadline(), which seems daft. fwiw, Modules/_bsddb.c does exactly that. Interesting. The problem with readline.c doing this is that it gets implicitly imported by the interpreter -- although only for interactive sessions. Maybe that's not that big a deal. I'd still prefer to change the functions (would updating the PEP be in order here? Obviously, I'd update the api documentation). Is there a good reason to *not* call PyEval_InitThreads when using a threaded Python? Sounds like it would just be easier to implicitly call it during Py_Initialize some day. -bob ___ Python-Dev mailing list [email protected] http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] Re: Security capabilities in Python
On Sat, 9 Apr 2005, Fredrik Lundh wrote: > Ka-Ping wrote: > > counter = Counter() > > readonly_facet = facet(counter, ['value']) > > > > If i've done this correctly, it should be impossible to alter the > > contents of the list or the counter, given only the immutable_facet > > or the readonly_facet, after restrict() has been called. > > I'm probably missing something, but a straightforward reflection > approach seems to work on my machine: That's funny. After i called restrict() Python didn't let me get im_self. >>> restrict() >>> readonly_facet.value > >>> readonly_facet.value.im_self Traceback (most recent call last): File "", line 1, in ? RuntimeError: restricted attribute >>> It doesn't matter if i make the facet before or after restrict(). >>> restrict() >>> rf2 = facet(counter, ['value']) >>> rf2.value > >>> rf2.value.im_self Traceback (most recent call last): File "", line 1, in ? RuntimeError: restricted attribute >>> I'm using Python 2.3 (#1, Sep 13 2003, 00:49:11) [GCC 3.3 20030304 (Apple Computer, Inc. build 1495)] on darwin -- ?!ng ___ Python-Dev mailing list [email protected] http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] Security capabilities in Python
On Apr 9, 2005, at 2:13 PM, Michael Hudson wrote: The funniest I know is part of PyPy: def extract_cell_content(c): """Get the value contained in a CPython 'cell', as read through the func_closure of a function object.""" # yuk! this is all I could come up with that works in Python 2.2 too class X(object): def __eq__(self, other): self.other = other x = X() x_cell, = (lambda: x).func_closure x_cell == c return x.other It would be unfortunate for PyPy (and IMHO, very un-pythonic) if this process became impossible. It would be quite fortunate if you didn't have to do all that, and cell just had a "value" attribute, though. James ___ Python-Dev mailing list [email protected] http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] Security capabilities in Python
On Sat, 9 Apr 2005, Jp Calderone wrote: > Does using the gc module to bypass this security count? If so: > > [EMAIL PROTECTED]:~$ python -i facet.py > >>> import gc > >>> c = readonly_facet.__getattr__.func_closure[1] > >>> r = gc.get_referents(c)[0] > >>> r.n = 'hax0r3d' > >>> readonly_facet.value() > 'hax0r3d' > >>> You can't get func_closure in restricted mode. (Or at least, i can't, using the Python included with Mac OS 10.3.8.) >>> restrict() >>> readonly_facet.__getattr__.func_closure Traceback (most recent call last): File "", line 1, in ? RuntimeError: restricted attribute >>> Even though this particular example doesn't work in restricted mode, it's true that the gc module violates capability discipline, and you would have to forbid its import. In any real use case, you would have to restrict imports anyway to prevent access to sys.modules or loading of arbitrary binaries. For a version that restricts imports, see: http://zesty.ca/python/facet.py Let me know if you figure out how to defeat that. (This is a fun exercise, but with a potential purpose -- it would be nice to have a coherent story on this for Python 3000, or maybe even Python 2.x.) -- ?!ng ___ Python-Dev mailing list [email protected] http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] Security capabilities in Python
On Sat, 9 Apr 2005, Michael Hudson wrote: > The funniest I know is part of PyPy: > > def extract_cell_content(c): > """Get the value contained in a CPython 'cell', as read through > the func_closure of a function object.""" > # yuk! this is all I could come up with that works in Python 2.2 too > class X(object): > def __eq__(self, other): > self.other = other > x = X() > x_cell, = (lambda: x).func_closure > x_cell == c > return x.other That's pretty amazing. > It would be unfortunate for PyPy (and IMHO, very un-pythonic) if this > process became impossible. Not a problem. func_closure is already a restricted attribute. IMHO, the clean way to do this is to provide a built-in function to get the cell content in a more direct and reliable way, and then put that in a separate module with other interpreter hacks. That both makes it easier to do stuff like this, and easier to prevent it simply by forbidding import of that module. -- ?!ng ___ Python-Dev mailing list [email protected] http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] Security capabilities in Python
Ka-Ping Yee wrote: On Sat, 9 Apr 2005, Jp Calderone wrote: Does using the gc module to bypass this security count? If so: [EMAIL PROTECTED]:~$ python -i facet.py >>> import gc >>> c = readonly_facet.__getattr__.func_closure[1] >>> r = gc.get_referents(c)[0] >>> r.n = 'hax0r3d' >>> readonly_facet.value() 'hax0r3d' >>> You can't get func_closure in restricted mode. (Or at least, i can't, using the Python included with Mac OS 10.3.8.) >>> restrict() >>> readonly_facet.__getattr__.func_closure Traceback (most recent call last): File "", line 1, in ? RuntimeError: restricted attribute >>> Even though this particular example doesn't work in restricted mode, it's true that the gc module violates capability discipline, and you would have to forbid its import. In any real use case, you would have to restrict imports anyway to prevent access to sys.modules or loading of arbitrary binaries. For a version that restricts imports, see: http://zesty.ca/python/facet.py Let me know if you figure out how to defeat that. you should probably search the list and look at my old attacks against restricted execution, there's reason why is not much supported anymore. One can still try to use it but needs to be extremely careful or use C defined proxies... etc. (This is a fun exercise, but with a potential purpose -- it would be nice to have a coherent story on this for Python 3000, or maybe even Python 2.x.) -- ?!ng ___ Python-Dev mailing list [email protected] http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/pedronis%40strakt.com ___ Python-Dev mailing list [email protected] http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] Security capabilities in Python
On Apr 9, 2005, at 5:37 PM, Ka-Ping Yee wrote:
Let me know if you figure out how to defeat that.
You can protect against this, too, but it does show that it's *really*
hard to get restricting code right...I'm of the opinion that it's not
really worth it -- you should just use OS protections.
untrusted_module.py:
class foostr(str):
def __eq__(self, other):
return True
def have_at_it(immutable_facet, readonly_facet):
getattr(immutable_facet, foostr('append'))(5)
print immutable_facet
James
___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe:
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] Security capabilities in Python
On Sat, 9 Apr 2005, James Y Knight wrote: > You can protect against this, too, but it does show that it's *really* > hard to get restricting code right... Good point. If you can't trust ==, then you're hosed. > I'm of the opinion that it's not > really worth it -- you should just use OS protections. This i disagree with, however. OS protections are a few orders of magnitude more heavyweight and vastly more error-prone than using a language with simple, clear semantics. Predictable code behaviour is good. -- ?!ng ___ Python-Dev mailing list [email protected] http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
