Есть похожий вопрос, который касается сценария «обтекания», где вы хотите заменить, например, cd
команду, которая вызывает встроенную функцию cd
.
Тем не менее, в свете shellshock и др. И зная, что bash импортирует функции из среды, я провел несколько тестов и не могу найти способ безопасного вызова встроенной функции cd
из моего скрипта.
Учти это
cd() { echo "muahaha"; }
export -f cd
Любые скрипты, вызываемые в этой среде, cd
будут ломаться (учитывайте эффекты чего-то вроде cd dir && rm -rf .
).
Существуют команды для проверки типа команды (удобно называются type
) и команды для выполнения встроенной версии, а не функции ( builtin
и command
). Но, о чудо, они также могут быть переопределены с помощью функций
builtin() { "$@"; }
command() { "$@"; }
type() { echo "$1 is a shell builtin"; }
Даст следующее:
$ type cd
cd is a shell builtin
$ cd x
muahaha
$ builtin cd x
muahaha
$ command cd x
muahaha
Есть ли способ безопасно заставить bash использовать встроенную команду или, по крайней мере, обнаружить, что команда не является встроенной, без очистки всей среды?
Я понимаю, что если кто-то контролирует вашу среду, вы, вероятно, все равно испорчены, но, по крайней мере, для псевдонимов у вас есть возможность не вызывать псевдоним, вставив \
перед ним.
env
команды раньше, например так:env -i <SCRIPT.sh>
env
не переопределено как функция. Это ужасно Сначала я подумал, что помогут специальные символы - вызов с указанием полного пути/
, использование.
источника и т. Д. Но они также могут быть использованы для имен функций! Вы можете переопределить любую функцию, которую хотите, но трудно вернуться к вызову исходной команды.#/bin/sh
если это не интерактивная оболочка по умолчанию.Ответы:
Оливье Д почти правильный, но вы должны установить
POSIXLY_CORRECT=1
перед запускомunset
. POSIX имеет понятие специальных встроенных модулей , и bash поддерживает это .unset
является одним из таких встроенных. ИскатьSPECIAL_BUILTIN
вbuiltins/*.c
в источнике Баш для списка, он включает в себяset
,unset
,export
,eval
иsource
.Мошенник
unset
теперь был удален из среды, если сброситьcommand
,type
,builtin
то вы должны быть в состоянии продолжать, ноunset POSIXLY_CORRECT
если вы полагаетесь на не-POSIX поведения или расширенные функции Баш.Однако это не относится к псевдонимам, поэтому вы должны использовать его,
\unset
чтобы убедиться, что он работает в интерактивной оболочке (или всегда, еслиexpand_aliases
он действует).Для параноика это должно все исправить, я думаю:
(
while
,do
,done
И[[
являются зарезервированными словами и не нужны меры предосторожности.) Обратите внимание , что мы используем ,unset -f
чтобы быть уверенным в неустановленных функций, хотя переменные и функции разделяют то же пространство имен , что это возможно для обоих существовать одновременно (благодаря Этан Рейснер) , в этом случае Отмена дважды также сделает свое дело. Вы можете пометить функцию только для чтения, bash не мешает вам отключить функцию readonly вплоть до bash-4.2, bash-4.3 предотвращает вас, но она по-прежнему учитывает специальные встроенные функции, когдаPOSIXLY_CORRECT
она установлена.Чтение только
POSIXLY_CORRECT
не является реальной проблемой, это не логическое значение или флаг, при котором его наличие активирует режим POSIX, поэтому, если он существует как доступный только для чтения, вы можете полагаться на функции POSIX, даже если значение пустое или равно 0. Вам просто нужно сбрасывать проблемные функции другим способом, чем описано выше, возможно, с помощью функции вырезания и вставки:(и игнорировать любые ошибки) или участвовать в некоторых других сценариях .
Другие заметки:
function
является зарезервированным словом, оно может быть псевдонимом, но не может быть переопределено функцией. (Псевдонимfunction
мягко неприятен, потому что\function
не подходит для его обхода)[[
,]]
являются зарезервированными словами, они могут быть псевдонимами (которые будут игнорироваться), но не могут быть переопределены функцией (хотя функции могут быть названы так)((
не является допустимым именем для функции или псевдонимомисточник
unset
et al от перезаписи.-f
аргументеunset
, не так ли? В противном случае, если определены как переменная, так и функция с именем, совпадающим со встроенным, тогдаunset
сначала будет выбрана переменная для сброса. Кроме того, это не работает, если установлена какая-либо из затемняющих функцийreadonly
, не так ли? (Хотя это можно обнаружить и можно сделать фатальную ошибку.) Также это не соответствует[
встроенному, как кажется.\unset -f unset
имеет смысл, учитывая, что это будет сделано в цикле чтения. Еслиunset
это функция, вы\unset
обычно разрешаете ее вместо встроенной, но вы можете использовать ее\unset
безопасно, пока действует режим POSIX. Явный вызов\unset -f
на[
,.
и:
может быть хорошей идеей , хотя, как ваши регулярных выражений исключает их. Я хотел бы также добавить-f
к\unset
в петле, и будет\unset POSIXLY_CORRECT
после цикла, а не раньше.\unalias -a
(после\unset -f unalias
) также позволяет безопасно избежать побега по последующим командам.[[ ${POSIXLY_CORRECT?non-POSIX mode shell is untrusted}x ]]
это приведет к тому, что неинтерактивный скрипт завершит работу с ошибкой, указанной, если переменная не установлена, или продолжит работу, если она установлена (пусто, или любое значение).\unset
» ... Следует отметить, что цитирование любого символа (символов) будет работать, чтобы избежать расширения псевдонима, а не только первого.un"se"t
будет работать так же хорошо, хотя и менее читабельным. «Первое слово каждой простой команды, если оно не заключено в кавычки, проверяется на наличие псевдонима». - Баш РефДа, это. Если вы запускаете скрипт в неизвестной среде, все может пойти не так, начиная с того,
LD_PRELOAD
что процесс оболочки выполнит произвольный код еще до того, как он прочитает ваш скрипт. Попытка защитить от враждебной среды изнутри сценария тщетна.Sudo очищает окружающую среду, удаляя все, что похоже на определение функции bash, уже более десяти лет. Начиная с Shellshock , другие среды, которые запускают сценарий оболочки в среде, не являющейся полностью доверенной, следовали этому примеру.
Вы не можете безопасно запускать сценарий в среде, которая была установлена ненадежным объектом. Поэтому беспокоиться об определениях функций не является продуктивным. Очистите вашу среду, и при этом переменные, которые bash будет интерпретировать как определения функций.
источник
/bin/cat
chroot, может вызывать что угодно.) Дезинфекция среды действительно дает вам здравый смыслPATH
(если, конечно, вы делаете это правильно). Я все еще не понимаю твою точку зрения.Вы можете использовать
unset -f
для удаления встроенных функций, команды и типа.источник
unset() { true; }
позаботится об этом.