Имитация O_NOFOLLOW (2): Безопасен ли этот другой подход? - PullRequest
3 голосов
/ 30 мая 2010

В качестве дополнительного вопроса к этому я подумал о другом подходе, основанном на ответе @ caf для случая, когда я хочу добавить в файл name и создайте его, если он не существует.

Вот что я придумал:

  1. Создать временный каталог с режимом 0700 во системном временном каталоге в той же файловой системе, что и файл name.
  2. Открыть файл name только для чтения и O_CREAT. ОС может следовать name, если это символическая ссылка.

    Используйте mkstemp, чтобы создать временный файл во временном каталоге, и попытайтесь rename временный файл. созданный mkstemp для файла name.

    Открыть файл name только для чтения и O_CREAT | O_EXCL.
  3. Итеративная попытка сделать жесткую ссылку на name во временном имени во временном каталоге. Если когда-либо вызов link завершится неудачно из-за ошибки, отличной от «цель ссылки существует» (errno EEXIST), затем завершите работу. (Может быть, кто-то пришел и удалил файл на name, кто знает?)
  4. Используйте lstat на temp_name (жесткая ссылка). Если S_ISLNK(lst.st_mode), то выйдите.
  5. open temp_name для написания и добавления (O_WRONLY | O_APPEND).
  6. Выпиши все. Закройте дескриптор файла.
  7. unlink жесткая ссылка.
  8. Удалить временный каталог.

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

Безопасна ли эта процедура против атак по символическим ссылкам? Например, может ли злонамеренный процесс обеспечить, чтобы индекс для name представлял обычный файл на время проверки lstat, а затем сделать индекс символической ссылкой с temp_name жесткая ссылка теперь указывает на новую символическую ссылку?

Я предполагаю, что вредоносный процесс не может повлиять на temp_name.

EDIT: link не перезаписывает цель, поэтому создание временного файла-заполнителя - это не то, что я хотел сделать. С тех пор я обновил свой код и обновил шаги, описанные выше.

EDIT2: Я сейчас использую альтернативную процедуру для шага 2 для создания файла name, если он не существует, который, я не думаю, восприимчив к этой проблеме .

EDIT3: Даже лучше, чем переименование временного, пустого, обычного файла в name, что также приводит к удалению ссылок name, затем переименование, я могу открыть файл O_RDONLY | O_CREAT | O_EXCL.

Стандарт POSIX для open гласит:

Если установлены O_EXCL и O_CREAT и path называет символическую ссылку, open() завершится ошибкой и установит errno в EEXIST, независимо от содержимого символической ссылки.

1 Ответ

1 голос
/ 31 мая 2010

Что ж, есть одна проблема с шагом 2 («Открыть файл name только для чтения и O_CREAT. Операционная система может следовать name, если это символическая ссылка.»), Которая, если она полностью используется, может разрешить непривилегированному процессу по существу touch любой путь в файловой системе. Последствия этого включают принудительную проверку диска при следующей перезагрузке (касаясь /forcefsck), а также другие, более разрушительные вещи. Например, при обновлении с Debian Lenny на Squeeze и dbus, и образ ядра должны быть обновлены одновременно, поскольку каждый из соответствующих пакетов зависит от другого (новый dbus не работает со старым ядром и старым dbus не работает с новым ядром). Способ, которым администратор обходит эту циклическую зависимость, заключается в touch определенном пути, который сообщает новому пакету dbus, что образ ядра будет обновлен до следующей перезагрузки. Однако, если вредоносный процесс управляет этим путем до touch перед первым обновлением и перезагрузкой во время обновления с Lenny до Squeeze, система может не загружаться. Первое обновление, если я правильно помню, устанавливает новый dbus, но вам нужно явно обновить заново, чтобы установить новый образ ядра. Одно обновление с последующей перезагрузкой может привести к блокировке системы.

Просматривая источник GNU Coreutils 'touch, выясняется, что они устанавливают только временные метки файла, но не создают файл, если он не существует, когда передается touch --no-dereference вариант. Они делают это с помощью служебной функции lutimens от gnulib, которая оборачивает utimensat в Linux, позволяя меткам времени самого файла символьных ссылок, если это так, обновляться при Linux> = 2.6.22.

...