Добрый день, встала задача необходимости закрытия определенного файла из ядра по имеющемуся FILE_OBJECT'y. Глянул на ZwCloseHandle он в общем то делает следующее: 1. Убивает handle 2. Отправляет CLEANUP 3. Посылает CLOSE 4. Убивает FILE_OBJECT повторяю все эти нехитрые манипуляции, кроме 1-ой (на счет корректного уничтожения FILE_OBJECT я не уверен). Отправляю CLEANUP и CLOSE так: Код (Text): /*привязанное событие*/ irp->UserIosb = &IoStatusBlock; irp->Tail.Overlay.Thread = PsGetCurrentThread(); irp->Tail.Overlay.OriginalFileObject = FileObject; irp->RequestorMode = KernelMode; irp->Flags = IRP_CLOSE_OPERATION | IRP_SYNCHRONOUS_API; ioStackLocation = IoGetNextIrpStackLocation(irp); ioStackLocation->MajorFunction = IRP_MJ_CLEANUP; ioStackLocation->DeviceObject = DeviceObject; ioStackLocation->FileObject = FileObject; IoSetCompletionRoutine(irp, ClearFileComplete, 0, TRUE, TRUE, TRUE); IoCallDriver(DeviceObject, irp); KeWaitForSingleObject(&event, Executive, KernelMode, TRUE, 0); ClearFileComplete Код (Text): status=(*Irp->UserIosb =Irp->IoStatus).Status; if( !NT_SUCCESS(Irp->IoStatus.Status) ) { DbgPrint((" CLOSE ERROR ON IRP: %x\n", Irp->IoStatus.Status )); } KeSetEvent(Irp->UserEvent, 0, FALSE); IoCompleteRequest(Irp, IO_NO_INCREMENT); return status; В итоге не всегда, и на некоторых прилоениях вылетает синька. Код (Text): ADDITIONAL_DEBUG_TEXT: Use '!findthebuild' command to search for the target build information. If the build information is available, run '!findthebuild -s ; .reload' to set symbol path and load symbols. MODULE_NAME: SDbgMsg FAULTING_MODULE: 804d7000 nt DEBUG_FLR_IMAGE_TIMESTAMP: 4db8111b READ_ADDRESS: unable to get nt!MmSpecialPoolStart unable to get nt!MmSpecialPoolEnd unable to get nt!MmPoolCodeStart unable to get nt!MmPoolCodeEnd fffffff4 FAULTING_IP: nt!ObQueryNameString+2f 805c49db 8a470c mov al,byte ptr [edi+0Ch] MM_INTERNAL_CODE: 0 DEFAULT_BUCKET_ID: DRIVER_FAULT BUGCHECK_STR: 0x50 LAST_CONTROL_TRANSFER: from 8052036a to 804f9f33 STACK_TEXT: WARNING: Stack unwind information not available. Following frames may be wrong. f78eaa34 8052036a 00000050 fffffff4 00000000 nt!KeBugCheckEx+0x1b f78eaa9c 80544578 00000000 fffffff4 00000000 nt!MmTrimAllSystemPagableMemory+0x6c7e f78eaad4 f78a7b2d f78eab1c 806e0030 f78e0000 nt!Kei386EoiHelper+0x26cc f78eabdc 80582488 00000000 e11627f8 00000808 SDbgMsg+0xb2d f78eac48 8058269b 830713e0 8336fe00 00000000 nt!NtWriteFile+0x5596 f78eac68 805c4a79 830713e0 8336fe00 e11f8008 nt!NtWriteFile+0x57a9 f78ead38 806203b1 830713e0 e11f8008 00000808 nt!ObQueryNameString+0xcd f78ead7c 8053876d 831945b0 00000000 8334a640 nt!LsaDeregisterLogonProcess+0x7d43 f78eadac 805cff64 831945b0 00000000 00000000 nt!ExQueueWorkItem+0x1a3 f78eaddc 805460de 8053867e 00000001 00000000 nt!PsRemoveCreateThreadNotifyRoutine+0x214 00000000 00000000 00000000 00000000 00000000 nt!KiDispatchInterrupt+0x72e STACK_COMMAND: kb FOLLOWUP_IP: SDbgMsg+b2d f78a7b2d 0fb6c0 movzx eax,al SYMBOL_STACK_INDEX: 3 SYMBOL_NAME: SDbgMsg+b2d FOLLOWUP_NAME: MachineOwner IMAGE_NAME: SDbgMsg.sys BUCKET_ID: WRONG_SYMBOLS Followup: MachineOwner Если файл не закрывать все работает отлично. Дамп пока предаставить не могу так как инет не позволяет. Итого вопрос: как корректно в ядре закрывать файлы по FILE_OBJECT
h0t Возможно вы имели ввиду ZwClose а не ZwCloseHandle? FILE_OBJECT будет уничтожен, если кол-во хендлов и кол-во ссылок станет равно нулю.
чужые обьекты, после MJ_CREATE в функции завершения хочу закрыть тот объект который создался а статус поменять на нет доступа
Если это нужно делать только в Post-Create, то нет ничего проще - IoCancelFileOpen(), только не забудь при этом в pIrp->IoStatus.Status установить код статуса, для которого NT_SUCCESS() вернёт FALSE, иначе отмена по факту выполнена не будет.
Разобрался, на самом деле как я и полагал CLOSE посылать не обязательно. А просто нужно с KfRaiseIrql играться)))) стормозил чуть-чуть)))) x64 спасибо, я так и думал что Вы поможете)
x64 Такой вопрос, при вызове IoCancelFileOpen убивает файловый объект, и это ладно, но менеджер кэша после этого все равно пытается работать с полями файлового объекта, что приводит к синьке в разнообразных функциях, например в CcFlushCache (я читаю файл до IoCancelFileOpen). Как заставить кэш отпустить объект до IoCancelFileOpen? К сожалению в MSDN написано
Эта функция шлёт IRP_MJ_CLEANUP в файловую систему, ничего более. Файловый объект удаляется I/O-менеджером чуть позже. Есть некоторые нюансы при чтении/записи файла из Create-обработчиков. Вкратце, есть 3 способа решить эту проблему (все действия выполнять перед вызовом IoCancelFileOpen()). Самое простое это позвать CcPurgeCacheSection(), если этот вызов вернёт TRUE, то кэш очищен и ничего более делать не требуется. Если нет, то можно попробовать позвать MmFlushImageSection(..., MmFlushForWrite) и затем MmForceSectionClosed(..., TRUE). Эти два метода требуют определённой синхронизации и внимательного чтения документации. Альтернативный вариант заключается в том, чтобы полностью отказаться от использования оригинального файлового объекта в операциях чтения/записи, а создавать новый вызовом IoCreateFile(). В этом случае будут проблемы с рекурсией, но они решаемые. Покажи полный исходник своего Post-Create обработчика и выложи дамп падения (желательно дамп памяти ядра). На самом деле, подобной ситуации быть не должно, если файл открывается впервые. Если же это повторное открытие, тогда да, данные в кэше останутся даже после уничтожения второго файлового объекта. Кстати, есть ещё один простой способ очистить кэши - тупо открыть этот же файл повторно с отключённым кэшированием, но этот вариант аналогичен использованию вспомогательного файлового объекта, что описано выше.
На счет IoCreateFile уже сам начал задумываться но видимо MmFlushImageSection мой вариант... При первом открытии все OK, проблемы начинаются как раз при повторных открытиях (кстати что забавно работает на NTFS на остальных ФС валится) Еще раз спасибо, буду пробовать... x64 кстати любопытно: IRP_MJ_CREATE вниз вместо IoCreateFile не возымеет должного эффекта?
Начал вызывать перед IoCancelFileOpen зову CcPurgeCacheSection она радостно возвращает TRUE. но вылет все равно... Код (Text): NTSTATUS HookDone( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context ) { PDEVICE_EXTENSION hookExt; PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation( Irp ); PFILE_OBJECT FileObject =currentIrpStack->FileObject; LARGE_INTEGER sizeCreateFile={0}; LARGE_INTEGER filePos={0}; UCHAR string[1024]; hookExt = DeviceObject->DeviceExtension; if( FilterOn && hookExt->Hooked && currentIrpStack->MajorFunction == IRP_MJ_CREATE ) { if (...){ ..... FDriverReadFile(hookObject->FileSystemDevice,FileObject,&filePos,buffer,readFileSize); CcPurgeCacheSection(FileObject->SectionObjectPointer, NULL,0,TRUE); IoCancelFileOpen(hookExt->FileSystemDevice,FileObject); Irp->IoStatus.Status = STATUS_ACCESS_DENIED; Irp->IoStatus.Information = 0; } } if( Irp->PendingReturned ) { IoMarkIrpPending( Irp ); } return Irp->IoStatus.Status; } и дамп http://www.sendspace.com/file/9f2n47
Покажи полный исходник FDriverReadFile(). И попробуй вариант с MmFlushImageSection() и MmForceSectionClosed(), только перед ними не забудь синхронизировать свои действия с менеджером кэша, захватив и тут же освободив соответствующий лок по адресу pFcb -> Header.PagingIoResource вызовами ExAcquireResourceExclusiveLite(..., TRUE) и ExReleaseResourceLite(), при этом pFcb = pFileObject -> FsContext. Это всё хаки, на самом деле, но должно работать по идее, а сделать по уму как я подскажу потом. Да, кстати, если на файле кто-то создаёт секцию (т.е. MMF-файл), то чистить кэш бесполезно, никакого эффекта не будет, it's by NT design.
Код (Text): ULONG FDriverReadFile( PDEVICE_OBJECT DeviceObject, PFILE_OBJECT FileObject, PLARGE_INTEGER pReadOffset, PVOID FileReadBuffer, ULONG FileReadBufferLength ) { PIRP irp; KEVENT event; IO_STATUS_BLOCK IoStatusBlock; PIO_STACK_LOCATION ioStackLocation; KeInitializeEvent(&event, SynchronizationEvent, FALSE); irp = IoAllocateIrp(DeviceObject->StackSize, FALSE); if(!irp) return FALSE; irp->AssociatedIrp.SystemBuffer = FileReadBuffer; irp->UserEvent = &event; irp->UserIosb = &IoStatusBlock; irp->Tail.Overlay.Thread = PsGetCurrentThread(); irp->Tail.Overlay.OriginalFileObject = FileObject; irp->RequestorMode = KernelMode; irp->Flags = DO_BUFFERED_IO; irp->UserBuffer = FileReadBuffer; ioStackLocation = IoGetNextIrpStackLocation(irp); ioStackLocation->MajorFunction = IRP_MJ_READ; ioStackLocation->DeviceObject = DeviceObject; ioStackLocation->FileObject = FileObject; ioStackLocation->Parameters.Read.Length = FileReadBufferLength; if (pReadOffset) ioStackLocation->Parameters.Read.ByteOffset = *pReadOffset; IoSetCompletionRoutine(irp, ReadFileComplete, 0, TRUE, TRUE, TRUE); IoCallDriver(DeviceObject, irp); KeWaitForSingleObject(&event, Executive, KernelMode, TRUE, 0); IoFreeIrp(irp); return IoStatusBlock.Information; } NTSTATUS ReadFileComplete( PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID Context ) { *Irp->UserIosb = Irp->IoStatus; if( !NT_SUCCESS(Irp->IoStatus.Status) ) { DbgPrint((" READ ERROR ON IRP: %x\n", Irp->IoStatus.Status )); } KeSetEvent(Irp->UserEvent, 0, FALSE); return STATUS_MORE_PROCESSING_REQUIRED; } как то так... MMF меня не волнуют к счастью)
Код не самый плохой, но так делать не принято: - Вместо IoAllocateIrp() следует использовать IoBuildSynchronousFsdRequest(). - При использовании IoBuildSynchronousFsdRequest() вызов IoFreeIrp() не нужен. - Событие следует инициализировать как NotificationEvent, а не SynchronizationEvent. И самое главное, что я забыл написать выше: если у тебя драйвер только под Windows XP и выше, тогда ты можешь воспользоваться IoCreateFileSpecifyDeviceObjectHint() с указанием нижележащего девайса, далее по хендлу получить адрес файлового объекта, который уже и использовать для Read/Write-подзапросов. Это легко и непринуждённо решит твою проблему с кэшем, но для Windows 2000 работать не будет. Тебе виднее.