Здравствуйте, Аноним, Вы писали:
А>Здравствуйте! А>Помогите, пожалуйста, найти грамотное решение вот такой задачки.
А>Есть файловый фильтр, осуществляющий фильтрацию IRP_MJ_CREATE. А>Этот фильтр на основе тех или иных критериев должен сделать одно из следующего:
А>Разрешить операцию, т.е. просто переслать запрос ниже. А>Запретить операцию, т.е. завершить запрос с соответствующим статусом. А>Спросить у пользователя "что делать с этим запросом?".
А>Вот сейчас думаю как грамотно реализовать третий пункт? А>Придумалось пока вот что:
[skipped]
Примерно такой механизм что вы описали выше работает давно, называется "Inverted call", поищите по этим ключевым словам и найдете подробное описание.
Искать можете на рсдн, найдете много чего, а также в оригинале (если я конечно не ошибаюсь насчет источника) эта статья есть на osronline.com
Механизм примерно следующий: user-mode приложение шлет запрос драйверу, драйвер помечает его как pending, приложение дожидается завершения запроса, получая из него необходимые данные, как то "Спросить у пользователя что делать с этим запросом?", в котором и содержится необходимая информация о самом запросе. А в ответ приложение шлет новый запрос, содержащий ответ, ну и соответственно информацию позволяющую идентифицировать то самое действие о котором драйвер хотел спросить у приложения. Драйвер получив данный запрос выполняет соответствующие действия, чаще всего заверщает опреацию с соответствующим статусом. А также приложение посылает новый запрос, на тот случай если драйверу опять понадобится что то спросить у приложения.
Так как был упомянут файловый фильтр, думаю будет нелишним напомнить, что если используется minifilter модель для фильтрации, то есть такой неплохой механизм, как FilterCommunicationPort, вполне себе эффективный механизм
Как грамотно организовать выборку из KM ?
От:
Аноним
Дата:
30.10.07 15:24
Оценка:
Здравствуйте!
Помогите, пожалуйста, найти грамотное решение вот такой задачки.
Есть файловый фильтр, осуществляющий фильтрацию IRP_MJ_CREATE.
Этот фильтр на основе тех или иных критериев должен сделать одно из следующего:
Разрешить операцию, т.е. просто переслать запрос ниже.
Запретить операцию, т.е. завершить запрос с соответствующим статусом.
Спросить у пользователя "что делать с этим запросом?".
Вот сейчас думаю как грамотно реализовать третий пункт?
Придумалось пока вот что:
1. Драйвер создаёт именованное событие через IoCreateNotificationEvent() с именем что-то типа \??\EventName. Юзермодное приложение открывает это событие через OpenEvent().
2. Драйвер создаёт внутренний список (очередь FIFO) pending-запросов.
3. Для всех поступающих IRP, соответствующих определённым критериям, драйвер делает следующее:
3.1. Создаёт примерно такую структуру:
3.2. Ставит её во внутреннюю очередь.
3.3. Ставит глобальное событие \??\EventName в состояние signaled.
3.4. Входит в ожидание события REQUEST_ENTRY.Event через KeWaitForSingleObject().
4. Приложение получает уведомление о событии \??\EventName через WaitForSingleObject().
5. По получении уведомления приложение шлёт что-то типа IOCTL_QUERY_REQUEST_DATA драйверу.
6. Драйвер заполняет буфер приложения данными по первому запросу в очереди (в том числе передаёт и указатель на IRP) и завершает запрос IOCTL_QUERY_REQUEST_DATA.
7. Приложение отображает пользователю окно с данными запроса (например, имя файла) и пользователь жмёт, например, либо "Разрешить" либо "Запретить".
8. Приложение шлёт драйверу что-то типа IOCTL_RESOLVE_REQUEST вот с такой примерно структурой:
9. Драйвер по получении IOCTL_RESOLVE_REQUEST делает следующее:
9.1. Прочёсывает всю свою внутреннюю очередь и ищет в ней указанный IRP по указателю RESOLVE_ENTRY.Irp.
9.2. Если нашёл — ставит поле REQUEST_ENTRY.UserAction в значение RESOLVE_ENTRY.UserAction.
9.3. Ставит событие REQUEST_ENTRY.Event в состояние signaled.
10. Далее запрос IRP_MJ_CREATE, который заснул в ожидании события REQUEST_ENTRY.Event, просыпается и происходит следующее:
10.1. Считывается значения поля REQUEST_ENTRY.UserAction и запоминается в локальной переменной.
10.2. REQUEST_ENTRY удаляется из внутреней очереди и уничтожается.
10.3. Выполняется выбранное пользователем действие.
Вот так, что-то вроде того .
Просьба к гуру: прокомментируйте, пожалуйста, мои мысли.
Насколько приведённый алгоритм грамотен?
Какие могут быть подводные камни?
Как можно сделать безопаснее / красивее / эффективнее?
Спасибо!
Re[2]: Как грамотно организовать выборку из KM ?
От:
Аноним
Дата:
06.11.07 13:56
Оценка:
AF>Примерно такой механизм что вы описали выше работает давно, называется "Inverted call"
Ok, я понял. Значит двигаюсь я в правильном направлении.
Вот ещё вопросы:
1. А существует ли способ обменяться вопросом/ответом с приложением с помощью одного IOCTL, посланного приложением ? Как такое можно реализовать ?
2. Что вы можете сказать конкретно по моей реализации ?
3. Зачем помечать IRP как pending, когда можно банально войти в ожидание по KeWaitForSingleObject(), благо IRQL позволяет ? Или в этом есть какой-то смысл, которого я не замечаю ?
Здравствуйте, Аноним, Вы писали:
А>1. А существует ли способ обменяться вопросом/ответом с приложением с помощью одного IOCTL, посланного приложением ? Как такое можно реализовать ?
Так и делается обычно. IRP, посылаемый драйверу, может содержать ответ пользователя на текущий запрос, а при завершении драйвер может передать с помощью того же IRP новый запрос. Ну и так по кругу
А>2. Что вы можете сказать конкретно по моей реализации ?
Избыточна, по-моему. Зачем событие дополнительное, если и так собираетесь обмениваться IRP, факт получения/завершения которых и так уже сами по себе события, которые и нужно мониторить. Плюс еще ваша реализация не учитывает возможность отмены (IoCancelIrp) оригинального запроса ввода-вывода в процессе ожидания реакции пользователя. Наконец, заставлять поток ждать не нужно, если операция асинхронная (хотя у вас в примере всегда синхронный CREATE рассматривается, но вдруг планируется на другие события подобную схему распространить).
А>3. Зачем помечать IRP как pending, когда можно банально войти в ожидание по KeWaitForSingleObject(), благо IRQL позволяет ? Или в этом есть какой-то смысл, которого я не замечаю ?
А если вы обрабатываете асинхронную операцию? Ждать нельзя долго. Плюс cancellation.. В висте уже create — опреация в принципе отменяемая, так что если планируются задержки (а они неизбежны, если пользователь участвует в принятии решения по запросу , то и IRP_MJ_CREATE из вашего примера нужно откладывать и завершать из рабочего потока, установив cancel-процедуру перед этим.
В общем читайте пример от OSR. Брать "как есть" не рекомендую. Советую ознакомиться с Cancel-Safe IRP Queues и реализовать у себя для организации очередей IRP.
Re[4]: Группировка запросов!
От:
Аноним
Дата:
09.11.07 17:29
Оценка:
Здравствуйте, Sergey Storozhevykh, Вы писали:
Сергей, большое спасибо вам за ответы !
Всё получилось за исключением одного.
Проблема вот в чём.
Берём Блокнот, пытаемся открыть файл.
Если на первый же запрос IRP_MJ_CREATE от Блокнота на этот файл ответить STATUS_ACCESS_DENIED, то Блокнот скажет "Отказано в доступе" и, естественно, ничего не откроет.
Но вот если на первый запрос ответить STATUS_SUCCESS, то Блокнот, цука такая, пошлёт ещё около 3х запросов IRP_MJ_CREATE для этого же файла.
На основании серии одинаковых сообщений от юзермодной части приложения пользователь сделает вывод что-то вроде "Мой Блокнот сошёл с ума! Он открывает один и тот же файл 5 раз подряд!! Хелп!!!".
Т.е. проблема сводиться к группировке запросов от одного и того же приложения для одного и того же файла, чтобы лишний раз не тревожить пользователя.
Кто как борол сие безобразие? Какие есть способы?
Спасибо!
Здравствуйте, Аноним, Вы писали:
А>На основании серии одинаковых сообщений от юзермодной части приложения пользователь сделает вывод что-то вроде "Мой Блокнот сошёл с ума! Он открывает один и тот же файл 5 раз подряд!! Хелп!!!". А>Т.е. проблема сводиться к группировке запросов от одного и того же приложения для одного и того же файла, чтобы лишний раз не тревожить пользователя.
По-моему, ничего группировать не нужно. Обычно для разрешения таких ситуаций используются разные типы правил, которые генерируются при ответе пользователя. Причем пользователь сам определяет как ваша программа себя должна вести в дальнейшем.
Можно в диалоге пользователю предоставить выбор:
1. Разрешить однократно. Запрос разрешается, дополнительные правила не генерируются. Каждый последующий подобный запрос будет приводить к задействованию режима обучения и требовать реакции пользователя.
2. Разрешить такой запрос для данного экземпляра приложения. Тогда запрос разрешается, в драйвер уходит правило, разрешающее данному процессу (идентифицируемому по PID, например), выполнять подобные запроосы. В правило можно добавить другие параметры: пользователя, например. Соответственно пользователя больше не побеспокоят одинаковые лерны от этого процесса. При завершении процесса правило автоматически удаляется.
3. Разрешить данный тип запросов для конкретного приложения (например, read/write file.dat для notepad.exe от имени user1). Причем приложение желательно идентифицировать не только по имени, но и по хешу.
4. Разрешить все запросы для этого приложения/экземпляра приложения.
Можно еще придумать варианты, в зависимости от того, что хотите получить. Режим обучения для того и нужен, чтоб программа могла на основе ответа пользователя сгенерировать правила, описывающие конкретную ситуцию, с тем чтоб в дальнейшем не беспокоить пользователя. И важно пользователю дать возможность самому решать как себя в дальнейшем ваша программа должна вести при обнаружении похожих ситуаций.
Re[6]: Группировка запросов!
От:
Аноним
Дата:
12.11.07 12:56
Оценка:
SS>Можно в диалоге пользователю предоставить выбор: SS>1. Разрешить однократно. Запрос разрешается, дополнительные правила не генерируются. Каждый последующий подобный запрос будет приводить к задействованию режима обучения и требовать реакции пользователя. SS>2. Разрешить такой запрос для данного экземпляра приложения. Тогда запрос разрешается, в драйвер уходит правило, разрешающее данному процессу (идентифицируемому по PID, например), выполнять подобные запроосы. В правило можно добавить другие параметры: пользователя, например. Соответственно пользователя больше не побеспокоят одинаковые лерны от этого процесса. При завершении процесса правило автоматически удаляется. SS>3. Разрешить данный тип запросов для конкретного приложения (например, read/write file.dat для notepad.exe от имени user1). Причем приложение желательно идентифицировать не только по имени, но и по хешу. SS>4. Разрешить все запросы для этого приложения/экземпляра приложения.
Спасибо вам, Сергей!
Очень интересные мысли!
Я чего я сам не догадался...