Ошибка при создании временного файла, необходимого для завершения установки компаса

Обновлено: 29.06.2024

Программисты часто создают временные файлы в каталогах, доступных для записи всем (примерами являются /tmp и /var/tmp в UNIX и %TEMP% в Windows) и могут регулярно очищаться (например, каждую ночь или во время перезагрузки).

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

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

  1. Используйте другие низкоуровневые механизмы IPC (межпроцессного взаимодействия), такие как сокеты или разделяемая память.
  2. Используйте механизмы IPC более высокого уровня, такие как удаленные вызовы процедур.
  3. Используйте безопасный каталог или тюрьму, доступ к которой возможен только для экземпляров приложения (гарантируя, что несколько экземпляров приложения, работающих на одной платформе, не будут конкурировать).

Существует множество различных механизмов IPC; некоторые требуют использования временных файлов, а другие нет. Примером механизма IPC, использующего временные файлы, является функция POSIX mmap(). Сокеты Berkeley, POSIX Local IPC Sockets и System V Shared Memory не требуют временных файлов. Поскольку многопользовательский характер общих каталогов представляет неотъемлемую угрозу безопасности, использование общих временных файлов для IPC не рекомендуется.

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

  • Создаются непредсказуемые имена файлов.
  • Создано с уникальными именами
  • Открывается, только если файл еще не существует (атомарное открытие)
  • Открыто с эксклюзивным доступом
  • Открыто с соответствующими разрешениями
  • Удаляется перед выходом из программы

В следующей таблице перечислены общие функции временных файлов и их соответствие этим критериям:

Соответствие файловых функций критериям для временных файлов

tmpnam_s
(Приложение K)

tmpfile_s
(Приложение K)

Непредсказуемое имя

Уникальное имя

Атомное открытие

Эксклюзивный доступ

Если поддерживается ОС

Если поддерживается ОС

Соответствующие разрешения

Если поддерживается ОС *

Если поддерживается ОС

Файл удален

* Если программа завершается аварийно, это поведение определяется реализацией.

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

Уникальные и непредсказуемые имена файлов

Привилегированные программы, создающие временные файлы в доступных для записи каталогах, могут быть использованы для перезаписи защищенных системных файлов. Злоумышленник, который может предсказать имя файла, созданного привилегированной программой, может создать символическую ссылку (с тем же именем, что и у файла, используемого программой), чтобы указать на защищенный системный файл. Если привилегированная программа не закодирована безопасным образом, она будет следовать символической ссылке вместо того, чтобы открывать или создавать файл, который она должна использовать. В результате защищенный системный файл, на который указывает символическая ссылка, может быть перезаписан при выполнении программы [HP 2003]. Аналогичным образом можно использовать непривилегированные программы для перезаписи защищенных пользовательских файлов.

Эксклюзивный доступ

Эксклюзивный доступ предоставляет неограниченный доступ к файлам процессу блокировки, но запрещает доступ ко всем другим процессам и устраняет возможность возникновения состояния гонки в заблокированной области. (См. Безопасное кодирование в C и C++, глава 8 [Seacord 2013].)

Файлы или области файлов можно заблокировать, чтобы предотвратить одновременный доступ двух процессов. Windows поддерживает два типа блокировки файлов:

  • Общие блокировки, предоставляемые функцией LockFile() , запрещают любой доступ для записи к заблокированной области файла, но разрешают одновременный доступ для чтения ко всем процессам.
  • Эксклюзивные блокировки, обеспечиваемые функцией LockFileEx() , предоставляют неограниченный доступ к файлам блокирующему процессу и запрещают доступ всем остальным процессам.

В обоих случаях блокировка снимается вызовом UnlockFile() .

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

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

  • Обязательная блокировка работает только в локальных файловых системах и не распространяется на сетевые файловые системы (например, NFS или AFS).
  • Файловые системы должны быть смонтированы с поддержкой обязательной блокировки, которая по умолчанию отключена.
  • Блокировка зависит от бита идентификатора группы, который может быть отключен другим процессом (таким образом снята блокировка).

