Windows System Software -- Consulting, Training, Development -- Unique Expertise, Guaranteed Results

Home NTDEV
Before Posting...
Please check out the Community Guidelines in the Announcements and Administration Category.

More Info on Driver Writing and Debugging


The free OSR Learning Library has more than 50 articles on a wide variety of topics about writing and debugging device drivers and Minifilters. From introductory level to advanced. All the articles have been recently reviewed and updated, and are written using the clear and definitive style you've come to expect from OSR over the years.


Check out The OSR Learning Library at: https://www.osr.com/osr-learning-library/


Filtering disk IO

MikaeMikae Member Posts: 371
Hello list.

I have a mini filter driver that monitors several events in kernel and also wants to know about I/O performed on disk drives. The driver gets notifications if a disk is opened via \\.\PhysicalDrive%d and doesn't get them if a disk is opened via device interface.

It looks that the problem is related to 'direct open' but I am not really sure. So, how it could be solved assuming that I want to get notifications about _all_ IOs performed on a disk regardless of how it was opened? Is disk upper filter the only solution in this case?

Thanks.

Comments

  • MikaeMikae Member Posts: 371
    Hm, should I crosspost to NTFSD to get more attention?
  • Scott_Noone_(OSR)Scott_Noone_(OSR) Administrator Posts: 3,362
    The symbolic link and device interface GUID paths should be equivalent. Did
    you dump the resulting handle from each open (!handle) and see where each
    points to?

    There can be lots of things in play here. The first thing to note is that
    there are (effectively) four types of mountable device objects in Windows:

    1. Disk
    2. Volume
    3. CD-ROM
    4. Tape

    If you attempt to open any of these device object types by name and *request
    data access*, the I/O Manager triggers mount processing. If no file system
    claims the underlying media as being their own then the I/O Manager's RAW
    file system claims the device. I/O requests against the resulting file
    object are then targeted by the RAW file system.

    This can make for some ugly combinations. For example, you may have a volume
    that contains a partition from an existing disk. The volume may have NTFS
    mounted on it, but if you open the underlying disk directly you get a RAW
    file system instance (the volume is formatted with NTFS, not the disk). A
    file system filter would have separate instances for each of these (one for
    NTFS and one for RAW).

    In the cases where the caller doesn't ask for data access, the open goes to
    the top of the device stack for the specified device (disk/volume/cd/tape).
    No file systems are involved, which shouldn't matter anyway as there is no
    ability to perform data access.

    Hence my suggestion to dump the resulting handle and see where the
    underlying file object is pointing.

    Of course, all of the above only applies to opens from user mode. A kernel
    mode component can do whatever they want, so they could send I/Os directly
    to the disk and bypass the file system (or the disk driver, for that
    matter). For example, the kernel mode portion of the shadow copy service
    writes directly to the COW area on the disk without using the file system.
    The only way to see these writes would be from a disk filter.

    -scott
    OSR
    @OSRDrivers

    wrote in message news:[email protected]

    Hello list.

    I have a mini filter driver that monitors several events in kernel and also
    wants to know about I/O performed on disk drives. The driver gets
    notifications if a disk is opened via \\.\PhysicalDrive%d and doesn't get
    them if a disk is opened via device interface.

    It looks that the problem is related to 'direct open' but I am not really
    sure. So, how it could be solved assuming that I want to get notifications
    about _all_ IOs performed on a disk regardless of how it was opened? Is disk
    upper filter the only solution in this case?

    Thanks.

    -scott
    OSR

  • Maxim_S._ShatskihMaxim_S._Shatskih Member Posts: 10,396
    > matter). For example, the kernel mode portion of the shadow copy service
    > writes directly to the COW area on the disk without using the file system.
    > The only way to see these writes would be from a disk filter.

    Are they using the DASD path in the FSD? or bypassing FSD totally?

    I really, really expect that the first is the answer :-)

    --
    Maxim S. Shatskih
    Microsoft MVP on File System And Storage
    [email protected]
    http://www.storagecraft.com
  • MikaeMikae Member Posts: 371
    Handle for:

    h = CreateFileA("\\\\.\\PhysicalDrive0", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, 0, 0);

    looks like this:

    kd> !handle a4 f

    PROCESS 83cf3440 SessionId: 1 Cid: 0fb4 Peb: 7ffd9000 ParentCid: 0298
    DirBase: 1ea284e0 ObjectTable: 83e18bc8 HandleCount: 41.
    Image: ScratchPad.exe

    Handle table at 83e18bc8 with 41 entries in use

    00a4: Object: 85043400 GrantedAccess: 0012019f Entry: 83e49148
    Object: 85043400 Type: (83a2ab90) File
    ObjectHeader: 850433e8 (new version)
    HandleCount: 1 PointerCount: 1


    kd> !fileobj 85043400



    Device Object: 0x849e97b8 \Driver\Disk
    Vpb: 0x849e9730
    Event signalled
    Access: Read Write SharedRead SharedWrite SharedDelete

    Flags: 0x44000a
    Synchronous IO
    No Intermediate Buffering
    Handle Created
    Volume Open

    FsContext: 0x83acf930 FsContext2: 0x00000000
    CurrentByteOffset: 0

    kd> !devstack 0x849e97b8
    !DevObj !DrvObj !DevExt ObjectName
    849e93f8 \Driver\partmgr 849e94b0
    > 849e97b8 \Driver\Disk 849e9870 DR0
    849e9ef0 \Driver\storflt 849e8aa0
    848cf020 \Driver\ACPI 83a4a770
    848cc908 \Driver\atapi 848cc9c0 IdeDeviceP0T0L0-0
    !DevNode 848d7950 :
    DeviceInst is "IDE\DiskVirtual_HD______________________________1.1.0___\5&35dc7040&0&0.0.0"
    ServiceName is "disk"


    When nt!ntWriteFile calls IoGetRelatedDeviceObject the function switches to another stack resulting in:


    kd> !devstack @eax
    !DevObj !DrvObj !DevExt ObjectName
    > 8508a980 \FileSystem\FltMgr 8508aa38
    83acf878 \FileSystem\RAW 83acf930


    It looks different when a disk is opened by interface symlink:

    h = CreateFileW(pDetailData->DevicePath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_FLAG_NO_BUFFERING, 0);

    //I tried with and without FILE_FLAG_NO_BUFFERING

    kd> !handle dc

    PROCESS 83cf3440 SessionId: 1 Cid: 0fb4 Peb: 7ffd9000 ParentCid: 0298
    DirBase: 1ea284e0 ObjectTable: 83e18bc8 HandleCount: 55.
    Image: ScratchPad.exe

    Handle table at 83e18bc8 with 55 entries in use

    00dc: Object: 85040b48 GrantedAccess: 0012019f Entry: 83e491b8
    Object: 85040b48 Type: (83a2ab90) File
    ObjectHeader: 85040b30 (new version)
    HandleCount: 1 PointerCount: 1


    kd> !fileobj 85040b48



    Device Object: 0x848cc908 \Driver\atapi
    Vpb is NULL
    Event signalled

    Flags: 0x4000a
    Synchronous IO
    No Intermediate Buffering
    Handle Created

    CurrentByteOffset: 0

    kd> !devstack 0x848cc908
    !DevObj !DrvObj !DevExt ObjectName
    849e93f8 \Driver\partmgr 849e94b0
    849e97b8 \Driver\Disk 849e9870 DR0
    849e9ef0 \Driver\storflt 849e8aa0
    848cf020 \Driver\ACPI 83a4a770
    > 848cc908 \Driver\atapi 848cc9c0 IdeDeviceP0T0L0-0
    !DevNode 848d7950 :
    DeviceInst is "IDE\DiskVirtual_HD______________________________1.1.0___\5&35dc7040&0&0.0.0"
    ServiceName is "disk"



    So VPB is NULL and IoGetRelatedDeviceObject doesnt switch stacks:


    kd> !devstack @eax
    !DevObj !DrvObj !DevExt ObjectName
    > 849e93f8 \Driver\partmgr 849e94b0
    849e97b8 \Driver\Disk 849e9870 DR0
    849e9ef0 \Driver\storflt 849e8aa0
    848cf020 \Driver\ACPI 83a4a770
    848cc908 \Driver\atapi 848cc9c0 IdeDeviceP0T0L0-0
    !DevNode 848d7950 :
    DeviceInst is "IDE\DiskVirtual_HD______________________________1.1.0___\5&35dc7040&0&0.0.0"
    ServiceName is "disk"

    Does it mean that a user mode application might open a disk bypassing FltMgr? Why opening by interface differs from open by legacy symlink?
  • Scott_Noone_(OSR)Scott_Noone_(OSR) Administrator Posts: 3,362
    The FSD is somewhat involved in that files are used for the storage.
    However, actual I/O to the files goes directly down the volume stack and
    into the disk stack.

    -scott
    OSR
    @OSRDrivers

    "Maxim S. Shatskih" wrote in message news:[email protected]

    > matter). For example, the kernel mode portion of the shadow copy service
    > writes directly to the COW area on the disk without using the file system.
    > The only way to see these writes would be from a disk filter.

    Are they using the DASD path in the FSD? or bypassing FSD totally?

    I really, really expect that the first is the answer :-)

    --
    Maxim S. Shatskih
    Microsoft MVP on File System And Storage
    [email protected]
    http://www.storagecraft.com

    -scott
    OSR

  • Scott_Noone_(OSR)Scott_Noone_(OSR) Administrator Posts: 3,362
    Thanks for the debugger output, that certainly clears things up.

    This is really cute and I must now admit that I clearly never fully thought
    through this particular case. You are absolutely correct, the device
    interface takes a different path than the symbolic link name. The reason why
    is in the output you provided...

    In the symbolic link case, the file object is an open instance of a Disk
    device object:

    kd> !fileobj 85043400
    Device Object: 0x849e97b8 \Driver\Disk
    Vpb: 0x849e9730

    This is due to the fact that Disk calls IoCreateSymbolicLink and points this
    link to its own FDO. Note the presence of the VPB, hence the I/O requests
    are going to traverse to the file system stack.

    However, in the case of the device interface the symbolic link that you
    ultimately open points to the disk's PDO (created by ATAPI):

    kd> !fileobj 85040b48
    Device Object: 0x848cc908 \Driver\atapi

    This must not have been created with a device type of FILE_DEVICE_DISK
    because it doesn't have a VPB. If there's no VPB, the I/O request goes to
    the top of the device stack (which would be to PartMgr in this case).

    (As an aside: you don't get this problem in the volume stack because the
    symbolic link name (HarddiskVolumeX) and the device interface both point to
    the PDO created by volmgr, which has a VPB.)

    So, you get two I/O paths to the disk from user mode. This makes for some
    fun trivia points such as one path (PhysicalDriveX) implements share access
    and the other (device interface) does not. Therefore you can open
    PhysicalDriveX exclusively, but that doesn't do you any good if someone else
    opens via device interface.


    Neat stuff and it highlights the problems with having multiple names in the
    device stack. Bottom line: get yourself a disk filter if you really care
    about this.

    -scott
    OSR
    @OSRDrivers

    wrote in message news:[email protected]

    Handle for:

    h = CreateFileA("\\\\.\\PhysicalDrive0", GENERIC_READ | GENERIC_WRITE,
    FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING,
    0, 0);

    looks like this:

    kd> !handle a4 f

    PROCESS 83cf3440 SessionId: 1 Cid: 0fb4 Peb: 7ffd9000 ParentCid: 0298
    DirBase: 1ea284e0 ObjectTable: 83e18bc8 HandleCount: 41.
    Image: ScratchPad.exe

    Handle table at 83e18bc8 with 41 entries in use

    00a4: Object: 85043400 GrantedAccess: 0012019f Entry: 83e49148
    Object: 85043400 Type: (83a2ab90) File
    ObjectHeader: 850433e8 (new version)
    HandleCount: 1 PointerCount: 1


    kd> !fileobj 85043400



    Device Object: 0x849e97b8 \Driver\Disk
    Vpb: 0x849e9730
    Event signalled
    Access: Read Write SharedRead SharedWrite SharedDelete

    Flags: 0x44000a
    Synchronous IO
    No Intermediate Buffering
    Handle Created
    Volume Open

    FsContext: 0x83acf930 FsContext2: 0x00000000
    CurrentByteOffset: 0

    kd> !devstack 0x849e97b8
    !DevObj !DrvObj !DevExt ObjectName
    849e93f8 \Driver\partmgr 849e94b0
    > 849e97b8 \Driver\Disk 849e9870 DR0
    849e9ef0 \Driver\storflt 849e8aa0
    848cf020 \Driver\ACPI 83a4a770
    848cc908 \Driver\atapi 848cc9c0 IdeDeviceP0T0L0-0
    !DevNode 848d7950 :
    DeviceInst is
    "IDE\DiskVirtual_HD______________________________1.1.0___\5&35dc7040&0&0.0.0"
    ServiceName is "disk"


    When nt!ntWriteFile calls IoGetRelatedDeviceObject the function switches to
    another stack resulting in:


    kd> !devstack @eax
    !DevObj !DrvObj !DevExt ObjectName
    > 8508a980 \FileSystem\FltMgr 8508aa38
    83acf878 \FileSystem\RAW 83acf930


    It looks different when a disk is opened by interface symlink:

    h = CreateFileW(pDetailData->DevicePath, GENERIC_READ | GENERIC_WRITE,
    FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING,
    FILE_FLAG_NO_BUFFERING, 0);

    //I tried with and without FILE_FLAG_NO_BUFFERING

    kd> !handle dc

    PROCESS 83cf3440 SessionId: 1 Cid: 0fb4 Peb: 7ffd9000 ParentCid: 0298
    DirBase: 1ea284e0 ObjectTable: 83e18bc8 HandleCount: 55.
    Image: ScratchPad.exe

    Handle table at 83e18bc8 with 55 entries in use

    00dc: Object: 85040b48 GrantedAccess: 0012019f Entry: 83e491b8
    Object: 85040b48 Type: (83a2ab90) File
    ObjectHeader: 85040b30 (new version)
    HandleCount: 1 PointerCount: 1


    kd> !fileobj 85040b48



    Device Object: 0x848cc908 \Driver\atapi
    Vpb is NULL
    Event signalled

    Flags: 0x4000a
    Synchronous IO
    No Intermediate Buffering
    Handle Created

    CurrentByteOffset: 0

    kd> !devstack 0x848cc908
    !DevObj !DrvObj !DevExt ObjectName
    849e93f8 \Driver\partmgr 849e94b0
    849e97b8 \Driver\Disk 849e9870 DR0
    849e9ef0 \Driver\storflt 849e8aa0
    848cf020 \Driver\ACPI 83a4a770
    > 848cc908 \Driver\atapi 848cc9c0 IdeDeviceP0T0L0-0
    !DevNode 848d7950 :
    DeviceInst is
    "IDE\DiskVirtual_HD______________________________1.1.0___\5&35dc7040&0&0.0.0"
    ServiceName is "disk"



    So VPB is NULL and IoGetRelatedDeviceObject doesnt switch stacks:


    kd> !devstack @eax
    !DevObj !DrvObj !DevExt ObjectName
    > 849e93f8 \Driver\partmgr 849e94b0
    849e97b8 \Driver\Disk 849e9870 DR0
    849e9ef0 \Driver\storflt 849e8aa0
    848cf020 \Driver\ACPI 83a4a770
    848cc908 \Driver\atapi 848cc9c0 IdeDeviceP0T0L0-0
    !DevNode 848d7950 :
    DeviceInst is
    "IDE\DiskVirtual_HD______________________________1.1.0___\5&35dc7040&0&0.0.0"
    ServiceName is "disk"

    Does it mean that a user mode application might open a disk bypassing
    FltMgr? Why opening by interface differs from open by legacy symlink?

    -scott
    OSR

  • Maxim_S._ShatskihMaxim_S._Shatskih Member Posts: 10,396
    > This is due to the fact that Disk calls IoCreateSymbolicLink and points this
    > link to its own FDO.

    Great to know that the disks are also such, not only CD/DVD drives :-)

    The same issue is with CD/DVD drives: the \\.\D: name, and the PnP devinterface name, reference the different DOs - one references the FDO and another the PDO in the same stack.

    Then the ACL of the _referenced_ DO is used to check the access rights.

    This is since Vista I think. I've noticed it around 2008.

    And yes, this introduces some complexity to "open SCSI device" path to send SPTI/MMC commands to the CD/DVD drive.

    --
    Maxim S. Shatskih
    Microsoft MVP on File System And Storage
    [email protected]storagecraft.com
    http://www.storagecraft.com
  • greg_jacklingreg_jacklin Member Posts: 71
    volsnap (shadow copy service) writes directly lower volume drivers (volmgr). sending writes above itself is a locking nightmare. volsnap also writes to the BPB. it gets a bit tricky however as it needs detect format and other FS operations.
Sign In or Register to comment.

Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Upcoming OSR Seminars
OSR has suspended in-person seminars due to the Covid-19 outbreak. But, don't miss your training! Attend via the internet instead!
Writing WDF Drivers 7 Dec 2020 LIVE ONLINE
Internals & Software Drivers 25 Jan 2021 LIVE ONLINE
Developing Minifilters 8 March 2021 LIVE ONLINE