Форум программистов «Весельчак У»
  *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

  • Рекомендуем проверить настройки временной зоны в вашем профиле (страница "Внешний вид форума", пункт "Часовой пояс:").
  • У нас больше нет рассылок. Если вам приходят письма от наших бывших рассылок mail.ru и subscribe.ru, то знайте, что это не мы рассылаем.
   Начало  
Наши сайты
Помощь Поиск Календарь Почта Войти Регистрация  
 
Страниц: [1]   Вниз
  Печать  
Автор Тема: FS Filter  (Прочитано 13946 раз)
0 Пользователей и 5 Гостей смотрят эту тему.
resource
Молодой специалист

ru
Offline Offline
Пол: Мужской

« : 29-03-2010 08:56 » 

Всем здравствуйте.

Друзья есть борьба с фильтром файловой системы (не минифильтр), и есть такой старый топик https://forum.shelek.ru/index.php/topic,4349.0.html. Ситуация в чем то на мою похожа, но по большей части совершенно обратная.
Моя проблема в том, что я не получаю IRP_MJ_CLOSE для некоторых открытых файлов. Понимаю, звучит как бред, мол ладно еще IRP_MJ_CREATE, а IRP_MJ_CLOSE то полюбому должен приходить, но этот бред я вижу своими глазами. Причем, что самое интересное, как и в том старом посте, после запуска filemon, что называется прорвало, всё приходит нормально. Как? Что это?

Еще не могу решить такой вопрос. Насколько я понимаю, при получении IRP_MJ_CLOSE уже нельзя полагаться на FileObject->FileName, как собственно и на многое другое. Но мне-то надо знать как называется закрываемый файл. Сначала пробовал узнать имя через IRP_MJ_QUERY_INFORMATION, но быстро осознал к чему приводит такая затея. Вот решил сохранять Имя пришедшее вместе с IRP_MJ_CREATE, с целью его последующего получения при обработке IRP_MJ_CLOSE. Сделал наподобие как у Руссиновича - хэш-таблица. Но такая штука получается, что в IRP_MJ_CREATE поступает один и тот же указатель на FileObject, но с разными именами. Один раз для самого файла, а второй - для его потока. Причем FileObject для потока (хотя по указателю это один и тот же FileObject что и для самого файла) не содержит флага FO_STREAM_FILE, и вообще не понимаю как определить, что это именно поток, не глядя на имя (которое при IRP_MJ_CLOSE может быть и недоступно вовсе).
Записан
Ochkarik
Модератор

ru
Offline Offline
Пол: Мужской

« Ответ #1 : 29-03-2010 12:13 » new

это тоже на произвольных файлах случается? или на вполне определенных?

PS может быть вы ложно видите запросы для тех IRP_MJ_CREATE, которые были завершены со статусом ошибки?
как вообще у вас подсчет идет?
Записан

