Skip to content

VNX-781: Improper Address Validation in IOCTL with METHOD_NEITHER I/O Control Code

Windows driver reads of a METHOD_NEITHER Type3InputBuffer, Irp->UserBuffer or KMDF unsafe user buffer with no ProbeForRead, ProbeForWrite, MmProbeAndLockPages or WdfRequestProbeAndLock call nearby.

Updated 02 Nov 2026Checked against cli@de9b52a
Field Value
Rule ID VNX-781
Severity Medium
SARIF level warning
Kind sast
Languages C, C++
CWE CWE-781
CAPEC CAPEC-97
ATT&CK T1557
CWSS vector CWSS:1.0/TI:M/AP:RU/AL:S/IC:N/FC:LT/RP:RU/RL:S/AV:L/AS:N/IN:A/SC:A/BI:M/DI:H/EX:M/EC:N/P:C
Tags windows-driver ioctl method-neither cwe-781
Source internal/sast/rules/vnx-781.rego

Overview

This rule flags C and C++ Windows driver code that reads Parameters.DeviceIoControl.Type3InputBuffer or Irp->UserBuffer (the raw user-mode pointers of a METHOD_NEITHER IOCTL), or calls KMDF WdfRequestRetrieveUnsafeUserInputBuffer/OutputBuffer, when no ProbeForRead, ProbeForWrite, MmProbeAndLockPages or WdfRequestProbeAndLockUserBufferForRead/ForWrite call appears in the 30 lines above or 40 below. Buffered and direct-I/O buffers (SystemBuffer, MdlAddress) and user-mode DeviceIoControl callers are not reported; whether the probe covers the same pointer and length is not checked. Without validation, a malicious user-mode process can supply kernel-space addresses, causing the driver to read from or write to kernel memory under attacker control. This maps to CWE-781: Improper Address Validation in IOCTL with METHOD_NEITHER I/O Control Code.

Why This Matters

Kernel drivers operate at ring 0 with full access to all memory. An IOCTL handler that accepts a user-provided address without validation can be exploited to read kernel memory (information disclosure including KASLR bypass) or write to kernel memory (privilege escalation to SYSTEM). This vulnerability class has been extensively exploited by local privilege escalation exploits.

What Gets Flagged

// FLAGGED: IOCTL handler without ProbeForRead/ProbeForWrite
NTSTATUS DriverDispatch(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
    PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(Irp);
    ULONG code = stack->Parameters.DeviceIoControl.IoControlCode;

    if (code == IOCTL_MY_CODE) {  // METHOD_NEITHER
        PVOID inputBuffer = stack->Parameters.DeviceIoControl.Type3InputBuffer;
        // MISSING: ProbeForRead(inputBuffer, length, alignment)
        RtlCopyMemory(localBuf, inputBuffer, length);  // dangerous
    }
}

Remediation

// SAFE: validate user-space addresses before access
NTSTATUS DriverDispatch(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
    PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(Irp);
    PVOID inputBuffer = stack->Parameters.DeviceIoControl.Type3InputBuffer;
    ULONG inputLength = stack->Parameters.DeviceIoControl.InputBufferLength;

    __try {
        ProbeForRead(inputBuffer, inputLength, sizeof(UCHAR));
        RtlCopyMemory(localBuf, inputBuffer, inputLength);
    } __except (EXCEPTION_EXECUTE_HANDLER) {
        return GetExceptionCode();
    }
}

Use METHOD_BUFFERED or METHOD_IN_DIRECT/METHOD_OUT_DIRECT IOCTL types where the I/O Manager handles buffering and validation automatically.

References

Suppressing this rule

Put a nosec comment on the line, or on line 1 to cover the whole file. Use the comment marker of the file’s language (#, //, -- or ;):

# nosec vnx-781
// nosec vnx-781

Or record an ignore rule: vulnetix ignore add --rule vnx-781 --reason "...". See Suppressing findings.

Edit this pageSources: cli/internal/sast/rules/vnx-781.rego, cli/internal/sast/docs/vnx-781.md
esc
↑ ↓ move↵ openSearches in your browser. A key like autonomy.max or a code like threshold_required jumps straight to it.