В чому проблема
По-перше, як і для багатьох утиліт, у вас виникне проблема з іменами файлів, починаючи з -. Перебуваючи в:
sh -c 'inline sh script here' other args
Інші аргументи передаються до inline sh script; з perlеквівалентом,
perl -e 'inline perl script here' other args
Інші аргументи перевіряються на наявність більш варіантів PERL перший, не інлайн сценарію. Так, наприклад, якщо -eBEGIN{do something evil}в поточному каталозі є файл, який називається ,
perl -ne 'inline perl script here;' *
(з чи без -n) зробить щось зле.
Як і для інших утиліт, вирішення цього завдання - використання маркера кінця параметрів ( --):
perl -ne 'inline perl script here;' -- *
Але навіть тоді це все ще небезпечно, і це стосується <>оператора, який використовує -n/ -p.
Проблема пояснюється в perldoc perlopдокументації.
Цей спеціальний оператор використовується для зчитування одного рядка (один запис; записи за замовчуванням є рядками) вводу, де цей вхід надходить з кожного переданого аргументу по черзі @ARGV.
В:
perl -pe '' a b
-pпередбачає while (<>)цикл навколо коду (тут порожній).
<>спочатку відкриється a, прочитає записи по одному рядку, поки файл не вичерпається, а потім відкриється b...
Проблема полягає в тому, що для відкриття файлу він використовує першу, небезпечну форму open:
open ARGV, "the file as provided"
З цією формою, якщо аргумент є
"> afile", відкривається afileв режимі письма,
"cmd|", він працює cmdі читає його вихід.
"|cmd", у вас відкритий потік для запису на вхід cmd.
Так, наприклад:
perl -pe '' 'uname|'
Не виводить вміст файла, що називається uname|(ідеально правильне ім'я файлу btw), але вихід unameкоманди.
Якщо ви працюєте:
perl -ne 'something' -- *
І хтось створив файл з назвою rm -rf "$HOME"|(знову-таки цілком правильне ім'я файлу) у поточному каталозі (наприклад, через те, що цей каталог колись могли записувати інші, або ви витягнули хитромудрий архів, або ви виконали якусь команду dodgy, або була використана інша вразливість у якомусь іншому програмному забезпеченні), то ви великі проблеми. Сфери, де важливо знати про цю проблему, - це інструменти, які автоматично обробляють файли в публічних областях /tmp(наприклад, інструменти, які можуть бути викликані такими інструментами).
Файли називаються > foo, foo|, |fooє проблемою. Але в меншій мірі < fooі fooз провідними або кінцевими символами інтервалів ASCII (включаючи пробіл, вкладку, новий рядок, cr ...), а це означає, що ці файли не будуть оброблені, або неправильний буде.
Також майте на увазі, що деякі символи в деяких багатобайтових наборах символів (наприклад, ǖу BIG5-HKSCS) закінчуються на байт 0x7c, кодування |.
$ printf ǖ | iconv -t BIG5-HKSCS | od -tx1 -tc
0000000 88 7c
210 |
0000002
Тож у локалі, що використовують цю гарнітуру,
perl -pe '' ./nǖ
Спробував би запустити ./n\x88команду , як perlби НЕ намагатися інтерпретувати це ім'я файлу локалі користувача!
Як виправити / обійти
AFAIK, ви нічого не можете зробити, щоб змінити таку небезпечну поведінку за замовчуванням perlраз і назавжди для всієї системи.
По-перше, проблема виникає лише з символами на початку та в кінці імені файлу. Отже, хоча perl -ne '' *або perl -ne '' *.txtє проблемою,
perl -ne 'some code' ./*.txt
не тому , що всі аргументи тепер починаються з ./і закінчуються .txt(так не -, <, >, |, космос ...). В цілому, це хороша ідея , щоб Приставка кульки з ./. Це також дозволяє уникнути проблем з файлами, що викликаються -або починаються з -багатьох інших утиліт (і ось, це означає, що вам більше не потрібен --маркер кінця параметрів ( ).
Використання -Tдля включення taintрежиму допомагає певною мірою. Вона скасує команду, якщо зустрінеться такий шкідливий файл (лише для випадків >і |випадків, а не <пробілів).
Це корисно при інтерактивному використанні таких команд, оскільки це попереджає про те, що відбувається щось хитре. Це може виявитися небажаним при автоматичній обробці, оскільки це означає, що хтось може зробити цю обробку невдалою, просто створивши файл.
Якщо ви хочете обробити кожен файл, незалежно від їх імені, ви можете використовувати в ARGV::readonly perlмодуль на CPAN ( до жаль , як правило , не встановлюється за умовчанням). Це дуже короткий модуль, який робить:
sub import{
# Tom Christiansen in Message-ID: <24692.1217339882@chthon>
# reccomends essentially the following:
for (@ARGV){
s/^(\s+)/.\/$1/; # leading whitespace preserved
s/^/< /; # force open for input
$_.=qq/\0/; # trailing whitespace preserved & pipes forbidden
};
};
В основному, це sanitizes @ARGV, перетворюючи, " foo|"наприклад, на "< ./ foo|\0".
Ви можете зробити те ж саме у BEGINзаяві у вашій perl -n/-pкоманді:
perl -pe 'BEGIN{$_.="\0" for @ARGV} your code here' ./*
Тут ми спростимо його на основі припущення, ./яке використовується.
Побічним ефектом цього (та ARGV::readonly), хоча, є те, що $ARGVв your code hereпоказах, що слідує символ NUL.
Оновити 2015-06-03
perlv5.21.5 і вище є новий <<>>оператор, який поводиться так, <>за винятком того, що він не буде виконувати цю спеціальну обробку. Аргументи вважатимуться лише іменами файлів. Тож із цими версіями тепер можна писати:
perl -e 'while(<<>>){ ...;}' -- *
(не забудьте --або не використовуйте ./*), не боячись перезаписати файли або виконати несподівані команди.
-n/ -pвсе ж використовуйте небезпечну <>форму. І будьте обережні посилання, як і раніше, дотримуйтесь, так що це не означає, що це безпечно використовувати у ненадійних каталогах.