Re: Is it possible to get the erroneous variable when getting a NameError exception?

2009-12-26 Thread Stephen Hansen
On Sat, Dec 26, 2009 at 4:34 AM, Michael Fötsch  wrote:

> To explain, "().__class__.__base__.__subclasses__()" gives you a list of
> all object-derived classes, i.e., of *all* classes that exist in the
> surrounding program. If you can find just one class that allows you to do
> something subtle or dangerous, you're done.
>
>
Aiee, I forgot about that. I stand corrected. :)

Okay, I'll go back to the 'eval is almost never what you wanna do' camp
again :)

--S
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Is it possible to get the erroneous variable when getting a NameError exception?

2009-12-26 Thread Dotan Barak



A simple expression is enough to write to files, for example.

Try this expression in Python 3.0:

   [x for x in ().__class__.__base__.__subclasses__() if x.__name__ == 
'_FileIO'][0]('hello.txt', 'w').write('Hello, World!')



To explain, "().__class__.__base__.__subclasses__()" gives you a list 
of all object-derived classes, i.e., of *all* classes that exist in 
the surrounding program. If you can find just one class that allows 
you to do something subtle or dangerous, you're done.


See also:
- "Controlling Access to Resources Within The Python Interpreter" 
(http://people.cs.ubc.ca/~drifty/papers/python_security.pdf)

- http://evoque.gizmojo.org/usage/restricted/



To write your own restricted expression parser, the standard module 
"ast" is quite useful. For example, ast.parse("my_number < 10") gives 
you a syntax tree similar to this:


  ast.Expr(ast.Compare(ops=[ast.Lt], left=ast.Name(id="my_number"), 
comparators=[ast.Num(n=10)]))


From there, you can implement your own logic to traverse the tree, 
which gives you very fine-grained control over the kinds of 
expressions to allow, where to look up variable names, how to react to 
errors, etc.



Kind Regards,
M.F.

Hi all.

First of all, thank you very much for your response.

The answers I got made me think if I'm trying to solve a problem because 
of the way I'm doing things;
I tried to evaluate a string that a user supplied to me and try to get 
the various python exceptions to

make the user understand what was his error.

My original idea was to get the bad symbol, and print the user a more 
"friendly" error message.


I think that the direction that Michael showed me is better, and It is a 
better solution
(maybe, first I need to traverse the tree, give the right error 
messages  and only then execute the eval).


Thanks!!!
Dotan

--
http://mail.python.org/mailman/listinfo/python-list


Re: Is it possible to get the erroneous variable when getting a NameError exception?

2009-12-26 Thread Michael Fötsch

Stephen Hansen wrote:

Dotan Barak wrote:


... eval("my_number < 10", {"__builtins__":None}, {})


Hm, is this true, though? Is there anything subtle or dangerous possible 
here? He's using eval-- so no statements, its only an expression. He's 
passing in a 'globals' which has __builtins__ set to None, so this 
environment has access to -- basically nothing. Then the locals 
dictionary is empty as well, though I assume he'll fill it with things 
like my_number.


A simple expression is enough to write to files, for example.

Try this expression in Python 3.0:

   [x for x in ().__class__.__base__.__subclasses__() if x.__name__ == 
'_FileIO'][0]('hello.txt', 'w').write('Hello, World!')



To explain, "().__class__.__base__.__subclasses__()" gives you a list of 
all object-derived classes, i.e., of *all* classes that exist in the 
surrounding program. If you can find just one class that allows you to 
do something subtle or dangerous, you're done.


See also:
- "Controlling Access to Resources Within The Python Interpreter" 
(http://people.cs.ubc.ca/~drifty/papers/python_security.pdf)

- http://evoque.gizmojo.org/usage/restricted/



To write your own restricted expression parser, the standard module 
"ast" is quite useful. For example, ast.parse("my_number < 10") gives 
you a syntax tree similar to this:


  ast.Expr(ast.Compare(ops=[ast.Lt], left=ast.Name(id="my_number"), 
comparators=[ast.Num(n=10)]))


From there, you can implement your own logic to traverse the tree, 
which gives you very fine-grained control over the kinds of expressions 
to allow, where to look up variable names, how to react to errors, etc.



Kind Regards,
M.F.
--
http://mail.python.org/mailman/listinfo/python-list


Re: Is it possible to get the erroneous variable when getting a NameError exception?

2009-12-25 Thread Stephen Hansen
On Fri, Dec 25, 2009 at 8:00 PM, Dave Angel  wrote:

>  Dotan Barak wrote:
>>>
>>> Recover the exception, and examine the tuple of args or the message
>>> string.
>>> >>> try:
>>> ... eval("my_number < 10", {"__builtins__":None}, {})
>>> ... except NameError,e:
>>> ... print e.args
>>> ... print e.message
>>> ...
>>> ("name 'my_number' is not defined",)
>>> name 'my_number' is not defined
>>>
>>>  I think there's a more fundamental question here.  You're apparently
> looking to build your own error message instead of using the one already
> generated.  But as you point out, you might end up parsing the existing
> error message in order to do that, and that's fragile coding.  My take is
> that if you're using "eval" in your code, your user is clearly a programmer.
>  So why are you not letting that programmer see the real error message,
> instead of trying to pretty it up?  You can add to the message, but
> shouldn't need to hide the original one.
>
> To put it the other way around, if your user can't understand the python
> error messages, you should probably not be using unrestricted "eval" on
> something that user supplies.  Lots more errors than NameError, and many of
> them are more subtle and dangerous.
>
>
Hm, is this true, though? Is there anything subtle or dangerous possible
here? He's using eval-- so no statements, its only an expression. He's
passing in a 'globals' which has __builtins__ set to None, so this
environment has access to -- basically nothing. Then the locals dictionary
is empty as well, though I assume he'll fill it with things like my_number.

Its sort of an interesting use for 'eval' that I hadn't ever considered
before, really: ISTM that there's only three possible results.. a NameError,
a SyntaxError, or a safely evaluated expression based on certain pre-defined
objects. Okay, maybe one or two other simple exceptions if one tries to do
strange things with dictionaries/etc in the expression. You can't even make
it blow up to trigger a MemoryError, with some insane list comprehension
because you don't even have access to range(). Unless he's passing an
arbitrarily long string into the expression.

I'm normally against eval -- but maybe I'm blind in not seeing the possible
exploit or subtlety here in this eval-with-zero-access.

--S
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Is it possible to get the erroneous variable when getting a NameError exception?

2009-12-25 Thread Dave Angel

Dotan Barak wrote:
On 
25/12/2009 19:27, Gary Herron wrote:

Dotan Barak wrote:

Recover the exception, and examine the tuple of args or the message 
string.

>>> try:
... eval("my_number < 10", {"__builtins__":None}, {})
... except NameError,e:
... print e.args
... print e.message
...
("name 'my_number' is not defined",)
name 'my_number' is not defined


First of all, thank - I really appreciate your response.
:)

I must admit that i don't like the idea of parsing a string (if 
tomorrow the format of the message will change,

i will be in a deep trouble ...).