Удаление перед прекращением действия

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

Пример несовместимого кода ( fopen()/open() с tmpnam() )

В этом примере несоответствующего кода создается файл с жестко заданным именем file_name (предположительно в общем каталоге, таком как /tmp или C:\Temp ):

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

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

Поскольку tmpnam() не гарантирует уникальность имени, а fopen() не предоставляет возможности для эксклюзивного открытия, этот код по-прежнему уязвим.

В следующем несоответствующем примере кода делается попытка решить проблему, используя функцию POSIX open() и предоставляя механизм, указывающий, был ли открыт для записи существующий файл или создан новый файл [IEEE Std 1003.1:2013]. . Если флаги O_CREAT и O_EXCL используются вместе, функция open() завершается ошибкой, когда файл, указанный в параметре имя_файла, уже существует. Чтобы предотвратить открытие и усечение существующего файла, включите флаги O_CREAT и O_EXCL при вызове open():

Этот вызов open() завершается ошибкой, когда имя_файла уже существует, в том числе когда это символическая ссылка, но предположительно все еще требуется временный файл. Кроме того, не гарантируется, что метод, используемый tmpnam() для генерации имен файлов, будет непредсказуемым, что дает злоумышленнику возможность заранее угадать имя файла.

Следует соблюдать осторожность при использовании O_EXCL с удаленными файловыми системами, поскольку он не работает с NFS версии 2. В NFS версии 3 добавлена ​​поддержка режима O_EXCL в open() ; см. IETF RFC 1813 [Callaghan 1995], в частности значение EXCLUSIVE для аргумента режима CREATE .

Кроме того, функция open(), как указано в Стандарте информационных технологий — интерфейс переносимой операционной системы (POSIX®), базовые спецификации, выпуск 7 [IEEE Std 1003.1:2013], не не включает поддержку общих или монопольных блокировок. Однако системы BSD поддерживают два дополнительных флага, позволяющих получить эти блокировки:

  • O_SHLOCK : атомарно получить общую блокировку.
  • O_EXLOCK : атомарное получение эксклюзивной блокировки.

Пример несовместимого кода ( tmpnam_s()/open() , Приложение K, POSIX)

Функция tmpnam_s() стандартной функции C создает строку, которая является допустимым именем файла и не совпадает с именем существующего файла. Она почти идентична функции tmpnam(), за исключением добавленного аргумента maxsize для предоставленного буфера.

Ненормативный текст стандарта C, подраздел K.3.5.1.2 [ISO/IEC 9899:2011], также рекомендует следующее:

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

При реализации сокращается пространство для уникальных имен и повышается предсказуемость получаемых имен. В общем, Приложение K не устанавливает каких-либо критериев предсказуемости имен. Например, имя, сгенерированное функцией tmpnam_s из Microsoft Visual Studio, состоит из сгенерированного программой имени файла и, после первого вызова tmpnam_s(), расширения файла из последовательных чисел в базе 32 (.1-.1vvvvvu).

Пример несовместимого кода ( mktemp()/open() , POSIX)

Функция POSIX mktemp() берет заданный шаблон имени файла и перезаписывает его часть для создания имени файла. Шаблон может быть любым именем файла, к которому добавлено ровно шесть символов X (например, /tmp/temp.XXXXXX ). Шесть завершающих X заменяются текущим номером процесса и/или уникальной комбинацией букв.

Функция mktemp() помечена как "LEGACY" в выпуске 6 базовых спецификаций Open Group [Open Group 2004]. Страница руководства для mktemp() дает более подробную информацию:

Никогда не используйте mktemp() . Некоторые реализации следуют BSD 4.3 и заменяют XXXXXX текущим идентификатором процесса и одной буквой, так что может быть возвращено не более 26 различных имен. Так как, с одной стороны, имена легко угадать, а с другой стороны, существует гонка между проверкой существования имени и открытием файла, каждое использование mktemp() представляет собой угрозу безопасности. mkstemp(3) избегает гонки.

Пример несовместимого кода ( tmpfile() )

