Handling shutdown in KMDF filter - device-driver

I'm working on kmdf volume filter driver and wanted to handle shutdown. The article WDM IRPs and KMDF Event Callback and comments in the WDF book seems to suggest that the WDF supports IRP_MJ_SHUTDOWN only for control(non PNP) deivce. So I added call to WdfControlDeviceInitSetShutdownNotification(WdfDeviceShutdown) for my control object and that allowed me to save file to same volume at the time of shutdown. However the document sys that WdfDeviceShutdown is called before flush which I'm not seeing. I've callback for flush using EvtDeviceWdmIrpPreprocess(IRP_MJ_FLUSH). Looking at the Dbg print, I always see flush callback before WdfDeviceShutdown callback.
I wonder if I'm missing something. Any comments on this behavior will help me understand this better. I'm seeing flush before because control device is at volume filter level which is below file system hence executive flushes file system buffer before closing/notifying my device.
Note: If I use WdfControlDeviceInitSetShutdownNotification(WdfDeviceLastChanceShutdown) I get error 0xc0000189 (STATUS_TOO_LATE) when I try to write to the file.

Related

swapbuffers minifilter problems

I implemented a minifilter driver using the swapbuffers example. I made two changes:
attach only to \Device\HarddiskVolume3
encryption XORing with 0xFF
Encryption works, but the volume3 (which in my system is E:) not working. E: is not recognized file system. chkdsk E: results all boot sectors corrupted message.
After investigations (using procmon.exe): the chkdsk.exe creates a shadow copy of volume. If the driver attaches the shadow copy too the chkdsk E: is OK, the filesystem is perfect. But E: remains unrecognized.
Any idea what I should change?
Assuming no simple mistake was made, that is, the volume was unmounted, you added the filter, and remounted, obviously the mount/filesystem is not using your filter.
I noticed a comment in the example code about "not for kernel mode drivers".
What you want to research is "whole disk encryption". A google search AND search on: windows whole disk encryption will help.
In particular, TrueCrypt does what you want. Since it is open source, and is available on sourceforge.net, you could download the source and figure out how to hook your stuff in by learning how TrueCrypt does it.
Just one problem: TrueCrypt has security gaps, so the sourceforge.net page is now just migration info to BitLocker. But, it still exists and other pages have been created where you can get it. Notably, a fork of TrueCrypt is VeraCrypt
Just one of the pages in the search is: http://www.howtogeek.com/203708/3-alternatives-to-the-now-defunct-truecrypt-for-your-encryption-needs/
UPDATE
Note: After I wrote this update, I realized that there may be hope ... So, keep reading.
Minifilter appears to be for filesystems but not underlying storage. It may work, you just need to find a lower level hook. What about filter stack altitute? Here's a link: https://msdn.microsoft.com/en-us/library/windows/hardware/ff540402%28v=vs.85%29.aspx It also has documentation on fltmc and the !fltkd debugger extension
In this [short] blog: http://blogs.msdn.com/b/erick/archive/2006/03/27/562257.aspx it says:
The Filter Manager was meant to create a simple mechanism for drivers to filter file system operations: file system minifilter drivers. File system minifilter driver are located between the I/O manager and the base filesystem, not between the filesystem and the storage driver(s) like legacy file system filter drivers.
Figuring out what that means will help. Is the hook point between FS and I/O manager [which I don't know about] sufficient? Or, do you need to hook between filesystem and storage drivers [implying legacy filter]?
My suspicion is that a "legacy" driver filter may be what you need, if the minifilter does not have something that can do the same.
Since your hooks need to work on unmounted storage so that chkdsk will work, this may imply the legacy filter. On the other hand, you mentioned that you were able to hook the shadow copy and it worked for chkdsk. That implies minifilter has the right stuff.
Here's a link that I think is a bit more informative: http://blogs.msdn.com/b/ntdebugging/archive/2013/03/25/understanding-file-system-minifilter-and-legacy-filter-load-order.aspx It has a direct example about the altitute of an encryption filter. You just may need more hook points and to lower the altitude of your minifilter
UPDATE #2
Swapbuffers just hooks a few things: IRP_MJ_READ, IRP_MJ_WRITE, IRP_MJ_DIRECTORY_CONTROL. These are file I/O related, not device I/O related. The example is fine, just not necessarily for your purposes.
The link I gave you to fltmc is one page in MS's entire reference for filters. If you meander around that, you'll find more interesting things like IoGetDeviceAttachmentBaseRef, IoGetDiskDeviceObject. You need to find the object for the device and filter its I/O operations.
I think that you'll have to read the reference material in addition to examples. As I've said previously, your filter needs to hook more or different things.
In the VeraCrypt source, the Driver subdirectory is an example of the types of things you may need to do. In DriveFilter.c, it uses IRP_MJ_READ but also uses IRP_MN_START_DEVICE [A hook when the device is started].
Seriously, this may be more work than you imagine. Is this just for fun, or is this just a test case for a much larger project?

problems is mini-filter while filtering volume mounts

[OS: WinXP on VirtualBox, HostOS: win7]
We are developing a mini-filter driver and we are trying to block mounting of usb devices based on some conditions.
the mini-filter watches for IRP_MJ_VOLUME_MOUNT and whenever a usb drive is inserted, in the pre-callback, it asks userland whether or not to allow mount the drive using FltSendMessage.
In the userland, after FltGetMessage and before FltReplyMessage, certain conditions are checked and corresponding value is replied back to the driver.
This all is working fine, but we are experiencing two problems or lets say inconveniences.
The condition checking takes about 4-5 seconds [data is sent and received over network]. During this period, the Windows Explorer just hangs. And whatever the actions such as navigations, are performed as soon as FltReplyMessage is called. If I click anywhere such as the start menu, nothing happens until FltReplyMessage is called. Other applications such as VLC function normally [ie, the disk can be accessed].
When the usb drive is not allowed to mount the volume, it continues to try mounting the volume several times!
The workaround we used is to maintain a list of recently inserted devices and reject them if the GUID is present in the list.
I read somewhere that the mount point can be deleted using DeleteVolumeMountPoint and if we need to allow that device in future then we need to delete a reg key which contains the unique ID of device which can be obtained sending MOUNTDEV_UNIQUE_ID to the device. We tried to achieve this, but were unsuccessful to correctly obtain the unique ID. [we were unable to allocate enough memory for the MOUNTDEV_UNIQUE_ID structure. Tried new and malloc(enough size) but then sizeof(varUniqueID) returned just 4, and calling DeviceIoControl with that resulted in "More Data is available" error. We are doing in userland. Should this be done in kernel?]
Whew! a long post!
We would really appreciate any help we can get!
Cheers!
As far as your first concern there is not much you can do unless there is a way you can cache the data needed in the driver based on volume unique ids.
This way there will only be a Flt call per mount.
I am not sure about your requirements, but if the data needed to make a decision is over network then you will suffer from this delay one way or another. It is crucial for the driver to be able to cache its own data without having to even call into user-mode after a first mount attempt of the same device.
For the second point for sure you could do it in either user-mode or kernel-mode. Could you provide a code snip to check for any mistakes ?
Cheers,
Gabriel

What is the proper way to acknowledge an ATA/IDE interrupt?

I am currently working on a hobby OS, specifically the ATA driver. I am having some issues with PIO data-in commands with interrupts. I am trying to execute the READ MULTIPLE command to read multiple sectors from the drive, block by block, with an interrupt firing for each block.
If I request a read of 4 blocks (1 sector per block). I expect to get 4 interrupts, one for each data block. Upon receiving the 4th interrupt I can identify that I've transferred all data and update my request structure accordingly. However, in VirtualBox I've found that after the last data block has been transferred I received yet another interrupt (STATUS = 0x50, READY, OVERLAPPED MODE SERVER REQ). I can simply read the STATUS register then to clear it, but I don't think I should ever receive the 5th interrupt according to the specs.
So what is the proper way acknowledge an interrupt issued by an ATA device?
In this example I issue a READ MULTIPLE command, and then my ISR does the following:
disables CPU interrupts, sets nIEN
Read a single data block (not sector!) fro the DATA register,
If all data has been read, read the STATUS register to clear the 'extra' interrupt
Exit by clearing nIEN, and sending EOI's to both the master and slave PICs
The ATA specs for the PIO data-in command protocol don't indicate that you need to read the status register. From that I assumed that when I receive an interrupt all I have to do is follow the protocol and finish by sending the EOIs to the PICs. As for the setting/clearing of nIEN, in dealing with VirtualBox I've found that if I don't do this I don't receive any interrupts past the first one. So I set nIEN when entering the ISR, then clear it before I leave. I'd think that wouldn't have any effect, but it must be related to reading/writing that specific register.
This always happens to me, I post a question I've been struggling with, only to find the answer myself shortly after.
The ATA-6 spec I've been referencing has this one line in the PIO data-in section (9.5):
When in this state, the host shall read the device Status register.
With ATA the Status register has a side-effect: it clears a pending interrupt. I knew this, but I didn't correctly read this part before. It doesn't mention why you should read the register, it just states it exactly as above.
The important part is how this works with the interrupt handler. After issuing a PIO data-in command, once the INTRQ is asserted, you simply read the Status register once to clear the interrupt, then continue to processes the interrupt and return as normal (just sending EOIs to the PICs.) What had me confused is that none of the documentation I read mentioned exactly how this should work with interrupts (receive an INTRQ, read Status, processes interrupt.) Most online guides only deal with polled IO.
This is one of the difficulties with low-level programming, key details, such as needing to read the Status register in the ISR, are often glanced over. This one was left as a single line in the protocol description. Call me picky but I just would have expected more emphasis on this point.

How to peek at STDIN with Delphi 7?

In a Delphi 7 console application, how can I check whether stdin holds a character, without blocking until one is entered?
My plan is that this console program will be executed by a GUI program, and its stdin will be written to by the GUI program.
So I want my console app to periodically check stdin, but I can't find a way of doing this without blocking.
I have looked at this answer, which gets me a stream pointing to stdin, but there's still no way to "peek" as far as I can see.
I think you have already found the right way to read stdin. It is meant to block when there's nothing more to be read.
The standard way to handle this is to use a separate thread to handle the pipe. When it receives new data from stdin it signals this to the processing thread, for example with a message passing mechanism.
Having said all that, if you really want to poll you can call PeekNamedPipe to check if there is data in the pipe.
You could as the other answer says use threads, but even then you might have problems (using the threading method) unless you also investigate overlapped IO.
I normally use overlapped IO with serial ports rather than stdin, where "read a character if one is ready" is commonly needed, and where non-blocking IO is a usual way of working. You should be able to adapt the technique shown here. However, if I was writing an application that was keyboard driven (instead of purely driven by say, a file redirected to standard input) I would let go of StdIN, and use a CRT type unit. So, if you don't mind letting go of StdIn, and simply want to have a keyboard-driven input model, you could look at console based APIs and abandon the very limiting StdIn capabilities. For an example of a "kbhit" function that uses the Win32 Console APIs see here.
There is no other way (as far as i know), as reading from a pipe inside a separate thread. Otherwise as you already have seen, the readfile operation will block. I wrote an example how to do this, an example project is also available: redirect stdoutput
Edit: Well, reading your question another time, i understand that your problem lies within the console program, not the calling application. I wonder what your console application expects, normally a console application knows when it needs input and cannot proceede until the user enters this information. Do you need to check for an exit?
For a Stream if you .Read() the function result is the number of bytes read which will be zero if there was nothing there even if you asked for more. From the Delphi help for Classes.TStream.Read:
Read is used in cases where the number of bytes to read from the stream is not necessarily fixed. It attempts to read up to Count bytes into buffer and returns the number of bytes actually read.

Overlapped serial port and Blue Screen of Death

I created a class that handles serial port asynchronously. I use it to communicate with a modem. I have no idea why, but sometimes, when I close my application, I get the Blue Screen and my computer restarts. I logged my code step by step, but when the BSOD appeared, and my computer restarted, the file into which I was logging data contained only white spaces. Therefore I have no idea, what the reason of the BSOD could be.
I looked through my code carefully and I found several possible reasons of the problem (I was looking for all that could lead to accessing unallocated memory and causing AV exceptions).
When I rethought the idea of asynchronous operations, a few things came to my mind. Please verify whether these are right:
1) WaitCommEvent() takes a pointer to the overlapped structure. Therefore, if I call WaitCommEvent() inside a function and then leave the function, the overlapped structure cannot be a local variable, right? The event mask variable and event handle too, right?
2) ReadFile() and WriteFile() also take references or pointers to variables. Therefore all these variables have to be accessible until the overlapped read or write operations finish, right?
3) I call WaitCommEvent() only once and check for its result in a loop, in the mean time doing other things. Because I have no idea how to terminate asynchronous operations (is it possible?), when I destroy my class that keeps a handle to a serial port, I first close the handle, and then wait for the event in the overlapped structure that was used when calling the WaitCommEvent() function. I do this to be sure that the thread that waits asynchronously for a comm event does not access any fields of my class which is destroyed. Is it a good idea or is it stupid?
try
CloseHandle(FSerialPortHandle);
if Assigned(FWaitCommEvent) then
FWaitCommEvent.WaitFor(INFINITE);
finally
FSerialPortHandle := INVALID_HANDLE_VALUE;
FreeAndNil(FWaitCommEvent);
end;
Before I noticed all these, most of the variables mentioned in point one and two were local variables of the functions that called the three methods above. Could it be the reason of the BSOD or should I look for some other mistakes in my code?
When I corrected the code, the BSOD stopped occuring, but It might be a coincidence. How do you think?
Any ideas will be appreciated. Thanks in advance.
I read the CancelIo() function documentation and it states that this method cancells all I/O operations issued by the calling thread. Is it OK to wait for the FWaitCommEvent after calling CancelIo() if I know that WaitCommEvent() was issued by a different thread than the one that calls CancelIo()?
if Assigned(FWaitCommEvent) and CancelIo(FSerialPortHandle) then
begin
FWaitCommEvent.WaitFor(INFINITE);
FreeAndNil(FWaitCommEvent);
end;
I checked what happens in such case and the thread calling this piece of code didn't get deadlocked even though it did not issue WaitCommEvent(). I tested in on Windows 7 (if it matters). May I leave the code as is or is it dangerous? Maybe I misunderstood the documentation and this is the reason of my question. I apologize for asking so many questions, but I really need to be sure about that.
Thanks.
An application running as a standard user should never be able to cause a bug check (a.k.a. BSOD). (And an application running as an Administrator should have to go well out of its way to do so.) Either you ran into a driver bug or you have bad hardware.
By default, Windows is configured to save a minidump in %SystemRoot%\minidump whenever a bug check occurs. You may be able to determine more information about the crash by loading the minidump file in WinDbg, configuring WinDbg to use the Microsoft public symbol store, and running the !analyze -v command in WinDbg. At the very least, this should identify what driver is probably at fault (though I would guess it's your modem driver).
Yes, you do need to keep the TOverlapped structure available for the duration of the overlapped operation. You're going to call GetOverlappedResult at some point, and GetOverlappedResult says it should receive a pointer to a structure that was used when starting the overlapped operation. The event mask and handle can be stored in local variables if you want; you're going to have a copy of them in the TOverlapped structure anyway.
Yes, the buffers that ReadFile and WriteFile use must remain valid. They do not make their own local copies to use internally. The documentation for ReadFile even says so:
This buffer must remain valid for the duration of the read operation. The caller must not use this buffer until the read operation is completed.
If you weren't obeying that rule, then you were likely reading into unreserved stack space, which could easily cause all sorts of unexpected behavior.
To cancel an overlapped I/O operation, use CancelIo. It's essential that you not free the memory of your TOverlapped record until you're sure the associated operation has terminated. Likewise for the buffer you're reading or writing. CancelIo does not cancel the operation immediately, so your buffers might still be in use even after you call it.

Resources