Shell Script mktemp, ¿cuál es el mejor método para crear una canalización con nombre temporal?

30

Sé que es mejor crear archivos temporales mktemp, pero ¿qué pasa con las canalizaciones con nombre?

Prefiero que las cosas sean tan compatibles con POSIX como sea posible, pero Linux solo es aceptable. Evitar los bashismos es mi único criterio difícil, mientras escribo dash.

JM Becker
fuente

Respuestas:

41
tmppipe=$(mktemp -u)
mkfifo -m 600 "$tmppipe"

A diferencia de la creación de archivos normal, que es propensa a ser secuestrada por un archivo existente o un enlace simbólico, la creación de una canalización de nombre mkfifoo la función subyacente crea un nuevo archivo en el lugar especificado o falla. Algo así : >fooes inseguro porque si el atacante puede predecir el resultado, mktempentonces el atacante puede crear el archivo de destino por sí mismo. Pero mkfifo foofallaría en tal escenario.

Si necesita portabilidad POSIX completa, mkfifo -m 600 /tmp/myfifoes seguro contra el secuestro pero propenso a una denegación de servicio; sin acceso a un generador de nombre de archivo aleatorio fuerte, necesitaría administrar los intentos de reintento.

Si no le importan los sutiles problemas de seguridad relacionados con los archivos temporales, puede seguir una regla simple: crear un directorio privado y mantener todo allí.

tmpdir=
cleanup () {
  if [ -n "$tmpdir" ] ; then rm -rf "$tmpdir"; fi
  if [ -n "$1" ]; then kill -$1 $$; fi
}
tmpdir=$(mktemp -d)
trap 'cleanup' EXIT
trap 'cleanup HUP' HUP
trap 'cleanup TERM' TERM
trap 'cleanup INT' INT
mkfifo "$tmpdir/pipe"
Gilles 'SO- deja de ser malvado'
fuente
En realidad, ayer elegí esto como mi solución, estaba esperando para ver si alguien lo publicó, o uno mejor. También sentí que el dir era el camino a seguir, en mi caso. Independientemente ... Gracias por la ayuda, lo aprecio.
JM Becker
1
¿No debería ser el comando trampa trap "rm -rf '$tempdir'" EXIT HUP INT TERM? ¿Puede trap hacer su propia expansión variable?
Seis
@Six Su comando se expandiría $tempdiren el momento en que trapse evalúa el comando, no en el momento en que se activa la trampa. En este caso, no hace ninguna diferencia, excepto que su código se rompe horriblemente si el valor de tempdircontiene una comilla simple, mientras que mi código siempre funciona.
Gilles 'SO- deja de ser malvado'
@Gilles Esa es una buena característica. Había probado su ejemplo de comillas simples sin suerte, así que pensé que trap no podía evaluar variables en tiempo de ejecución. Resultó que my $tempdirfue declarado localmente y debe definirse globalmente para que trap tenga acceso a él. Tiene sentido ahora ...
Seis
1
@Gilles ... siempre y cuando el $tempdir valor tampoco cambie, lo cual es aceptable básicamente para todos los propósitos. Solo tenga cuidado de no usar el mismo nombre para crear múltiples archivos /
directorios
3

Una alternativa más segura es usar mktemppara crear un directorio de forma segura, luego colocar su canalización con nombre dentro de ese directorio, y hacer una rm -R $dirpara deshacerse de él al final.

David Parks
fuente
Opté por crear el FIFO en un mktempdirectorio, ya que era realmente la única respuesta aceptable. En caso de que no lo haya notado, @Gilles ya publicó esta respuesta en profundidad.
JM Becker
2

Utilice la opción "ejecución en seco":

mkfifo $(mktemp -ut pipe.XXX)
polemon
fuente
1
Según las páginas del manual, el uso de la -uopción "no se recomienda".
dogbane
@dogbane Así es el uso de -t, pero mientras funcione de manera confiable, iría con él.
polemon
lo siento, ¿dónde dice que -tse desaconseja?
dogbane
2
@dogbane Si es de alguna manera crítica, haría una pequeña aplicación C, llamando a la mkstemp()función ( linux.die.net/man/3/mkstemp ). El -tcambio no se desaconseja, es -pmi mal.
polemon
1

Puede usar mktemppara crear un archivo temporal, luego eliminarlo y crear una tubería con el mismo nombre.

Por ejemplo:

TMPPIPE=$(mktemp -t pipe.XXX) && {
    rm -f $TMPPIPE
    mkfifo $TMPPIPE
}
dogbane
fuente
¿Eliminar el $TMPPIPEantes de mkfifoevitar el problema 'inseguro' asociado de hacer TMPPIPE=`mktemp -u` ; mkfifo $TMPPIPE?
JM Becker
1
@TechZilla mkfifoes realmente seguro, a diferencia de la creación de archivos habitual desde el shell. Si no fuera así, crear un archivo y luego eliminarlo no ayudaría en absoluto (de hecho, facilitaría enormemente el trabajo del atacante al no requerir que adivine el nombre del archivo). Entonces, la respuesta de dogbane funciona, pero la creación de archivos intermedios es una complicación inútil.
Gilles 'SO- deja de ser malvado'
1
@Gilles, ¿sabe en qué sentido la mktemppágina del manual llama a la -uopción 'insegura'?
JM Becker
@dogbane, voté por su respuesta y sus comentarios, que sentí que eran sólidos. Aunque, ya completé esto ayer. Estaba esperando ver cuándo alguien publicó mi solución o, con suerte, una mejor. Entonces, aunque lo usé mktemp -d, todavía obtuve algunos puntos por su aporte. Gracias por toda su ayuda, ¡realmente lo aprecio!
JM Becker
1
@TechZilla mktemp -uno es seguro al crear un archivo normal, ya que proporciona la protección contra la denegación de servicio (si el nombre que genera es lo suficientemente impredecible) pero no impide que un atacante cree el archivo bajo la nariz del programa. Crear un fifo en lugar de un archivo normal es un caso de uso raro que la página del manual no aborda.
Gilles 'SO- deja de ser malvado'
0

Use mkfifoo mknoden Unix, donde dos procesos separados pueden acceder a la tubería por nombre: un proceso puede abrirlo como lector y el otro como escritor.

mkfifo my_pipe
gzip -9 -c < my_pipe > out.gz
cat file > my_pipe

La tubería con nombre se puede eliminar como cualquier archivo:

rm my_pipe

mkfifo --mode=0666 /tmp/namedPipe
gzip --stdout -d file.gz > /tmp/namedPipe

NamedPipe se puede usar un archivo normal para leer solo una vez.

http://www.linuxjournal.com/article/2156

Nikhil Mulley
fuente
2
Soy completamente consciente de las tuberías con nombre, y mkfifo. No aborda mi pregunta sobre las canalizaciones con nombre temporales , más de mkdirlo que abordaría la creación de directorios temporales.
JM Becker
2
¿Cómo aborda esto los problemas que se mktempabordan para crear de forma segura una tubería con nombre?
camh
1
oh ok, lo mejor es crearlos en / tmp, son archivos temporales por definición y se borrarán una vez que el sistema se reinicie. O mejor aún, tenga una función de shell que cree la tubería nombrada a partir del mktempresultado mismo (por supuesto, eliminando primero el archivo temporal y luego ejecutándolo mkfifoen el mismo). mktempTambién se puede utilizar para crear un directorio temporal, intente con el -t -dinterruptor.
Nikhil Mulley