No momento, estou escrevendo um script bash que usa inotifywait
para executar determinadas ações em uma lista de arquivos e diretórios fornecida pelo usuário.
Chegou ao meu conhecimento que, ao contrário de muitas ferramentas de shell, inotifywait
não é possível separar registros de saída com extensão \0
. Isso deixa a possibilidade de ataques de injeção com nomes de arquivos especificamente criados, mas legais (contendo novas linhas).
Eu gostaria de contornar isso para garantir que meu script não apresente vulnerabilidades desnecessárias. Minha abordagem é a seguinte:
- Certifique-se de que todos os arquivos/caminhos passados para
inotifywait
assistir tenham as barras invertidas à direita removidas - Formate
inotifywait
a saída com--format "%e %w%f//"
para produzir a saída da seguinte forma:<EVENT LIST> <FILE PATH>//
- Saída do tubo
inotifywait
para sed; qualquer//
encontrado nas extremidades das linhas com\0
- Use o loop bash
while read
para ler\0
registros separados - Isso significa que após o primeiro registro, todos os registros seguintes terão uma nova linha inicial extra. Isso é arrancado
- Cada registro pode então ser dividido no primeiro espaço - antes do espaço está a lista de eventos (separados por vírgula conforme inotifywait) - e após o espaço o caminho completo associado ao evento
#!/bin/bash
shopt -s extglob
watchlist=("${@}")
# Remove trailing slashes from any watchlist elements
watchlist=("${watchlist[@]%%+(/)}")
# Reduce multiple consecutive slashes to singles as per @meuh
watchlist=("${watchlist[@]//+(\/)/\/}")
printf -vnewline "\n"
inotifywait -qrm "${watchlist[@]}" --format "%e %w%f//" | \
sed -u 's%//$%\x00%' | \
while IFS= read -r -d '' line; do
line="${line#${newline}}"
events="${line%% *}"
filepath="${line#* }"
printf "events=%s\nfilepath=%q\n" "$events" "$filepath"
done
Tanto quanto eu posso dizer, isso lida com nomes de arquivos/caminhos contendo caracteres engraçados - espaços, novas linhas, aspas, etc. Mas parece um truque bastante deselegante.
Para os fins desta questão, a ${watchlist[]}
matriz é apenas copiada dos parâmetros da linha de comando, mas essa matriz pode ser construída de outra forma e pode conter caracteres "engraçados".
Existem caminhos maliciosos que podem quebrar isso? ou seja, tornar o conteúdo das variáveis
$events
e incorreto para um determinado evento?$filepath
Se for à prova d'água, existe alguma maneira mais limpa de fazer isso?
Observe que sei que poderia facilmente escrever um programa c para chamar inotify_add_watch()
e amigos para contornar isso. Mas por enquanto devido a outras dependências estou trabalhando no bash.
Estou em dúvida se devo postar isso aqui ou codereview.SE ou mesmo o so.SE principal.
Existe um fork que suporta saída delimitada por NUL, você pode usá-lo assim:
Observe que esta versão não adiciona nova linha por padrão quando --format é usado.
Você precisaria higienizar
watchlist
para substituir qualquer um//
por/
. Considere um diretório chamado\nabc
(onde\n
é uma nova linha):Se passado o diretório
t//$'\nabc'
, você verá a saída com falso//
no final das linhas:Observe que você também pode usar
-c
em vez de--format
obter uma saída no estilo csv , que coloca aspas duplas nos nomes dos arquivos com novas linhas, mas é mais difícil de analisar e, no meu caso, despejos principais no exemplo acima.Saída de exemplo para
-c
etouch t/$'new\nfile'
: