¿Ejecuta un programa C que no es de confianza en una caja de arena en Linux que le impide abrir archivos, bifurcar, etc.?


110

Me preguntaba si existe una forma de ejecutar un programa C que no sea de confianza en un entorno de pruebas en Linux. ¿Algo que evitaría que el programa abra archivos o conexiones de red, o bifurque, ejecutivo, etc.?

Sería un pequeño programa, una tarea, que se carga en un servidor y se ejecutan pruebas unitarias en él. Entonces el programa sería de corta duración.


¿Es esto como un solo programa en C que necesita ejecutar 1 vez durante 5 minutos, o algo que necesita ejecutar constantemente?
bwawok

Sería un pequeño programa que se carga y tiene pruebas unitarias ejecutadas en él. Entonces el programa sería de corta duración.
Frank

¿Qué distribución está usando el sistema? Algunas distribuciones tienen herramientas listas para usar para el sandboxing. ¿Su sistema tiene algún modelo de seguridad como SELinux o AppArmor habilitado?
thkala

Estoy usando Fedora 13. Estoy investigando la política de SELinux Sandbox. Me pregunto qué otras opciones existen.
Frank

Respuestas:


47

He utilizado Systrace para proteger programas que no son de confianza tanto de forma interactiva como en modo automático. Tiene unptrace() backend basado en que permite su uso en un sistema Linux sin privilegios especiales, así como un backend mucho más rápido y potente que requiere parchear el kernel.

También es posible crear una caja de arena en sistemas similares a Unix usando chroot(1), aunque eso no es tan fácil ni seguro. Los contenedores de Linux y las jaulas FreeBSD son una mejor alternativa a chroot. Otra alternativa en Linux es utilizar un marco de seguridad como SELinux o AppArmor , que es lo que yo propondría para los sistemas de producción.

Podríamos ayudarlo más si nos dijera qué es exactamente lo que desea hacer.

EDITAR:

Systrace funcionaría para su caso, pero creo que algo basado en el modelo de seguridad de Linux como AppArmor o SELinux es una alternativa más estándar y, por lo tanto, preferida, dependiendo de su distribución.

EDITAR 2:

Si bien chroot(1)está disponible en la mayoría (¿todos?) De los sistemas tipo Unix, tiene bastantes problemas:

  • Se puede romper. Si realmente va a compilar o ejecutar programas C que no son de confianza en su sistema, es especialmente vulnerable a este problema. Y si sus estudiantes son como los míos, alguien intentará escapar de la cárcel.

  • Tiene que crear una jerarquía de sistema de archivos completamente independiente con todo lo necesario para su tarea. No es necesario tener un compilador en el chroot, pero se debe incluir todo lo que se requiera para ejecutar los programas compilados. Si bien hay utilidades que ayudan con esto, todavía no es trivial.

  • Tienes que mantener el chroot. Dado que es independiente, los archivos chroot no se actualizarán junto con su distribución. Tendrá que volver a crear el chroot con regularidad o incluir las herramientas de actualización necesarias en él, lo que esencialmente requeriría que sea una distribución de Linux completa. También deberá mantener sincronizados los datos del sistema y del usuario (contraseñas, archivos de entrada, etc.) con el sistema host.

  • chroot()solo protege el sistema de archivos. No evita que un programa malicioso abra conexiones de red o que uno mal escrito absorba todos los recursos disponibles.

El problema del uso de recursos es común a todas las alternativas. Las cuotas del sistema de archivos evitarán que los programas llenen el disco. La configuración adecuada ulimit( setrlimit()en C) puede proteger contra el uso excesivo de la memoria y cualquier bomba de bifurcación, así como detener los acaparadores de CPU. nice(1)puede reducir la prioridad de esos programas para que la computadora pueda usarse para cualquier tarea que se considere más importante sin ningún problema.


systrace funcionó para mí para programas simples, pero se atascó indefinidamente cuando GNU como (1) lo ejecuta GCC. Así que me di por vencido. Es un error no solucionado en systrace: forum.soft32.com/linux/…
pts

¿Existe alguna forma de garantizar que la memoria compartida, las colas de mensajes y los semáforos no se compartan entre los procesos de espacio aislado?
Daveagp

1
El enlace de systrace está roto.
Collin

2
¿Qué pasa con Firejail? No tienes que mantener el fs más usándolo.
m3nda

18