RTFM уже хоть раз наконец!  RTFM :[ ну или хотя бы STFW...
resource
Молодой специалист

ru
Offline Offline
Пол: Мужской

« Ответ #2 : 29-03-2010 12:26 » 

PS может быть вы ложно видите запросы для тех IRP_MJ_CREATE, которые были завершены со статусом ошибки?

Я сперва так и подумал. Посмотрел вывод DbgPrint - вроде нормально всё, всмысле файл открывается. Впоследствие повырезал из кода всё что только можно и добавил максимум вывода (диагностики).  получилось примерно так

Код:
//------------------------------------------------------------------------------------------
NTSTATUS
SFsCreate(
PDEVICE_OBJECT pDeviceObject,
PIRP pIrp
)
{
NTSTATUS NtStatus, localStatus;
PIO_STACK_LOCATION pStack;
PSFSFILTER_EXTENSION pDevExt;
KEVENT waitEvent;
UNICODE_STRING usFullPath;
BOOLEAN bCheckFStat;

PAGED_CODE();

DBGPRINT(("---> SFsCreate\n"));

pDevExt = (PSFSFILTER_EXTENSION)pDeviceObject->DeviceExtension;
pStack = IoGetCurrentIrpStackLocation(pIrp);

ASSERT(pStack);

usFullPath.Buffer = NULL;
usFullPath.Length = 0;
usFullPath.MaximumLength = 0;

bCheckFStat = TRUE;

DBGPRINT(("FileObject: 0x08%x\n", pStack->FileObject));

if (pStack->FileObject)
{
DBGPRINT(("FileName: %wZ\nCreate options: 0x%08x\nIrpSP->Flags: 0x%08x\n"
"Flags: 0x%08x\nFsContext: 0x%08x\nFsContext2: 0x%08x\n"
"RelatedFileObject: 0x%08x\n",
&pStack->FileObject->FileName,
pStack->Parameters.Create.Options,
pStack->Flags,
pStack->FileObject->Flags,
pStack->FileObject->FsContext,
pStack->FileObject->FsContext2,
(PVOID)pStack->FileObject->RelatedFileObject));

localStatus = SFsGetFullPath( pDeviceObject,
&pStack->FileObject->FileName,
&usFullPath,
TRUE);

DBGPRINT(("DeviceName: %wZ\nDosDevName: %wZ\nFullFileName: %wZ\n",
&pDevExt->TargetDeviceName,
&pDevExt->DosDeviceName,
&usFullPath));


if (usFullPath.Buffer)
{
ExFreePoolWT(usFullPath.Buffer);
usFullPath.Buffer = NULL;
}
}

KeInitializeEvent(&waitEvent, NotificationEvent, FALSE);
IoCopyCurrentIrpStackLocationToNext(pIrp);

IoSetCompletionRoutine( pIrp,
SFsStandartCompletionRoutine,
&waitEvent,
TRUE,
TRUE,
TRUE);

NtStatus = IoCallDriver(pDevExt->LowerDeviceObject, pIrp);

if (NtStatus == STATUS_PENDING)
{
KeWaitForSingleObject( &waitEvent,
Executive,
KernelMode,
FALSE,
NULL);

ASSERT(NtStatus == STATUS_SUCCESS);
}

DBGPRINT(("==AFTER OPEN==\nFlags: 0x%08x\nFsContext: 0x%08x\n"
"FsContext2: 0x%08x\nRelatedFileObject: 0x%08x\n",
pStack->FileObject->Flags,
pStack->FileObject->FsContext,
pStack->FileObject->FsContext2,
(PVOID)pStack->FileObject->RelatedFileObject));

if (bCheckFStat)
{
DBGPRINT(("Operation status: 0x%08x\n",
pIrp->IoStatus.Information));
}

NtStatus = pIrp->IoStatus.Status;
IoCompleteRequest(pIrp, IO_NO_INCREMENT);

DBGPRINT(("<--- SFsCreate [Status: 0x%x]\n\n", NtStatus));

return NtStatus;
}

Код:
//------------------------------------------------------------------------------------------
NTSTATUS
SFsClose(
PDEVICE_OBJECT pDeviceObject,
PIRP pIrp
)
{
NTSTATUS NtStatus/*, localStatus*/;
PIO_STACK_LOCATION pStack;
PSFSFILTER_EXTENSION pDevExt;
UNICODE_STRING usFileName;
KEVENT waitEvent;

PAGED_CODE();

DBGPRINT(("---> SFsClose\n"));

pDevExt = (PSFSFILTER_EXTENSION)pDeviceObject->DeviceExtension;
pStack = IoGetCurrentIrpStackLocation(pIrp);

DBGPRINT(("FileObject: 0x08%x\n", pStack->FileObject));

if (pStack->FileObject)
{
DBGPRINT(("IrpSP->Flags: 0x%08x\nFlags: 0x%08x\nFsContext: 0x%08x\n"
"FsContext2: 0x%08x\nRelatedFileObject: 0x%08x\n",
pStack->Flags,
pStack->FileObject->Flags,
pStack->FileObject->FsContext,
pStack->FileObject->FsContext2,
(PVOID)pStack->FileObject->RelatedFileObject));

DBGPRINT(("DeviceName: %wZ\nDosDevName: %wZ\nFileName: %wZ\n",
&pDevExt->TargetDeviceName,
&pDevExt->DosDeviceName,
&pStack->FileObject->FileName));

}

KeInitializeEvent(&waitEvent, NotificationEvent, FALSE);
IoCopyCurrentIrpStackLocationToNext(pIrp);

IoSetCompletionRoutine( pIrp,
SFsStandartCompletionRoutine,
&waitEvent,
TRUE,
TRUE,
TRUE);

NtStatus = IoCallDriver(pDevExt->LowerDeviceObject, pIrp);

if (NtStatus == STATUS_PENDING)
{
KeWaitForSingleObject( &waitEvent,
Executive,
KernelMode,
FALSE,
NULL);

ASSERT(NtStatus == STATUS_SUCCESS);
}

NtStatus = pIrp->IoStatus.Status;

IoCompleteRequest(pIrp, IO_NO_INCREMENT);

DBGPRINT(("<--- SFsClose [Status: 0x%x]\n\n", NtStatus));

return NtStatus;
}

Извиняюсь за форматирование. У меня в редакторе это выглядит несколько по другому.

По поводу потоков.
Потоки от файлов отличаются на практике тем, что после открытия их FsContext'ы (оба) остаются нулевыми. Но это весьма косвенный признак. Кроме того это видно уже только после открытия. Странно что не передается флаг FO_STREAM_FILE

Собственно прилагаю лог. В логе имеет смысл смотреть на подопытный файл RFC1035.TXT (по этому имени поиск делать). Видно что он открыт больше раз чем закрыт. На строки "File hashed. OpenFilesCount:" можно не обращать внимания

* VMCHN501_5.rar (215.78 Кб - загружено 631 раз.)
« Последнее редактирование: 29-03-2010 12:35 от resource » Записан
resource
Молодой специалист

ru
Offline Offline
Пол: Мужской

« Ответ #3 : 31-03-2010 12:42 » 

Проблему с неприходящим IRP_MJ_CLOSE решил, заблокировав все FastIO. Но тут имеет место такой факт, при завершении работы (конкретно речь о ребуте) винда, как я думал, должна закрыть все открытые файлы. В своей хэш-таблице я вижу около 1200 оставшихся записей именно на тот момент когда машина уже ребутится. Я как-то думал что это число должно стремиться к нулю. Это нормальная ситуация или такого быть не должно?
В мою хэш-таблицу записи попадают с двумя ключами: 1) Указатель на FileObject, который абсолютно точно является величиной постоянной и измениться никак не может. 2) значение равное (FsContext ^ FsContext2).
Зачем второй ключ, тем более такой извратный? Дело в том, что указатель FileObject для файла и для потока может быть одинаковым. А второй ключ решает проблему уникальности записи в хэш-таблице. Но вот могут ли измениться FsContext и FsContext2 для файла - это мне не известно, и в этом может быть вся проблема. Если они и могут измениться, то изменяются по всей видимости крайне редко, поскольку вход в систему выполняется примерно при таком же количестве открытых файлов (я сомтрю по количеству записей в хэш-таблице: чуть больше 1200), что и выход из нее.

