1
votes

I'm learning Windows kernel programming, and I'm wondering how do I pass a byte array from a kernel driver to my user-mode application, where the kernel driver initiates the call?

If I were to do this among user-mode processes (say, from a service to a GUI app) I'd use a named pipe or a shared memory with a named event and a named mutex for synchronization. But I'm lost what to do on the kernel driver side.

Here's my actual example: I have a kernel callback function that can be called any time with a STRING. I then need to pass the string from within it to my currently running user-mode process and to alert it.

1
I'm not sure I follow. Do you mean that you provide a callback function to the kernel, for it to call? Because if it were the other way around then you would already have the data inside your program. - John Bollinger
@JohnBollinger: My kernel driver sets up a callback function that is called from within the kernel space. After that I need to pass a byte array supplied in the callback function to my running user-mode process. - MikeF
Ok. Then how is the user-mode process associated with the driver in the first place? That is, how does the driver know where to deliver the data? - John Bollinger
This sort of thing is usually done via DeviceIoControl, you would pass in the buffer that will later get filled, your driver initially returns STATUS_IO_PENDING and then completes the operation when the data is ready )having filled in the buffer the user mode code provided). It is not at all typical for user mode code to pass a callback function to kernel mode. - SoronelHaetir
@SoronelHaetir: Thanks. I did more research while waiting, and that was one of the suggested methods. Although, how would it work if Driver-Defined IOCTL's i/o may remain pending for an indefinite time? I also saw references to using PnP for this kinda purpose, and namely IoReportTargetDeviceChangeAsynchronous() on the driver side, and RegisterDeviceNotification() and WM_DEVICECHANGE on the user side (w/o using an actual hardware device.) Additionally a section object via ZwCreateSection() was suggested. I'm just not sure what's the recommended approach here? - MikeF

1 Answers

2
votes

There are tons of ways for kernel-mode to user-mode Inter-Process Communication, and different requirements can suit different techniques.

For starters, you have the option of named pipes (even in kernel-mode). However, there's something you should know... It isn't officially documented for a normal kernel-mode device driver (although there is a documented interface for Filesystem Mini-Filter device drivers).

If you want to use a named pipe from a normal kernel-mode device driver, you'll have to locate the address to NtCreateNamedPipeFile or rely on IoCreateFile (which NtCreateNamedPipeFile relies on internally, using an undocumented structure).

For using a named pipe from a Filesystem Mini-Filter device driver, you have FltCreateNamedPipeFile.

Moving on from the named pipes idea, you have the option of Local Procedure Calls! However, once again, another dead-end in terms of documentation. It is relatively straight forward to do it as a client in kernel-mode though. There's a documented interface for Ports with a Filesystem Mini-Filter device driver though: FltCreateCommunicationPort.

Moving on again, you could attach to the user-mode client and write directly to its memory.

If you really wanted, you could rely on something simple like a shared event to notify the user-mode client that you've just attached to it and written into its virtual memory.