__mingw_aligned_offset_malloc and __mingw_aligned_offset_realloc
lack an overflow check on the internal size computation and return an
undersized non-NULL buffer for sizes near SIZE_MAX.
Affected:
mingw-w64-crt/misc/mingw-aligned-malloc.c
- `__mingw_aligned_offset_malloc` (and `__mingw_aligned_malloc`, which wraps it)
- `__mingw_aligned_offset_realloc` (and `__mingw_aligned_realloc`, which wraps it)
This is similar to CVE-2026-0861 and CVE-2026-95619.
Class: CWE-190 (Integer Overflow) -> CWE-131 (Incorrect Buffer Size Calculation)
-> CWE-787 (Out-of-bounds Write)
Both functions compute their backing allocation as
malloc (size + (alignment + GAP (offset) + sizeof (void *))); /* malloc */
realloc (p0, size + (alignment + GAP (offset) + sizeof (void *))); /* realloc */
with no check that the addition does not overflow size_t. When size is within alignment + sizeof(void*) - 1 bytes of SIZE_MAX (with offset == 0), the sum wraps to a small value, the underlying allocator succeeds, and a non-NULL, correctly-aligned pointer to a tiny block is returned as if it were the huge size requested. The expected behavior is to fail (return NULL / ENOMEM).
The overflow window scales with the requested alignment. Measured on x86-64:
alignment 32 -> wraps for size > SIZE_MAX - 39 (i.e. (size_t)-39 ..)
alignment 1024 -> wraps for size > SIZE_MAX - 1031
This is the fallback path used when the target CRT does not export
_aligned_malloc, and whenever the __mingw_aligned_* symbols are called directly.
NOTE: native Windows msvcrt.dll / UCRT are NOT affected -- they guard the
addition and correctly return NULL. Wine's msvcrt reimplementation is affected
by the same class of bug, reported as https://bugs.winehq.org/show_bug.cgi?id=60378
#include <malloc.h>
#include <stdio.h>
extern void *__mingw_aligned_malloc(size_t, size_t);
int main(void) {
void *p = __mingw_aligned_malloc((size_t)-1025, 1024);
printf("p = %p\n", p); /* non-NULL: BUG (should be NULL) */
return 0;
}
Expected: p == NULL, errno == ENOMEM.
Observed: p != NULL, pointing at a handful of bytes.
A caller whose size is derived from arithmetic that can reach near-SIZE_MAX
(upstream overflow, (size_t)-1 sentinels, attacker-influenced length math)
receives a valid-looking aligned pointer to an undersized block; subsequent
writes corrupt the heap (CWE-787). The bug also defeats the standard NULL-check
defensive idiom.
N.B. calling __mingw_aligned_msize on the wrapped block returns an incorrect near-SIZE_MAX value rather than the true (tiny) size that was actually allocated, so a caller cannot detect the undersized allocation via the size-query API either. This is a consequence of the same overflow; fixing the malloc/realloc calls resolves it, and __mingw_aligned_msize needs no separate change.