Последствия безопасности рабочего жемчуга-ne' …' *

Нет всего один awk и несколько выпусков его. Существует много awk реализаций, которые у каждого есть несколько версий. Все Нельды имеют свой собственный набор инструментов, который они поддерживают внутренний и программное обеспечение, которое поставлется с одним Unix и которое использует те инструменты, обычно полагаются на тех, которые точной версией той самой реализации.

Если Вы начинаете заменять /usr/bin/awk с GNU awk, как может быть загружен с http://gnu.org, затем Вы столкнетесь с проблемами.

Некоторые Нельды действительно упаковывают версии альтернативного или Бесплатного программного обеспечения некоторых стандартных утилит. Обычно они делают это путем установки их в другом месте (/opt/gnu например, для инструментов GNU) или под другим именем (gawk для GNU awk). Если не можно загрузить их как источник и создать их и установить их в другом месте или под другим именем вручную сами.

Однако Солярис, как известно, имеет очень старые и нестандартные версии некоторых утилит в /usr/bin и сохраните современные / стандартные версии в другом месте.

Это имеет место awk. /usr/bin/awk на Солярисе основан на исходном awk с 1979. awk переписали приблизительно 1988 и назвали nawk. Все современные awk реализации основаны на этом nawk (поскольку это что POSIX awk спецификация на основе).

На Солярисе, если Вы обновляете Ваш $PATH помещать себя в среду стандарта/POSIX (который обычно включает помещение /usr/xpg4/bin и/или /usr/xpg6/bin в начале $PATH), затем awk будет стандартный. С другой стороны, можно звонить nawk вместо awk.

Это - то же для sh, можно использовать /usr/xpg4/bin/sh или ksh.

В стандарте sh (то есть, нет /bin/sh на Солярисе), можно также использовать

 command -p awk

Убеждаться назвать портативный awk вместо старого.

28
27.11.2014, 00:55
2 ответа

В чем проблема

Во-первых, как и для многих утилит, у вас будет проблема с именами файлов, начинающимися с - . Находясь в:

sh -c 'inline sh script here' other args

Остальные аргументы передаются в встроенный скрипт sh ; с эквивалентом 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 .

In:

perl -pe '' a b

-p подразумевает while (<>) цикл вокруг кода (здесь пусто).

<> сначала откроет a , прочитает записи по одной строке, пока файл не будет исчерпан, а затем откроет b ...

Проблема в что для открытия файла используется первая небезопасная форма open :

open ARGV, "the file as provided"

В этой форме, если аргумент

  • «> файл» , открывается файл в режиме записи,
  • «cmd |» , он запускает cmd и считывает его вывод.
  • "| cmd" , у вас открыт поток для записи на вход cmd .

Так, например:

perl -pe '' 'uname|'

Выводит не содержимое файла с именем uname | (вполне допустимое имя файла, кстати), а вывод команды uname .

Если вы работаете:

perl -ne 'something' -- *

И кто-то создал файл с именем rm -rf "$ HOME" | (опять же совершенно правильное имя файла) в текущем каталоге (например, потому что это каталог был когда-то доступен для записи другим, или вы извлекли хитрый архив, или вы выполнили какую-то хитрую команду, или другая уязвимость в каком-то другом программном обеспечении была использована), тогда у вас большие проблемы. Области, в которых важно знать об этой проблеме, - это инструменты, автоматически обрабатывающие файлы в общедоступных областях, таких как / tmp (или инструменты, которые могут быть вызваны такими инструментами).

Файлы с именами > 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 (но не на - , <,> , | , пробел ...). В более общем плане рекомендуется использовать префикс globs с помощью ./ . Это также позволяет избежать проблем с файлами, называемыми - или начинающимися с - , со многими другими утилитами (и здесь это означает, что вам не нужны параметры конца ( - - ) маркер больше нет).

Использование -T для включения режима taint в некоторой степени помогает. Команда прервет команду, если обнаружится такой вредоносный файл (только для случаев > и | , но не < или пробелов).

Это полезно при использовании таких команд в интерактивном режиме, поскольку предупреждает вас о том, что происходит что-то хитрое. Однако это может быть нежелательно при выполнении некоторой автоматической обработки, поскольку это означает, что кто-то может заставить эту обработку выйти из строя, просто создав файл.

Если вы хотите обрабатывать каждый файл, независимо от его имени, вы можете использовать модуль ARGV :: readonly perl на CPAN (к сожалению, обычно не устанавливается По умолчанию). Это очень короткий модуль, который выполняет:

 sub import {
 # Tom Christiansen in Message-ID: <24692.1217339882@chthon> 
 # по существу рекомендует следующее: 
для ( @ARGV) {
s / ^ (\ s +) /.\/$ 1 /; # сохранены начальные пробелы 
s / ^ / 

По сути, он санирует @ARGV, превращая "foo |" , например, в "<./ foo | \ 0" .

Вы можете сделать то же самое в операторе BEGIN в вашей команде perl -n / -p :

perl -pe 'BEGIN{$_.="\0" for @ARGV} your code here' ./*

Здесь мы упрощаем его, предполагая, что ./ уже используется.

Побочным эффектом этого (и ARGV :: readonly ) является то, что $ ARGV в ваш код здесь показывает этот завершающий символ NUL.

Обновление от 03.06.2015

perl v5.21.5 и выше содержит новый оператор << >> , который ведет себя как <> , за исключением того, что он не выполняют эту специальную обработку. Аргументы будут рассматриваться только как имена файлов. Таким образом, с этими версиями теперь вы можете написать:

perl -e 'while(<<>>){ ...;}' -- *

(не забудьте - или использовать ./* ), не опасаясь перезаписи файлов или выполнения неожиданных команд. .

-n / -p по-прежнему используют опасную форму <> . И будьте осторожны, символические ссылки все еще отслеживаются, так что это не обязательно означает, что их безопасно использовать в ненадежных каталогах.

34
27.01.2020, 19:39

@В дополнение к @Ответу Стефана Шазеляса, нам не нужно беспокоиться по этому поводу, если мы используем опцию командной строки -i:

$ perl -pe '' 'uname|'
Linux

$ perl -i -pe '' 'uname|'
Can't open uname|: No such file or directory.

Поскольку при использовании опции -i, perl использовали stat для проверки состояния файла перед его обработкой:

$ strace -fe trace=stat perl -pe '' 'uname|'
stat("/home/cuonglm/perl5/lib/perl5/5.20.1/x86_64-linux", 0x7fffd44dff90) = -1 ENOENT (No such file or directory)
stat("/home/cuonglm/perl5/lib/perl5/5.20.1", 0x7fffd44dff90) = -1 ENOENT (No such file or directory)
stat("/home/cuonglm/perl5/lib/perl5/x86_64-linux", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
Process 6106 attached
Linux
Process 6105 suspended
Process 6105 resumed
Process 6106 detached
--- SIGCHLD (Child exited) @ 0 (0) ---

$ strace -fe trace=stat perl -i -pe '' 'uname|'
stat("/home/cuonglm/perl5/lib/perl5/5.20.1/x86_64-linux", 0x7fffdbaf2e50) = -1 ENOENT (No such file or directory)
stat("/home/cuonglm/perl5/lib/perl5/5.20.1", 0x7fffdbaf2e50) = -1 ENOENT (No such file or directory)
stat("/home/cuonglm/perl5/lib/perl5/x86_64-linux", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
stat("uname|", 0x785f40)                = -1 ENOENT (No such file or directory)
Can't open uname|: No such file or directory.
9
27.01.2020, 19:39

Теги

Похожие вопросы