1

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.

MikeF
  • 1,021
  • 9
  • 29
  • 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 Jun 19 '18 at 17:54
  • @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 Jun 19 '18 at 18:03
  • 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 Jun 19 '18 at 18:10
  • 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 Jun 19 '18 at 20:42
  • @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 Jun 19 '18 at 20:54
  • most power way - use `FltRegisterFilter` + `FltCreateCommunicationPort` from kernel. `FltStartFiltering` you can even not call if not need attach to volumes. from user mode `FilterConnectCommunicationPort`, `FilterGetMessage`, etc – RbMm Jun 22 '18 at 23:32
  • @RbMm: Thanks I shall try it. By "most powerful way" you mean the fastest communication, or the most options that it provides? Can you clarify? – MikeF Jun 23 '18 at 00:41
  • i mean by functional - both sides can send and receiver messages (in kernel mode via callback, in user mode - asynchronous call), use any size buffers, etc. of course exist many another. say driver can insert apc to registered user thread (say this thread open handle on device), but buffers here need allocate separate yourself. user can set request to driver and driver pending this request and complete on event, but user need in advance send this requests.. – RbMm Jun 23 '18 at 07:16

1 Answers1

2

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.

ImmortaleVBR
  • 640
  • 5
  • 10
  • Thanks for your suggestions. I'll have to research them. I keep seeing a lot of references to undocumented stuff in the kernel space though. For instance, even MSDN may give a function and not explain the members of the struct it returns. Ex: `IoGetCurrentProcess()`. Is that a normal thing? In user mode it is generally frowned upon to use undocumented APIs. – MikeF Jun 20 '18 at 22:23
  • @MikeF I agree with you about the undocumented APIs, I neither think it is a good idea. Sometimes you may not have a choice depending on what you're trying to do though, which is a shame. About IoGetCurrentProcess, that is supposed to return a pointer to the _EPROCESS structure, but we aren't supposed to mess with the fields (or access them) since it is an opaque structure. Microsoft will have reasons for why they did this, but you can still read/write to the fields via memory access if you have the offsets (bad idea, the offsets can change at any time). – ImmortaleVBR Jun 20 '18 at 22:25
  • Also a side question. I posted a comment above. Through my own research I found out that `IoReportTargetDeviceChangeAsynchronous()` may be used to marshal an arbitrary size struct into user-mode process, which can use `RegisterDeviceNotification()` to retrieve it via `WM_DEVICECHANGE` message. Is there a reason that may not work? (i.e. being too slow, unreliable? since we're dealing with window messages there. Or is it bad to use a PnP device concept without an actual device.) – MikeF Jun 20 '18 at 22:26
  • @MikeF I've never done that before so I don't think it would be a good idea for me to give advice on it, but you could try it out as an experiment and see if it works out well for your requirements. I'm sorry I cannot provide any real insight into that idea. I guess another member active here may stumble on this thread, see the comments and would know enough about that topic to chime in and answer that one... hopefully. – ImmortaleVBR Jun 20 '18 at 22:35