cwindowswinapiioctltun

DeviceIoControl returning ERROR_ACCESS_DENIED


I'm trying to interface with a driver for creating TUN interfaces (WinTun), but in order to send and receive data from them I need to register a ring buffer. The code I'm using looks something like this (I omitted the part where I create the device with SetupApi, as that seems to be working):

#include <windows.h>
#include <winioctl.h>
#include <stdio.h>

#define REGISTER_RINGS_IOCTL CTL_CODE(51820U, 0x970U, METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA)

#define BUF_CAPACITY 0x20000
#define BUF_TRAILING 0x10000

typedef struct {
    volatile ULONG Head;
    volatile ULONG Tail;
    volatile LONG Alertable;
    UCHAR Data[BUF_CAPACITY + BUF_TRAILING];
} TUN_RING;

typedef struct {
    ULONG Size;
    UCHAR Data;
} TUN_PACKET;

typedef struct {
    struct {
        ULONG RingSize;
        TUN_RING *Ring;
        HANDLE TailMoved;
    } Send, Receive;
} TUN_REGISTER_RINGS;

int main() {

    HANDLE device = CreateFileW(
        L"\\\\?\\ROOT#NET#0006#{cac88484-7515-4c03-82e6-71a87abac361}",
        // ^^ This comes from the omitted code ^^
        GENERIC_READ | GENERIC_WRITE,
        FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
        NULL,
        OPEN_EXISTING,
        0,
        NULL
    );

    if(device == INVALID_HANDLE_VALUE) {
        printf("The device does not exist\n");
        return -1;
    }

    TUN_RING Send, Receive = {0};

    TUN_REGISTER_RINGS params = {
        .Send.RingSize = sizeof(TUN_RING),
        .Send.Ring = &Send,
        .Send.TailMoved = CreateEventW(NULL, FALSE, FALSE, NULL),

        .Receive.RingSize = sizeof(TUN_RING),
        .Receive.Ring = &Receive,
        .Receive.TailMoved = CreateEventW(NULL, FALSE, FALSE, NULL),
    };

    DWORD bytes;

    BOOL ret = DeviceIoControl(
        device,
        REGISTER_RINGS_IOCTL,
        &params,
        sizeof(TUN_REGISTER_RINGS),
        NULL,
        0,
        &bytes,
        NULL
    );

    if(ret == 0) {
        printf("Err: %d\n", GetLastError());
        return -2;
    }

    return 0;
}

My problem is that this code fails at DeviceIoControl with error 5, which corresponds to ERROR_ACCESS_DENIED.

I have no idea why that is happening as the program is already running with admin privileges and the device handle has been opened with the recommended attributes (as you can see here). Sorry for the lack of extra information but I don't have much experience when it comes to windows drivers and don't know how to debug this any further.

I think the problem might have to do with this check in the source code of the driver, as it appears to be stopping before checking the input buffer (it should rerurn INVALID_PARAMETER when I put garbage in the input buffer, but that doesn't happen).

Again, sorry if I misunderstood something or missed something critical but I am learning all of this as I go, thanks in advance!


Solution

  • Found the solution. As @RbMm described, the code that creates the security descriptor only allows access to LocalSystem. That means that it is the only account allowed to talk to the driver.