I/O manager validation of input / output buffer addresses?

Hey, there’s a (poorly written) driver that exposes a memory copy IOCTL to usermode.
Sending a request with an input buffer pointing at a kerne address, and output buffer pointing at a UM address works, the driver reads kernel memory to UM (poorly written as said)
However, when passing a usermode address as the input buffer, and kernel mode address as the output buffer (trying to write usermode memory to kernel), the said IOCTL handler is not even invoked. So surely I/O manager detects something is bad here and drops the IRP? Anyone familiar with such check? The IOCTL is method buffered if it’s worth mentioning

You would have to provide more details. You can't literally pass a kernel address as a parameter to DeviceIoControl. Those addresses are validated. Now, if you are passing the address of a pointer (indirect), then they can't be validated at the I/O level.

I passed a kernel address (the address of a global variable in a driver), worked when passed as input buffer to DeviceIoControl (memory pointed by this global was copied). Didn’t work when passed as the output buffer (the data it points to wasn’t overwritten and as mentioned, the IOCTL handler wasn’t even hit. It failed at the I/O level).
What other details would be helpful here?
IOCTL is METHOD_BUFFERED, FILE_ANY_ACCESS

Just jumping into the thread, your observation about METHOD_BUFFERED and how the I/O manager seems to drop the request when a kernel address is passed as the output buffer is consistent with how the I/O manager performs address validation.

In METHOD_BUFFERED, both the input and output buffers are copied to and from the same system buffer allocated by the I/O manager (i.e., Irp->AssociatedIrp.SystemBuffer). When you call DeviceIoControl, the I/O manager probes and captures both buffers to ensure they're valid user-mode addresses. If you pass a kernel-mode pointer as the output buffer, that probe will fail and the IRP won't even reach the driver — hence your handler not being invoked.

When you pass a kernel address as the input buffer, it can still "succeed" if the address is readable in the current context (e.g., mapped global kernel memory). But doing the opposite (copying to a kernel address from user-mode) doesn't work because the I/O manager expects to write to the output buffer on behalf of the driver, and that fails validation if the address lies in kernel space.

If you’re trying to copy memory into a specific kernel address, METHOD_NEITHER might be the more appropriate mechanism, though that comes with obvious safety implications and must be handled very carefully in the driver.

Hope this helps clarify.