Escribí una descripción general de las técnicas de sandboxing en LinuxRecientemente . Creo que su enfoque más fácil sería usar contenedores de Linux (lxc) si no le importa bifurcar y demás, lo que realmente no importa en este entorno. Puede darle al proceso un sistema de archivos raíz de solo lectura, una conexión de red de bucle de retorno aislada, y aún puede eliminarlo fácilmente y establecer límites de memoria, etc.

Seccomp va a ser un poco difícil, ya que el código ni siquiera puede asignar memoria.

Selinux es la otra opción, pero creo que podría ser más trabajo que un contenedor.


6

Puede usar Qemu para probar tareas rápidamente. Este procedimiento a continuación toma menos de 5 segundos en mi computadora portátil de 5 años.

Supongamos que el estudiante tiene que desarrollar un programa que tome entradas sin firmar, cada una en su propia línea, hasta que llegue una línea con "-1". A continuación, el programa debería promediar todas las entradas y generar "Promedio:% f". Así es como puede probar el programa completamente aislado:

  1. Primero, obtenga root.binde Jslinux, lo usaremos como área de usuario (tiene el compilador tcc C):

    wget https://github.com/levskaya/jslinux-deobfuscated/raw/master/root.bin

  2. Queremos incluir la presentación del estudiante root.bin, así que configure el dispositivo de bucle:

    sudo losetup /dev/loop0 root.bin

    (también podría usar fuseext2 para esto, pero no es muy estable. Si se estabiliza, no necesitará root para nada de esto)

  3. Crea un directorio vacío:

    mkdir mountpoint

  4. Monte root.bin:

    sudo mount /dev/loop0 mountpoint

  5. Ingrese al sistema de archivos montado:

    cd mountpoint.

  6. Fijar derechos:

    sudo chown -R `whoami` .

  7. mkdir -p etc/init.d
  8. vi etc/init.d:

    #!/bin/sh
    cd /root
    echo READY 2>&1 > /dev/ttyS0
    tcc assignment.c 2>&1 > /dev/ttyS0
    ./a.out 2>&1 > /dev/ttyS0
    
  9. chmod +x etc/init.d/rcS

  10. Copie el envío a la VM:

    cp ~/student_assignment.c root/assignment.c

  11. Salga del FS raíz de la VM:

    cd ..

  12. sudo umount mountpoint
  13. Ahora que la imagen está lista, solo necesitamos ejecutarla. Compilará y ejecutará el envío después de arrancar.
  14. mkfifo /tmp/guest_output
  15. Abra una terminal separada y comience a escuchar la salida de invitados:

    dd if=/tmp/guest_output bs=1

  16. En otra terminal:

    qemu-system-i386 -kernel vmlinuz-3.5.0-27-generic -initrd root.bin -monitor stdio -nographic -serial pipe:/tmp/guestoutput (Acabo de usar el kernel de Ubuntu aquí, pero muchos kernels funcionarán)

  17. Cuando la salida del invitado muestra "LISTO", puede enviar claves a la VM desde el indicador qemu. Por ejemplo, para probar esta tarea, puede hacer

    (qemu) sendkey 1
    (qemu) sendkey 4
    (qemu) sendkey ret
    (qemu) sendkey 1
    (qemu) sendkey 0
    (qemu) sendkey ret
    (qemu) sendkey minus
    (qemu) sendkey 1
    (qemu) sendkey ret
    
  18. Ahora Average = 12.000000debería aparecer en la tubería de salida de invitado. Si no es así, el estudiante reprobó.

  19. Salir de qemu: quit

Un programa que pasa la prueba está aquí: https://stackoverflow.com/a/14424295/309483 . Solo use en tcclib.hlugar de stdio.h.


5

Prueba Linux en modo de usuario . Tiene una sobrecarga de rendimiento de aproximadamente un 1% para trabajos con uso intensivo de CPU, pero puede ser 6 veces más lento para trabajos con uso intensivo de E / S.


4

Firejail es una de las herramientas más completas para hacer eso: admite seccomp, contenedores del sistema de archivos, capacidades y más:

https://firejail.wordpress.com/features-3/


Esta respuesta es excelente, realmente merece más votos positivos considerando que firejail se mantiene activamente con una excelente documentación, abarca la mayoría, si no todas, las otras respuestas y está diseñado para ser relativamente fácil de usar.
Jeff Hykin

3

Ejecutarlo dentro de una máquina virtual debería ofrecerle toda la seguridad y restricciones que desee.

QEMU sería una buena opción para eso y todo el trabajo (descargar la aplicación, actualizar la imagen del disco, iniciar QEMU, ejecutar la aplicación dentro de él y guardar la salida para su posterior recuperación) podría programarse para ejecuciones de pruebas automatizadas.


