Handling IOCTL_KS_READ_STREAM in KMDF filter driver

Inspired by the following article - http://www.osronline.com/article.cfm?article=446 - I decided to try it out and write a simple filter driver for IMAGE class devices (webcams).

I have succesfully created and installed a simple filter driver that passes through all requests and prints out some information to DbgView.

Then, I have experimented with blocking IOCTL_KS_READ_STREAM control code - simply marked it as completed with WdfRequestComplete(request, STATUS_UNSUCCESSFUL).

Then, I planned to modify the requested picture (e.g. fill it with green color) and finally complications arose.
IOCTL_KS_READ_STREAM: Queue 0x0000057FE4E51758, Request 0x0000057FE4F2FCD8 OutputBufferLength 128 InputBufferLength 0 IoControlCode 3096599

From the debug output I see that I should supply something to the OutputBuffer.
However, the documenation says about InputBuffer - “The application places a pointer to an array of KSSTREAM_HEADER structures in the InBuffer parameter. Each describes a packet of data to be read.” (http://msdn.microsoft.com/en-us/library/windows/hardware/ff560827(v=vs.85).aspx)

Also, I couldn’t get neither the output nor the input one with WdfRequestRetrieveOutputBuffer routine. I receive an error - STATUS_INVALID_DEVICE_REQUEST. I’m pretty sure that it means “something about neither buffered nor direct I/O” - but I cannot get what should I do with that.

Another article (http://msdn.microsoft.com/en-us/library/windows/hardware/ff565432(v=vs.85).aspx) says something about “checking the validity of the user buffer’s address range and check whether the appropriate read or write access is permitted, using the ProbeForRead and ProbeForWrite support routines.”

I’m not sure if I’m on the right way. What should I do to get access to data buffer in order to modify it? I hope Tim R. could give me a clue…

Thanks a lot,
Anton

xxxxx@gmail.com wrote:

Inspired by the following article - http://www.osronline.com/article.cfm?article=446 - I decided to try it out and write a simple filter driver for IMAGE class devices (webcams).

You have embarked on a dangerous and obstacle-filled journey. The exact
ioctl interface to kernel streaming drivers is not documented, and it
doesn’t follow the rules used by other ioctls.

Then, I planned to modify the requested picture (e.g. fill it with green color) and finally complications arose.
IOCTL_KS_READ_STREAM: Queue 0x0000057FE4E51758, Request 0x0000057FE4F2FCD8 OutputBufferLength 128 InputBufferLength 0 IoControlCode 3096599

From the debug output I see that I should supply something to the OutputBuffer.
However, the documenation says about InputBuffer - “The application places a pointer to an array of KSSTREAM_HEADER structures in the InBuffer parameter. Each describes a packet of data to be read.” (http://msdn.microsoft.com/en-us/library/windows/hardware/ff560827(v=vs.85).aspx)

Also, I couldn’t get neither the output nor the input one with WdfRequestRetrieveOutputBuffer routine. I receive an error - STATUS_INVALID_DEVICE_REQUEST. I’m pretty sure that it means “something about neither buffered nor direct I/O” - but I cannot get what should I do with that.

Yes. All of the KS ioctls use “neither” buffering, which means there
are no rules. The ioctls contain raw user-mode pointers. Making things
even more exciting, there is a filter driver called “ksthunk” that
partially processes the ioctl and does some of the mappings.

The documentation for IOCTL_KS_READ_STREAM says that the KSSTREAM_HEADER
“array” goes in the input buffer. There are three problems with that
statement. First, it’s false. The KSSTREAM_HEADER goes in the output
buffer. Second, it’s never an array. There’s always exactly one. A
custom KS application might send more, but essentially 100% of video
streaming happens through one of the two proxies (DShow’s ksproxy or
Media Foundation’s devproxy), and they both send exactly one. Third,
for a video stream, you actually get a KSSTREAM_HEADER followed by a
KS_FRAME_INFO. That’s why it’s 128 bytes, when a KSSTREAM_HEADER is
only 56 bytes.

The UserBuffer in the IRP points to the kernel address of the
KSSTREAM_HEADER. The Type3InputBuffer and SystemBuffer fields are not
used. Up through Win 7, ksthunk helpfully maps the actual frame buffer
(KSSTREAM_HEADER.Data) in the MdlAddress field, but in Win 8 it no
longer does that.

What that means is that you *must* use an EvtInCallerContext callback to
pre-process the IRP. The IRP and the header both can contain user-mode
addresses which you have to handle. You will have to manipulate the IRP
fields directly. In your callback, IF the MdlAddress exists, that’s
your frame buffer. Otherwise, use
WdfRequestRetrieveUnsafeUserOutputBuffer to get the KSSTREAM_HEADER,
fetch the user-mode address from that, and use
WdfRequestProbeAndLockUserBufferForWrite to map it. You will have to
save this information in a context structure for later use.

After you modify the frame buffer, you’ll set KSSTREAM_HEADER.DataUsed,
and complete the request using the size of the original request’s output
buffer (that is, sizeof(KSSTREAM_HEADER)+sizeof(KS_FRAME_INFO)). In
addition, for Windows 8 you’ll need to set
KS_FRAME_INFO.FrameCompletionNumber to an incrementing value.
Otherwise, KS throws your frames away.

IOCTL_KS_PROPERTY is handled in an entirely different and even more
bizarre manner.


Tim Roberts, xxxxx@probo.com
Providenza & Boekelheide, Inc.

>> You have embarked on a dangerous and obstacle-filled journey.
Yes, I have already realized this myself…

Thanks for your quick response Tim. Just wanted to leave here a message that I will postpone this task for a while.