CVE Patch Review

GHSA-C55G-RP4X-FX84: Root-cause fix for SpriteFont parser integer overflow

GHSA-C55G-RP4X-FX84 · Updated 2026-05-18 Root-cause

Summary

The patch addresses the core arithmetic flaw in DirectX Tool Kit's SpriteFont parsing path by widening the multiplication used in BinaryReader::ReadArray and rejecting byte counts that exceed 32-bit bounds. This directly prevents crafted element counts from wrapping the computed buffer advance on 32-bit targets, which was the condition enabling out-of-bounds access.

Analysis

Vulnerability

GHSA-C55G-RP4X-FX84 describes a 32-bit integer overflow in the DirectX Tool Kit SpriteFont parser. The vulnerable operation is in BinaryReader::ReadArray, where the parser computed the end pointer using a multiplication performed in a width that could wrap on 32-bit architectures. A crafted .spritefont file could supply an attacker-controlled elementCount such that sizeof(T) * elementCount overflowed, causing size validation to be bypassed and enabling heap buffer overflow or out-of-bounds read conditions during parsing.

The relevant vulnerable code from the referenced commit shows the unchecked pointer advance:

uint8_t const* newPos = mPos + sizeof(T) * elementCount;

Because the byte-count calculation was not performed in a sufficiently wide integer type before pointer arithmetic, the parser could derive an incorrect newPos and accept malformed input as if it were in bounds. This matches the advisory's description of integer overflow leading to out-of-bounds access on 32-bit systems.

Sources: commit ef1bd5d7f492c39dd0cd87493ba8ea38725c9791, GitHub Security Advisory, CVE Reports summary.

Patch

The patch changes the byte-count computation to use 64-bit arithmetic and explicitly rejects values that exceed UINT32_MAX before performing pointer advancement. The patched snippet in Src/BinaryReader.h is:

uint64_t byteCount = uint64_t(sizeof(T)) * uint64_t(elementCount);
            if (byteCount > UINT32_MAX)
                throw std::overflow_error("ReadArray");

            uint8_t const* newPos = mPos + static_cast<size_t>(byteCount);

This is a targeted arithmetic hardening change. It removes the overflow primitive by ensuring the multiplication cannot wrap in 32-bit intermediate arithmetic, then fails closed when the requested array size exceeds the supported range. Only after validation does the code convert to size_t for pointer arithmetic.

Review

Pros

  • The patch directly addresses the root arithmetic bug identified in the advisory rather than relying on downstream bounds checks.
  • Using uint64_t for the multiplication prevents wraparound in the intermediate byte-count calculation.
  • The explicit byteCount > UINT32_MAX guard makes the failure mode deterministic and converts malformed input into an exception instead of memory corruption.
  • The change is minimal and localized to the generic array-reading helper, which is likely to protect all parser call sites that depend on ReadArray.

Cons

  • The visible patch snippet only shows overflow prevention for the byte-count computation; it does not by itself demonstrate any broader parser hardening such as format-level sanity limits.
  • The guard is framed around a 32-bit maximum. That aligns with the reported issue, but the snippet alone does not show whether all subsequent comparisons and remaining-size calculations are consistently widened as well.
  • The commit also contains unrelated documentation changes in .github/copilot-instructions.md, which add noise around the security-relevant delta.

Verdict

Root-cause.

The patch fixes the actual vulnerability mechanism documented in the advisory: integer overflow in BinaryReader::ReadArray during byte-count calculation. By widening the multiplication and rejecting oversized results before pointer advancement, it closes the bypass that allowed malformed .spritefont files to evade size validation on 32-bit architectures. Based on the provided diff, this is an appropriate and technically sound remediation for the reported issue.

Sources