Я видел в нескольких местах советы использовать следующую фразу:
#!/usr/bin/env bash
вместо
#!/usr/bin/bash
Моя инстинктивная реакция: «А что, если кто-то заменит этот исполняемый файл своим собственным, скажем, в ~/.local/bin
?» Этот каталог часто устанавливается в пути пользователя перед общесистемными путями. Я вижу, что это часто поднимается как проблема безопасности как побочное замечание, а не что-то, что следует воспринимать всерьез, но я хотел проверить теорию.
Чтобы попробовать это, я сделал следующее:
echo -e "#!/usr/bin/python\nprint 'Hacked!'" > $HOME/.local/bin/bash
chmod 755 $HOME/.local/bin/bash
PATH=$HOME/.local/bin env bash
Это дает
/usr/bin/env: ‘bash’: No such file or directory
Чтобы проверить, улавливает ли он вообще что-нибудь, я также сделал
echo -e "#!/usr/bin/python\nprint 'Hacked!'" > $HOME/.local/bin/perl
chmod 755 $HOME/.local/bin/perl
PATH=$HOME/.local/bin env perl
который печатает, как я и ожидал,
Hacked!
Может кто-нибудь объяснить мне, почему заменитель bash
не найден, а заменитель perl
есть? Это какая-то мера "безопасности", которая (с моей точки зрения) не соответствует сути?
EDIT: Поскольку мне подсказали: я не спрашиваю, чем /usr/bin/env bash
это отличается от использования /bin/bash
. Я задаю вопрос, как указано выше.
EDIT2: Должно быть, я что-то делал не так. Попробовал еще раз сегодня (используя явный путь env
вместо неявного), и никакого поведения "не найдено".
решение1
«что если кто-то заменит этот исполняемый файл своим собственным, скажем, в ~/.local/bin ?
Тогда сценарий для них не работает.
Но это не имеет значения, поскольку они могли бы взломать скрипт другими способами или запустить другую программу напрямую, не вмешиваясь PATH
в env
.
Если только ваши пользователи не имеютдругойкаталоги пользователей в их PATH
, или могут редактировать каталоги PATH
других пользователей, на самом деле нет никакой возможности, что один пользователь испортит другой.
Однако если бы это был не скрипт оболочки, а что-то, что предоставляет дополнительные привилегии, например, setuid-обертка для какой-то программы, то все было бы иначе. В этом случае это было бынеобходимыйиспользовать абсолютный путь для запуска программы, поместить ее в каталог, который непривилегированные пользователи не смогут изменить, и очистить среду при запуске программы.
решение2
Что касается разницы в поведении между оболочкой и perl
, perl
то в отличие от нее оболочка проверяет первую строку, чтобы определить, что именно следует запустить:
$ cat tcl
#!/usr/bin/env tclsh
puts "TCL running as [pid]"
$ perl tcl
TCL running as 39689
$ cat sbcl
#!/opt/local/bin/sbcl --script
(format t "~a running as ~a~%" 'lisp (sb-unix:unix-getpid))
$ perl sbcl
LISP running as 39766
$
Использование этой функции включает в себя:написание тестов на каком-либо другом языке, кроме perlпоэтому можно иметь TAP-совместимые скрипты на других языках и prove
что-то еще будет запускать их правильно.
решение3
Здесь нет риска для безопасности. /usr/bin/env
предполагается, что он выбирает соответствующий двоичный файл в соответствии со средой пользователя. Так что если пользователь установил свой собственный bash
в ~/.local/bin
, то /usr/bin/env
он действительно должен попытаться использовать его (например, он мог скомпилировать версию с дополнительными функциями, которые недоступны в общесистемной версии, и предпочел бы использовать ее вместо общесистемной версии). То же самое касается любого другого двоичного файла/интерпретатора. Нет риска для безопасности, потому что пользователь не сможет запустить ничего, что он бы не смог запустить в любом случае.
Что касается того, почему в вашем случае подстановка не срабатывает, я сомневаюсь, что это как-то связано с /usr/bin/env
. Попробуйте запустить PATH=~/.local/bin bash
, PATH=~/.local/bin bash <path-to-script>
(так он будет называться при запуске скрипта) и PATH=~/.local/bin /usr/bin/env bash
посмотрите, какой из них не сработает. Это должно дать подсказку о том, на что ссылается ошибка "файл не найден".