Драйверы - фильтры
Драйверы - фильтры
Система ввода/вывода Windows NT является расширяемой. Один из методов расширения возможностей системы ввода/вывода - разработка и применение драйверов-фильтров.
Драйвер-фильтр - это промежуточный драйвер, перехватывающий запросы, предназначенные некоторым программным модулям (например, драйверу файловой системы или драйверу диска). Перехватив запрос, драйвер-фильтр имеет возможность либо расширения, либо замещения функциональности, обеспечиваемой первоначальным получателем запроса. Драйвер-фильтр может, либо использовать сервисы драйвера, которому изначально предназначался запрос, либо использовать сервисы других программных модулей уровня ядра для обеспечения дополнительной функциональности. Драйверы-фильтры могут встраиваться в любое место в стеке драйверов, их может быть несколько, в том числе расположенных подряд.
Примером использования драйвера-фильтра может послужить реализация прозрачного зашифрования/расшифрования данных, хранимых на диске или в сети. Ни одна из поставляемых с ОС Windows NT файловых систем (FASTFAT, NTFS, CDFS, LAN Manager Redirector) не обеспечивает поддержки прозрачного зашифрования данных перед записью их на диск (или отправкой в сеть) и расшифрования данных перед предоставлением их авторизированному пользователю. Но для того, чтобы выполнять шифрование, необязательно реализовать свой собственный драйвер файловой системы или специальный драйвер диска. Достаточно разработать драйвер-фильтр, располагающийся либо выше драйвера файловой системы (в этом случае драйвер-фильтр сможет обработать запрос перед тем, как драйвер файловой системы получит возможность его увидеть), либо ниже драйвера файловой системы (этот случай позволяет драйверу-фильтру выполнить любые требуемые операции после того, как драйвер файловой системы завершит свою задачу, и перед тем, как запрос будет получен драйвером диска (или сетевым драйвером)).
Драйвер-фильтр также может выполнять автоматическое обнаружение в реальном времени сигнатур вирусов в файлах (в том числе и файлах, полученных из сети). Фундаментальные шаги в разработке драйверов-фильтров:
Каждый объект-устройство имеет поле, называемое AttachedDevice и содержащее указатель на объект-устройство, созданное драйвером-фильтром, который первым присоединил свое устройство. Если это поле содержит NULL, значит нет присоединенных устройств. В процессе присоединения нового объекта-устройства, процедура присоединения пройдет по связанному списку присоединенных устройств до конца и выполнит присоединение нового объекта-устройства к последнему объекту-устройству в этом списке. В результате, любой запрос на создание/открытие, предназначающийся некоторому объекту-устройству, будет перенаправляться последнему (в его списке присоединенных устройств) объекту-устройству. То есть последнему драйверу-фильтру, ассоциированному с последним объектом-устройством. Аналогично, при вызове функции, которая по имени объекта-устройства возвращает его указатель, будет возвращен указатель на объект-устройство, являющийся последним в списке присоединенных устройств.
Но важно заметить, что диспетчер ввода/вывода проходит до конца списка присоединенных устройств не во всех случаях. Например, никакого перенаправления не будет, если будет вызвана функция IoCallDriver(). Следовательно, чтобы обращение к драйверу назначения не миновало драйвер-фильтр, этот драйвер-фильтр должен присоединить свой объект-устройство к объекту-устройству драйвера-назначения, прежде, чем вышележащий драйвер вызовет процедуру определения указателя нижележащего объекта-устройства по его имени (это делается во время запроса на открытие), а затем будет использовать этот указатель (в частности при вызове функции IoCallDriver()).
Ниже рассмотрены основные принципы, которых необходимо придерживаться при разработке драйвера-фильтра, а также недостатки, из-за которых применение драйверов-фильтров становится нежелательным:
Несмотря на то, что все драйверы должны отвечать на стандартное множество запросов, выдаваемых менеджером ввода/вывода, в реальности, в случае разработки собственного драйвера-фильтра, нужно знать очень тонкие взаимосвязи, которые проявляются в зависимости от того, на каком уровне иерархии находится драйвер-фильтр. Возможны случаи, когда драйвер одной файловой системы запрашивает сервисы у драйвера другой файловой системы, или когда промежуточный драйвер запрашивает сервисы вышележащего драйвера файловой системы.
Например, в случае фильтрации всех запросов, предназначенных некоторому логическому тому, управляемому драйвером файловой системы (NTFS), необходимо понимать всевозможные пути вовлечения драйвера NTFS в обработку запроса, так как во всех этих случаях будут вовлекаться процедуры распределения драйвера-фильтра. Процедуры обработки запроса на чтения/запись драйвера файловой системы могут вовлекаться несколькими путями, например: из потока режима ядра, вызвавшего системные сервисы ZwReadFile(), ZwWriteFile(); из потока пользовательского режима, вызвавшего системные сервисы NtReadFile(), NtWriteFile(); из диспетчера памяти из-за обращения к отсутствующей странице спроецированного файла; из диспетчера кэша в результате асинхронного сброса буферов диспетчера кэша на диск; и так далее.
В некоторых ситуациях может быть приемлемым то, что драйвер - фильтр отправляет запрос ввода/вывода на асинхронное выполнение, но в других ситуациях (например, при обслуживании обращения к отсутствующей странице) драйвер-фильтр не должен этого делать, иначе это приведет к взаимной блокировке или зависанию.
В случае, когда драйвер-фильтр привязывается к объекту-устройству нижнего уровня (например, к устройству, представляющему физический диск), то возникают другие проблемы, с которыми сталкивается подобный драйвер-фильтр. Например, пакеты IRP, посланные драйверу диска, могут быть чаще всего ассоциированными пакетами, созданными драйвером файловой системы, и поэтому драйвер-фильтр не должен пытаться в свою очередь создавать ассоциированные пакеты. Обычно от драйверов дисков ожидают, что они будут выполнять операции асинхронно, поэтому драйвер-фильтр должен удовлетворять этим ожиданиям.
На всех уровнях, которые будут обсуждаться в дальнейшем, возможны реализация и применение драйверов-фильтров.