[Python-ideas] A limited exec

Laurens Van Houtven _ at lvh.io
Fri Jul 19 10:19:00 CEST 2013


On Fri, Jul 19, 2013 at 9:43 AM, Hua Lu <gotoalanlu at gmail.com> wrote:

> Hey Laurens,
>
> Thanks for the feedback. I am still waiting for NumPy in PyPy mostly. I
> know this blacklist approach is a losing battle, but for the time being,
> maybe it could be of value?
>

Maybe :) I just wouldn't put any money on it just because I haven't figured
out how to break it yet, since, historically, like you implied, every time
we've tried it it didn't actually work :)

Do you need NumPy + PyPy for you to be able to switch *entirely* to PyPy,
or do you actually need it for the things that would do safe eval?

A different approach that someone in #python has used with some success is
running the interpreter in Qemu with an immutable filesystem and COW Qemu
image. He'd then communicate with it over (I believe) a fake serial port.


> I am aware that f_globals could break things. However, barring 'private'
> attribute access, I am wondering if it is reachable. I used the code from
> http://www.reddit.com/r/Python/comments/hftnp/ask_rpython_recovering_cleared_globals/c1v3l4ias a test.
>

As above: I haven't figured out how yet, since I can't get getattr and
accessing __globals__ *seemingly* needs two underscores.


>  Can you give me a code snippet which breaks this?
>

I don't have time to finish it right now, but here's the WIP from some
"working" 2.x code that I've tried to port to 3.x.

=====
dunder = "\x5f\x5f"
globals = getattr((lambda: None), dunder + "globals" + dunder)
builtins = globals[dunder + "builtins" + dunder]
dunder_import = getattr(builtins, dunder + "import" + dunder)
new = dunder_import("new")

kaboom_code = new.code(0, 5, 8, 0, "KABOOM", (), (),(), "", "", 0, "")
kaboom_fun = new.function(kaboom_code, {})
kaboom_fun()
=====

As you can see, the eventual thing really can be a single expression, it's
just expanded into a bunch of assignments since that makes it easier to
read.

There's two remaining issues for it to be ported to Py3k:

1. Figure out how to access __globals__, which is the new spelling of
func_globals
2. Replace the "new" module with the "types" module

I'm also not sure if "KABOOM" maps to a sequence of opcodes in 3.x that
will actually go KABOOM ;-) In 2.x, it should map to a bunch of binary
opcodes, which, on an empty stack, will obviously segfault :-)

My other approach was to just base64 the entire thing and exec the
unbase64-d version, but that doesn't work in 3.x either since exec is a
function now instead of a statement, so clearing globals is actually an
effective way to get rid of it...

So, in closing: for now I haven't quite figured out how to break it, but
that's with spending like 10 minutes on it, and I'm not particularly
familiar with 3.x... It appears to work, and it certainly will foil most
attempts to get past it, but it's a very thin spit-and-sticks kind of
"works", so I wouldn't trust it too much ;-)

cheers
lvh
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-ideas/attachments/20130719/ad917d8b/attachment-0001.html>


More information about the Python-ideas mailing list