[Python-Dev] Challenge: Please break this! (was: Reviving restricted mode)

2009-02-23 Thread tav
Hey all,

As an attempt to convince everyone of the merits of my functions-based
approach to security, I've come up with a simple challenge. I've
attached it as safelite.py

The challenge is simple:

* Open a fresh Python interpreter
* Do:  from safelite import FileReader
* You can use FileReader to read files on your filesystem
* Now find a way to *write* to the filesystem from your interpreter

Please note that the aim of this isn't to protect Python against
crashes/segfaults or exhaustion of resources attacks, so those don't
count.

I'm keen to know your experiences even if you don't manage to write to
the filesystem -- and especially if you do!

Dinner and drinks on me for an evening -- when you are next in London
or I am in your town -- to the first person who manages to break
safelite.py and write to the filesystem.

Good luck and thanks! =)

 If you block __closure__ and __globals__ on function objects you will get a
 semblance of a private namespace. That way you might (I have not thought
 this one through like securing the interpreter for embedding) be able to get
 what you need to safely pass in Python code through the globals of the code
 being executed.

Brett, this is exactly what I do. You also need to restrict func_code.
The patch is simply for closing the other loopholes:
type.__subclasses__, GeneratorType.gi_frame and gi_code. All possible
in a patch of 6 lines of code thanks to Python's existing restricted
framework in the interpreter.

Please review and accept =)

* http://codereview.appspot.com/20051
* http://codereview.appspot.com/21051

Thanks!

-- 
love, tav

plex:espians/tav | t...@espians.com | +44 (0) 7809 569 369
http://tav.espians.com | @tav | skype:tavespian

Please try and break this.

On a fresh Python interpreter, do the following:

   from safelite import FileReader

You should now be able to read files as you want...

Now, please try and *write* to a file on the filesystem from within the
interpreter.

Please note that the aim of this isn't to protect Python against segfaults or
exhaustion of resources attacks, so those don't count.

Let me know t...@espians.com or Python-Dev how your experience goes -- whether
this seems to work for you or not. Thanks!



import __builtin__
import sys

from sys import _getframe as get_frame
from types import FunctionType, GeneratorType

__all__ = ['FileReader']

# --
# map funktion attribute names for python versions = 2.6
# --

FUNCTION_PY26_ATTRS = {
'func_code': '__code__',
'func_globals': '__globals__',
'func_closure': '__closure__'
}

# --
# sekure the interpreter!
# --

def secure_python():
Remove insecure variables from the Python interpreter.

from ctypes import pythonapi, POINTER, py_object

get_dict = pythonapi._PyObject_GetDictPtr
get_dict.restype = POINTER(py_object)
get_dict.argtypes = [py_object]

def dictionary_of(ob):
dptr = get_dict(ob)
if dptr and dptr.contents:
return dptr.contents.value

if sys.version_info = (3, 0):
py_version = 2
elif sys.version_info = (2, 6):
py_version = 1
else:
py_version = 0

for attr in FUNCTION_PY26_ATTRS.keys():
if py_version = 1:
del dictionary_of(FunctionType)[attr]
if py_version = 1:
del dictionary_of(FunctionType)[FUNCTION_PY26_ATTRS[attr]]

del dictionary_of(type)['__subclasses__']
del dictionary_of(GeneratorType)['gi_frame']

if py_version:
del dictionary_of(GeneratorType)['gi_code']

def secure_python_builtins():
Remove dangerous builtins like ``file`` and patch appropriately.

for item in ['open', 'file', 'execfile']:
del __builtin__.__dict__[item]

def null(*args, **kwargs):
pass

import linecache
linecache.open = FileReader

import site
site.file = FileReader

__builtin__.__import__ = null

# --
# pseudo-klass-like namespase wrapper
# --

class NamespaceContext(type):
A Namespace Context metaclass.

def __call__(klass, __getter):
for name, obj in __getter:
setattr(klass, name, obj)
return type.__call__(klass, __getter)

