Shell Script mktemp, qual é o melhor método para criar pipe nomeado temporário?

30

Estou ciente de que é melhor criar arquivos temporários mktemp, mas e os pipes nomeados?

Prefiro que as coisas sejam o mais compatível possível com POSIX, mas apenas o Linux é aceitável. Evitar Bashisms é o meu único critério difícil, enquanto escrevo dash.

JM Becker
fonte

Respostas:

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

Ao contrário da criação regular de arquivos, que é propensa a ser invadida por um arquivo existente ou por um link simbólico, a criação de um canal de nome mkfifoou a função subjacente cria um novo arquivo no local especificado ou falha. Algo como : >fooé inseguro porque, se o invasor puder prever a saída dele mktemp, poderá criar o arquivo de destino para si mesmo. Mas mkfifo foofalharia em tal cenário.

Se você precisar de portabilidade total do POSIX, mkfifo -m 600 /tmp/myfifoé seguro contra seqüestros, mas propenso a uma negação de serviço; sem acesso a um gerador de nome de arquivo aleatório forte, você precisaria gerenciar tentativas de repetição.

Se você não se importa com os sutis problemas de segurança dos arquivos temporários, pode seguir uma regra simples: crie um diretório privado e mantenha tudo lá.

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- parar de ser mau'
fonte
Na verdade, eu já escolhi isso como minha solução ontem, estava esperando para ver se alguém postou ou uma melhor. Eu também senti que o dir era o caminho a percorrer, no meu caso. Independentemente disso ... Obrigado pela ajuda, agradeço.
JM Becker
11
O comando trap não deveria ser trap "rm -rf '$tempdir'" EXIT HUP INT TERM? Armadilha pode fazer sua própria expansão variável?
Seis
@Six Seu comando se expandirá $tempdirno momento em que o trapcomando for avaliado, não no momento em que a armadilha for acionada. Nesse caso, não faz diferença, exceto que o seu código quebra horrivelmente se o valor de tempdircontiver uma única citação, enquanto o meu código sempre funciona.
Gilles 'SO- stop be evil'
@ Gilles Esse é um bom recurso. Eu tentei o seu exemplo de aspas simples sem sorte, então pensei que o trap não podia avaliar variáveis ​​em tempo de execução. Aconteceu que o meu $tempdirfoi declarado localmente e deve ser definido globalmente para que a armadilha tenha acesso a ele. Faz sentido agora ...
Seis
11
@ Gilles ... desde que o $tempdir valor também não seja alterado, o que é aceitável para basicamente todos os fins. Basta ter cuidado para não usar o mesmo nome para criar vários temporários arquivos / diretórios ...
MestreLion
3

Uma alternativa mais segura é usar mktemppara criar um diretório com segurança e, em seguida, colocar seu pipe nomeado dentro desse diretório, fazer um rm -R $dirpara se livrar dele no final.

David Parks
fonte
Optei por criar o FIFO em um mktempdiretório, pois essa era realmente a única resposta aceitável. Caso você não tenha notado, o @Gilles já postou essa resposta em profundidade.
perfil completo de JM Becker
2

Use a opção "execução a seco":

mkfifo $(mktemp -ut pipe.XXX)
polemon
fonte
11
De acordo com as páginas de manual, o uso da -uopção "não é incentivado".
31412 dogbane
@dogbane Assim é o uso de -t, mas, desde que funcione de forma confiável, eu aceitaria.
precisa saber é
desculpe, onde diz que isso -té desencorajado?
22412 dogbane
2
@dogbane Se for de alguma forma crítica, eu faria um pequeno aplicativo C, chamando a mkstemp()função ( linux.die.net/man/3/mkstemp ). A -ttroca não é desanimada, é -pruim.
Polemon
1

Você pode usar mktemppara criar um arquivo temporário, excluí-lo e criar um pipe nomeado com o mesmo nome.

Por exemplo:

TMPPIPE=$(mktemp -t pipe.XXX) && {
    rm -f $TMPPIPE
    mkfifo $TMPPIPE
}
dogbane
fonte
A exclusão do $TMPPIPEantes mkfifoevita o problema "inseguro" associado a isso TMPPIPE=`mktemp -u` ; mkfifo $TMPPIPE?
JM Becker
11
O @TechZilla mkfifoé realmente seguro, ao contrário da criação normal de arquivos a partir do shell. Caso contrário, criar um arquivo e excluí-lo não ajudariam em nada (na verdade, facilitaria muito o trabalho do invasor, não exigindo que ele adivinhasse o nome do arquivo). Portanto, a resposta do dogbane funciona, mas a criação intermediária de arquivos é uma complicação inútil.
Gilles 'SO- stop be evil'
11
@Gilles, você sabe a respeito da mktemppágina de manual chamada -uopção 'insegura'?
JM Becker
@dogbane, votei na sua resposta e nos seus comentários que senti serem sólidos. Embora eu já tenha concluído isso ontem ... estava esperando para ver quando alguém postou minha solução ou, espero, uma melhor. Então, embora eu tenha usado mktemp -dvocê ainda tem alguns pontos para sua contribuição. Obrigado por toda a sua ajuda, eu realmente aprecio isso!
JM Becker
11
O @TechZilla mktemp -unão é seguro ao criar um arquivo comum, porque fornece proteção contra negação de serviço (se o nome gerado for suficientemente imprevisível), mas não impede que um invasor crie o arquivo sob o nariz do programa. Criar um fifo em vez de um arquivo normal é um caso de uso raro que a página de manual não aborda.
Gilles 'SO- stop be evil'
0

Use mkfifoou mknodno Unix, onde dois processos separados podem acessar o canal pelo nome - um processo pode abri-lo como um leitor e o outro como um escritor.

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

O pipe nomeado pode ser excluído como qualquer arquivo:

rm my_pipe

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

O NamedPipe pode ser usado como arquivo regular para leitura apenas uma vez.

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

Nikhil Mulley
fonte
2
Estou ciente dos pipes nomeados e mkfifo. Ele não aborda minha pergunta sobre pipes nomeados temporários , mais do que mkdirtrataria da criação de diretórios temporários.
JM Becker
2
Como isso mktempresolve os problemas abordados para criar com segurança um pipe nomeado?
Camh
11
oh ok, o melhor é criá-los em / tmp, eles são arquivos temporários por definição e serão limpos assim que o sistema reiniciar. Ou melhor ainda, tenha uma função shell que criará o tubo nomeado a partir do mktempresultado em si (é claro, excluindo o arquivo temporário primeiro e depois executando mkfifoo mesmo). mktemptambém pode ser usado para criar um diretório temporário, tente com -t -dswitch.
precisa saber é o seguinte