aboutsummaryrefslogtreecommitdiff
path: root/pypy
diff options
context:
space:
mode:
authorAlexander Hesse <webmaster@aquanasoft.de>2013-01-06 21:30:35 +0100
committerAlexander Hesse <webmaster@aquanasoft.de>2013-01-06 21:30:35 +0100
commit84c8c653bf5fc39a68b2441780539ab961cd7521 (patch)
treecae049db98ef1cc4cfa97e17814b739aa288ba15 /pypy
parentgoal/test -> goal/test2 (diff)
downloadpypy-84c8c653bf5fc39a68b2441780539ab961cd7521.tar.gz
pypy-84c8c653bf5fc39a68b2441780539ab961cd7521.tar.bz2
pypy-84c8c653bf5fc39a68b2441780539ab961cd7521.zip
Renamed pypy_interact to pypy.sandbox.pypysandbox. Removed pypydir import from cbuild
Diffstat (limited to 'pypy')
-rw-r--r--pypy/bin/pypysandbox5
-rw-r--r--pypy/sandbox/__init__.py1
-rwxr-xr-xpypy/sandbox/pypysandbox.py129
-rw-r--r--pypy/sandbox/test/test_pypysandbox.py81
4 files changed, 216 insertions, 0 deletions
diff --git a/pypy/bin/pypysandbox b/pypy/bin/pypysandbox
new file mode 100644
index 0000000000..f236f296ef
--- /dev/null
+++ b/pypy/bin/pypysandbox
@@ -0,0 +1,5 @@
+#!/usr/bin/env pypy
+
+from pypy.sandbox import pypysandbox
+
+pypysandbox.main() \ No newline at end of file
diff --git a/pypy/sandbox/__init__.py b/pypy/sandbox/__init__.py
new file mode 100644
index 0000000000..bc63beba4a
--- /dev/null
+++ b/pypy/sandbox/__init__.py
@@ -0,0 +1 @@
+# empty \ No newline at end of file
diff --git a/pypy/sandbox/pypysandbox.py b/pypy/sandbox/pypysandbox.py
new file mode 100755
index 0000000000..b9bd4605e3
--- /dev/null
+++ b/pypy/sandbox/pypysandbox.py
@@ -0,0 +1,129 @@
+#! /usr/bin/env python
+
+"""Interacts with a PyPy subprocess translated with --sandbox.
+
+Usage:
+ pypy_interact.py [options] <executable> <args...>
+
+Options:
+ --tmp=DIR the real directory that corresponds to the virtual /tmp,
+ which is the virtual current dir (always read-only for now)
+ --heapsize=N limit memory usage to N bytes, or kilo- mega- giga-bytes
+ with the 'k', 'm' or 'g' suffix respectively.
+ --timeout=N limit execution time to N (real-time) seconds.
+ --log=FILE log all user input into the FILE.
+ --verbose log all proxied system calls.
+
+Note that you can get readline-like behavior with a tool like 'ledit',
+provided you use enough -u options:
+
+ ledit python -u pypy_interact.py pypy-c-sandbox -u
+"""
+
+import sys, os
+sys.path.insert(0, os.path.realpath(os.path.join(os.path.dirname(__file__), '..', '..', '..')))
+from rpython.translator.sandbox.sandlib import SimpleIOSandboxedProc
+from rpython.translator.sandbox.sandlib import VirtualizedSandboxedProc
+from rpython.translator.sandbox.vfs import Dir, RealDir, RealFile
+import pypy
+LIB_ROOT = os.path.dirname(os.path.dirname(pypy.__file__))
+
+class PyPySandboxedProc(VirtualizedSandboxedProc, SimpleIOSandboxedProc):
+ argv0 = '/bin/pypy-c'
+ virtual_cwd = '/tmp'
+ virtual_env = {}
+ virtual_console_isatty = True
+
+ def __init__(self, executable, arguments, tmpdir=None, debug=True):
+ self.executable = executable = os.path.abspath(executable)
+ self.tmpdir = tmpdir
+ self.debug = debug
+ super(PyPySandboxedProc, self).__init__([self.argv0] + arguments,
+ executable=executable)
+
+ def build_virtual_root(self):
+ # build a virtual file system:
+ # * can access its own executable
+ # * can access the pure Python libraries
+ # * can access the temporary usession directory as /tmp
+ exclude = ['.pyc', '.pyo']
+ if self.tmpdir is None:
+ tmpdirnode = Dir({})
+ else:
+ tmpdirnode = RealDir(self.tmpdir, exclude=exclude)
+ libroot = str(LIB_ROOT)
+
+ return Dir({
+ 'bin': Dir({
+ 'pypy-c': RealFile(self.executable),
+ 'lib-python': RealDir(os.path.join(libroot, 'lib-python'),
+ exclude=exclude),
+ 'lib_pypy': RealDir(os.path.join(libroot, 'lib_pypy'),
+ exclude=exclude),
+ }),
+ 'tmp': tmpdirnode,
+ })
+
+def main():
+ from getopt import getopt # and not gnu_getopt!
+ options, arguments = getopt(sys.argv[1:], 't:hv',
+ ['tmp=', 'heapsize=', 'timeout=', 'log=',
+ 'verbose', 'help'])
+ tmpdir = None
+ timeout = None
+ logfile = None
+ debug = False
+ extraoptions = []
+
+ def help():
+ print >> sys.stderr, __doc__
+ sys.exit(2)
+
+ for option, value in options:
+ if option in ['-t', '--tmp']:
+ value = os.path.abspath(value)
+ if not os.path.isdir(value):
+ raise OSError("%r is not a directory" % (value,))
+ tmpdir = value
+ elif option == '--heapsize':
+ value = value.lower()
+ if value.endswith('k'):
+ bytes = int(value[:-1]) * 1024
+ elif value.endswith('m'):
+ bytes = int(value[:-1]) * 1024 * 1024
+ elif value.endswith('g'):
+ bytes = int(value[:-1]) * 1024 * 1024 * 1024
+ else:
+ bytes = int(value)
+ if bytes <= 0:
+ raise ValueError
+ if bytes > sys.maxint:
+ raise OverflowError("--heapsize maximum is %d" % sys.maxint)
+ extraoptions[:0] = ['--heapsize', str(bytes)]
+ elif option == '--timeout':
+ timeout = int(value)
+ elif option == '--log':
+ logfile = value
+ elif option in ['-v', '--verbose']:
+ debug = True
+ elif option in ['-h', '--help']:
+ help()
+ else:
+ raise ValueError(option)
+
+ if len(arguments) < 1:
+ help()
+
+ sandproc = PyPySandboxedProc(arguments[0], extraoptions + arguments[1:],
+ tmpdir=tmpdir, debug=debug)
+ if timeout is not None:
+ sandproc.settimeout(timeout, interrupt_main=True)
+ if logfile is not None:
+ sandproc.setlogfile(logfile)
+ try:
+ sandproc.interact()
+ finally:
+ sandproc.kill()
+
+if __name__ == '__main__':
+ main() \ No newline at end of file
diff --git a/pypy/sandbox/test/test_pypysandbox.py b/pypy/sandbox/test/test_pypysandbox.py
new file mode 100644
index 0000000000..771655d614
--- /dev/null
+++ b/pypy/sandbox/test/test_pypysandbox.py
@@ -0,0 +1,81 @@
+import os, sys, stat, errno
+from pypy.sandbox.pypysandbox import PyPySandboxedProc
+from rpython.translator.interactive import Translation
+
+from pypy.module.sys.version import CPYTHON_VERSION
+from pypy.tool.lib_pypy import LIB_PYTHON
+
+VERSION = '%d.%d' % CPYTHON_VERSION[:2]
+SITE_PY_CONTENT = LIB_PYTHON.join('site.py').read()
+ERROR_TEXT = os.strerror(errno.ENOENT)
+
+def assert_(cond, text):
+ if not cond:
+ print "assert failed:", text
+ raise AssertionError
+
+def mini_pypy_like_entry_point(argv):
+ """An RPython standalone executable that does the same kind of I/O as
+ PyPy when it starts up.
+ """
+ assert_(len(argv) == 3, "expected len(argv) == 3")
+ assert_(argv[1] == 'foo', "bad argv[1]")
+ assert_(argv[2] == 'bar', "bad argv[2]")
+ env = os.environ.items()
+ assert_(len(env) == 0, "empty environment expected")
+ assert_(argv[0] == '/bin/pypy-c', "bad argv[0]")
+ st = os.lstat('/bin/pypy-c')
+ assert_(stat.S_ISREG(st.st_mode), "bad st_mode for /bin/pypy-c")
+ for dirname in ['/bin/lib-python/' + VERSION, '/bin/lib_pypy']:
+ st = os.stat(dirname)
+ assert_(stat.S_ISDIR(st.st_mode), "bad st_mode for " + dirname)
+ assert_(os.environ.get('PYTHONPATH') is None, "unexpected $PYTHONPATH")
+ try:
+ os.stat('site')
+ except OSError:
+ pass
+ else:
+ assert_(False, "os.stat('site') should have failed")
+
+ try:
+ os.stat('/bin/lib-python/%s/site.pyc' % VERSION)
+ except OSError:
+ pass
+ else:
+ assert_(False, "os.stat('....pyc') should have failed")
+ fd = os.open('/bin/lib-python/%s/site.py' % VERSION,
+ os.O_RDONLY, 0666)
+ length = 8192
+ ofs = 0
+ while True:
+ data = os.read(fd, length)
+ if not data: break
+ end = ofs+length
+ if end > len(SITE_PY_CONTENT):
+ end = len(SITE_PY_CONTENT)
+ assert_(data == SITE_PY_CONTENT[ofs:end], "bad data from site.py")
+ ofs = end
+ os.close(fd)
+ assert_(ofs == len(SITE_PY_CONTENT), "not enough data from site.py")
+ assert_(os.getcwd() == '/tmp', "bad cwd")
+ assert_(os.strerror(errno.ENOENT) == ERROR_TEXT, "bad strerror(ENOENT)")
+ assert_(os.isatty(0), "isatty(0) returned False")
+ # an obvious 'attack'
+ try:
+ os.open('/spam', os.O_RDWR | os.O_CREAT, 0666)
+ except OSError:
+ pass
+ else:
+ assert_(False, "os.open('/spam') should have failed")
+ return 0
+
+
+def setup_module(mod):
+ t = Translation(mini_pypy_like_entry_point, backend='c', sandbox=True)
+ mod.executable = str(t.compile())
+
+
+def test_run():
+ sandproc = PyPySandboxedProc(executable, ['foo', 'bar'])
+ returncode = sandproc.interact()
+ assert returncode == 0