def __str__(klass):
return 'NamespaceContext%s' % (tuple(klass.__dict__.keys()),)

def _Namespace():

__private_data = {}

def Namespace(*args, **kwargs):
Return a Namespace from the current scope or the given arguments.

class NamespaceObject(tuple):

__metaclass__ = NamespaceContext
__slots__ = ()


Re: [Python-Dev] Challenge: Please break this! (was: Reviving restricted mode)

2009-02-23 Thread Brett Cannon
On Mon, Feb 23, 2009 at 12:10, tav t...@espians.com wrote:

 Hey all,

 As an attempt to convince everyone of the merits of my functions-based
 approach to security, I've come up with a simple challenge. I've
 attached it as safelite.py

 The challenge is simple:

 * Open a fresh Python interpreter
 * Do:  from safelite import FileReader
 * You can use FileReader to read files on your filesystem
 * Now find a way to *write* to the filesystem from your interpreter

 Please note that the aim of this isn't to protect Python against
 crashes/segfaults or exhaustion of resources attacks, so those don't
 count.

 I'm keen to know your experiences even if you don't manage to write to
 the filesystem -- and especially if you do!

 Dinner and drinks on me for an evening -- when you are next in London
 or I am in your town -- to the first person who manages to break
 safelite.py and write to the filesystem.

 Good luck and thanks! =)

  If you block __closure__ and __globals__ on function objects you will get
 a
  semblance of a private namespace. That way you might (I have not thought
  this one through like securing the interpreter for embedding) be able to
 get
  what you need to safely pass in Python code through the globals of the
 code
  being executed.

 Brett, this is exactly what I do.


Ah, OK. I just quickly looked at your patches on codereview and noticed that
neither __closure__ or __globals__  have been touched.


 You also need to restrict func_code.


I assume you are worried about getting a hold of the code type and
constructing code objects from scratch?



 The patch is simply for closing the other loopholes:
 type.__subclasses__, GeneratorType.gi_frame and gi_code. All possible
 in a patch of 6 lines of code thanks to Python's existing restricted
 framework in the interpreter.

 Please review and accept =)


I personally don't have the time. The feedback in this email is all I can
spare.

-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


Re: [Python-Dev] Challenge: Please break this! (was: Reviving restricted mode)

2009-02-23 Thread tav
Hey Brett,

 Ah, OK. I just quickly looked at your patches on codereview and noticed that
 neither __closure__ or __globals__  have been touched.

Those are already restricted by Python when __builtins__ is not the
same as the standard one.

 I assume you are worried about getting a hold of the code type and
 constructing code objects from scratch?

Right. And, func_code is restricted too so didn't need any additional support.

 Please review and accept =)

 I personally don't have the time. The feedback in this email is all I can
 spare.

That's cool -- thanks for this much!

I'm hoping someone out there has a few spare minutes.

The patch is just 6 lines of code...

Someone? Pretty please? =)

-- 
love, tav

plex:espians/tav | t...@espians.com | +44 (0) 7809 569 369
http://tav.espians.com | @tav | skype:tavespian
___
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


Re: [Python-Dev] Challenge: Please break this! (was: Reviving restricted mode)

2009-02-23 Thread Steven Bethard
On Mon, Feb 23, 2009 at 12:10 PM, tav t...@espians.com wrote:
 Hey all,

 As an attempt to convince everyone of the merits of my functions-based
 approach to security, I've come up with a simple challenge. I've
 attached it as safelite.py

 The challenge is simple:

 * Open a fresh Python interpreter
 * Do:  from safelite import FileReader
 * You can use FileReader to read files on your filesystem
 * Now find a way to *write* to the filesystem from your interpreter

If you really want people to try and break it, I suggest you send it
to c.l.py - there are load of people there with too much time on their
hands. ;-)

