Can't use subprocess.Popen() after os.chroot() - why?

E

Erik

Hi All,

I'm trying to do the following:

import os
from subprocess import Popen, PIPE

os.chroot("/tmp/my_chroot")
p = Popen("/bin/date", stdin=PIPE, stdout=PIPE, stderr=PIPE)
stdout_val, stderr_val = p.communicate()
print stdout_val

but the Popen call is dying with the following exception:

Traceback (most recent call last):
File "./test.py", line 7, in <module>
p = Popen("/bin/date", stdin=PIPE, stdout=PIPE, stderr=PIPE)
File "/home/erik/lib/python2.7/subprocess.py", line 679, in __init__
File "/home/erik/lib/python2.7/subprocess.py", line 1224, in _execute_child
File "/home/erik/lib/python2.7/pickle.py", line 1382, in loads
File "/home/erik/lib/python2.7/pickle.py", line 858, in load
File "/home/erik/lib/python2.7/pickle.py", line 971, in load_string
LookupError: unknown encoding: string-escape

Am I missing something here? does the chroot environment need to be populated with more than just the date executable in this case? I can't seem to find any examples of this & would appreciate any insight.

Thanks,
Erik.
 
A

Alain Ketterlin

Erik said:
import os
from subprocess import Popen, PIPE

os.chroot("/tmp/my_chroot")
p = Popen("/bin/date", stdin=PIPE, stdout=PIPE, stderr=PIPE)
stdout_val, stderr_val = p.communicate()
print stdout_val

but the Popen call is dying with the following exception:

Traceback (most recent call last):
File "./test.py", line 7, in <module>
p = Popen("/bin/date", stdin=PIPE, stdout=PIPE, stderr=PIPE)
File "/home/erik/lib/python2.7/subprocess.py", line 679, in __init__
File "/home/erik/lib/python2.7/subprocess.py", line 1224, in _execute_child
File "/home/erik/lib/python2.7/pickle.py", line 1382, in loads
File "/home/erik/lib/python2.7/pickle.py", line 858, in load
File "/home/erik/lib/python2.7/pickle.py", line 971, in load_string
LookupError: unknown encoding: string-escape

Am I missing something here? does the chroot environment need to be
populated with more than just the date executable in this case?

Yes, because /bin/date is probably dynamically linked: you need the libs
as well. (Try first with a statically linked executable, e.g.,
/bin/busybox, and everything should be ok).

I agree the message is strange. For some reason, subprocess is calling
pickle.loads, which calls rep.decode("string-escape"), which probably
needs to access some file and fails because of the chroot().

I woud advise to use the chroot command instead of chrooting your python
process, if that's possible for you.

-- Alain.
 
H

Hans Mulder

Yes, because /bin/date is probably dynamically linked: you need the libs
as well. (Try first with a statically linked executable, e.g.,
/bin/busybox, and everything should be ok).

/bin/date also needs timezone information from either /etc/localtime
or /usr/share/zoneinfo/ (depends on whether the environment variable
TZ is set).

It may need other data files as well (e.g. for localization).
I agree the message is strange. For some reason, subprocess is calling
pickle.loads, which calls rep.decode("string-escape"), which probably
needs to access some file and fails because of the chroot().

The child process tries to exec /bin/date and fails. The child process
then pickles the resulting exception and sends it to the parent via
a pipe that the parent has created for this purpose. The parent then
tries to unpickle the exception and fails to find the string-escape
decoder in its usual place, due to the chroot.

If you fix that, then the parent process will be able to re-raise the
exception from the child process (which may or may not confuse you).
I woud advise to use the chroot command instead of chrooting your python
process, if that's possible for you.

You'll find you need to copy a lot of dynamic libraries and several
data files to your chroot box, before the normal commands in /bin work.

Keep in mind that the more features you copy to the chroot jail, the
easier it becomes to escape from it.

Hope this helps,

-- HansM
 
N

Nobody

I'm trying to do the following:
os.chroot("/tmp/my_chroot")
p = Popen("/bin/date", stdin=PIPE, stdout=PIPE, stderr=PIPE)
but the Popen call is dying with the following exception:
LookupError: unknown encoding: string-escape

Am I missing something here? does the chroot environment need to be
populated with more than just the date executable in this case?

Yes. It also needs to include any parts of the Python run-time which
Python will try to load while executing subsequent code. In this case, the
module which implements the string-escape encoding.

But fixing that will probably show up yet more files which need to exist
within the pseudo-root. E.g. any shared libraries which the executable
needs (probably at least libc), and any data files which those libraries
need (in the case of /bin/date, it may need /etc/timezone; many programs
may require locale data if you aren't in the "C" locale, and so on).

Whether from Python or from C, chroot() requires a good understanding of
the low-level details of your operating system. If you don't know how to
build a minimal Linux distribution from scratch, you're going to have to
learn many of those details in order to use chroot().

For any non-trivial chroot() usage, it's often easier to install a small
newlib+busybox-based Linux distribution under the pseudo-root than to try
to re-use files from and existing (presumably glibc+coreutils-based)
desktop/server distribution.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,787
Messages
2,569,630
Members
45,335
Latest member
Tommiesal

Latest Threads

Top