Почему действие '-execdir' небезопасно для каталога, который находится в PATH?

Почему небезопасно использовать комбинацию -execdir действие поиска при использовании -exec нет?

Когда я запускаю команду ниже, я получаю следующее сообщение:

/path/to/currentDir/$ find . -type f -name 'partOfFileNames*' -execdir rm -- {} +

find: The current directory is included in the PATH environment variable, which is insecure 
in combination with the -execdir action of find.  Please remove the current directory 
from your $PATH (that is, remove "." or leading or trailing colons)

Что может вызвать появление этого приглашения?

4 ответа

Решение

Вы можете запустить не ту программу. Кто-то может заставить вас запустить их программу.

-execdir action запускает вашу команду из каталога, в котором находятся найденные файлы. когда $PATH содержит относительные пути, такие как . или что-нибудь, что не начинается с /, -execdir небезопасен, поскольку каталог, в котором находится файл (или другой каталог, разрешенный относительно него), также может содержать исполняемый файл с тем же именем, что и файл, который вы пытаетесь запустить. Этот потенциально ненадежный исполняемый файл затем будет запущен.

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

Если все в вашем PATH Переменная окружения является абсолютным путем, эта ошибка не должна возникать, даже если каталог, который вы ищете, и -execdir Из этого содержится в PATH, (Я проверил, что это работает.) Если вы считаете, что у вас нет относительных каталогов в $PATH но все еще получаете эту ошибку, пожалуйста, обновите ваш вопрос с деталями, включая вывод echo "$PATH",

Конкретный пример.

В качестве примера того, что может пойти не так, предположим:

  • Алиса имеет . в ее $PATH потому что она хочет иметь возможность запускать программы в любом каталоге она cd не потрудившись приписать их имена ./,
  • Ева Алиса поделилась /home/eve/shared с Алисой
  • Алиса хочет статистику (строки, слова, байты) на .c файлы, которыми Ева поделилась с ней.

Итак, Алиса бежит:

find ~eve/shared -name \*.c -execdir wc {} \;

К сожалению для Алисы, Ева создала свой собственный сценарий, назвал его wc установите его исполняемым (chmod +x) и поместил его тайно в один из каталогов под /home/eve/shared, Сценарий Евы выглядит так:

#!/bin/sh
/usr/bin/wc "$@"
do_evil    # Eve replaces this command with whatver evil she wishes to do

Поэтому, когда Алиса использует find с -execdir бежать wc в файлах, которыми поделилась Ева, и он попадает в файлы в том же каталоге, что и пользовательские файлы Евы wc сценарий Евы wc работает - со всеми привилегиями Алисы!

(Будучи хитрым, Ева сделала ее wc скрипт действует как обёртка для системы wc Алиса даже не узнает, что что-то пошло не так, т.е. do_evil был запущен. Однако возможны и более простые, а также более сложные варианты.)

Как find предотвращает это.

find предотвращает возникновение этой проблемы безопасности, отказываясь принять -execdir действие, когда $PATH содержит относительный каталог.

find предлагает два диагностических сообщения в зависимости от конкретной ситуации.

  • Если . в $PATH тогда (как вы видели) написано:

    find: The current directory is included in the PATH environment variable, which is insecure in combination with the -execdir action of find. Please remove the current directory from your $PATH (that is, remove "." or leading or trailing colons)

    Это, вероятно, имеет специальное сообщение для . дело как то особенно распространено.

  • Если относительный путь, кроме . --сказать, foo - появляется в $PATH и ты бежишь find с -execdir, это говорит:

    find: The relative path `foo' is included in the PATH environment variable, which is insecure in combination with the -execdir action of find. Please remove that entry from $PATH

Лучше не иметь относительных путей в $PATH совсем.

Риск иметь . или другие относительные пути в $PATH особенно усиливается при использовании утилиты, которая автоматически меняет каталог, поэтому find не позволит вам использовать -execdir в этой ситуации.

Но имея относительные пути, особенно ., в вашем $PATH по своей сути рискованно и действительно лучше избегать в любом случае. Рассмотрим вымышленную ситуацию в примере выше. Предположим, вместо запуска find Алиса просто cd с ~eve/shared/blah и работает wc *.c, Если blah содержит Еву wc сценарий, do_evil работает как Алиса.

Здесь очень подробная информация. Еще одна отличная ссылка здесь. Цитировать из первой ссылки:

Опция -execdir - более современная опция, введенная в GNU find - попытка создать более безопасную версию -exec. Он имеет ту же семантику, что и -exec, с двумя важными улучшениями:

Он всегда предоставляет абсолютный путь к файлу (использование относительного пути к файлу действительно опасно в случае -exec).

Помимо обеспечения абсолютного пути, он также проверяет переменную PATH на безопасность (если точка присутствует в переменной PATH env, вы можете забрать исполняемый файл из неправильного каталога)

Из второй ссылки:

Действие '-execdir' отказывается что-либо делать, если текущий каталог включен в переменную среды $PATH. Это необходимо, потому что "-execdir" запускает программы в том же каталоге, в котором он находит файлы - в общем, такой каталог может быть доступен для записи ненадежным пользователям. По тем же причинам "-execdir" не позволяет отображать "{}" в названии команды для запуска.

xargs а также bash -c cd обходной путь

Хорошо, я сдаюсь

find . -type f |
  xargs -I '{}' bash -c 'cd "$(dirname "{}")" && pwd && echo "$(basename "{}")"'

sed обходной путь

Немного менее приятно, чем предыдущий обходной путь:

PATH="$(echo "$PATH" | sed -E 's/(^|:)[^\/][^:]*//g')" find . -execdir echo '{}' \;

Тестовый пример:

[ "$(printf '/a/b::c/d:/e/f\n' | sed -E 's/(^|:)[^\/][^:]*//g')" = '/a/b:/e/f' ] || echo fail

За rename в частности, вы также можете обойти некоторые регулярные выражения Perl: https://stackoverflow.com/questions/16541582/finding-multiple-files-recursively-and-renaming-in-linux/54163971

RTFS надеюсь, что сокрушительный

Для тех, кто надеется, что существует способ игнорировать find Самоуверенность, позвольте мне раздавить это из некоторого источника:

Из этого мы видим, что, похоже, нет способа отключить проверку пути.

Точное правило, которое он проверяет: сбой, если PATH либо пусто, либо не начинается с /,

Основная проблема со значением системной переменной PATH который содержит относительные папки в нем, поэтому по соображениям безопасности find Команда не позволит вам выполнять двоичные файлы, потому что потенциально она может выполнять неправильные программы.


Так, например, если у вас есть текущая директория в вашей переменной PATH согласно предупреждению, которое вы получаете:

Текущий каталог включен в переменную окружения PATH.

и вы запустите свою команду:

find . -type f -name 'partOfFileNames*' -execdir rm -- {} +

на случай если у вас будет локальный скрипт (rm с исполняемыми флагами), содержащий rm -fr / в нем он может удалить все ваши файлы, потому что вместо ожидаемого выполнения /bin/rmисполнишь rm из текущего каталога, так что, вероятно, это не то, что вы хотели.


В качестве примечания, это известная проблема в Travis CI ( GH # 2811), когда происходит сбой с ошибкой:

find: Относительный путь `./node_modules/.bin'включен в переменную среды PATH, которая небезопасна в сочетании с действием -execdir команды find. Пожалуйста, удалите эту запись из $PATH

Таким образом, решение состоит в том, чтобы удалить затронутую запись из переменной PATH, например

PATH=`echo $PATH | sed -e 's/:\.\/node_modules\/\.bin//'`

как предложил Дрогус. Прогресс этой ошибки, можно следить на GH # 4862.


Вот обходное решение Bash версии:

PATH=${PATH//:\.\/node_modules\/\.bin/}

Пример использования (прохождение фильтруется PATH к конкретной команде):

env PATH=${PATH//:\.\/node_modules\/\.bin/} find . -type f

Обходной путь - передать пользовательский PATH перед командой, например

PATH=/usr/bin find . -type f -name 'partOfFileNames*' -execdir echo rm -- {} +

Вышеупомянутый обходной путь предотвратит загрузку глобального $PATH, но наши собственные.


Вот еще один пример (более гибкий), предполагающий, что мы хотим запустить cat команда:

PATH=$(dirname $(which find)):$(dirname $(which cat)) find /etc -name hosts -execdir cat {} ';'

или:

PATH=$(dirname $(which cat find) | paste -sd:) find ...

бегом $(dirname $(which cat)) мы вычисляем, где находится наша команда для запуска.

Другие вопросы по тегам