Is there is another way which doesn't involve string parsing?

Thanks
Dotan



I think there's a more fundamental question here.  You're apparently 
looking to build your own error message instead of using the one already 
generated.  But as you point out, you might end up parsing the existing 
error message in order to do that, and that's fragile coding.  My take 
is that if you're using "eval" in your code, your user is clearly a 
programmer.  So why are you not letting that programmer see the real 
error message, instead of trying to pretty it up?  You can add to the 
message, but shouldn't need to hide the original one.


To put it the other way around, if your user can't understand the python 
error messages, you should probably not be using unrestricted "eval" on 
something that user supplies.  Lots more errors than NameError, and many 
of them are more subtle and dangerous.


DaveA

--
http://mail.python.org/mailman/listinfo/python-list


Re: Is it possible to get the erroneous variable when getting a NameError exception?

2009-12-25 Thread Gary Herron

Dotan Barak wrote:

On 25/12/2009 19:27, Gary Herron wrote:

Dotan Barak wrote:

Recover the exception, and examine the tuple of args or the message 
string.

>>> try:
... eval("my_number < 10", {"__builtins__":None}, {})
... except NameError,e:
... print e.args
... print e.message
...
("name 'my_number' is not defined",)
name 'my_number' is not defined


First of all, thank - I really appreciate your response.
:)

I must admit that i don't like the idea of parsing a string (if 
tomorrow the format of the message will change,

i will be in a deep trouble ...).

Is there is another way which doesn't involve string parsing?

Thanks
Dotan
OK.  Try this:  Executing your code attempts to lookup variables in a 
local dictionary.   You can rig up a local dictionary of your own 
choosing -- in this case, I have it print the name of any variable that 
is being looked up before actually doing the lookup.But at that 
point, you have what you want, that is, the name as a string -- you can 
do with it as you will -- record it, or print your nice error, or ...


