Mailing List Archive

rexec question
Hello again,
it seems that I did not really understand how to work with the rexec
module.
The problem is that I do not know how to access an object defined in
the *calling* namespace inside the r_exec/r_eval call like in the
following example:

import rexec

class foo:
def start(self):
print "foo running"


def rexectest():
o = foo()
filter = rexec.RExec()
filter.r_exec("o.start()")

>>> rexectest()
Traceback (innermost last):
File "<stdin>", line 1, in ?
File "rexecquestion.py", line 11, in rexectest
filter.r_exec("o.start()")
File "/wrk2/tele2/doering/gnu/lib/python1.5/rexec.py", line 253, in r_exec
exec code in m.__dict__
File "<string>", line 1, in ?
NameError: o


Any hints for a newbie?

Ralf
--
No sig -- no fun
rexec question [ In reply to ]
There are two completely seperate namespaces that come into play with
rexec. The first is the namespace of the "controlling code," i.e. the
part of your program that created the RExec. The second is the
namespace of the "controlled code," i.e. the code you're running
inside the RExec. Names defined in one namespace do not appear in the
other namespace.

If you want to names 'foo' or 'o' to be visible in the RExec, you need
to define them there. For example:

Python 1.5.2+ (#11, Jun 22 1999, 18:01:08) [C] on sunos5
Copyright 1991-1995 Stichting Mathematisch Centrum, Amsterdam
startup
>>> import rexec
>>> code = """class foo:
... def start(self):
... print "foo running"
...
... o = foo()
... o.start()
... """
>>>
>>> filter = rexec.RExec()
>>> filter.r_exec(code)
foo running
>>>


jeremy
rexec question [ In reply to ]
[.Just rememberer that the basic of using rexec are explained in Andrew
Kuchling's howto: http://www.python.org/doc/howto/rexec/rexec.html]

>>>>> "RD" == Ralf Doering <ralf.doering@Prakinf.TU-Ilmenau.DE> writes:

[near miss in my previous attempt to answer the question]

RD> Thanks for your response. Do yo see any way to get an *already*
RD> defined object into the namespace of rexec? The object we talk
RD> about will be unpickled from a byte stream and has to be
RD> executed in the restricted environment. So, how can I get this
RD> unpickled object into RExec and run it in this namespace? Seems
RD> that I`m a little confused about the namespaces and how to
RD> define entrys in RExec`s namespace ...

I should have answered this question from the outset. The restricted
execution environment is definitely more interesting when there are
objects defined in the controlling environment that are all accessible
in the restricted environment.

There is no direct way to add a name binding to the restricted
execution environment. You need to modify one of the modules that
exists in rexec, typically its __main__.

Here's a simple approach that would work:

class RExecEx(rexec.RExec):
"""Adds method for setting attribute in rexec environment"""
def setattr(self, name, value, bastion=1):
if bastion:
value = Bastion.Bastion(value)
setattr(self.modules['__main__'], name, value)

In most cases, you want to pass a Bastion to the untrusted code rather
than passing the object directly. The howto and the Bastion module
documentation explain this.

I've included a short script that illustrates the damage the untrusted
code can do if you don't use a bastion.

Jeremy



import rexec
import Bastion

class Foo:
_priveleged = 12

def bar(self):
return self._priveleged

spam = Foo()

untrusted_code = """print "Initial value:", spam.bar()
print "Attempting to read privleged attribute:",
try:
x = spam._priveleged
print "succeeded"
except AttributeError:
print "failed"
pass
print "Attempting to modify object:",
spam._priveleged = 15
if spam.bar() == 15:
print "internally modified",
else:
print "internally unmodified",
if spam._priveleged == 15:
print "externally modified"
else:
print "externally unmodified"
print "Final value:", spam.bar()
"""

renv = rexec.RExec()

print "Running user code with direct access to object"
setattr(renv.modules['__main__'], 'spam', spam)
renv.r_exec(untrusted_code)
print "Value outside rexec:", spam.bar()
print

spam = Foo()
print "Running user code with access through Bastion"
setattr(renv.modules['__main__'], 'spam', Bastion.Bastion(spam))
renv.r_exec(untrusted_code)
print "Value outside rexec:", spam.bar()
rexec question [ In reply to ]
Jeremy Hylton <jeremy@cnri.reston.va.us> writes:


[...]

THX again for the response. It does help me to understand what
happens, but I need a little bit more help to solve my problem.

> I should have answered this question from the outset. The restricted
> execution environment is definitely more interesting when there are
> objects defined in the controlling environment that are all accessible
> in the restricted environment.
>
> There is no direct way to add a name binding to the restricted
> execution environment. You need to modify one of the modules that
> exists in rexec, typically its __main__.
>
> Here's a simple approach that would work:
>
> class RExecEx(rexec.RExec):
> """Adds method for setting attribute in rexec environment"""
> def setattr(self, name, value, bastion=1):
> if bastion:
> value = Bastion.Bastion(value)
> setattr(self.modules['__main__'], name, value)
>
> In most cases, you want to pass a Bastion to the untrusted code rather
> than passing the object directly. The howto and the Bastion module
> documentation explain this.

OK, I made an "setattr" enhanced version of rexec like suggested.

To illustrate what I do not understand until now:

>>> class t:
... def t1(self):
... print "open is:", open
...
>>> r = RExecEx()
>>> r.r_exec("""print "open is", open""")
open is <method RExec.r_open of RExecEx instance at 1fa7e8>
>>> o = t()
>>> r.setattr("o",o)
>>> r.r_exec("o.t1()")
open is: <built-in function open>


The problem to import from the controlling environment to the
restricted environment is solved. However, the restricted execution of
the code of the "imported" object does not work like expected.
The call to o.t1() uses the builtin open function instead of r_open.
Please, can somebody enlighten me ...
Again, the problem is: I have got an object, which is unpickled from a
bytestream. A specific method of this object should be called and the
code should be executed in an restricted environment.

Ralf
--
No sig -- no fun