Поделиться через


защита Run-Down

Драйверы режима ядра могут использовать защиту от запуска для безопасного доступа к объектам в общей системной памяти, созданных и удаленных другим драйвером режима ядра.

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

Драйвер, принадлежащий общему объекту, может позволить другим драйверам получить и освободить защиту от запуска объекта. Если защита от разрушения действует, драйвер, не являющийся владельцем, может получить доступ к объекту без риска его удаления до окончания доступа. Перед началом доступа драйвер, обращающийся к объекту, запрашивает защиту от преждевременного доступа. Для долго существующего объекта этот запрос почти всегда одобряется. После завершения доступа драйвер доступа освобождает ранее полученную защиту от запуска объекта.

Основные протоколы защиты от отключения системы

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

Драйвер, обращаюющийся к общему объекту, вызывает подпрограмму ExAcquireRundownProtection, чтобы запросить защиту от запуска объекта. После завершения доступа этот драйвер вызывает процедуру ExReleaseRundownProtection, чтобы освободить защиту от запуска объекта.

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

При подготовке к удалению общего объекта драйвер-владелец вызывает подпрограмму ExWaitForRundownProtectionRelease для ожидания завершения работы объекта. Во время этого вызова ExWaitForRundownProtectionRelease ожидает освобождения всех ранее предоставленных экземпляров защиты от запуска объекта, но предотвращает предоставление новых запросов на защиту от запуска объекта. После завершения последнего защищённого доступа и освобождения всех экземпляров защиты от завершения ExWaitForRundownProtectionRelease возвращает управление, и драйвер может безопасно удалить объект.

ExWaitForRundownProtectionRelease блокирует выполнение вызывающего потока драйвера до тех пор, пока все драйверы, удерживающие защиту завершения работы на общем объекте, не снимут эту защиту. Чтобы ExWaitForRundownProtectionRelease не блокировал выполнение в течение чрезмерно длительных периодов, потоки драйвера, обращающиеся к общему объекту, должны избегать приостановки, пока они удерживают защиту завершения объекта. По этой причине доступ к драйверам следует вызывать ExAcquireRundownProtection и ExReleaseRundownProtection в критическом регионе или защищенном регионе или во время выполнения в IRQL = APC_LEVEL.

Применения защиты от полного разряда

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

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

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

Структура EX_RUNDOWN_REF

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

Чтобы начать общий доступ к объекту, драйвер, принадлежащий объекту, вызывает ExInitializeRundownProtection для инициализации структуры EX_RUNDOWN_REF, связанной с объектом. После инициализации драйвер владения может сделать эту структуру доступной для других драйверов, которым требуется доступ к объекту. Обращающиеся драйверы передают эту структуру в качестве параметра вызовам ExAcquireRundownProtection и ExReleaseRundownProtection, которые получают и освобождают защиту от остановки объекта. Драйвер владения передает эту структуру в качестве параметра вызов exWaitForRundownProtectionRelease, который ожидает запуска объекта, чтобы его можно было безопасно удалить.

Сравнение с блокировками

Защита от износа — один из нескольких способов обеспечить безопасный доступ к общему ресурсу. Другой подход — использовать взаимоисключаемую блокировку программного обеспечения. Если драйверу требуется доступ к объекту, который в настоящее время заблокирован другим драйвером, первый драйвер должен ждать, пока второй драйвер отпустит блокировку. Однако получение и освобождение блокировок может стать узким местом производительности, и блокировки могут потреблять большие объемы памяти. При неправильном использовании блокировки могут привести к тому, что драйверы, конкурирующие за те же общие объекты, становятся взаимоблокируемыми. Усилия по обнаружению и предотвращению взаимоблокировок обычно требуют значительного перераспределения вычислительных ресурсов.

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

Другие подпрограммы защиты от истощения ресурсов

Несколько других остаточных подпрограмм защиты доступны, в дополнение к тем, которые упоминались ранее. Эти дополнительные подпрограммы могут использоваться некоторыми драйверами.

Подпрограмма exReInitializeRundownProtection позволяет ранее использовать структуру EX_RUNDOWN_REF, связанную с новым объектом, инициализирует защиту запуска в этом объекте.

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

Подпрограммы ExAcquireRundownProtectionEx и ExReleaseRundownProtectionEx похожи на ExAcquireRundownProtection и ExReleaseRundownProtection. Эти четыре подпрограммы увеличивают или уменьшают количество экземпляров защиты от сбоя, которые применяются к общему объекту. В то время как ExAcquireRundownProtection и ExReleaseRundownProtection увеличивают это число на один, ExAcquireRundownProtectionEx и ExReleaseRundownProtectionEx увеличивают и уменьшают количество на произвольные значения.

Защита запуска с поддержкой кэша

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

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

Чтобы использовать ссылку на разбор с учетом кэша, выполните следующие действия.

  1. Создайте объект EX_RUNDOWN_REF_CACHE_AWARE, выполнив одно из следующих действий:
  2. Запросите защиту от запуска объекта перед доступом к нему, вызвав подпрограмму ExAcquireRundownProtectionCacheAware. Эта подпрограмма возвращает значение TRUE, если запрос предоставлен или false, если объект запущен.
  3. Отпустите защиту от запуска объекта после доступа к нему, вызвав подпрограмму ExReleaseRundownProtectionCacheAware.
  4. Дождитесь запуска объекта перед удалением, вызвав подпрограмму ExWaitForRundownProtectionReleaseCacheAware. Эта подпрограмма блокирует текущий поток, пока не будут освобождены все экземпляры защиты от запуска объекта.
  5. Если драйвер вызывал ExAllocateCacheAwareRundownProtection ранее, он должен вызвать ExFreeCacheAwareRundownProtection, чтобы освободить ссылку на завершение.

Чтобы повторно использовать ссылку на структурирование с учетом кэша, выполните следующие действия.

  1. После вызова ExWaitForRundownProtectionReleaseCacheAwareвызовите ExRundownCompletedCacheAware, чтобы указать, что запуск старого объекта завершен.
  2. Вызовите ExReInitializeRundownProtectionCacheAware, чтобы повторно инициализировать ссылку после запуска связанного объекта.
  3. Теперь драйвер снова может вызвать ExAcquireRundownProtectionCacheAware.

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