Функция tmpfile() создает временный двоичный файл, который отличается от любого другого существующего файла и автоматически удаляется при его закрытии или завершении программы.

Должна быть возможность открывать временные файлы не менее TMP_MAX в течение всего времени существования программы. (Это ограничение может использоваться совместно с tmpnam() .) Подпункт 7.21.4.4, параграф 6 стандарта C позволяет использовать значение макроса TMP_MAX до 25.

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

Пример несовместимого кода ( tmpfile_s() , Приложение K)

Функция tmpfile_s() создает временный двоичный файл, который отличается от любого другого существующего файла и автоматически удаляется при его закрытии или завершении программы. Если программа завершается аварийно, удаление открытого временного файла определяется реализацией.

Файл открывается для обновления в режиме "wb+", что означает "урезать до нулевой длины или создать бинарный файл для обновления". В той степени, в которой базовая система поддерживает эти концепции, файл открывается с исключительным (не общим) доступом и имеет разрешение на доступ к файлу, которое запрещает другим пользователям в системе доступ к файлу.

Должна быть возможность открыть не менее TMP_MAX_S временных файлов в течение всего времени существования программы. (Это ограничение может использоваться совместно с tmpnam_s() .) Значение макроса TMP_MAX_S должно быть только 25 [ISO/IEC 9899:2011].

Стандарт C, подпункт K3.5.1.2, параграф 7, отмечает следующее относительно использования tmpfile_s() вместо tmpnam_s() [ISO/IEC 9899:2011]:

После того, как программа получает имя файла с помощью функции tmpnam_s и до того, как программа создаст файл с таким именем, существует вероятность того, что кто-то другой может создать файл с таким же именем. Чтобы избежать этого состояния гонки, по возможности следует использовать функцию tmpfile_s вместо tmpnam_s. Одной из ситуаций, требующих использования функции tmpnam_s, является ситуация, когда программе необходимо создать временный каталог, а не временный файл.

Функция tmpfile_s() не должна использоваться с реализациями, создающими временные файлы в общем каталоге, таком как /tmp или C: , поскольку эта функция не позволяет пользователю указать каталог, в котором должен находиться временный файл. создан.

Соответствующее решение ( mkstemp() , POSIX)

Алгоритм mkstemp() для выбора имен файлов показал себя невосприимчивым к атакам. Функция mkstemp() доступна в системах, поддерживающих Open Group Base Specifications Issue 4, версии 2 или выше.

Вызов mkstemp() заменяет шесть X в строке шаблона шестью случайно выбранными символами и возвращает файловый дескриптор для файла (открытого для чтения и записи), как в этом совместимом решении:

Однако это решение нельзя использовать последовательно, поскольку функция mkstemp() заменяет "XXXXXX" в шаблоне при первом вызове. Это не проблема, пока шаблон повторно инициализируется перед повторным вызовом mkstemp(). Если шаблон не инициализирован повторно, функция mkstemp() вернет -1 и оставит шаблон без изменений, поскольку шаблон не содержит шести символов X.

В выпуске 6 базовой спецификации Open Group [Open Group 2004] не указаны разрешения, с которыми создается файл, поэтому они определяются реализацией. Однако стандарт IEEE 1003.1, издание 2013 г. [IEEE Std 1003.1:2013] определяет их как S_IRUSR|S_IWUSR (0600).

Это совместимое решение вызывает определяемую пользователем функцию secure_dir() (например, определенную в FIO15-C. Убедитесь, что операции с файлами выполняются в безопасном каталоге), чтобы убедиться, что временный файл находится в безопасном каталоге.

Детали реализации

Для GLIBC версии 2.0.6 и более ранних файл создается с разрешениями 0666; для GLIBC версии 2.0.7 и выше файл создается с разрешениями 0600. В NetBSD файл создается с разрешениями 0600. Это создает угрозу безопасности, поскольку злоумышленник получит доступ для записи к файлу сразу после создания. Следовательно, программам нужна закрытая версия функции mkstemp(), в которой эта проблема, как известно, исправлена.

