Shell Script mktemp, quelle est la meilleure méthode pour créer un canal nommé temporaire?

30

Je suis conscient qu'il est préférable de créer des fichiers temporaires avec mktemp, mais qu'en est-il des canaux nommés?

Je préfère que les choses soient aussi conformes que possible à POSIX, mais Linux seul est acceptable. Éviter les bashismes est mon seul critère difficile, au moment où j'écris dash.

JM Becker
la source

Réponses:

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

Contrairement à la création régulière de fichiers, susceptible d'être détournée par un fichier existant ou un lien symbolique, la création d'un canal de nom mkfifoou la fonction sous - jacente crée un nouveau fichier à l'emplacement spécifié ou échoue. Quelque chose comme : >foon'est pas sûr car si l'attaquant peut prédire la sortie de mktempl'attaquant, il peut créer le fichier cible pour lui-même. Mais mkfifo fooéchouerait dans un tel scénario.

Si vous avez besoin de la pleine portabilité POSIX, mkfifo -m 600 /tmp/myfifoest sûr contre le détournement mais enclin à un déni de service; sans accès à un puissant générateur de noms de fichiers aléatoires, vous devez gérer les tentatives de nouvelle tentative.

Si vous ne vous souciez pas des subtils problèmes de sécurité liés aux fichiers temporaires, vous pouvez suivre une règle simple: créer un répertoire privé et tout y conserver.

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, arrête de faire le mal
la source
En fait, j'ai déjà choisi cela comme solution plus tôt hier, j'attendais de voir si quelqu'un l'a posté, ou mieux. J'ai également senti que le dir était la voie à suivre, dans mon cas. Quoi qu'il en soit ... Merci pour l'aide, je l'apprécie.
JM Becker
1
La commande trap ne devrait-elle pas être trap "rm -rf '$tempdir'" EXIT HUP INT TERM? Le piège peut-il faire sa propre expansion variable?
Six
@Six Votre commande se développerait $tempdirau moment où la trapcommande est évaluée, pas au moment où l'interruption est déclenchée. Dans ce cas, cela ne fait aucune différence, sauf que votre code casse horriblement si la valeur de tempdircontient un seul guillemet, alors que mon code fonctionne toujours.
Gilles 'SO- arrête d'être méchant'
@Gilles C'est une fonctionnalité intéressante. J'avais essayé votre exemple de devis unique sans chance, donc je pensais que trap n'était pas en mesure d'évaluer les variables au moment de l'exécution. Il s'est avéré que my a $tempdirété déclaré localement et il doit être défini globalement pour que trap puisse y accéder. Ça a du sens maintenant ...
Six
1
@Gilles ... tant que la $tempdir valeur ne change pas non plus, ce qui est acceptable à toutes fins utiles.
Faites
3

Une alternative plus sûre consiste à utiliser mktemppour créer un répertoire en toute sécurité, puis placez votre canal nommé dans ce répertoire, faites un rm -R $dirpour vous en débarrasser à la fin.

David Parks
la source
J'ai choisi de créer le FIFO dans un mktemprépertoire, car c'était vraiment la seule réponse acceptable, juste au cas où vous ne l'auriez pas remarqué, @Gilles a déjà posté cette réponse en profondeur.
JM Becker
2

Utilisez l'option "dry-run":

mkfifo $(mktemp -ut pipe.XXX)
polemon
la source
1
Selon les pages de manuel, l'utilisation de l' -uoption "n'est pas encouragée".
Dogbane
@dogbane Il en va de même pour l'utilisation -t, mais tant que cela fonctionne de manière fiable, j'irais avec.
polemon
désolé, où est-il dit que -tc'est découragé?
dogbane
2
@dogbane Si c'est critique, je ferais une petite application C, appelant la mkstemp()fonction ( linux.die.net/man/3/mkstemp ). L' -tinterrupteur n'est pas découragé, c'est -pmon mauvais.
polemon
1

Vous pouvez utiliser mktemppour créer un fichier temporaire, puis le supprimer et créer un canal nommé avec le même nom.

Par exemple:

TMPPIPE=$(mktemp -t pipe.XXX) && {
    rm -f $TMPPIPE
    mkfifo $TMPPIPE
}
dogbane
la source
La suppression de l' $TMPPIPEavant avant mkfifoévite-t-elle le problème «dangereux» associé TMPPIPE=`mktemp -u` ; mkfifo $TMPPIPE?
JM Becker
1
@TechZilla mkfifoest en fait sûr, contrairement à la création habituelle de fichiers à partir du shell. Si ce n'était pas le cas, créer un fichier puis le supprimer ne serait d'aucune utilité (en fait, cela faciliterait grandement le travail de l'attaquant en ne l'obligeant pas à deviner le nom du fichier). La réponse de dogbane fonctionne donc, mais la création de fichier intermédiaire est une complication inutile.
Gilles 'SO- arrête d'être méchant'
1
@Gilles, Savez-vous à quel égard la mktemppage de manuel a appelé l' -uoption «dangereux»?
JM Becker
@dogbane, j'ai voté en faveur de votre réponse et de vos commentaires qui m'ont paru solides. Bien que j'aie déjà terminé cela hier .. J'attendais juste de voir quand quelqu'un a posté ma solution ou, espérons-le, une meilleure. Donc, même si j'ai utilisé, mktemp -dvous avez quand même obtenu quelques points pour votre contribution. Merci pour toute votre aide, je l'apprécie vraiment!
JM Becker
1
@TechZilla mktemp -un'est pas sûr lors de la création d'un fichier normal, car il offre une protection contre le déni de service (si le nom qu'il génère est suffisamment imprévisible) mais n'empêche pas un attaquant de créer le fichier sous le nez du programme. La création d'un fifo au lieu d'un fichier normal est un cas d'utilisation rare que la page de manuel ne traite pas.
Gilles 'SO- arrête d'être méchant'
0

Utilisez mkfifoou mknodsous Unix, où deux processus distincts peuvent accéder au canal par son nom - un processus peut l'ouvrir en tant que lecteur et l'autre en tant que rédacteur.

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

Le canal nommé peut être supprimé comme n'importe quel fichier:

rm my_pipe

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

NamedPipe peut être utilisé dans un fichier normal pour une seule lecture.

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

Nikhil Mulley
la source
2
Je suis parfaitement au courant des pipes nommées et mkfifo. Il ne répond pas à ma question sur les canaux nommés temporaires , pas plus qu'à la mkdircréation de répertoires temporaires.
JM Becker
2
Comment cela résout-il les problèmes liés mktempà la création en toute sécurité d' un canal nommé?
camh
1
oh ok, le mieux est de les créer sous / tmp, ce sont des fichiers temporaires par définition et disparaîtront une fois le système redémarré. Ou mieux encore, disposez d'une fonction shell qui créera le tube nommé à partir du mktemprésultat lui-même (bien sûr, en supprimant d'abord le fichier temporaire, puis en l'exécutant mkfifo). mktemppeut également être utilisé pour créer un répertoire temporaire, essayez avec -t -dswitch.
Nikhil Mulley