É possível usar 'find -exec sh -c' com segurança?

22

Estou tentando usar find to echo 0 em alguns arquivos, mas aparentemente isso só funciona com sh -c :

find /proc/sys/net/ipv6 -name accept_ra -exec sh -c 'echo 0 > {}' \;

Mas usar sh -c com find -exec me deixa muito desconfortável porque suspeito de citar problemas. Eu brinquei um pouco com isso e aparentemente minhas suspeitas eram justificadas:

  • Minha configuração de teste:

    martin@dogmeat ~ % cd findtest 
    martin@dogmeat ~/findtest % echo one > file\ with\ spaces
    martin@dogmeat ~/findtest % echo two > file\ with\ \'single\ quotes\'
    martin@dogmeat ~/findtest % echo three > file\ with\ \"double\ quotes\"
    martin@dogmeat ~/findtest % ll
    insgesamt 12K
    -rw-rw-r-- 1 martin martin 6 Sep 17 12:01 file with "double quotes"
    -rw-rw-r-- 1 martin martin 4 Sep 17 12:01 file with 'single quotes'
    -rw-rw-r-- 1 martin martin 4 Sep 17 12:01 file with spaces
    
  • Usar find -exec sem sh -c parece funcionar sem problemas - não é necessário citar aqui:

    martin@dogmeat ~ % find findtest -type f -exec cat {} \;
    one
    two
    three
    
  • Mas quando estou usando sh -c {} parece exigir algum tipo de cotação:

    martin@dogmeat ~ % LANG=C find findtest -type f -exec sh -c 'cat {}' \;
    cat: findtest/file: No such file or directory
    cat: with: No such file or directory
    cat: spaces: No such file or directory
    cat: findtest/file: No such file or directory
    cat: with: No such file or directory
    cat: single quotes: No such file or directory
    cat: findtest/file: No such file or directory
    cat: with: No such file or directory
    cat: double quotes: No such file or directory
    
  • As aspas duplas funcionam desde que nenhum nome de arquivo contenha aspas duplas:

    martin@dogmeat ~ % LANG=C find findtest -type f -exec sh -c 'cat "{}"' \;
    one
    two
    cat: findtest/file with double: No such file or directory
    cat: quotes: No such file or directory
    
  • Aspas simples funcionam desde que nenhum nome de arquivo contenha aspas simples:

    martin@dogmeat ~ % LANG=C find findtest -type f -exec sh -c "cat '{}'" \;
    one
    cat: findtest/file with single: No such file or directory
    cat: quotes: No such file or directory
    three
    

Não encontrei uma solução que funcione em todos os casos. Há algo que estou negligenciando ou que está usando sh -c em find -exec inerentemente inseguro?

    
por Martin von Wittich 17.09.2014 / 12:08

1 resposta

34

Nunca incorpore {} no código da shell! Isso cria uma vulnerabilidade de injeção de comando. Observe que, para cat "{}" , não apenas os caracteres " , \ , ' , $ também são um problema (considere, por exemplo, um arquivo chamado ./$(reboot)/accept_ra ).

(a propósito, algumas find implementações ganham ' Deixe-o fazer isso, e POSIX deixa o comportamento não especificado quando {} não está sozinho em um argumento para find )

Aqui, você desejaria passar os nomes de arquivos como argumentos separados para sh (não no argumento código ) e o script sh inline (o código argumento) para se referir a eles usando parâmetros posicionais:

find . -name accept_ra -exec sh -c 'echo 0 > "$1"' sh {} \;

Ou para evitar a execução de um sh por arquivo:

find . -name accept_ra -exec sh -c 'for file do
  echo 0 > "$file"; done' sh {} +

Observe que o segundo sh acima vai para o $0 do script embutido. Você deve usar algo relevante lá (como sh ou find-sh ), não coisas como _ , - , -- ou a sequência vazia, pois o valor em $0 é usado para as mensagens de erro da shell :

$ find . -name accept_ra -exec sh -c 'echo 0 > "$1"' inline-sh {} \;
inline-sh: ./accept_ra: Permission denied
    
por 17.09.2014 / 12:26

Tags