CVE-2026-20820 — CLFS ScanContainers Integer Overflow (IOCTL 0x80076816)

Last updated: 2026-04-10
Component: clfs.sys
Bug Class: Integer overflow → OOB write
Status: Patched (2026)
Exploited ITW: Unknown
Related: Clfs, Integer Overflows
Tags: clfs, integer-overflow, ioctl, oob-write, kernel-mode, lpe, scancontainers


Summary

CVE-2026-20820 is an integer overflow in CClfsRequest::ScanContainers, triggered via IOCTL 0x80076816 (METHOD_OUT_DIRECT). The vulnerability: the output buffer size calculation multiplies ContainerCount * sizeof(CLS_CONTAINER_INFORMATION) (0x240 bytes each) but does NOT account for the 0x38-byte CLS_SCAN_CONTEXT header that also resides in the same output buffer. This allows the last CLS_CONTAINER_INFORMATION structure to be written 0x38 bytes past the end of the allocated output buffer — an OOB write of up to 0x240 bytes with partially controlled data.


IOCTL Details

IOCTL Code:        0x80076816
Direction:         METHOD_OUT_DIRECT
Input buffer:      ContainerCount (ULONG), scan context parameters
Output buffer:     [CLS_SCAN_CONTEXT (0x38 bytes)] [CLS_CONTAINER_INFORMATION[N] (0x240 bytes each)]

Vulnerable Code Path

// CClfsRequest::ScanContainers:
//   User-supplied ContainerCount from IOCTL input
//   Calculated buffer requirement:
output_size = ContainerCount * sizeof(CLS_CONTAINER_INFORMATION);  // 0x240 * N
//   BUT: the output buffer also contains a CLS_SCAN_CONTEXT header (0x38 bytes):
//   Actual buffer layout: [0x38-byte header][0x240-byte entry #0][...][0x240-byte entry #N-1]
//   
//   No check: output_size + 0x38 <= MDL_output_buffer_length ?
//
//   When writing entry #N-1:
write_address = output_buffer + 0x38 + (N-1) * 0x240;
//   If ContainerCount is crafted such that:
//   (ContainerCount-1) * 0x240 + 0x38 > MDL_buffer_size
//   → writes 0x240 bytes past the end of the output MDL mapping

CLS_SCAN_CONTEXT Structure (0x38 bytes)

typedef struct _CLS_SCAN_CONTEXT {
    CLFS_NODE_ID      cidNode;         // +0x00: type + size
    HANDLE            hLog;            // +0x08: log file handle
    ULONG             cIndex;          // +0x10: current scan position
    ULONG             cContainers;     // +0x14: containers per scan
    ULONG             cContainersReturned; // +0x18
    CLS_LOG_INFORMATION_CLASS eInformation; // +0x1C
    CLS_CONTAINER_INFORMATION pinfoContainer; // +0x20: starts at +0x20, size 0x18?
    // ...total 0x38 bytes
} CLS_SCAN_CONTEXT, *PCLS_SCAN_CONTEXT;

CLS_CONTAINER_INFORMATION Structure (0x240 bytes)

typedef struct _CLS_CONTAINER_INFORMATION {
    ULONG             FileAttributes;   // +0x000
    ULONGLONG         CreationTime;     // +0x008
    ULONGLONG         LastAccessTime;   // +0x010
    ULONGLONG         LastWriteTime;    // +0x018
    LONGLONG          ContainerSize;    // +0x020
    ULONG             FileNameActualLength; // +0x028
    ULONG             FileNameLength;   // +0x02C
    WCHAR             FileName[ANYSIZE_ARRAY]; // +0x030: up to 0x210 bytes
    CLFS_CONTAINER_STATE State;         // overlaps FileName tail region
    ULONG             PhysicalContainerId;
    ULONG             LogicalContainerId;
    // ...total 0x240 bytes
} CLS_CONTAINER_INFORMATION, *PCLS_CONTAINER_INFORMATION;

The overflow writes: container State flags + PhysicalContainerId + LogicalContainerId + FileName tail (attacker-controlled container file names) — partially controlled OOB write data.


Exploitation Approach

OOB Write Target

The output MDL maps to a kernel buffer. The OOB write lands at (MDL_mapped_va + MDL_size) — the next kernel pool allocation after the output buffer.

Grooming: Create output buffers of known size. The adjacent pool allocation can be a target object (pipe attribute, registry value buffer, etc.) whose fields overlap with the OOB write offset.

Controlled Data in OOB Region

The FileName field of CLS_CONTAINER_INFORMATION is populated from actual container file names. By creating containers with carefully crafted names, the attacker partially controls what data is written OOB. Specifically:

  • State (ULONG): container state flags — not fully controlled
  • PhysicalContainerId/LogicalContainerId (ULONGs): container IDs — sequential, predictable
  • FileName tail: WCHAR string from attacker-named container file — controlled up to ~0x200 bytes

Affected API

// User-mode trigger:
BOOL CreateLogContainerScanContext(
    HANDLE hLog,
    ULONG cFromContainer,
    ULONG cContainers,          // ← ContainerCount — attacker controls
    CLS_LOG_INFORMATION_CLASS eInformation,
    PCLS_SCAN_CONTEXT pScanContext,
    LPOVERLAPPED pOverlapped
);

// Then: ScanLogContainers() issues IOCTL 0x80076816 with ContainerCount in input

Notes

  • Requires medium integrity (any standard user account)
  • No special kernel object or prior info leak required to trigger the OOB
  • Partially controlled data limits exploitation compared to fully controlled OOB writes
  • Full exploit PoC not publicly available as of 2026-04-10

References

  • CVE-2026-20820 root cause analysis (raw_sources in this knowledge base)
  • Microsoft MSRC — CVE-2026-20820 advisory