language-agnostic operating-system sandbox system-calls

language agnostic - ¿Cómo hacen los sitios como codepad.org e ideone.com para su programa Sandbox?



language-agnostic operating-system (3)

Hace algún tiempo, estaba buscando una solución de espacio aislado para usar en un sistema de evaluación de tareas automatizado para estudiantes de CS. Al igual que todo lo demás, existe un equilibrio entre las distintas propiedades:

  • Aislamiento y granularidad de control de acceso
  • Rendimiento y facilidad de instalación / configuración

Finalmente me decidí por una arquitectura de varios niveles, basada en Linux:

  • Nivel 0 - Virtualización:

    Al usar una o más instantáneas de máquinas virtuales para todas las asignaciones dentro de un rango de tiempo específico, fue posible obtener varias ventajas:

    • Separación clara de datos sensibles y no sensibles.

    • Al final del período (por ejemplo, una vez al día o después de cada sesión), la VM se apaga y se reinicia desde la instantánea, eliminando así cualquier remanente de código malicioso o malicioso.

    • Un primer nivel de aislamiento de recursos informáticos: cada VM tiene recursos limitados de disco, CPU y memoria y no se puede acceder directamente al equipo host.

    • Filtrado directo de la red: al tener la VM en una interfaz interna, el firewall en el host puede filtrar selectivamente las conexiones de red.

      Por ejemplo, una VM destinada a probar estudiantes de un curso introductorio de programación podría tener bloqueadas todas las conexiones entrantes y salientes, ya que los estudiantes de ese nivel no tendrían asignaciones de programación de red. En niveles más altos, las máquinas virtuales correspondientes podrían, por ejemplo, tener todas las conexiones salientes bloqueadas y permitir la conexión entrante solo desde el interior de la facultad.

    También tendría sentido tener una máquina virtual separada para el sistema de envío basado en la web, una que podría cargar archivos a las máquinas virtuales de evaluación, pero hacer poco más.

  • Nivel 1 - Limitaciones básicas del sistema de operación:

    En un sistema operativo Unix que contendría el acceso tradicional y los mecanismos de control de recursos:

    • Cada programa de espacio aislado podría ejecutarse como un usuario separado, tal vez en una cárcel chroot separada.

    • Estrictos permisos de usuario, posiblemente con ACL.

    • límites de recursos ulimit en el tiempo de procesador y uso de memoria.

    • Ejecución en condiciones nice para reducir la prioridad sobre procesos más críticos. En Linux también puede usar ionice y cpulimit : no estoy seguro de qué equivalentes existen en otros sistemas.

    • Cuotas de disco.

    • Filtrado de conexión por usuario

    Es probable que desee ejecutar el compilador como un usuario ligeramente más privilegiado; más memoria y tiempo de CPU, acceso a herramientas de compilación y archivos de encabezado, etc.

  • Nivel 2 - Restricciones avanzadas del sistema operativo:

    En Linux, considero que es el uso de un Módulo de seguridad de Linux, como AppArmor o SELinux para limitar el acceso a archivos específicos y / o llamadas al sistema. Algunas distribuciones de Linux ofrecen algunos perfiles de seguridad de espacio aislado, pero aún puede ser un proceso largo y doloroso para que algo como esto funcione correctamente.

  • Nivel 3 - Soluciones de espacio aislado de espacio de usuario:

    He utilizado Systrace con éxito en pequeña escala, como se menciona en esta respuesta mía anterior . Existen muchas otras soluciones de sandboxing para Linux, como libsandbox . Dichas soluciones pueden proporcionar un control más detallado sobre las llamadas al sistema que se pueden utilizar que las alternativas basadas en LSM, pero pueden tener un impacto mensurable en el rendimiento.

  • Nivel 4 - Ataques preventivos:

    Como usted mismo compilará el código, en lugar de ejecutar binarios existentes, tiene algunas herramientas adicionales en sus manos:

    • Restricciones basadas en métricas de código; por ejemplo, un simple programa "Hello World" nunca debería tener más de 20-30 líneas de código.

    • Acceso selectivo a las bibliotecas del sistema y archivos de encabezado; si no desea que sus usuarios llamen a connect() , puede restringir el acceso a socket.h .

    • Análisis de código estático; no permitir código ensamblador, literales "extraños" (es decir, código shell) y el uso de funciones restringidas del sistema.

    Un programador competente podría sortear tales medidas, pero a medida que aumente la relación costo-beneficio, sería mucho menos probable que persistan.

  • Nivel 0-5 - Monitoreo y registro:

    Debe controlar el rendimiento de su sistema y registrar todos los intentos fallidos. No solo sería más probable que interrumpa un ataque en curso a nivel de sistema, sino que también podría utilizar medios administrativos para proteger su sistema, como por ejemplo:

    • llamando a los funcionarios de seguridad que estén a cargo de tales asuntos.

    • encontrando a ese pequeño hacker persistente y ofreciéndoles un trabajo.

El grado de protección que necesita y los recursos que está dispuesto a gastar para configurarlo depende de usted.

Necesito compilar y ejecutar scripts enviados por el usuario en mi sitio, de forma similar a lo que hacen el codepad y el ideone . ¿Cómo puedo proteger estos programas para que los usuarios malintencionados no eliminen mi servidor?

Específicamente, quiero encerrarlos dentro de un directorio vacío y evitar que lean o escriban en cualquier lugar fuera de eso, que consuman demasiada memoria o CPU, o que hagan cualquier otra cosa maliciosa.

Tendré que comunicarme con estos programas a través de pipes (over stdin / stdout) desde fuera del sandbox.


Soy el desarrollador de libsandbox mencionado por @thkala, y lo recomiendo para su uso en su proyecto.

Algunos comentarios adicionales sobre la respuesta de @ thkala,

  1. es justo clasificar libsandbox como herramienta user-land, pero libsandbox integra mecanismos de seguridad de nivel de sistema operativo estándar (es decir, chroot, setuid y quota de recursos);
  2. restringir el acceso a los encabezados C / C ++, o el análisis estático del código de los usuarios, NO evita que se invoquen las funciones del sistema como connect() . Esto se debe a que el código de usuario puede (1) declarar prototipos de función por sí mismos sin incluir encabezados de sistema, o (2) invocar las llamadas subyacentes del sistema kernel-land sin tocar las funciones de envoltura en libc ;
  3. La protección en tiempo de compilación también merece atención porque el código malicioso C / C ++ puede agotar su CPU con infinitas repeticiones de plantilla o preprocesamiento de expansión de macros;

codepad.org tiene algo basado en geordi , que ejecuta todo en un chroot (es decir, restringido a un subárbol del sistema de archivos) con restricciones de recursos, y utiliza la API ptrace para restringir el uso del programa no confiable de las llamadas al sistema. Ver http://codepad.org/about .

Anteriormente utilicé Systrace , otra utilidad para restringir las llamadas al sistema.

Si la política está configurada correctamente, se evitará que el programa que no es de confianza rompa nada en la zona de pruebas o acceda a todo lo que no debería, por lo que no es necesario colocar programas en chroots separados y crearlos y eliminarlos para cada ejecución. Aunque eso proporcionaría otra capa de protección, que probablemente no dañaría.