Steve
-- 
I'm not *in*-sane. Indeed, I am so far *out* of sane that you appear a
tiny blip on the distant coast of sanity.
--- Bucky Katt, Get Fuzzy
___
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


Re: [Python-Dev] Challenge: Please break this! (was: Reviving restricted mode)

2009-02-23 Thread Guido van Rossum
I sent a link out to Twitter...

On Mon, Feb 23, 2009 at 12:40 PM, Steven Bethard
steven.beth...@gmail.com wrote:
 On Mon, Feb 23, 2009 at 12:10 PM, tav t...@espians.com wrote:
 Hey all,

 As an attempt to convince everyone of the merits of my functions-based
 approach to security, I've come up with a simple challenge. I've
 attached it as safelite.py

 The challenge is simple:

 * Open a fresh Python interpreter
 * Do:  from safelite import FileReader
 * You can use FileReader to read files on your filesystem
 * Now find a way to *write* to the filesystem from your interpreter

 If you really want people to try and break it, I suggest you send it
 to c.l.py - there are load of people there with too much time on their
 hands. ;-)

 Steve
 --
 I'm not *in*-sane. Indeed, I am so far *out* of sane that you appear a
 tiny blip on the distant coast of sanity.
--- Bucky Katt, Get Fuzzy




-- 
--Guido van Rossum (home page: http://www.python.org/~guido/)
___
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


Re: [Python-Dev] Challenge: Please break this! (was: Reviving restricted mode)

2009-02-23 Thread Victor Stinner
 The challenge is simple:

 * Open a fresh Python interpreter
 * Do:  from safelite import FileReader
 * You can use FileReader to read files on your filesystem
 * Now find a way to *write* to the filesystem from your interpreter

Well, the challenge is to get access to a module. And... it's quite simple :-p

$ ./python
 from safelite import FileReader
 __builtins__.file
Traceback (most recent call last):
  File stdin, line 1, in module
AttributeError: 'module' object has no attribute 'file'
 reload(__builtins__)
module '__builtin__' (built-in)
 file('0wn3d', 'w').write('w00t\n')

$ cat 0wn3d
w00t

 Dinner and drinks on me for an evening -- when you are next in London
 or I am in your town -- to the first person who manages to break
 safelite.py and write to the filesystem.

Cool. It's a good reason to go to Pycon UK this yeak ;-)

-- 
Victor Stinner aka haypo
http://www.haypocalc.com/blog/
___
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


Re: [Python-Dev] Challenge: Please break this! (was: Reviving restricted mode)

2009-02-23 Thread tav
Woo!

  victor  file('0wn3d', 'w').write('w00t\n')
  victor Cool. It's a good reason to go to Pycon UK this yeak ;-)

Thank you so much Victor! Please mail/phone me when you are heading to
London and I shall honour the evening out!

Now, how about this adapted version without reload?

I could make life much easier for myself by just removing all builtins
except the fundamental types, but this is way more interesting!!

Please continue the challenge the same as before, but with the new safelite.py

  steven If you really want people to try and break it, I
  steven suggest you send it to c.l.py

Done.

-- 
love, tav

plex:espians/tav | t...@espians.com | +44 (0) 7809 569 369
http://tav.espians.com | http://twitter.com/tav | skype:tavespian

Please try and break this.

On a fresh Python interpreter, do the following:

   from safelite import FileReader

You should now be able to read files as you want...

Now, please try and *write* to a file on the filesystem from within the
interpreter.

Please note that the aim of this isn't to protect Python against segfaults or
exhaustion of resources attacks, so those don't count.

Let me know t...@espians.com or Python-Dev how your experience goes -- whether
this seems to work for you or not. Thanks!



import __builtin__
import sys

from sys import _getframe as get_frame
from types import FunctionType, GeneratorType

__all__ = ['FileReader']

# --
# map funktion attribute names for python versions = 2.6
# --

FUNCTION_PY26_ATTRS = {
'func_code': '__code__',
'func_globals': '__globals__',
'func_closure': '__closure__'
}

# --
# sekure the interpreter!
# --

def secure_python():
Remove insecure variables from the Python interpreter.

from ctypes import pythonapi, POINTER, py_object

get_dict = pythonapi._PyObject_GetDictPtr
get_dict.restype = POINTER(py_object)
get_dict.argtypes = [py_object]

def dictionary_of(ob):
dptr = get_dict(ob)
if dptr and dptr.contents:
return dptr.contents.value

if sys.version_info = (3, 0):
py_version = 2
elif sys.version_info = (2, 6):
py_version = 1
else:
py_version = 0

for attr in FUNCTION_PY26_ATTRS.keys():
if py_version = 1:
del dictionary_of(FunctionType)[attr]
if py_version = 1:
del dictionary_of(FunctionType)[FUNCTION_PY26_ATTRS[attr]]

del dictionary_of(type)['__subclasses__']
del dictionary_of(GeneratorType)['gi_frame']

if py_version:
del dictionary_of(GeneratorType)['gi_code']

def secure_python_builtins():
Remove dangerous builtins like ``file`` and patch appropriately.

# thanks Victor Stinner!

for item in ['open', 'file', 'execfile', 'reload']:
del __builtin__.__dict__[item]

def null(*args, **kwargs):
pass

import linecache
linecache.open = FileReader

import site
site.file = FileReader

__builtin__.__import__ = null

# --
# pseudo-klass-like namespase wrapper
# --

class NamespaceContext(type):
A Namespace Context metaclass.

def __call__(klass, __getter):
for name, obj in __getter:
setattr(klass, name, obj)
return type.__call__(klass, __getter)

def __str__(klass):
return 'NamespaceContext%s' % (tuple(klass.__dict__.keys()),)

def _Namespace():

__private_data = {}

def Namespace(*args, **kwargs):
Return a Namespace from the current scope or the given arguments.

class NamespaceObject(tuple):

__metaclass__ = NamespaceContext
__slots__ = ()

def __new__(klass, __getter):
return tuple.__new__(klass, __getter)

ns_items = []; populate = ns_items.append

if args or kwargs:

frame = None

for arg in args:
kwargs[arg.__name__] = arg

for name, obj in kwargs.iteritems():
if isinstance(obj, FunctionType):
populate((name, staticmethod(obj)))
else:
populate((name, obj))

else:

frame = get_frame(1)

for name, obj in frame.f_locals.iteritems():
if isinstance(obj, FunctionType):
if not (name.startswith('_') and not name.startswith('__')):
populate((name, staticmethod(obj)))
elif name.startswith('__') and name.endswith('__'):
populate((name, obj))

del frame, args, kwargs

 

Re: [Python-Dev] Challenge: Please break this! (was: Reviving restricted mode)

2009-02-23 Thread Guido van Rossum
On Mon, Feb 23, 2009 at 1:12 PM, Victor Stinner
victor.stin...@haypocalc.com wrote:
 The challenge is simple:

 * Open a fresh Python interpreter
 * Do:  from safelite import FileReader
 * You can use FileReader to read files on your filesystem
 * Now find a way to *write* to the filesystem from your interpreter

 Well, the challenge is to get access to a module. And... it's quite simple :-p

 $ ./python
 from safelite import FileReader
 __builtins__.file
 Traceback (most recent call last):
  File stdin, line 1, in module
 AttributeError: 'module' object has no attribute 'file'
 reload(__builtins__)
 module '__builtin__' (built-in)
 file('0wn3d', 'w').write('w00t\n')

 $ cat 0wn3d
 w00t

 Dinner and drinks on me for an evening -- when you are next in London
 or I am in your town -- to the first person who manages to break
 safelite.py and write to the filesystem.

 Cool. It's a good reason to go to Pycon UK this yeak ;-)

Tav should have made another stipulation: the attack must not be
trivial to fix. This one seems trivial, e.g. by adding 'reload' to the
list in secure_python_builtins().

-- 
--Guido van Rossum (home page: http://www.python.org/~guido/)
___
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


Re: [Python-Dev] Challenge: Please break this! (was: Reviving restricted mode)

2009-02-23 Thread Guido van Rossum
On Mon, Feb 23, 2009 at 1:36 PM, Guido van Rossum gu...@python.org wrote:
 On Mon, Feb 23, 2009 at 1:12 PM, Victor Stinner
 victor.stin...@haypocalc.com wrote:
 The challenge is simple:

 * Open a fresh Python interpreter
 * Do:  from safelite import FileReader
 * You can use FileReader to read files on your filesystem
 * Now find a way to *write* to the filesystem from your interpreter

 Well, the challenge is to get access to a module. And... it's quite simple 
 :-p

 $ ./python
 from safelite import FileReader
 __builtins__.file
 Traceback (most recent call last):
  File stdin, line 1, in module
 AttributeError: 'module' object has no attribute 'file'
 reload(__builtins__)
 module '__builtin__' (built-in)
 file('0wn3d', 'w').write('w00t\n')

 $ cat 0wn3d
 w00t

 Dinner and drinks on me for an evening -- when you are next in London
 or I am in your town -- to the first person who manages to break
 safelite.py and write to the filesystem.

 Cool. It's a good reason to go to Pycon UK this yeak ;-)

 Tav should have made another stipulation: the attack must not be
 trivial to fix. This one seems trivial, e.g. by adding 'reload' to the
 list in secure_python_builtins().

I take it back, we need to find all the trivial ones too.

BTW Tav, you ought to create a small website for this challenge. A
blog post or wiki page would suffice.

-- 
--Guido van Rossum (home page: http://www.python.org/~guido/)
___
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


Re: [Python-Dev] Challenge: Please break this! (was: Reviving restricted mode)

2009-02-23 Thread Victor Stinner
Le Monday 23 February 2009 22:36:47, vous avez écrit :
  reload(__builtins__)
 (...)

 Tav should have made another stipulation: the attack must not be
 trivial to fix.

Why not? Any hole is enough to break a jail. The cracker doesn't care if it's 
trivial to fix or not :-p

-- 
Victor Stinner aka haypo
http://www.haypocalc.com/blog/
___
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


Re: [Python-Dev] Challenge: Please break this! (was: Reviving restricted mode)

2009-02-23 Thread Farshid Lashkari
It seems like some code in safelite passes a file object to
isinstance. By overriding the builtin isinstance function I can get
access to the original file object and create a new one. Here is the
code I used:

from safelite import FileReader

_real_file = None

def _new_isinstance(obj,types):
global _real_file
if _real_file is None and obj.__class__.__name__ == 'file':
_real_file = obj.__class__
return _old_isinstance(obj,types)

_old_isinstance = __builtins__.isinstance
__builtins__.isinstance = _new_isinstance

FileReader('nul')

f = _real_file('foo.txt','w')
f.write('hello')
f.close()

-Farshid


On Mon, Feb 23, 2009 at 12:10 PM, tav t...@espians.com wrote:
 Hey all,

 As an attempt to convince everyone of the merits of my functions-based
 approach to security, I've come up with a simple challenge. I've
 attached it as safelite.py

 The challenge is simple:

 * Open a fresh Python interpreter
 * Do:  from safelite import FileReader
 * You can use FileReader to read files on your filesystem
 * Now find a way to *write* to the filesystem from your interpreter

 Please note that the aim of this isn't to protect Python against
 crashes/segfaults or exhaustion of resources attacks, so those don't
 count.

 I'm keen to know your experiences even if you don't manage to write to
 the filesystem -- and especially if you do!

 Dinner and drinks on me for an evening -- when you are next in London
 or I am in your town -- to the first person who manages to break
 safelite.py and write to the filesystem.

 Good luck and thanks! =)

 If you block __closure__ and __globals__ on function objects you will get a
 semblance of a private namespace. That way you might (I have not thought
 this one through like securing the interpreter for embedding) be able to get
 what you need to safely pass in Python code through the globals of the code
 being executed.

 Brett, this is exactly what I do. You also need to restrict func_code.
 The patch is simply for closing the other loopholes:
 type.__subclasses__, GeneratorType.gi_frame and gi_code. All possible
 in a patch of 6 lines of code thanks to Python's existing restricted
 framework in the interpreter.

 Please review and accept =)

 * http://codereview.appspot.com/20051
 * http://codereview.appspot.com/21051

 Thanks!

 --
 love, tav

 plex:espians/tav | t...@espians.com | +44 (0) 7809 569 369
 http://tav.espians.com | @tav | skype:tavespian

 ___
 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/flashk%40gmail.com


___
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


Re: [Python-Dev] Challenge: Please break this! (was: Reviving restricted mode)

2009-02-23 Thread Antoine Pitrou
Farshid Lashkari flashk at gmail.com writes:
 
 It seems like some code in safelite passes a file object to
 isinstance. By overriding the builtin isinstance function I can get
 access to the original file object and create a new one. Here is the
 code I used:

I guess Tav should open a restaurant :-)



