2010-03-31 15 views
6
  • Quiero anexar datos a un archivo en/tmp.
  • Si el archivo no existe quiero crearlo
  • No me importa si alguien más posee el archivo. La información no es secreta
  • No quiero que alguien pueda competir-condicionar esto para escribir en otro lado, o en otro archivo.

¿Cuál es la mejor manera de hacerlo?¿Cómo debo protegerme contra los ataques de enlaces duros?

Aquí está mi pensamiento:

fd = open("/tmp/some-benchmark-data.txt", O_APPEND | O_CREAT | O_NOFOLLOW | O_WRONLY, 0644); 
fstat(fd, &st); 
if (st.st_nlink != 1) { 
    HARD LINK ATTACK! 
} 

problema con esto: Alguien puede vincular el archivo a un archivo de corta duración de la mina, de manera que /tmp/some-benchmark-data.txt es lo mismo que/tmp/tmpfileXXXXXX que otro script mío está usando (y se abrió correctamente usando O_EXCL y todo eso). Mis datos de referencia se anexan a este archivo/tmp/tmpfileXXXXXX, mientras todavía se usa.

Si mi otra secuencia de comandos pasó a abrir su archivo temporal, entonces elimínelo, luego úselo; entonces el contenido de ese archivo se corrompería con mis datos de referencia. Esta otra secuencia de comandos tendría que eliminar su archivo entre open() y fstat() del código anterior.

Así, en otras palabras:

This script   Dr.Evil  My other script or program 
            open(fn2, O_EXCL | O_CREAT | O_RDWR) 
        link(fn1,fn2) 
open(fn1, ...) 
            unlink(fn2) 
fstat(..)=>link is 1 
write(...) 
close(...) 
            write(...) 
            seek(0, ...) 
            read(...) => (maybe) WRONG DATA! 

Y por lo tanto, la solución anterior no funciona. Posiblemente haya otros ataques.

¿Cuál es el camino correcto? Además de no usar un directorio de escritura mundial.

Editar: Con el fin de proteger contra el resultado de que el usuario del mal crea el archivo con su/su propiedad y los permisos, o simplemente permisos incorrectos (por dura que une su archivo y luego retirar el original, o un enlace duro una archivo efímero tuyo) Puedo verificar los bits de propiedad y permiso después de la verificación nlink.

No habría problemas de seguridad, pero también evitaría sorpresas. El peor caso es que obtengo algunos de mis propios datos (de otro archivo) al principio del archivo copiados de algún otro archivo mío.

Editar 2: creo que es casi imposible proteger contra alguien difíciles de vincular el nombre de un archivo que está abierto, borrado y luego se usa. Ejemplos de esto son los empaquetadores EXE, que a veces incluso ejecutan el archivo eliminado a través de/proc/pid/fd-num. Compita con esto provocaría un error en la ejecución del programa empaquetado. Probablemente, lsof podría encontrar si alguien más tiene abierto el inodo, pero parece ser más problemático de lo que vale.

+0

Es solo un ataque antes de que se cree el archivo. Si soy un usuario estándar, puedo crear un enlace a cualquier archivo (incluso si no puedo escribir en ese archivo) en cualquier directorio en el que pueda escribir. Eso significa que puedo crear un archivo llamado '/ tmp/foo' que es un enlace duro de '/ etc/passwd'. Ahora cuando su programa escribe en '/ tmp/foo', realmente está escribiendo en'/etc/passwd'. Él quiere evitar esto asegurándose de que el suyo sea el primer enlace al inodo que creó. – Gabe

+0

@gabe: a la derecha. Por eso reviso st_nlink. Puede crear un nuevo enlace a los archivos de otras personas, pero no puede eliminarlos (disminuya el número de enlaces). – Thomas

+0

Buen punto, Thomas. Si mi comentario se ve raro es porque estaba respondiendo a otro comentario que se ha eliminado desde entonces. – Gabe

Respuesta

2

Hagas lo que hagas, generalmente obtendrás una condición de carrera donde otra persona crea un enlace, y luego la eliminará cuando se ejecute tu llamada al sistema fstat().

No ha dicho exactamente lo que está tratando de evitar. Ciertamente, hay parches de kernel que impiden crear enlaces (duros o simbólicos) a archivos que no son de su propiedad en directorios de escritura mundial (o directorios adhesivos).

Ponerlo en un directorio que no se pueda escribir en todo el mundo parece ser lo correcto.

SELinux, que parece ser la seguridad mejorada estándar de Linux, puede configurar políticas para prohibir a los usuarios hacer cosas malas que rompan su aplicación.

En general, si está ejecutando como root, no cree archivos en/tmp. Otra posibilidad es usar setfsuid() para configurar el uid del sistema de archivos a otra persona, y luego, si el usuario no puede escribir ese archivo, la operación simplemente fallará.

+0

Pensé en esto, pero si crean un enlace a un archivo que no les pertenece, entonces no podrán eliminar ese enlace. En un directorio o + t que/tmp es que solo puede eliminar los archivos (enlaces) que posee. Por lo tanto, no podrán volver a disminuir st_nlink a 1. – Thomas

+0

Sí, pero es posible que puedan eliminarlo del otro directorio en el que se encuentra, si tienen acceso de escritura. – MarkR

+0

Pero, ¿qué ganan entonces? ¿No es lo mismo que crear el archivo en/tmp el primer lugar al que se va a anexar? – Thomas

1

corto de lo que se acaba de ilustrar, la única cosa que he intentado terminó casi por igual racey y mucho más caro, estableciendo inotify relojes de encendido/tmp antes a la creación del archivo, lo que permite controlar el caso de una Hardlink en algunos casos.

Sin embargo, sigue siendo muy inestable e ineficaz, ya que también necesitaría completar una primera búsqueda de ancho de/tmp, al menos hasta el nivel que desea crear el archivo.

No existe (para mi conocimiento) una manera "segura" de evitar este tipo de raza, aparte de no utilizar directorios de escritura de palabras. ¿Cuáles son las consecuencias de que alguien intercepte su E/S a través de un enlace fijo ... obtendrían algo útil o simplemente harían que su aplicación muestre un comportamiento indefinido?

+0

Los datos en sí no son secretos. Solo se trata de datos de referencia. "La función X tardó 2 segundos". – Thomas

Cuestiones relacionadas