Во многих старых реализациях имя зависит от идентификатора процесса и времени, поэтому злоумышленник может заранее предсказать имя и создать приманку. FreeBSD изменила семейство mk*temp(), убрав компонент идентификатора процесса в имени файла и заменив все поле случайным кодированием base-62. Это значительно увеличивает количество возможных временных файлов для типичного использования шести X, а это означает, что даже mktemp() с шестью X достаточно (вероятностно) защищен от угадывания, за исключением случаев частого использования [Kennaway 2000].

Исключения

FIO21-C-EX1: Функцию tmpfile_s() Приложения K можно использовать, если все целевые реализации создают временные файлы в защищенных каталогах.

Оценка рисков

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

Code Manager требует координации между несколькими компонентами, включая r10k и службу синхронизации файлов. Если у вас есть проблемы с Code Manager, проверьте, работают ли эти компоненты.

Журналы диспетчера кода

Code Manager записывает в журнал Puppet Server. По умолчанию этот журнал находится в /var/log/puppetlabs/puppetserver/puppetserver.log. Дополнительные сведения о работе с журналами см. в документации по журналам Puppet Server.

Проверить статус диспетчера кода

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

Статус команды puppet-code подтверждает, что Code Manager и синхронизация файлов отвечают. Команда возвращает ту же информацию, что и конечная точка состояния Code Manager. По умолчанию команда возвращает сведения на информационном уровне; критический и отладочный не поддерживаются.

В следующей таблице показаны ошибки, которые могут появиться в выходных данных состояния марионеточного кода.
Ошибка Причина
Code Manager не удалось подключиться к серверу процесс pe-puppetserver не запущен
Диспетчер кода сообщает о недопустимой конфигурации Недопустимая конфигурация в /etc/puppetlabs/puppetserver /conf.d/code-manager.conf
Служба хранения синхронизации файлов сообщает о неизвестном статусе Время ожидания обратного вызова состояния истекло

Проверьте соединение с хранилищем элементов управления

Управляющий репозиторий контролирует создание сред и обеспечивает установку правильных версий всех необходимых модулей. Основной сервер должен иметь доступ к репозиторию управления и клонировать его от имени пользователя pe-puppet.

Чтобы убедиться, что Code Manager может подключиться к управляющему репозиторию, выполните:

Если соединение установлено правильно, эта команда возвращает список всех сред в контрольном репозитории или репозиториях.Если команда выполнена успешно, у ключа SSH есть правильные разрешения, URL-адрес Git для репозитория правильный, и пользователь pe-puppet может выполнять соответствующие операции.

Если соединение не работает должным образом, диспетчер кода сообщает об ошибке «Невозможно определить текущие ветки для исходной ошибки Git».

Неудачная команда также возвращает путь на основном сервере, который можно использовать для отладки ключа SSH и URL-адреса Git.

Проверьте Puppetfile на наличие ошибок

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

Создайте временный каталог /var/tmp/test-puppetfile на основном сервере для тестирования и поместите копию Puppetfile во временный каталог.

Затем вы можете проверить синтаксис и перечисленные источники в вашем Puppetfile .

Проверьте синтаксис Puppetfile

Чтобы проверить синтаксис Puppetfile, запустите r10k puppetfile check из временного каталога.

Если у вас есть синтаксические ошибки Puppetfile, исправьте синтаксис и повторите попытку. Если синтаксис правильный, команда печатает "Синтаксис в порядке".

Проверьте источники, указанные в Puppetfile

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

Во временном каталоге выполните следующую команду:

При этом будут установлены все модули, перечисленные в вашем Puppetfile , и вы сможете получить доступ ко всем перечисленным источникам. Обратите внимание на все возникающие ошибки. Проблемы с отдельными модулями могут вызвать проблемы для всей среды. Ошибки с отдельными модулями (например, проблемы с синтаксисом URL-адреса или версии Git) отображаются как общие ошибки для этого модуля.

После того, как вы исправите ошибки, повторите тестирование и исправьте ошибки, пока все ошибки не будут исправлены.