Вопрос о том как определить, файл или поток будет открыт пришедшим IRP_MJ_CREATE, я так понимаю, решается анализом имени, и только так, потому что соответствующие флаги не устанавливаются. По крайней мере, в отношении файлов - не всегда, а для потоков вообще никогда.
« Последнее редактирование: 31-03-2010 14:01 от resource » Записан
Ochkarik
Модератор

ru
Offline Offline
Пол: Мужской

« Ответ #4 : 31-03-2010 22:51 » 

по поводу FastIO...ходят слухи что есть документ fastIO.pdf в
"Работа с файлами очень хорошо изложена в OSR WhitePapers, включенных в IFS Server 2003. В частности, там есть и FastIO.pdf."
жаль ссылка на файл битая.
возможно стоит посмотреть на FastIoUnlockAll?
http://www.programmersheaven.com/download/2424/11/ZipView.aspx
кстати неплохой примерчик наверное... и кстати самого руссиновича. правда старый....
прикладываю целиком архив к сообщению)

* NTFILSRC.ZIP.zip (140.85 Кб - загружено 643 раз.)
« Последнее редактирование: 31-03-2010 22:53 от Ochkarik » Записан

RTFM уже хоть раз наконец!  RTFM :[ ну или хотя бы STFW...
resource
Молодой специалист

ru
Offline Offline
Пол: Мужской

« Ответ #5 : 31-03-2010 22:55 » 

Да, ссылка подустала. Меня вот сейчас больше волнует вопрос об открытых файлах. Но чувствую, теория тут врядли доступна.
Записан
x64
Участник

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #6 : 09-05-2010 09:22 » 

...не получаю IRP_MJ_CLOSE для некоторых открытых файлов.

Это ошибка. Возможно потому, что не все файлы закрываются во время работы твоего фильтра, что вполне естественно. А возможно потому, что ты неправильно считаешь открытия. Судя по коду выше, ты делаешь это в pre-create, а нужно делать в post-create (т.е. в функции завершения) и только в случае успешного статуса, при чём следует помнить две вещи: код STATUS_REPARSE не означает успех, и STATUS_PENDING начиная с Windows Vista - аналогично.

...при получении IRP_MJ_CLOSE уже нельзя полагаться на FileObject->FileName, как собственно и на многое другое. Но мне-то надо знать как называется закрываемый файл.

С именами работать можно двумя способами:

1. Закэшировать их где-нибудь в post-create и извлекать всегда из кэша.
2. Запрашивать по мере необходимости через IRP_MJ_QUERY_INFORMATION с классом FileNameInformation.

...в IRP_MJ_CREATE поступает один и тот же указатель на FileObject, но с разными именами. Один раз для самого файла, а второй - для его потока.

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

FileObject для потока ... не содержит флага FO_STREAM_FILE

Этот флаг устанавливается драйвером файловой системы для личных нужд и в IRP_MJ_CREATE ты его не увидишь, т.к. клиент при открытии файла не может знать, что именно он открывает - файл или поток. Этот флаг может быть установлен у файловых объектов, используемых в других операциях, например, IRP_MJ_READ или IRP_MJ_CLOSE.

...как определить, что это именно поток, не глядя на имя...

В лоб не получится совершенно точно. А вообще зря, ведь для NTFS, например, файловые потоки в имени отделяются двоеточием, т.е. как минимум для NTFS уже можно тупо проанализировать имя. Кроме того, можно перечислить все файловые потоки родителя через IRP_MJ_QUERY_INFORMATION с классом FileStreamInformation и сравнить имена опять же.
Записан
x64
Участник

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #7 : 09-05-2010 09:30 » 

Проблему с неприходящим IRP_MJ_CLOSE решил, заблокировав все FastIO.

Fast I/O не имеет никакого отношения к IRP_MJ_CLOSE.

...при завершении работы (конкретно речь о ребуте) винда, как я думал, должна закрыть все открытые файлы. В своей хэш-таблице я вижу около 1200 оставшихся записей именно на тот момент когда машина уже ребутится. Я как-то думал что это число должно стремиться к нулю. Это нормальная ситуация...?

Да, вполне.

В мою хэш-таблицу записи попадают с двумя ключами:

Достаточно использовать поле FsContext.

А второй ключ решает проблему уникальности записи в хэш-таблице.

Поле FsContext в случае локальных файловых систем типа FAT и NTFS содержит уникальное значение для каждого файла. Для сетевых файловых систем всё несколько сложнее.

Но вот могут ли измениться FsContext и FsContext2 для файла...

FsContext - нет.

Вопрос о том как определить, файл или поток будет открыт пришедшим IRP_MJ_CREATE, я так понимаю, решается анализом имени, и только так, потому что соответствующие флаги не устанавливаются. По крайней мере, в отношении файлов - не всегда, а для потоков вообще никогда.

Выше уже ответил.
Записан
resource
Молодой специалист

ru
Offline Offline
Пол: Мужской

« Ответ #8 : 09-05-2010 09:59 » 

x64, вы как я вижу, решили пройтись по старым темам. Это конечно ради бога.

Но вот по поводу уникальности FsContext. Вы посмотрите его значения в пределах одного файла и его потоков. Интересное дело. Для файла то он один, но вот для его потоков он вполне себе тот же самый. И если складывать только по FsContext, то в итоге не отличишь, для кого пришел IRP_MJ_CLOSE, для файла или для его потока.
Записан
x64
Участник

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #9 : 09-05-2010 16:54 » 

Цитата
Для файла то он один, но вот для его потоков он вполне себе тот же самый.

У файла и у потока могут совпадать FsContext только в случае, если это объект-поток, созданный непосредственно файловой системой для более эффективной работы с кэшем. Такие объекты-потоки проходят мимо IRP_MJ_CREATE и опознать их можно лишь по флагу FO_STREAM_FILE. И пара цитат в догонку:

Цитата
To be more precise, each file object that represents the same STREAM will have the same FsContext value. Since FAT volumes do not support multiple stream per file, it is equivalent to representing the entire file.  On NTFS however, since you can have multiple streams per file, this only uniquely identifies all opens for the same stream.

(c) Neal Christiansen
Microsoft File System Filter Group

Цитата
Traditionally, a file system associated a specific file state with the file object using the FsContext field of the FILE_OBJECT. This is often referred to either as the File Control Block or the Stream Control Block. The latter name reflects the support of streams as a first-class entity within the file system. This is important because normally (e.g., in a filter driver) we associate two FILE_OBJECTs together if they have the same FsContext pointer value. However, if the underlying file system supports streams, then these two values really represent the same stream and not the same file.

(c) OSR
Windows Streams - An Introduction to File System Streams

Собственно, на практике это таки подтверждается. Оговоримся только, что работает это только для локальных файловых систем, с редиректорами же всё чуть сложнее и не так стабильно уже. Т.е. я хочу сказать, что у C:\file.txt и C:\file.txt:stream контексты будут всё же разные и идентификация особых проблем не составляет. От себя могу ещё добавить, что имена для потоков лучше всего собирать именно в pre-create, потому что в post-create они иногда заменяются файловой системой на имя файла-контейнера, другими словами C:\file.txt:stream в pre-create будет выглядеть как C:\file.txt в post-create и запросить оригинальное имя потом уже будет проблематично. Почему так сделано лично мне не очевидно, но стоит иметь в виду во всяком случае.
Записан
resource
Молодой специалист

ru
Offline Offline
Пол: Мужской

« Ответ #10 : 10-05-2010 14:18 » 

Практику игнорировать невозможно. Я в своем фильтре обрабатывал исключительно IRP_MJ_CREATE и _CLOSE. Не скажу, что FsContext для файла и его потоков всегда одинаков, но то что это довольно частая ситуация - факт.
Записан
GG_shara
Постоялец

ua
Offline Offline
Пол: Мужской
Лицо под маской


« Ответ #11 : 26-05-2010 18:07 » 

надеюся что это тот самый искомый FastIO.pdf

* FastIo.pdf (46.47 Кб - загружено 1610 раз.)
Записан

Не смеши меня с точки зрения аэродинамики шмель не может летать
Страниц: [1]   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines