Вопрос о закрытии файла

Тема в разделе "WASM.NT.KERNEL", создана пользователем h0t, 10 авг 2011.

  1. h0t

    h0t Member

    Публикаций:
    0
    Регистрация:
    3 апр 2011
    Сообщения:
    735
    Добрый день, встала задача необходимости закрытия определенного файла из ядра по имеющемуся FILE_OBJECT'y.
    Глянул на ZwCloseHandle он в общем то делает следующее:
    1. Убивает handle
    2. Отправляет CLEANUP
    3. Посылает CLOSE
    4. Убивает FILE_OBJECT

    повторяю все эти нехитрые манипуляции, кроме 1-ой (на счет корректного уничтожения FILE_OBJECT я не уверен).
    Отправляю CLEANUP и CLOSE так:
    Код (Text):
    1. /*привязанное событие*/
    2.     irp->UserIosb = &IoStatusBlock;            
    3.     irp->Tail.Overlay.Thread = PsGetCurrentThread();
    4.     irp->Tail.Overlay.OriginalFileObject = FileObject;
    5.     irp->RequestorMode = KernelMode;               
    6.     irp->Flags = IRP_CLOSE_OPERATION | IRP_SYNCHRONOUS_API;
    7.    
    8.    
    9.     ioStackLocation = IoGetNextIrpStackLocation(irp);
    10.    
    11.     ioStackLocation->MajorFunction = IRP_MJ_CLEANUP;
    12.     ioStackLocation->DeviceObject = DeviceObject;              
    13.     ioStackLocation->FileObject = FileObject;
    14.  
    15.     IoSetCompletionRoutine(irp, ClearFileComplete, 0, TRUE, TRUE, TRUE);
    16.     IoCallDriver(DeviceObject, irp);
    17.     KeWaitForSingleObject(&event, Executive, KernelMode, TRUE, 0);
    ClearFileComplete
    Код (Text):
    1.     status=(*Irp->UserIosb =Irp->IoStatus).Status;
    2.      
    3.     if( !NT_SUCCESS(Irp->IoStatus.Status) ) {
    4.  
    5.         DbgPrint(("   CLOSE ERROR ON IRP: %x\n", Irp->IoStatus.Status ));
    6.     }
    7.    
    8.     KeSetEvent(Irp->UserEvent, 0, FALSE);
    9.    
    10.     IoCompleteRequest(Irp, IO_NO_INCREMENT);
    11.     return status;
    В итоге не всегда, и на некоторых прилоениях вылетает синька.

    Код (Text):
    1. ADDITIONAL_DEBUG_TEXT:  
    2. Use '!findthebuild' command to search for the target build information.
    3. If the build information is available, run '!findthebuild -s ; .reload' to set symbol path and load symbols.
    4.  
    5. MODULE_NAME: SDbgMsg
    6.  
    7. FAULTING_MODULE: 804d7000 nt
    8.  
    9. DEBUG_FLR_IMAGE_TIMESTAMP:  4db8111b
    10.  
    11. READ_ADDRESS: unable to get nt!MmSpecialPoolStart
    12. unable to get nt!MmSpecialPoolEnd
    13. unable to get nt!MmPoolCodeStart
    14. unable to get nt!MmPoolCodeEnd
    15.  fffffff4
    16.  
    17. FAULTING_IP:
    18. nt!ObQueryNameString+2f
    19. 805c49db 8a470c          mov     al,byte ptr [edi+0Ch]
    20.  
    21. MM_INTERNAL_CODE:  0
    22.  
    23. DEFAULT_BUCKET_ID:  DRIVER_FAULT
    24.  
    25. BUGCHECK_STR:  0x50
    26.  
    27. LAST_CONTROL_TRANSFER:  from 8052036a to 804f9f33
    28.  
    29. STACK_TEXT:  
    30. WARNING: Stack unwind information not available. Following frames may be wrong.
    31. f78eaa34 8052036a 00000050 fffffff4 00000000 nt!KeBugCheckEx+0x1b
    32. f78eaa9c 80544578 00000000 fffffff4 00000000 nt!MmTrimAllSystemPagableMemory+0x6c7e
    33. f78eaad4 f78a7b2d f78eab1c 806e0030 f78e0000 nt!Kei386EoiHelper+0x26cc
    34. f78eabdc 80582488 00000000 e11627f8 00000808 SDbgMsg+0xb2d
    35. f78eac48 8058269b 830713e0 8336fe00 00000000 nt!NtWriteFile+0x5596
    36. f78eac68 805c4a79 830713e0 8336fe00 e11f8008 nt!NtWriteFile+0x57a9
    37. f78ead38 806203b1 830713e0 e11f8008 00000808 nt!ObQueryNameString+0xcd
    38. f78ead7c 8053876d 831945b0 00000000 8334a640 nt!LsaDeregisterLogonProcess+0x7d43
    39. f78eadac 805cff64 831945b0 00000000 00000000 nt!ExQueueWorkItem+0x1a3
    40. f78eaddc 805460de 8053867e 00000001 00000000 nt!PsRemoveCreateThreadNotifyRoutine+0x214
    41. 00000000 00000000 00000000 00000000 00000000 nt!KiDispatchInterrupt+0x72e
    42.  
    43.  
    44. STACK_COMMAND:  kb
    45.  
    46. FOLLOWUP_IP:
    47. SDbgMsg+b2d
    48. f78a7b2d 0fb6c0          movzx   eax,al
    49.  
    50. SYMBOL_STACK_INDEX:  3
    51.  
    52. SYMBOL_NAME:  SDbgMsg+b2d
    53.  
    54. FOLLOWUP_NAME:  MachineOwner
    55.  
    56. IMAGE_NAME:  SDbgMsg.sys
    57.  
    58. BUCKET_ID:  WRONG_SYMBOLS
    59.  
    60. Followup: MachineOwner
    Если файл не закрывать все работает отлично.
    Дамп пока предаставить не могу так как инет не позволяет.

    Итого вопрос: как корректно в ядре закрывать файлы по FILE_OBJECT
     
  2. qwe8013

    qwe8013 New Member

    Публикаций:
    0
    Регистрация:
    28 май 2009
    Сообщения:
    198
    h0t
    Возможно вы имели ввиду ZwClose а не ZwCloseHandle?
    FILE_OBJECT будет уничтожен, если кол-во хендлов и кол-во ссылок станет равно нулю.
     
  3. x64

    x64 New Member

    Публикаций:
    0
    Регистрация:
    29 июл 2008
    Сообщения:
    1.370
    Адрес:
    Россия
    Какую задачу решаешь? Чьи файловые обьекты и с какой целью хочешь закрыть?
     
  4. h0t

    h0t Member

    Публикаций:
    0
    Регистрация:
    3 апр 2011
    Сообщения:
    735
    да оисался, я тоже так думал, но вот видимо MJ_CLOSE все таки не повод очищать, хотя я не проверял
     
  5. h0t

    h0t Member

    Публикаций:
    0
    Регистрация:
    3 апр 2011
    Сообщения:
    735
    чужые обьекты, после MJ_CREATE в функции завершения хочу закрыть тот объект который создался а статус поменять на нет доступа
     
  6. x64

    x64 New Member

    Публикаций:
    0
    Регистрация:
    29 июл 2008
    Сообщения:
    1.370
    Адрес:
    Россия
    Если это нужно делать только в Post-Create, то нет ничего проще - IoCancelFileOpen(), только не забудь при этом в pIrp->IoStatus.Status установить код статуса, для которого NT_SUCCESS() вернёт FALSE, иначе отмена по факту выполнена не будет.
     
  7. h0t

    h0t Member

    Публикаций:
    0
    Регистрация:
    3 апр 2011
    Сообщения:
    735
    спасибо, то что надо!
    p.s. все таки любопытно почему не всегда пашет мой способ, идей нет?
     
  8. h0t

    h0t Member

    Публикаций:
    0
    Регистрация:
    3 апр 2011
    Сообщения:
    735
    Разобрался, на самом деле как я и полагал CLOSE посылать не обязательно. А просто нужно с KfRaiseIrql играться)))) стормозил чуть-чуть))))

    x64 спасибо, я так и думал что Вы поможете)
     
  9. h0t

    h0t Member

    Публикаций:
    0
    Регистрация:
    3 апр 2011
    Сообщения:
    735
    x64
    Такой вопрос, при вызове IoCancelFileOpen убивает файловый объект, и это ладно, но менеджер кэша после этого все равно пытается работать с полями файлового объекта, что приводит к синьке в разнообразных функциях, например в CcFlushCache (я читаю файл до IoCancelFileOpen).

    Как заставить кэш отпустить объект до IoCancelFileOpen?

    К сожалению в MSDN написано
     
  10. x64

    x64 New Member

    Публикаций:
    0
    Регистрация:
    29 июл 2008
    Сообщения:
    1.370
    Адрес:
    Россия
    Эта функция шлёт IRP_MJ_CLEANUP в файловую систему, ничего более. Файловый объект удаляется I/O-менеджером чуть позже.

    Есть некоторые нюансы при чтении/записи файла из Create-обработчиков. Вкратце, есть 3 способа решить эту проблему (все действия выполнять перед вызовом IoCancelFileOpen()). Самое простое это позвать CcPurgeCacheSection(), если этот вызов вернёт TRUE, то кэш очищен и ничего более делать не требуется. Если нет, то можно попробовать позвать MmFlushImageSection(..., MmFlushForWrite) и затем MmForceSectionClosed(..., TRUE). Эти два метода требуют определённой синхронизации и внимательного чтения документации. Альтернативный вариант заключается в том, чтобы полностью отказаться от использования оригинального файлового объекта в операциях чтения/записи, а создавать новый вызовом IoCreateFile(). В этом случае будут проблемы с рекурсией, но они решаемые.

    Покажи полный исходник своего Post-Create обработчика и выложи дамп падения (желательно дамп памяти ядра). На самом деле, подобной ситуации быть не должно, если файл открывается впервые. Если же это повторное открытие, тогда да, данные в кэше останутся даже после уничтожения второго файлового объекта. Кстати, есть ещё один простой способ очистить кэши - тупо открыть этот же файл повторно с отключённым кэшированием, но этот вариант аналогичен использованию вспомогательного файлового объекта, что описано выше.
     
  11. h0t

    h0t Member

    Публикаций:
    0
    Регистрация:
    3 апр 2011
    Сообщения:
    735
    На счет IoCreateFile уже сам начал задумываться но видимо MmFlushImageSection мой вариант...

    При первом открытии все OK, проблемы начинаются как раз при повторных открытиях (кстати что забавно работает на NTFS на остальных ФС валится)

    Еще раз спасибо, буду пробовать...

    x64 кстати любопытно: IRP_MJ_CREATE вниз вместо IoCreateFile не возымеет должного эффекта?
     
  12. h0t

    h0t Member

    Публикаций:
    0
    Регистрация:
    3 апр 2011
    Сообщения:
    735
    Начал вызывать перед IoCancelFileOpen зову CcPurgeCacheSection она радостно возвращает TRUE. но вылет все равно...

    Код (Text):
    1. NTSTATUS HookDone(
    2.     IN PDEVICE_OBJECT DeviceObject,
    3.     IN PIRP Irp,
    4.     IN PVOID Context
    5.     )
    6. {
    7.     PDEVICE_EXTENSION hookExt;
    8.     PIO_STACK_LOCATION   currentIrpStack  = IoGetCurrentIrpStackLocation( Irp );
    9.     PFILE_OBJECT FileObject =currentIrpStack->FileObject;
    10.    
    11.     LARGE_INTEGER sizeCreateFile={0};
    12.     LARGE_INTEGER filePos={0};
    13.     UCHAR string[1024];
    14.     hookExt = DeviceObject->DeviceExtension;   
    15.    
    16.  
    17.     if( FilterOn && hookExt->Hooked && currentIrpStack->MajorFunction == IRP_MJ_CREATE ) {
    18.  
    19.         if (...){          
    20.             .....
    21.        
    22.            
    23.             FDriverReadFile(hookObject->FileSystemDevice,FileObject,&filePos,buffer,readFileSize);
    24.             CcPurgeCacheSection(FileObject->SectionObjectPointer, NULL,0,TRUE);
    25.             IoCancelFileOpen(hookExt->FileSystemDevice,FileObject);                
    26.             Irp->IoStatus.Status = STATUS_ACCESS_DENIED;
    27.             Irp->IoStatus.Information = 0;
    28.         }
    29.     }
    30.      
    31.     if( Irp->PendingReturned ) {
    32.  
    33.         IoMarkIrpPending( Irp );
    34.     }
    35.     return Irp->IoStatus.Status;
    36. }
    и дамп http://www.sendspace.com/file/9f2n47
     
  13. x64

    x64 New Member

    Публикаций:
    0
    Регистрация:
    29 июл 2008
    Сообщения:
    1.370
    Адрес:
    Россия
    А где ты, умник, файловый объект для этой операции возьмёшь?
     
  14. h0t

    h0t Member

    Публикаций:
    0
    Регистрация:
    3 апр 2011
    Сообщения:
    735
    Мда действительно ересь написал
     
  15. x64

    x64 New Member

    Публикаций:
    0
    Регистрация:
    29 июл 2008
    Сообщения:
    1.370
    Адрес:
    Россия
    Покажи полный исходник FDriverReadFile(). И попробуй вариант с MmFlushImageSection() и MmForceSectionClosed(), только перед ними не забудь синхронизировать свои действия с менеджером кэша, захватив и тут же освободив соответствующий лок по адресу pFcb -> Header.PagingIoResource вызовами ExAcquireResourceExclusiveLite(..., TRUE) и ExReleaseResourceLite(), при этом pFcb = pFileObject -> FsContext. Это всё хаки, на самом деле, но должно работать по идее, а сделать по уму как я подскажу потом. Да, кстати, если на файле кто-то создаёт секцию (т.е. MMF-файл), то чистить кэш бесполезно, никакого эффекта не будет, it's by NT design.
     
  16. h0t

    h0t Member

    Публикаций:
    0
    Регистрация:
    3 апр 2011
    Сообщения:
    735
    Код (Text):
    1. ULONG  FDriverReadFile(
    2.     PDEVICE_OBJECT DeviceObject,
    3.     PFILE_OBJECT FileObject,
    4.     PLARGE_INTEGER pReadOffset,
    5.     PVOID FileReadBuffer,
    6.     ULONG FileReadBufferLength
    7.     )
    8. {
    9.     PIRP irp;
    10.     KEVENT event;
    11.     IO_STATUS_BLOCK IoStatusBlock;
    12.     PIO_STACK_LOCATION ioStackLocation;    
    13.    
    14.     KeInitializeEvent(&event, SynchronizationEvent, FALSE);
    15.  
    16.    
    17.     irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
    18.     if(!irp)  return FALSE;
    19.    
    20.  
    21.  
    22.     irp->AssociatedIrp.SystemBuffer = FileReadBuffer;
    23.     irp->UserEvent = &event;                       
    24.     irp->UserIosb = &IoStatusBlock;            
    25.     irp->Tail.Overlay.Thread = PsGetCurrentThread();
    26.     irp->Tail.Overlay.OriginalFileObject = FileObject;
    27.     irp->RequestorMode = KernelMode;                   
    28.     irp->Flags = DO_BUFFERED_IO;   
    29.     irp->UserBuffer = FileReadBuffer;
    30.    
    31.    
    32.    
    33.    
    34.    
    35.     ioStackLocation = IoGetNextIrpStackLocation(irp);
    36.    
    37.     ioStackLocation->MajorFunction = IRP_MJ_READ;
    38.    
    39.     ioStackLocation->DeviceObject = DeviceObject;              
    40.     ioStackLocation->FileObject = FileObject;
    41.     ioStackLocation->Parameters.Read.Length = FileReadBufferLength;
    42.     if (pReadOffset) ioStackLocation->Parameters.Read.ByteOffset = *pReadOffset;
    43.    
    44.     IoSetCompletionRoutine(irp,  ReadFileComplete, 0, TRUE, TRUE, TRUE);
    45.  
    46.  
    47.     IoCallDriver(DeviceObject, irp);
    48.  
    49.  
    50.     KeWaitForSingleObject(&event, Executive, KernelMode, TRUE, 0);
    51.    
    52.  
    53.     IoFreeIrp(irp);
    54.    
    55.     return IoStatusBlock.Information;
    56. }
    57.  
    58. NTSTATUS  ReadFileComplete(
    59.     PDEVICE_OBJECT DeviceObject,
    60.     PIRP Irp,
    61.     PVOID Context
    62.     )
    63. {
    64.  
    65.     *Irp->UserIosb = Irp->IoStatus;
    66.     if( !NT_SUCCESS(Irp->IoStatus.Status) ) {
    67.  
    68.         DbgPrint((" READ  ERROR ON IRP: %x\n", Irp->IoStatus.Status ));
    69.     }
    70.  
    71.     KeSetEvent(Irp->UserEvent, 0, FALSE);
    72.    
    73.  
    74.    
    75.     return STATUS_MORE_PROCESSING_REQUIRED;
    76. }
    как то так...

    MMF меня не волнуют к счастью)
     
  17. x64

    x64 New Member

    Публикаций:
    0
    Регистрация:
    29 июл 2008
    Сообщения:
    1.370
    Адрес:
    Россия
    Код не самый плохой, но так делать не принято:

    - Вместо IoAllocateIrp() следует использовать IoBuildSynchronousFsdRequest().
    - При использовании IoBuildSynchronousFsdRequest() вызов IoFreeIrp() не нужен.
    - Событие следует инициализировать как NotificationEvent, а не SynchronizationEvent.

    И самое главное, что я забыл написать выше: если у тебя драйвер только под Windows XP и выше, тогда ты можешь воспользоваться IoCreateFileSpecifyDeviceObjectHint() с указанием нижележащего девайса, далее по хендлу получить адрес файлового объекта, который уже и использовать для Read/Write-подзапросов. Это легко и непринуждённо решит твою проблему с кэшем, но для Windows 2000 работать не будет.

    Тебе виднее.
     
  18. shchetinin

    shchetinin Member

    Публикаций:
    0
    Регистрация:
    27 май 2011
    Сообщения:
    715
    Это с какой радости не надо вызвать IoFreeIrp?
     
  19. x64

    x64 New Member

    Публикаций:
    0
    Регистрация:
    29 июл 2008
    Сообщения:
    1.370
    Адрес:
    Россия
    Пожалуйста, почитай документацию.
     
  20. shchetinin

    shchetinin Member

    Публикаций:
    0
    Регистрация:
    27 май 2011
    Сообщения:
    715
    x64
    Согласен, перепутал с IoBuildAsynchronousFsdRequest. ((