1

I am coding a kernel mode driver and pretending to send buffers from userland, I am doing it with DirectIO creating a file and symbolik link on service, and listening for IRP_MJ_WRITE and then sending data from userland with WriteFile.

I am receving everything well so far but I am getting it through MDL from address at Irp->UserBuffer as I am receiving Irp->AssociatedIrp.SystemBuffer and Irp->MdlAddress both NULL. No matter if I set the IO_BUFFERED flag or not.

I am wondering why this behavior as I am looking through the documentation and nothing is explaning this at the minute, and in theory Irp->UserBuffer should be an output buffer.

Could someone explain what's happening here?

The code example is the following:

Initialising driver

...
    // routine for handling write requests
    DriverObject->MajorFunction[IRP_MJ_WRITE] = DriverWrite;

    // Create device
    status = IoCreateDevice(DriverObject, 0, &DEVICE_NAME, FILE_DEVICE_UNKNOWN, FILE_DEVICE_SECURE_OPEN, FALSE, &DriverObject->DeviceObject);
    if (NT_SUCCESS(status))
    {
        DbgPrint("Device %wZ created", DEVICE_NAME);
    }
    else
    {
        DbgPrint("Could not create device %wZ", DEVICE_NAME);
    }

    // Create symbolic link, which is user-visible
    status = IoCreateSymbolicLink(&DEVICE_SYMBOLIC_NAME, &DEVICE_NAME);
    if (NT_SUCCESS(status))
    {
        DbgPrint("Symbolic link %wZ created", DEVICE_SYMBOLIC_NAME);
    }
    else
    {
        DbgPrint("Error creating symbolic link %wZ", DEVICE_SYMBOLIC_NAME);
    }

    DbgPrint("Driver loaded");
    return STATUS_SUCCESS;
...

WriteFile routine from other app in userland

[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr CreateFile(
    string lpFileName,
    uint dwDesiredAccess,
    uint dwShareMode,
    IntPtr lpSecurityAttributes,
    uint dwCreationDisposition,
    uint dwFlagsAndAttributes,
    IntPtr hTemplateFile);

[DllImport("kernel32.dll", SetLastError = true)]
static extern bool WriteFile(
    IntPtr hFile,
    byte[] lpBuffer,
    uint nNumberOfBytesToWrite,
    out uint lpNumberOfBytesWritten,
    IntPtr lpOverlapped);

[DllImport("kernel32.dll", SetLastError = true)]
static extern bool CloseHandle(IntPtr hObject);



IntPtr handle = CreateFile("\\\\.\\SampleDeviceLink", 0x40000000, 0, IntPtr.Zero, 3, 0, IntPtr.Zero);
if (handle.ToInt32() == -1)
{
    Console.WriteLine("Error opening the file");
    return;
}

string frase = "testing stuff";
byte[] data = Encoding.ASCII.GetBytes(frase);

uint bytesWritten;
bool success = WriteFile(handle, data, (uint)data.Length, out bytesWritten, IntPtr.Zero);
if (!success)
{
    Console.WriteLine("Error written the file");
}
else
{
    Console.WriteLine($"Written {bytesWritten}");
}
CloseHandle(handle);

Console.WriteLine("Press any key to close this..");
Console.ReadLine();

Then when executing this I am receiving on DriverWrite function an Irp that has:

Irp->AssociatedIrp.SystemBuffer -> NULL
Irp->MdlAddress -> NULL

But the size of the buffer is ok, obtained in this way:

PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
ULONG bufferSize = irpStack->Parameters.Write.Length;

And if I use the address located at Irp->UserBuffer to get the MDL then I can access the buffer through that; like this:

MDL* mdl = IoAllocateMdl(Irp->UserBuffer, bufferSize, FALSE, FALSE, NULL);
MmProbeAndLockPages(mdl, KernelMode, IoWriteAccess);
PVOID v_buffer = MmGetSystemAddressForMdlSafe(mdl, NormalPagePriority);
// Here v_buffer has what I sent from WriteFile
forlayo
  • 1,371
  • 2
  • 13
  • 23
  • "in theory Irp->UserBuffer should be an output buffer" I think you have that backwards. A `write()` operation has valid data passed from caller to driver, which is an [in] parameter. A `read()` operation has valid data when it returns from driver to caller, which is an [out] parameter. An `ioctl()` operation can have buffers in both directions. (Windows names: WriteFile, ReadFile, DeviceIoctl) – Ben Voigt May 04 '23 at 14:25
  • Also, during driver development you probably should test with a C++ userland app, where you can `#include ` and be guaranteed that all the function signatures are exactly correct, and where all the examples in the OS documentation just work without translation into a different language. – Ben Voigt May 04 '23 at 14:28
  • You need to set DO_BUFFERED_IO or DO_DIRECT_IO in the Flags field of DEVICE_OBJECT: https://learn.microsoft.com/en-us/windows-hardware/drivers/kernel/initializing-a-device-object – Luke May 04 '23 at 22:07
  • @Luke I tried that, but the behavior doesn't change.. And haven't found a explanation for this on the documentation.. – forlayo May 04 '23 at 22:25
  • I promise you it works. Perhaps you're using an older build of your driver. In the code you posted you're not setting a DriverUnload routine. – Luke May 04 '23 at 23:05

0 Answers0