diff --git a/common/lib/codejail/codejail/django_integration.py b/common/lib/codejail/codejail/django_integration.py new file mode 100644 index 0000000000..52306ba6f1 --- /dev/null +++ b/common/lib/codejail/codejail/django_integration.py @@ -0,0 +1,16 @@ +"""Django integration for codejail""" + +from django.core.exceptions import MiddlewareNotUsed +from django.conf import settings + +import codejail.jailpy + +class ConfigureCodeJailMiddleware(object): + """Middleware to configure codejail on startup.""" + + def __init__(self): + python_bin = settings.CODE_JAIL.get('python_bin') + if python_bin: + user = settings.CODE_JAIL['user'] + codejail.jailpy.configure(python_bin, user=user) + raise MiddlewareNotUsed diff --git a/common/lib/codejail/codejail/jailpy.py b/common/lib/codejail/codejail/jailpy.py index 2a8fd61b98..8f68ab33de 100644 --- a/common/lib/codejail/codejail/jailpy.py +++ b/common/lib/codejail/codejail/jailpy.py @@ -7,6 +7,7 @@ import os, os.path import resource import shutil import subprocess +import sys import threading import time @@ -16,21 +17,24 @@ from .util import temp_directory # Configure the Python command -SANDBOX_POSSIBILITIES = [ - "~/mitx_all/python-sandbox/bin/python", - "/usr/bin/python-sandbox", -] +PYTHON_CMD = None -for sandbox_python in SANDBOX_POSSIBILITIES: - sandbox_python = os.path.expanduser(sandbox_python) - if os.path.exists(sandbox_python): - PYTHON_CMD = [ - 'sudo', '-u', 'sandbox', - sandbox_python, '-E', - ] - break -else: - raise Exception("Couldn't find Python sandbox") +def configure(python_bin, user=None): + """Configure the jailpy module.""" + global PYTHON_CMD + PYTHON_CMD = [] + if user: + PYTHON_CMD.extend(['sudo', '-u', 'sandbox']) + PYTHON_CMD.extend([python_bin, '-E']) + +def is_configured(): + return bool(PYTHON_CMD) + +# By default, look where our current Python is, and maybe there's a +# python-sandbox alongside. Only do this if running in a virtualenv. +if hasattr(sys, 'real_prefix'): + if os.path.isdir(sys.prefix + "-sandbox"): + configure(sys.prefix + "-sandbox/bin/python", "sandbox") class JailResult(object): @@ -52,6 +56,9 @@ def jailpy(code, files=None, argv=None, stdin=None): .status: return status of the process: an int, 0 for successful """ + if not PYTHON_CMD: + raise Exception("jailpy needs to be configured") + with temp_directory(delete_when_done=True) as tmpdir: # All the supporting files are copied into our directory. diff --git a/common/lib/codejail/codejail/tests/test_jailpy.py b/common/lib/codejail/codejail/tests/test_jailpy.py index 74c475b63d..3c6d13b714 100644 --- a/common/lib/codejail/codejail/tests/test_jailpy.py +++ b/common/lib/codejail/codejail/tests/test_jailpy.py @@ -4,12 +4,17 @@ import textwrap import unittest from nose.plugins.skip import SkipTest -from codejail.jailpy import jailpy +from codejail.jailpy import jailpy, is_configured dedent = textwrap.dedent class JailPyHelpers(object): """Assert helpers for jailpy tests.""" + def setUp(self): + super(JailPyHelpers, self).setUp() + if not is_configured(): + raise SkipTest + def assertResultOk(self, res): self.assertEqual(res.stderr, "") self.assertEqual(res.status, 0) diff --git a/lms/envs/common.py b/lms/envs/common.py index 32a213f06e..b99efd60c3 100644 --- a/lms/envs/common.py +++ b/lms/envs/common.py @@ -242,6 +242,16 @@ MODULESTORE = { } CONTENTSTORE = None +#################### Python sandbox ############################################ + +CODE_JAIL = { + # Path to a sandboxed Python executable. None means don't bother. + 'python_bin': None, + # User to run as in the sandbox. + 'user': 'sandbox', +} + + ############################ SIGNAL HANDLERS ################################ # This is imported to register the exception signal handling that logs exceptions import monitoring.exceptions # noqa @@ -385,6 +395,7 @@ MIDDLEWARE_CLASSES = ( # 'debug_toolbar.middleware.DebugToolbarMiddleware', 'django_comment_client.utils.ViewNameMiddleware', + 'codejail.django_integration.ConfigureCodeJailMiddleware', ) ############################### Pipeline #######################################