
Ejecución segura de código
CodeJail gestiona la ejecución de código no confiable en sandboxes seguros. Está diseñado principalmente para la ejecución de Python, pero también puede usarse para otros lenguajes.
La seguridad se aplica con AppArmor. Si su sistema operativo no admite AppArmor, o si el perfil de AppArmor no está definido y configurado correctamente, CodeJail no protegerá la ejecución.
CodeJail está diseñado para ser configurable y se auto-configurará para la ejecución de Python si lo instala correctamente.
Un sandbox de CodeJail consta de varias partes:
#) Entorno del sandbox. Para una configuración de Python, esto sería Python y los paquetes centrales asociados como un virtualenv. Esto se denota a lo largo de este documento como . Es de solo lectura y se comparte entre las instanciaciones del sandbox.
El código en el sandbox también tiene acceso a las bibliotecas del sistema operativo en la medida en que el perfil de AppArmor lo permita.
#) Directorio de ejecución del sandbox. Es un directorio efímero de solo lectura llamado
como /tmp/codejail-XXXXXXXX que contiene el código enviado
(./jailed_code), archivos adicionales opcionales y un directorio temporal
de escritura (./tmp) que el código enviado puede usar como espacio de trabajo.
El código enviado es típicamente el código presentado por el estudiante para ser
probado en el servidor, y los archivos adicionales son típicamente un
python_lib.zip que contiene bibliotecas de calificación o utilidades.
Para ejecutarse, CodeJail requiere dos cuentas de usuario. Una cuenta es la cuenta
principal bajo la cual se ejecuta el código, que tiene acceso para crear
sandboxes. Esta se denominará <SANDBOX_CALLER>. La
segunda cuenta es la cuenta bajo la cual se ejecuta el sandbox. Esta es
típicamente la cuenta sandbox.
Actualmente se ha probado que esta biblioteca funciona con las siguientes versiones
Python:
Ubuntu:
(Tenga en cuenta que la versión de Python utilizada dentro del sandbox puede ser diferente de la versión utilizada para la propia biblioteca).
Estas instrucciones detallan cómo configurar su sistema operativo para que
CodeJail pueda ejecutar código Python de forma segura. Sin embargo, también es posible establecer
codejail.safe_exec.ALWAYS_BE_UNSAFE = True y ejecutar el Python enviado
directamente en la máquina, sin seguridad alguna. Esto puede ser adecuado para
las máquinas de los desarrolladores que no se preocupan por la seguridad y permite probar
una integración con la API de CodeJail. No debe utilizarse si cualquier entrada proviene
de fuentes no confiables. No use esta opción en sistemas de producción.
Para asegurar la ejecución de Python, creará un nuevo virtualenv. Esto significa que tendrá dos: el virtualenv principal para su proyecto y el nuevo para el código Python en el sandbox.
Elija un lugar para el nuevo virtualenv y llámelo . Será
detectado y utilizado automáticamente si lo coloca junto al
virtualenv existente, pero con -sandbox añadido. Así que si su virtualenv existente está en
/home/chris/ve/myproj, haga que sea /home/chris/ve/myproj-sandbox.
El usuario que ejecuta el LMS es <SANDBOX_CALLER>, por ejemplo, usted en
su máquina de desarrollo, o www-data en un servidor.
Otros detalles aquí que dependen de su configuración:
Cree el nuevo virtualenv, usando --copies para que haya un ejecutable de Python distinto que limitar::
$ sudo python3.12 -m venv --copies
De forma predeterminada, el virtualenv simplemente crearía un enlace simbólico al Python del sistema, y la configuración predeterminada de AppArmor en algunos sistemas operativos puede impedir que se aplique el confinamiento a ese enlace.
(Opcional) Si tiene paquetes particulares que desea que estén disponibles para su código en el sandbox, instálelos activando el virtualenv del sandbox y usando pip para instalarlos::
$ /bin/pip install -r requirements/sandbox.txt
Agregue un usuario sandbox::
$ sudo addgroup sandbox $ sudo adduser --disabled-login sandbox --ingroup sandbox
Permita que el servidor web ejecute el Python del sandbox como sandbox. Cree el archivo
/etc/sudoers.d/01-sandbox::
$ sudo visudo -f /etc/sudoers.d/01-sandbox
<SANDBOX_CALLER> ALL=(sandbox) SETENV:NOPASSWD:/bin/python <SANDBOX_CALLER> ALL=(sandbox) SETENV:NOPASSWD:/usr/bin/find <SANDBOX_CALLER> ALL=(ALL) NOPASSWD:/usr/bin/pkill
(Tenga en cuenta que el binario find puede ejecutar código arbitrario, por lo que este no es un archivo sudoers seguro para fines que no sean de codejail).
Edite un perfil de AppArmor. Este es un archivo de texto que especifica los límites del
ejecutable de Python en el sandbox. El archivo debe estar en /etc/apparmor.d y debe
nombrarse según el ejecutable, con las barras reemplazadas por puntos. Por
ejemplo, si su Python del sandbox está en /home/chris/ve/myproj-sandbox/bin/python,
entonces su perfil de AppArmor debe ser /etc/apparmor.d/home.chris.ve.myproj-sandbox.bin.python.
Si su CodeJail está configurado correctamente para usar safe_exec, pruebe estos comandos en su terminal de Python::
import codejail.jail_code
codejail.jail_code.configure('python', '<SANDENV>/bin/python', user='sandbox')
import codejail.safe_exec
jailed_globals = {}
codejail.safe_exec.safe_exec("output=open('/etc/passwd').read()", jailed_globals)
print(jailed_globals) # should be unreachable if codejail is working properly
Esto debería fallar con una excepción.
Si necesita cambiar los paquetes instalados en el virtualenv de su sandbox, deberá desactivar AppArmor, porque su Python del sandbox no tiene los derechos para modificar los archivos en su directorio site-packages.
Desactive AppArmor para su sandbox::
$ sudo apt-get install apparmor-utils # if you haven't already $ sudo aa-complain /etc/apparmor.d/home.chris.ve.myproj-sandbox.bin.python
Instale o modifique de otro modo los paquetes instalados::
$ pip install -r requirements/sandbox.txt
Vuelva a activar AppArmor para su sandbox::
$ sudo aa-enforce /etc/apparmor.d/home.chris.ve.myproj-sandbox.bin.python
Para ejecutar las pruebas, debe realizar los pasos de instalación estándar. Luego debe establecer las siguientes variables de entorno::
$ export CODEJAIL_TEST_USER=<owner of sandbox (usually 'sandbox')>
$ export CODEJAIL_TEST_VENV=<SANDENV>
Ejecute las pruebas con el Makefile::
$ make tests
Varias pruebas proxy se omiten si el modo proxy no está configurado.
CodeJail es lo suficientemente polivalente como para usarse en una variedad de proyectos para ejecutar código no confiable. Proporciona dos capas:
jail_code.py ofrece ejecución segura de subprocesos. Lo hace
ejecutando el programa en un subproceso gestionado por AppArmor.
safe_exec.py ofrece un manejo especializado de la ejecución de Python, usando
jail_code para proporcionar la semántica de la declaración exec de Python.
CodeJail ejecuta programas bajo AppArmor. AppArmor es una función proporcionada por el sistema operativo para limitar los recursos a los que los programas pueden acceder. Para ejecutar código Python con acceso limitado a los recursos, creamos un nuevo virtualenv, luego nombramos ese ejecutable de Python en un perfil de AppArmor y restringimos los recursos en ese perfil. CodeJail ejecutará el programa Python proporcionado con ese ejecutable, y AppArmor limitará automáticamente los recursos a los que puede acceder. CodeJail también usa setrlimit para limitar la cantidad de tiempo de CPU y/o memoria disponible para el proceso.
codejail.jail_code toma un programa para ejecutar, archivos para copiar en su
entorno, argumentos de línea de comandos y un flujo de stdin. Crea un
directorio temporal, crea o copia los archivos necesarios, inicia un subproceso para
ejecutar el código y devuelve la salida y el estado de salida del proceso.
codejail.safe_exec emula la declaración exec de Python. Toma un fragmento de
código Python y lo ejecuta usando jail_code, modificando el diccionario de globals como
efecto secundario. safe_exec hace esto serializando los globals hacia y desde
el subproceso como JSON.
Si codejail o AppArmor no están configurados correctamente, codejail puede recurrir a ejecutar código de forma insegura (sin sandbox). No es seguro por defecto. Los proyectos que integran codejail deberían considerar incluir un conjunto de pruebas en tiempo de ejecución que verifique el confinamiento adecuado al inicio antes de que se acepten entradas no confiables.
El aislamiento del sandbox se logra mediante el confinamiento de AppArmor. Codejail facilita esto, pero no puede aislar la ejecución sin el uso de AppArmor.
Los límites de recursos solo pueden restringirse usando los mecanismos que el rlimit de Linux pone a disposición. Algunas deficiencias notables:
FSIZE de rlimit puede limitar el tamaño de cualquier archivo individual que
un proceso pueda crear, y puede limitar la cantidad de archivos que tiene abiertos en un
momento dado, no puede limitar la cantidad total de archivos escritos y, por lo tanto,
no puede limitar la cantidad total de bytes escritos en todos los archivos.
Una mitigación parcial es restringir el tiempo máximo de ejecución. (Todos los archivos
escritos en el sandbox se eliminarán al final de la ejecución, en cualquier caso).NPROC restringe la capacidad del proceso actual para
crear nuevos hilos y procesos, pero el contador de uso (cuántos procesos
ya existen) es la suma en todos los procesos con el mismo UID, incluso en
otros contenedores en el mismo host donde el UID puede estar mapeado a un
nombre de usuario diferente. Esta restricción también se aplica al usuario de la aplicación debido a cómo se
aplican los rlimits. Incluso si se eligen UIDs para que no sean utilizados por otro
software en el host, múltiples procesos de sandbox de codejail en el mismo host
compartirán este grupo de uso y pueden reducir la capacidad de cada uno para crear
procesos. En esta situación, NPROC deberá establecerse más alto de lo que
sería para una instancia única de codejail que atiende una sola solicitud a la vez.Los sandboxes no tienen un aislamiento fuerte entre sí. Con una configuración adecuada, el código no confiable no debería poder descubrir otras ejecuciones de código activas, pero si se viola esta suposición, un sandbox podría interferir teóricamente con otro.
No reporte problemas de seguridad en público. Envíe un correo electrónico a [email protected].
Consulte el perfil de ejemplo en apparmor-profiles/. El perfil debe ser
personalizado para que coincida con la ubicación de su sandbox.
Analice los perfiles::
$ sudo apparmor_parser --replace --warn=all --warn=no-debug-cache --Werror <APPARMOR_FILE>
Reactive el virtualenv principal de su proyecto nuevamente.
Desactive el uso de PAM para establecer rlimits::
sed -i '/pam_limits.so/d' /etc/pam.d/sudo