2
No sé sobre el OP, pero lanzar una máquina virtual por programa de prueba sería inaceptable en muchos casos. En mi entorno (soy TA) puede haber hasta 200 estudiantes que presenten entre 10 y 12 programas cada uno en un período de 2 horas. Ningún programa se ejecuta durante más de 10 segundos de tiempo de CPU, pero cuando los envíos se acumulan, obtenemos tiempos de respuesta de 15 minutos o más. La introducción de una máquina virtual para cada programa empujaría el tiempo de CPU a 60 segundos o más por programa y no quiero pensar en los tiempos de respuesta en absoluto. Tal vez una máquina virtual por sesión, pero de ninguna manera podríamos hacer eso por programa ...
thkala

@thkala Este es un buen punto. Me gusta la idea de QEMU, pero iniciar una máquina virtual para cada envío no es bueno.
Frank

Bueno, en ese caso, mantenga la misma VM funcionando todo el tiempo.
Laurent Parenteau

¿Podrías hacer algo usando una instantánea de una máquina virtual que esté completamente iniciada y lista para compilar y ejecutar código? Para su información, las VM no son necesariamente inmunes a las perforaciones. También puede crear una versión de hardware de esto: un pequeño sistema que arranca una imagen de currículum desde un medio de solo lectura o en la red y proporciona salida a través de la red o en serie, luego se reinicia para el siguiente. Ha habido algunos avances de arranque rápido que ponen a Linux en funcionamiento en unos segundos.
Chris Stratton

@thkala: Eso significa que necesitaría menos de 3 segundos por envío si los ejecuta en serie. El enfoque que publiqué probablemente demore alrededor de 3 segundos en una máquina moderna (en serie). Si paraleliza (lo que también podría hacer) sería lo suficientemente rápido.
Janus Troelsen

3

Cuando se trata de sanboxing basado en ptrace (strace) check-out:

Sandbox " sydbox " y " pinktrace " biblioteca de programación " (es C99 pero hay enlaces a python y ruby ​​hasta donde yo sé).

Enlaces recopilados relacionados con el tema:

http://www.diigo.com/user/wierzowiecki/sydbox

(lo siento, no hay enlaces directos, pero todavía no hay suficientes puntos de reputación)



1

Esta biblioteca debería servir bien a su objetivo

http://sandbox.sourceforge.net

¡Buena suerte!


8
Esto no parece mantenerse activamente. También parece requerir un parche del kernel de Linux, lo que lo haría prácticamente inútil considerando que su última versión data de 2003.
thkala


-1

ok gracias a todas las respuestas me ayudaron mucho. Pero no sugeriría ninguno de ellos como una solución para la persona que hizo la pregunta original. Todas las herramientas mencionadas requieren mucho trabajo con el fin de probar el código de los estudiantes como maestro, tutor, prof. La mejor forma en este caso sería, en mi opinión, virtualbox. Ok, emula un sistema x68 completo y no tiene nada que ver con el significado del sandboxing de esta manera, pero si me imagino a mi profesor de programación, sería lo mejor para él. Entonces, "apt-get install virtualbox" en sistemas basados ​​en Debian, todos los demás diríjase a http://virtualbox.org/ , cree una , agregue una iso, haga clic en instalar, espere un poco y tenga suerte. Será mucho más fácil de usar para configurar user-mode-linux o hacer algunas cosas pesadas de strace ...

Y si tienes miedo de que tus estudiantes te pirateen, supongo que tienes un problema de autoridad y una solución para eso sería amenazarlos con que los demandarás a la luz del día si puedes demostrar solo un bocado de maleware en el trabajo que dan. tú...

Además, si hay una clase y el 1% es tan bueno como él podría hacer tales cosas, no los aburra con tareas tan simples y déles algunas grandes en las que tengan que codificar un poco más. El aprendizaje integrador es lo mejor para todos, así que no confíe en viejas estructuras estancadas ...

Y, por supuesto, nunca use la misma computadora para cosas importantes (como redactar certificaciones y exámenes), que está usando para cosas como navegar por la web y probar software.

Utilice una computadora fuera de línea para las cosas importantes y una computadora en línea para todas las demás cosas.

Sin embargo, para todos los demás que no son un maestro paranoico (no quiero ofender a nadie, solo soy la opinión de que debe aprender los conceptos básicos sobre seguridad y nuestra sociedad antes de comenzar a ser un maestro de programadores ...)

... donde estaba yo ... para todos los demás:

feliz pirateo !!

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.