2010-12-11 20 views
5

Me gustaría implementar un entorno limitado por ptrace() proceso que empiezo y creará todos sus hijos (incluidos nietos, etc.). El proceso principal ptrace(), es decir, el supervisor. sería un simple programa C o Python, y conceptualmente limitaría el acceso al sistema de archivos (basado en el nombre de la ruta y la dirección de acceso (lectura o escritura) y el acceso al socket (por ejemplo, no permitir la creación del socket).¿Cómo puede Linux trazar ser inseguro o contener una condición de carrera?

¿Qué debo prestar atención? para que el proceso ptrace() d y sus hijos (recursivamente) no puedan pasar por alto la caja de arena? ¿Hay algo especial que el supervisor debe hacer al fork() tiempo para evitar condiciones de carrera? ¿Es posible leer los argumentos del nombre de archivo por ejemplo rename() ? desde proceso hijo sin una condición de carrera

Esto es lo que ya he planeado hacer:

  • PTRACE_O_TRACEFORK | PTRACE_O_TRACEVFORK | PTRACE_O_TRACECLONE para evitar (algunos) coditions carrera cuando fork() ing
  • disallow todas las llamadas al sistema por defecto, y componer una lista blanca de sistema permitió llama
  • asegurarse de que los *at() variantes llamada al sistema (como openat) son adecuadamente protegido

¿A qué más debo prestar atención?

+0

¿Entonces básicamente está tratando de replicar el back-end basado en ptrace de Systrace (http://www.systrace.org/)? – thkala

+0

Sí, mi supervisor trabajaría de manera similar a systrace. Desafortunadamente, systrace parece no tener mantenimiento, no se compila de forma limpia, y también parece tener fallos (se colgó indefinidamente cuando guardé Sandbox GCC con GNU). – pts

Respuesta

11

El principal problema es que muchos argumentos de syscall, como nombres de archivos, se pasan al kernel como punteros de espacio de usuario. Cualquier tarea que se permite ejecutar simultáneamente y tiene acceso de escritura a la memoria a la que apunta el puntero puede modificar estos argumentos de manera efectiva después de que el supervisor los inspecciona y antes de que el kernel actúe sobre ellos. En el momento en que el núcleo sigue al puntero, el contenido apuntado puede haber sido cambiado deliberadamente por otra tarea programable (proceso o hilo) con acceso a esa memoria. Por ejemplo:

Thread 1       Supervisor    Thread 2 
----------------------------------------------------------------------------------------------------- 
strcpy(filename, "/dev/null"); 
open(filename, O_RDONLY); 
            Check filename - OK 
                  strcpy(filename, "/home/user/.ssh/id_rsa"); 
(in kernel) opens "/home/user/.ssh/id_rsa" 

Una forma de parar esto es no permitir llamar clone() con la bandera CLONE_VM, y, además, evitar cualquier creación de permisos de escritura MAP_SHARED mapas de memoria (o, al menos, un seguimiento de ellos de tal manera que usted niega cualquier syscall que intenta hacer referencia directa a los datos de dicho mapeo). También puede copiar cualquier argumento en un búfer-buffer no compartido antes de permitir que syscall continúe. Esto evitará efectivamente que se ejecute cualquier aplicación con subprocesos en la zona de pruebas.

La alternativa es SIGSTOP cada dos procesos en el grupo rastreado alrededor de cada syscall potencialmente peligroso, espere a que se detengan realmente, luego permita que se produzca el syscall. Después de que vuelva, usted los SIGCONT (a menos que ya estuvieran detenidos). Huelga decir que esto puede tener un impacto significativo en el rendimiento.

(También hay problemas análogos con los argumentos syscall que se pasan en la pila, y con las tablas compartidas de archivos abiertos).

+0

Aceptado, muy perspicaz, gracias! – pts

+0

¿por qué la solución de copia evita las aplicaciones con hilos? ¿No es la aplicación que espera que la llamada al sistema sea "un poco" atómica, de todos modos? – keppla

+1

@keppla: Porque no puede crear una región de memoria no compartida en una aplicación con subprocesos, ya que todos los subprocesos comparten la misma máquina virtual. La solución de copia a no compartida es para el caso de los argumentos de syscall en regiones de memoria compartidas con otros procesos. – caf

3

No ptrace solo recibe notificaciones después de los hechos? No creo que tengas la oportunidad de detener realmente el canto de syscall, solo para matarlo tan rápido como puedas una vez que veas algo "malvado".

Parece que estás buscando algo más como SELinux o AppArmor, donde puedes garantizar que ni siquiera una llamada ilegal puede pasar.

+0

En Linux, hay PTRACE_SYSEMU, que puede detener el syscall. También gracias por mencionar alternativas. Sin embargo, no veo por qué SELinux o AppArmor serían más seguros, siempre que no haya errores ni condiciones de carrera. ¿Es una suposición razonable? – pts

+1

Una forma común de deshabilitar un syscall es cambiarlo a getpid (2). – maat

Cuestiones relacionadas