`Find -exec sh -c` yi güvenle kullanmak mümkün mü?


29

Ben kullanmaya çalışıyorum findiçin echo 0bazı dosyalar halinde, ancak görünüşe göre bu sadece çalışır sh -c:

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

Ama kullanarak sh -cile find -execSorunlarım alıntı zanlısı çünkü markaların beni çok huzursuz hissediyorum. Bununla biraz uğraştım ve görünüşe göre şüphelerim haklı çıktı:

  • Test kurulumum:

    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
  • find -execOlmadan kullanmak sorunsuz çalışıyor sh -cgibi görünüyor - burada alıntı yapılması gerekmiyor:

    martin@dogmeat ~ % find findtest -type f -exec cat {} \;
    one
    two
    three
  • Ama kullandığımda sh -c {}bir çeşit alıntı yapılması gerekiyor gibi görünüyor:

    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
  • Çift tırnak, dosya adı çift tırnak içermediği sürece çalışır:

    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
  • Tek tırnak, hiçbir dosya adı tek tırnak içermediği sürece çalışır:

    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

Her durumda işe yarayan bir çözüm bulamadım. Orada bir şey bakan ediyorum, yoksa kullandığını sh -ciçinde find -execdoğal olarak tehlikelidir?

Yanıtlar:


40

Asla {}kabuk koduna gömme ! Bu bir komut enjeksiyon güvenlik açığı yaratır. Not için bunu cat "{}"bu, yaklaşık sadece "karakterler, \, `, $aynı zamanda bir sorun vardır (örneğin adlı bir dosya düşünün ./$(reboot)/accept_ra).

(bu arada, bazı finduygulamalar bunu yapmanıza izin vermez ve POSIX davranışı bırakır belirtilmemiş zaman {}kendi başına değil bir argüman find)

Burada, dosya adlarını ayrı ayrı argümanlar olarak sh( kod argümanında değil) ve shsatır içi komut dosyası ( kod argümanı) konumsal parametreler kullanarak başvurmak üzere iletmek istersiniz :

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

Veya shdosya başına bir çalıştırmayı önlemek için :

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

Aynı için de geçerlidir xargs -I{}ya da zsh's zargs -I{}. Yazmayın:

<list.txt xargs -I {} sh -c 'cmd> {}'

Bu, findyukarıdakilerle aynı şekilde bir komut enjeksiyonu güvenlik açığı olacaktır , ancak:

<list.txt xargs sh -c 'for file do cmd > "$file"; done' sh

Ayrıca, shdosya başına bir dosyayı çalıştırmaktan kaçınmanın yararı ve list.txthiçbir dosya içermediği zaman da hatadır .

İle zshs' zargs, muhtemelen çağırma yerine bir fonksiyonu kullanmak isterdim sh -c:

do-it() cmd > $1
zargs ./*.txt -- do-it

Yukarıdaki tüm örneklerde yukarıdaki ikinci shsatır içi komut dosyasının içine girdiğine dikkat edin $0. Orada alakalı bir şey (gibi kullanmalısınız shveya find-sh) değil şeyler gibi _, -, --, veya boş dize değeri olarak $0Shell'in hata iletileri için kullanılır:

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

GNU parallelfarklı çalışıyor. Bununla beraber, do not kullanmak istediğiniz sh -cşekilde parallelyerine zaten ve çalışır bir kabuk çalışıyor mu {}kabuk doğru sözdizimine alıntı argüman ile .

<list.txt PARALLEL_SHELL=sh parallel 'cmd > {}'

şu ikinci shyerini ise çok çalışır, yer tutucu çeşit gibi görünüyor _örneğin - Eğer bash internals aramak istiyorsanız çok kullanışlı: find /tmp -name 'fil*' -exec bash -c 'printf "%q\n" "$1"' _ {} \;. Ama bunun nerede belgelendiğini bilen var mı?
Florian Fida

1
@FlorianFida Kabuğun ilk argümanı olur $0(genellikle kabuğun adı. Bu senaryoda atlamanız gerekir, böylece normal konum argümanlarınızdan birini yemez.) Bu -c
konuyla ilgili


1
@phk, argv[0]burada değil , sadece $0betiğin içinde. Sven'in sayfası burada yanlış, bir rkabuk söyleyebileceği kadar sınırlı bir moda girmeyecek ve zshmodu değiştirerek değiştirmeyecek $0. (exec -a rksh ksh -c 'cd /')bir sınırlı çalışacak ksh, ama değil ksh -c 'cd /' rksh).
Stéphane Chazelas

1
Stéphane, sakıncası yoksa, "neden {} kabuk koduna gömülmediğini" açıklayan bir cevabınız var mı? Tüm cevapların bulsa da buldum ama bir tane bulamadım ama yemin edebildiğim halde bu konuyla ilgili yazmış olduğun bazı şeyleri gördüm ama bir cevap, hatırlama, sohbette bir yorum veya compunix gibi başka bir sitede hatırlayamadım. zaman varken ... Eğer /, siz "gömmek Asla {}" kısmında genişleyen misin yoksa biz özel bir Q örn olmalı sizce "kullanmakla Güvenlik etkileri findile -exec sh -cve gömme {}kabuk kodundaki" ?
don_crissti
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.