You probably want to change my def of __getitem__ to attempt the lookup 
first -- if that succeeds, return the value -- if it fails, then handle 
the error.


Good luck,

Gary Herron



class D(dict):
   def __getitem__(self, name):
   print 'retrieving', name
   return dict.__getitem__(self,name)

locals = D(b=123) # Defines b in a local dictionary
exec("a=2*b", locals)  # Looks up b in locals
print locals['a'] # Returns the result (stored in 'a' in locals)

locals = D() # Does not define b in the local dictionary
exec("a=2*b", locals) # Fails to find b in locals

--
http://mail.python.org/mailman/listinfo/python-list


Re: Is it possible to get the erroneous variable when getting a NameError exception?

2009-12-25 Thread Dotan Barak

On 25/12/2009 19:27, Gary Herron wrote:

Dotan Barak wrote:

Recover the exception, and examine the tuple of args or the message 
string.

>>> try:
... eval("my_number < 10", {"__builtins__":None}, {})
... except NameError,e:
... print e.args
... print e.message
...
("name 'my_number' is not defined",)
name 'my_number' is not defined


First of all, thank - I really appreciate your response.
:)

I must admit that i don't like the idea of parsing a string (if tomorrow 
the format of the message will change,

i will be in a deep trouble ...).

Is there is another way which doesn't involve string parsing?

Thanks
Dotan
--
http://mail.python.org/mailman/listinfo/python-list


Re: Is it possible to get the erroneous variable when getting a NameError exception?

2009-12-25 Thread Gary Herron

Dotan Barak wrote:

Hi.

I'm trying to evaluate a string and getting a NameError
(it is expected, since the variable my_number wasn't provided in the 
"locals" dictionary).


<--snip start-->
>>> eval("my_number < 10", {"__builtins__":None}, {})
Traceback (most recent call last):
  File "", line 1, in ?
  File "", line 0, in ?
NameError: name 'my_number' is not defined
<--snip end-->

My question is: how can i know which variable name / symbol causes the 
NameError exception?

In my example, this symbol is my_number.

Using that information, I will be able to print a nice error message 
to the user.



Thanks
Dotan




Recover the exception, and examine the tuple of args or the message string.
>>> try:
... eval("my_number < 10", {"__builtins__":None}, {})
... except NameError,e:
... print e.args
... print e.message
...
("name 'my_number' is not defined",)
name 'my_number' is not defined

--
http://mail.python.org/mailman/listinfo/python-list


Re: Is it possible to get the erroneous variable when getting a NameError exception?

2009-12-25 Thread Steven D'Aprano
On Fri, 25 Dec 2009 17:29:48 +0200, Dotan Barak wrote:

> Hi.
> 
> I'm trying to evaluate a string and getting a NameError (it is expected,
> since the variable my_number wasn't provided in the "locals"
> dictionary).
> 
> <--snip start-->
>  >>> eval("my_number < 10", {"__builtins__":None}, {})
> Traceback (most recent call last):
>File "", line 1, in ?
>File "", line 0, in ?
> NameError: name 'my_number' is not defined
> <--snip end-->
> 
> My question is: how can i know which variable name / symbol causes the
> NameError exception?
> In my example, this symbol is my_number.
> 
> Using that information, I will be able to print a nice error message to
> the user.

You mean just like the error message that Python already prints?

NameError: name 'my_number' is not defined

Don't waste your time re-inventing the wheel. But if you do insist on 
reinventing the wheel, here are some tools to help you:

try:
my_number
except NameError, e:
print str(e)
print type(e)
print e.args


-- 
Steven
-- 
http://mail.python.org/mailman/listinfo/python-list


Is it possible to get the erroneous variable when getting a NameError exception?

2009-12-25 Thread Dotan Barak

Hi.

I'm trying to evaluate a string and getting a NameError
(it is expected, since the variable my_number wasn't provided in the 
"locals" dictionary).


<--snip start-->
>>> eval("my_number < 10", {"__builtins__":None}, {})
Traceback (most recent call last):
  File "", line 1, in ?
  File "", line 0, in ?
NameError: name 'my_number' is not defined
<--snip end-->

My question is: how can i know which variable name / symbol causes the 
NameError exception?

In my example, this symbol is my_number.

Using that information, I will be able to print a nice error message to 
the user.



Thanks
Dotan


--
http://mail.python.org/mailman/listinfo/python-list