Запустите тест развертывания

Вручную запустите полное развертывание r10k, чтобы проверить не только синтаксис Puppetfile и доступ к указанному хосту, но и то, работает ли развертывание через r10k .

Эта команда пытается выполнить полное развертывание r10k на основе файла r10k.yaml, который использует Code Manager. Этот тест записывает только в промежуточный каталог кода. Это не запускает синхронизацию файлов и должно использоваться только для специального тестирования.

Запустите этот тест развертывания с помощью следующей команды:

Если эта команда выполнена успешно, каталог /etc/puppetlabs/code-staging будет заполнен средами на основе каталогов и всеми необходимыми модулями для каждой среды.

Если команда не удалась, скорее всего, ошибка связана с настройками Code Manager, характерными для r10k. Сообщения об ошибках указывают, какие настройки не работают.

Отслеживание журналов проблем с триггерами развертывания веб-перехватчиков

Проблемы, возникающие, когда развертывание Code Manager инициируется веб-перехватчиком, бывает сложно изолировать. Отслеживайте журналы триггера развертывания, чтобы найти проблему.

Развертывания, инициированные веб-перехватчиком в Stash/Bitbucket, GitLab или GitHub, регулируются аутентификацией и достигают конечной точки каждой службы /v1/webhook.

Если вы используете версию GitLab старше 8.5.0, аутентификация веб-перехватчика Code Manager не работает из-за длины маркера аутентификации. Чтобы использовать веб-перехватчик с GitLab, отключите аутентификацию или обновите GitLab.

Примечание. Если вы отключите аутентификацию веб-перехватчика, она будет отключена только для конечной точки /v1/webhook. Другие конечные точки (такие как /v1/deploys) по-прежнему контролируются аутентификацией. Невозможно отключить аутентификацию на любой другой конечной точке Code Manager.

Чтобы устранить проблемы с веб-перехватчиками, следуйте инструкциям Code Manager, отслеживая успехи и ошибки в журнале Puppet Server. Для этого откройте окно терминала и выполните:

Внимательно следите за журналом ошибок и информационных сообщений при запуске развертывания. Эти ошибки появляются только в файле puppetserver.log.

Если вы не можете определить проблему с вашим веб-перехватчиком на этом шаге, выполните развертывание вручную на конечной точке /v1/deploys, как описано в следующем разделе.

Отслеживание журналов на наличие проблем с триггером развертывания /v1/deploys

Проблемы, возникающие, когда развертывание Code Manager инициируется конечной точкой /v1/deploys, бывает сложно изолировать. Отслеживайте журналы триггера развертывания, чтобы найти проблему.

Прежде чем инициировать развертывание на конечной точке /v1/deploys, создайте токен проверки подлинности. Затем разверните одну или несколько сред с помощью следующей команды:

Информацию о формировании команд curl см. в разделе Заметки об использовании для примеров curl.

Этот запрос ожидает завершения развертывания и синхронизации с компиляторами ("wait": true), поэтому возвращает ошибки развертывания.

Кроме того, вы можете развернуть все среды с помощью следующей команды curl:

Проверьте файл console-services.log на наличие ошибок, возникающих из-за этой команды curl.

Время развертывания кода истекло

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

Если время развертывания истекает слишком рано, увеличьте ключ timeouts_deploy. Вам также может понадобиться увеличить timeouts_shutdown , timeouts_sync и timeouts_wait .

Синхронизация файлов останавливается, когда Code Manager пытается развернуть код

Развертывание кода Code Manager предполагает доступ ко множеству небольших файлов. Если вы храните свой код Puppet в сетевом хранилище, медленное сетевое или серверное оборудование может привести к низкой производительности развертывания.

Настройте сеть для множества небольших файлов или храните код Puppet в локальном хранилище или хранилище с прямым подключением.

Классы отсутствуют после развертывания

После успешного развертывания кода добавленный вами класс не отображается в консоли.

Если развертывание вашего кода работает, но добавленного вами класса нет в консоли:

Читайте также: