Расовые условия в списках команд оболочки - PullRequest
3 голосов
/ 03 марта 2012

Насколько безопасны списки команд в оболочке (или bash) от условий гонки?

if [ -h "$dir" ]; then
  echo 'Directory exists and is a symlink'
  exit 1
fi
cd "$dir"

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

Применимо ли это к || спискам команд? Другими словами: является ли приведенная ниже команда невосприимчивой к условиям гонки или же применяются те же правила, что и выше?

[ -h "$dir" ] || cd "$dir"

С сообщением об ошибке:

[ -h "$dir" ]
  && { echo 'Directory exists and is a symlink'; exit 1; }
  || cd "$dir"

Ответы [ 4 ]

3 голосов
/ 04 марта 2012

Это отличный образовательный вопрос, но на практике вы решаете не ту проблему. Вместо того, чтобы беспокоиться о проблемах параллелизма в сценариях, модель безопасности linux опирается на разрешения файловой системы.

Если вы обеспокоены тем, что злоумышленник может изменить рабочую среду под исполняемой программой, вам следует защитить среду: обеспечить, чтобы только у вас был доступ на запись к выполняемым сценариям и двоичным файлам, а также создавать файлы и каталоги. только в местах, в которые только вы можете писать.

Для двоичных исполняемых файлов рассмотрите использование бита setuid , который позволяет обычному пользователю выполнять их с повышенными привилегиями, но имейте в виду, что любой процесс, который выполняется таким образом, должен быть тщательно отлажен и проверен на наличие проблемы с безопасностью. Однако в большинстве дистрибутивов linux скрипты не запускаются таким образом.

Стоит отметить, что злоумышленник, получивший ваш (или root-пароль), может легко победить эту и другие меры безопасности, но в этом случае у вас возникнут большие проблемы. : -)

Удачи!

3 голосов
/ 06 марта 2012

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

Предположим, ради обсуждения, что мы пытаемся безопасно chdir в "foo". Первый способ - сохранить текущий каталог в дескрипторе открытого файла с open(".", O_RDONLY), lstat() каталогом "foo", записать полученные значения st_dev и st_ino, вызвать chdir ("foo"), а затем stat () ".". Сравните полученные значения st_dev и st_ino. Если они одинаковы, вы выиграли гонку. Если нет, выдайте сообщение об ошибке, fchdir() вернувшись назад, используя сохраненный fd, а затем либо прервите работу, либо повторите попытку.

Второй, менее переносимый способ - использовать fd = open("foo", O_RDONLY|O_NOFOLLOW), а затем fchdir(fd). Вы также можете использовать openat вместо open здесь. Проблема переносимости состоит в том, что не все системы имеют O_NOFOLLOW, и некоторые старые ядра не будут правильно интерпретировать этот флаг (вместо этого они игнорируют его, что является проблемой безопасности).

Для получения дополнительной информации взгляните на исходный код GNU find, в котором я столкнулся с некоторыми трудностями, чтобы избежать подобных проблем, используя метод, очень похожий на описанный выше.

Что касается решения этой проблемы в сценарии оболочки:

Если в вашей системе есть команда stat(1) или что-то вроде Perl, вы можете использовать ее для выполнения операций статистики; Вы можете записать результат в переменной оболочки. Это означает, что вы можете более или менее реализовать первый метод в сценарии оболочки, за исключением необходимости использовать fchdir для восстановления. Если можно просто немедленно прервать процесс, когда ваш сценарий оболочки проиграл гонку, вы, безусловно, можете адаптировать первый метод для использования в оболочке. Но в конце концов написать безопасный код в оболочке очень и очень сложно.

0 голосов
/ 07 марта 2012

Вообще говоря, нельзя избежать условий гонки в сценариях оболочки.Вам нужно будет использовать C и использовать безопасные интерфейсы TOCTTOU, такие как openat, fchdir и тому подобное.Избежать уязвимостей TOCTTOU (расы) нетривиально и требует тщательного изучения.

0 голосов
/ 04 марта 2012

Я не вижу причин, почему использование || не было бы уязвимо для того же состояния расы.На самом деле, чтобы он не был уязвимым, его нужно было бы реализовать с использованием

  • какой-то атомарной операции над файловой системой stat-and-chdir (что, я уверен, несуществовать), или

  • какая-то двойная проверка после cd, чтобы убедиться, что каталог все еще указывает на то же место, к которому он привык.

Я не гуру Баш, но я почти уверен, что ни один из этих случаев.

...