___
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


Re: [Python-Dev] Challenge: Please break this! (was: Reviving restricted mode)

2009-02-23 Thread Victor Stinner
Le Tuesday 24 February 2009 00:51:25 Farshid Lashkari, vous avez écrit :
 It seems like some code in safelite passes a file object to
 isinstance. By overriding the builtin isinstance function I can get
 access to the original file object and create a new one.

Wow, excellent idea!

-- 
Victor Stinner aka haypo
http://www.haypocalc.com/blog/
___
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


Re: [Python-Dev] Challenge: Please break this! (was: Reviving restricted mode)

2009-02-23 Thread Guido van Rossum
On Mon, Feb 23, 2009 at 4:06 PM, Victor Stinner
victor.stin...@haypocalc.com wrote:
 Le Tuesday 24 February 2009 00:51:25 Farshid Lashkari, vous avez écrit :
 It seems like some code in safelite passes a file object to
 isinstance. By overriding the builtin isinstance function I can get
 access to the original file object and create a new one.

 Wow, excellent idea!

I think in the next version Tav will have to stop the sharing of
__builtins__ between the supervisor and the sandboxed code. There are
too many tricks you can play with this.

-- 
--Guido van Rossum (home page: http://www.python.org/~guido/)
___
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


Re: [Python-Dev] Challenge: Please break this! (was: Reviving restricted mode)

2009-02-23 Thread tav
Hey all,

  victor Could you keep all versions of safelite.py?

I took Steven D'Aprano's advice and added a VERSION attribute and
state the latest version on
http://tav.espians.com/a-challenge-to-break-python-security.html

Is that okay?

  antoine I guess Tav should open a restaurant :-)

Hehe!! Thankfully I only offered to it to the first person *phew!*

  farshid It seems like some code in safelite passes
  farshid a file object to isinstance. By overriding the
  farshid builtin isinstance function I can get access to
  frashid the original file object and create a new one.

Farshid, this is beautiful!!!

Thank you -- it's very nicely done!!

Do you have a website I could link to from the blog article?

  guido I think in the next version Tav will have to stop
  guido the sharing of __builtins__ between the supervisor
  guido and the sandboxed code. There are too many
  guido tricks you can play with this.

Done.

The common pattern that arised out of the various
builtins-overriding-hacks is that safe code should *never* make
assumptions about the state of the globals. The use of closures seems
to fix this problem with an easily-auditable design pattern.

-- 
love, tav

plex:espians/tav | t...@espians.com | +44 (0) 7809 569 369
http://tav.espians.com | http://twitter.com/tav | skype:tavespian
___
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