Защита от запуска
Начиная с Windows XP защита от запуска доступна драйверам режима ядра. Драйверы могут использовать защиту от запуска для безопасного доступа к объектам в общей системной памяти, созданной и удаленной другим драйвером режима ядра.
Как сообщается, объект будет запущен , если все невыполненные доступы к объекту завершены, и новые запросы на доступ к объекту не будут предоставлены. Например, может потребоваться запустить общий объект, чтобы его можно было удалить и заменить новым объектом.
Драйвер, принадлежащий общему объекту, может позволить другим драйверам получить и освободить защиту от запуска объекта. Если защита от запуска действует, драйвер, отличный от владельца, может получить доступ к объекту без риска, что владелец удалит объект до завершения доступа. Перед запуском доступа доступ к драйверу запрашивает защиту от запуска объекта. Для длительного объекта этот запрос почти всегда предоставляется. После завершения доступа драйвер доступа освобождает ранее полученную защиту от запуска объекта.
Основные подпрограммы защиты от запуска
Чтобы начать общий доступ к объекту, драйвер, принадлежащий объекту, вызывает подпрограмму 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 добавим и уменьшать количество на произвольные суммы.
Защита запуска с поддержкой кэша
Ссылка на запуск — это компактная и быстрая структура данных, но она может привести к возникновению спорных моментов, когда многие процессоры пытаются получить ссылку одновременно. Это может повлиять на производительность и масштабируемость драйвера.
Чтобы избежать этой проблемы, можно использовать ссылку на запуск с поддержкой кэша для распределения отслеживания ссылок между несколькими строками кэша. Это снижает сорность кэша и повышает производительность драйвера на компьютерах с несколькими обработчиками.
Чтобы использовать ссылку на запуск с поддержкой кэша, выполните следующие действия.
- Создайте объект EX_RUNDOWN_REF_CACHE_AWARE, выполнив одно из следующих действий:
- Вызов ExAllocateCacheAwareRundownProtection. Обратите внимание, что это заботится о инициализации.
- Кроме того, чтобы управлять выделением памяти, вызовите ExSizeOfRundownProtectionCacheAware, выделите буфер возвращаемого размера, а затем передайте этот буфер и размер в ExInitializeRundownProtectionCacheAware.
- Запросите защиту от запуска объекта перед доступом к нему, вызвав подпрограмму ExAcquireRundownProtectionCacheAware . Эта подпрограмма возвращает значение TRUE, если запрос предоставлен или false, если объект запущен.
- Отпустите защиту от запуска объекта после доступа к нему, вызвав подпрограмму ExReleaseRundownProtectionCacheAware .
- Дождитесь запуска объекта перед удалением, вызвав подпрограмму ExWaitForRundownProtectionReleaseCacheAware. Эта подпрограмма блокирует текущий поток, пока не будут освобождены все экземпляры защиты от запуска объекта.
- Если драйвер с именем ExAllocateCacheAwareRundownProtection ранее, он должен вызвать ExFreeCacheAwareRundownProtection , чтобы освободить ссылку на rundown.
Чтобы повторно использовать ссылку на запуск с поддержкой кэша, выполните следующие действия.
- После вызова ExWaitForRundownProtectionReleaseCacheAware вызовите ExRundownCompletedCacheAware, чтобы указать, что запуск старого объекта завершен.
- Вызовите ExReInitializeRundownProtectionCacheAware , чтобы повторно инициализировать ссылку после запуска связанного объекта.
- Теперь драйвер может снова вызвать ExAcquireRundownProtectionCacheAware.
Справочник по запуску с поддержкой кэша имеет преимущество повышения производительности и масштабируемости в определенных ситуациях, но он потребляет больше памяти, чем обычная ссылка на запуск. Этот компромисс следует учитывать при выборе между двумя типами ссылок на rundown.