Здравствуйте. Пишу минифильтр файловой системы. Необходимо после записи файла на диск подписывать файл цифровой подписью, а перед чтением её проверять. Решил поступить следующим образом: при обработке IRP_MJ_WRITE после записи на диск в postoperation callback открывать файл, подсчитывать подпись и записывать её, например, в конец файла. Проблема в следующем: поскольку postoperation callback может быть вызвана на высоком IRQL, приходится откладывать обработку с помощью FltQueueDeferredIoWorkItem. Однако здесь - http://msdn.microsoft.com/en-us/library/ff543449(v=vs.85).aspx сказано, что этого нельзя делать для запросов типа IRP_MJ_WRITE и IRP_MJ_READ, так как может привести к дедлоку. Как обойти это ограничение? Если это невозможно, как подобная обработка должна выполняться правильно?
Вопрос всё ещё актуален! Неужели никто из здешних гуру не знает ответ? Или вопрос настолько глупый? x64, h0t, shchetinin, подскажите, пожалуйста, очень нужно!
_Researcher_ 1) Я толком не чего не понял из контекста задачи (( - Если хотите пописать файл то почему бы это не сделать при закрытии файла например? А проверять при открытии файла? - Если все таки хочешь формировать во время IRP_MJ_WRITE - IRP_MJ_READ то придется формировать контекст и подкитывать (Data,FltObjects). Делать отложеными IRP_MJ_WRITE, IRP_MJ_READ, IRP_MJ_FLUSH_BUFFERS действительно плохая идея, но если знать контекст, в некоторых функция это можно делать(Отложеный вызовы или же отдельный поток. ). Но это все равно криво.
Во – первых, спасибо большое за ответ! Задача такая: нужно сделать модель файловой системы с защитой от навязывания неактуальных файлов. Для этого надо перехватывать вызовы файловой системы прозрачно для приложений пользователя, для этого же нужна и цифровая подпись. Честно говоря, думал об этом в первую очередь, но проблема в том, что в модели файлы могут храниться на недоверенном сервере (т.е. эта ФС предполагается сетевой). Поскольку я мало знаком с драйверами сетевых ФС, для упрощения задачи было решено реализовать эту модель для локальной ФС. При этом мой фильтр предполагается доверенным компонентом, а всё, что лежит ниже, как бы недоверенное. Если проверять файл при открытии, то когда мы начнём из него читать, то может вернуться неактуальное/поддельное содержимое, и проверить это мы не сможем. Не могли бы вы про это рассказать поподробнее? Поделитесь, пожалуйста, примером, или хотя бы ссылкой, где про это можно почитать. Вообще я читал в WDK в разделе о минифильтрах про контексты, но там не очень понятно как работать с ними, и для чего они нужны (((. Подскажите, можно ли ещё что-нибудь почитать на эту тему?
_Researcher_ Я не совсем понял Ваш предполагаемый алгоритм. Если Вы будите считать ЭЦП при КАЖДОЙ операции чтения то это будут ТАКИЕ ТОРМОЗА, что вы работать вообще не сможете. (все таки проверка/создание подписи достаточно "жирная" операция) Где Вы предполагаете хранить подпись? Не забывайте про FastIO P.S. Вы хотите "добить" ваш вариант?(т.е. сделать отложенную обработку write)
h0t Да, спасибо за ответ, вы правильно поняли, хочу проверять подпись при каждом чтении с диска, а обновлять при каждой операции записи. Полностью с вами согласен насчёт тормозов при каждой операции чтения и записи. Но! Вот выдержка из статьи по созданию аналогичной ФС под unix по поводу чтения: 3.7. Reading a File The SiRiUS client takes the following steps to read a file. 1. Obtain the md-file and identify the file owner by extracting the user name tag from the first encrypted key block. Obtain the owner’s MSK using a public key server and verify the signature on the md-file. Also verify the freshness of the md-file. 2. Locate the encrypted key block with the reader’s user name in the md-file and decrypt the key block to obtain the FEK. 3. Obtain the d-file (файл данных) and verify the signature using the public key of the FSK. 4. Decrypt the encrypted file data with the FEK to obtain the file contents. (SiRiUS: Securing Remote Untrusted Storage – первая ссылка в гугле) Т.е. кроме проверки подписи, при чтении там проверяется ещё куча всего остального. Чтение там замедляется где-то в 18 раз (по данным в конце этой статьи). Написал в первом посте, что в конце файла, но я так полагаю, это не принципиально, можно, например, хранить её в дополнительном NTFS потоке. Или я здесь тоже чего-то недопонимаю? Тоже думал об этом, собираюсь подписывать файл только в случае непосредственной записи на диск (флаг IRP_NOCACHE в IrpFlags). Вы меня почти разубедили . Но дело в том, что я не вижу ему достойной замены. Открытие/закрытие конечно хорошо, и гораздо проще в реализации, но как решать проблемы, описанные в моём предыдущем посте? Ещё я думал над созданием подписи в preoperation callback’е перед записью на диск, там нет проблем с IRQL, но тогда нужно там считывать файл и определять какая его часть перезаписывается новыми данными, что тоже не слишком-то удобно. В общем, поэтому я и хотел бы прояснить у знающих людей какой из этих вариантов наиболее правильный. Если у кого-нибудь ещё есть какие-нибудь идеи на этот счёт, или кто-то видит ошибку в моих рассуждениях, буду очень благодарен вам за советы. Заранее спасибо.
Смотрите я возможно не до конца понял Вашей задумки, но думаю вот что: хранить подпись например в конце файла идея не очень удачна так как если некто контролирует целостность фала и ничего не знает о вашей системе, то можете получить не работоспособный компонент ( если не будите заморачиваться с перехватом процедур). И пару вопросов: 1. Не совсем понимаю как Вы хотите считать ЭЦП? при каждой операции чтения/записи пересчитывать ЭЦП для всего файла? 2. И последний вопрос Вы хотите "прикрыть" всю систему так включая системные компоненты?
h0t Да, вы правы, я не подумал об этом. Но вообще-то, это для меня не настолько важно, чтобы учитывать такие тонкости. Прочитайте ещё раз мои предыдущие посты внимательнее. Дело в том, что нужна достаточно примитивная модель криптографической ФС, а не полноценная реализация. Поэтому, я естественно не собираюсь контролировать всю систему, включая системные компоненты. К примеру, я могу подписывать только файлы .txt, .doc и т.д. По поводу пересчёта ЭЦП для всего файла. Да, наверное, пока планирую так и поступить для упрощения задачи (понимаю, что это приведёт к БОЛЬШИМ тормозам при увеличении размера файла). Вообще для улучшения производительности, например, в том же SiRiUS, файлы разбиваются на блоки, и считается ЭЦП для каждого блока в отдельности. Но мне пока нужна хотя бы простейшая реализация, и до тех проблем, про которые вы пишете, я ещё не добрался, сначала нужно решить текущие (в какой момент считать ЭЦП?), и получить хотя бы примитивно работающее решение.