FastMM4-AVX Integer Overflow in Large Block Allocation
Security Advisory CVE-2026-27123 / GHSA-f6jf-6w84-w2h7. Published: March 4, 2026. Fixed in FastMM4-AVX v1.0.9 (November 26, 2025).
Summary
FastMM4-AVX memory manager before version 1.0.9 is vulnerable to an integer overflow in the
AllocateLargeBlock function. When an application processes attacker-controlled
input that determines an allocation size near High(NativeUInt), the size
calculation wraps to a small value, causing VirtualAlloc to allocate an undersized
buffer. Subsequent writes by the caller produce a heap-based buffer overflow that can lead to
memory corruption, crash, and arbitrary code execution.
Severity: Critical (CVSS 4.0 Score: 9.3)
Vulnerability Details
| CVE ID | CVE-2026-27123 |
|---|---|
| GHSA ID | GHSA-f6jf-6w84-w2h7 |
| Vulnerability Type | Integer Overflow (CWE-190) leading to Heap-based Buffer Overflow (CWE-122) |
| Attack Type | Remote |
| Attack Vector | Network (via application-layer input: file parsing, protocol handling, deserialization) |
| Maintainer | Maxim Masiutin |
| Product | FastMM4-AVX Memory Manager for Delphi and FreePascal |
| Affected Component | AllocateLargeBlock, FastGetMem (Pascal and Assembly
paths) in FastMM4.pas |
| Affected Versions | All versions prior to v1.0.9 |
| Fixed Version | v1.0.9 (November 26, 2025) |
| Impact | Memory Corruption, Heap-based Buffer Overflow, Code Execution, Denial of Service |
CVSS Score
| CVSS Version | Score | Severity | Vector String |
|---|---|---|---|
| CVSS 4.0 | 9.3 | Critical | AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N |
Technical Details
Background
FastMM4-AVX is a high-performance memory manager for 32-bit and 64-bit Delphi and FreePascal
applications. Large block allocations (above roughly 256 KB) are routed through
AllocateLargeBlock, which computes the actual VirtualAlloc size by adding header
overhead and rounding up to granularity boundaries.
Root Cause
The vulnerable size calculation in AllocateLargeBlock:
LLargeUsedBlockSize := (ASize + LargeBlockHeaderSize + LargeBlockGranularity - 1 + BlockHeaderSize) and LargeBlockGranularityMask;
When ASize is close to High(NativeUInt), the addition of header
overhead overflows the unsigned integer, wrapping to a small value. For example, on a 64-bit
system, requesting $FFFFFFFFFFFF0000 bytes causes the sum to wrap to approximately
64 KB. VirtualAlloc allocates this tiny buffer, but the calling code believes it
holds the full multi-exabyte allocation and writes far beyond the buffer end, corrupting heap
memory.
Attack Scenario
- Attacker sends crafted input to a Delphi or FreePascal application (file, network packet, API call, deserialization payload)
- Application reads a size field from the input and calls
GetMem(size),SetLength(arr, size), or another allocation API - The size value near
High(NativeUInt)triggers integer overflow inAllocateLargeBlock VirtualAllocallocates a small buffer, typically around 64 KB- Application writes attacker-controlled data past the buffer end into adjacent heap metadata
- Heap metadata corruption enables arbitrary code execution or process crash
Affected Code Paths
AllocateLargeBlock: primary vulnerable function in both Debug and Release buildsFastGetMemPascal path (FPC/Linux): was missing size check before callingAllocateLargeBlockFastGetMem32-bit assembly path: no overflow guard before large block branchFastGetMem64-bit assembly path: no overflow guard before large block branch
Proof of Concept
All proof-of-concept cases require a build from a revision prior to commit
fa63fde with FastMM4-AVX active.
PoC A: Direct Oversized Allocation (64-bit)
Request a size near High(NativeUInt) and check whether a pointer is returned:
program PocOverflowA;
{$APPTYPE CONSOLE}
uses FastMM4;
var p: Pointer;
begin
p := GetMem(NativeUInt($FFFFFFFFFFFF0000));
if p <> nil then
begin
Writeln('VULNERABLE: pointer returned');
FreeMem(p);
end
else
Writeln('Protected or allocation failed safely');
end.
On a vulnerable build, GetMem returns a non-nil pointer for the tiny
underlying allocation. On a fixed build, it returns nil.
PoC B: Pure Pascal Path (FPC Linux)
Compile the dedicated regression suite with the Pascal-only path to exercise the gap that
motivated commit da01357:
cd Tests/Simple fpc -B -Mdelphi -Tlinux -Px86_64 -dDontUseASMVersion IntegerOverflowTest.dpr ./IntegerOverflowTest
Expected on vulnerable build: one or more overflow checks fail and the test exits with code 1. Expected on fixed build: all overflow checks return nil and the test exits with code 0.
PoC C: Edge Value (Commit 5141af4 Hardening)
This value previously passed the initial guard but triggered a range check error in FPC DEBUG mode:
program PocOverflowC;
{$APPTYPE CONSOLE}
uses FastMM4;
var p: Pointer;
begin
p := GetMem(NativeUInt($FFFFFFFFFFEFFFA9));
if p <> nil then
begin
Writeln('VULNERABLE: returned pointer for dangerous edge value');
FreeMem(p);
end
else
Writeln('Protected: rejected edge value');
end.
Fix Applied in Version 1.0.9
The fix was delivered in three commits on November 26, 2025, covering all affected code paths:
Commit 1: Primary Fix
Added MaxSafeLargeBlockSize constant and pre-calculation guard in
AllocateLargeBlock, plus equivalent guards in the 32-bit and 64-bit assembly
FastGetMem paths. Added Tests/Simple/IntegerOverflowTest.dpr and
updated CI workflow.
- Commit: fa63fde: Add integer overflow protection for large block allocations; add overflow checks in assembly; add IntegerOverflowTest
if ASize > MaxSafeLargeBlockSize then begin Result := nil; Exit; end;
Commit 2: Pascal FastGetMem Path
Added the missing overflow check to the pure Pascal FastGetMem path used by
FPC and Linux builds. Without this commit, the Pascal route could reach
AllocateLargeBlock without the size precheck.
- Commit: da01357: Add overflow check to Pascal FastGetMem path for FPC/Linux
if (ASize > 0) and (NativeUInt(ASize) <= MaxSafeLargeBlockSize) then Result := AllocateLargeBlock(ASize ...) else Result := nil;
Commit 3: Threshold Hardening
Lowered the 64-bit MaxSafeLargeBlockSize threshold from
$FFFFFFFFFFFE0000 to $FFFFFFFFFFE00000 to reject additional edge
values that triggered range check errors in FPC DEBUG builds. Updated CI policy to maintain
DEBUG coverage on Windows.
- Commit: 5141af4: Lower MaxSafeLargeBlockSize to $FFFFFFFFFFE00000 to reject DEBUG-mode edge values
Performance impact: less than 0.01% (one comparison instruction on a path that is never taken for any legitimate allocation size).
Fix Verification
The fix covers four independent code paths. Each path handles both signed-negative and
unsigned-overflow attack values and returns nil in both cases.
Path 1: Pascal AllocateLargeBlock (FastMM4.pas:8811)
The parameter is NativeUInt, so any signed-negative value passed from a caller
becomes a large unsigned value and is caught by the unsigned comparison:
function AllocateLargeBlock(ASize: NativeUInt; ...): Pointer;
if ASize > MaxSafeLargeBlockSize then {unsigned comparison}
begin
Result := nil;
Exit;
end;
Constants: 32-bit: $FFFE0000; 64-bit: $FFFFFFFFFFE00000.
Path 2: Pascal FastGetMem (FastMM4.pas:9991)
Double guard rejects both signed-negative values and unsigned-overflow values:
if (ASize > 0) and (NativeUInt(ASize) <= MaxSafeLargeBlockSize) then Result := AllocateLargeBlock(ASize ...) else Result := nil;
Path 3: 32-bit Assembly FastGetMem (FastMM4.pas:10652)
test eax,eax plus js rejects signed-negative values (sign flag
set); then unsigned cmp plus ja rejects overflow values:
test eax, eax ; sign bit set = signed-negative attack value js @DontAllocateLargeBlock cmp eax, MaxSafeLargeBlockSize ; unsigned comparison ja @DontAllocateLargeBlock ; JA = Jump if unsigned Above
Path 4: 64-bit Assembly FastGetMem (FastMM4.pas:11373)
Same pattern with 64-bit registers:
xor rax, rax ; pre-set return value to nil test rcx, rcx ; check sign bit js @Done ; reject signed-negative mov r8, MaxSafeLargeBlockSize cmp rcx, r8 ; unsigned comparison ja @Done ; reject unsigned overflow values call AllocateLargeBlock
Coverage Matrix
| Attack Value | 32-bit Signed | 32-bit Unsigned | 64-bit Signed | 64-bit Unsigned |
|---|---|---|---|---|
| -1 ($FF..FF) | Caught by js | Caught by ja | Caught by js | Caught by ja |
| $FFFFFFFFFFFF0000 | N/A (32-bit) | N/A (32-bit) | Caught by js | Caught by ja |
| MaxSafe + 1 | Caught by ja | Caught by ja | Caught by ja | Caught by ja |
| 0 | Returns nil | Returns nil | Returns nil | Returns nil |
| Normal (1 MB) | Passes OK | Passes OK | Passes OK | Passes OK |
Workarounds
Upgrading to v1.0.9 or later is the only complete fix. If upgrading is not immediately possible:
- Validate all allocation sizes in application code before calling
GetMem,ReallocMem, orSetLength. Reject any size that exceeds a reasonable application-specific maximum well belowHigh(NativeUInt). - There is no compile-time option in vulnerable FastMM4-AVX releases that enables the overflow check without patching the source.
- The upstream repository (pleriche/FastMM4) does not contain this fix and remains vulnerable.
CWE Mapping
- CWE-190: Integer
Overflow or Wraparound. The size arithmetic in
AllocateLargeBlockwraps around whenASizeis nearHigh(NativeUInt), causing the computed block size to be far smaller than requested. - CWE-122: Heap-based Buffer Overflow. The undersized allocation from the wrapped size causes subsequent writes by the caller to overflow the heap buffer, corrupting adjacent heap metadata.
Related Issues in Other Software
This vulnerability belongs to a well-documented class of integer overflow bugs in memory allocator size arithmetic. The following CVEs share the same root cause pattern:
- CVE-2017-17426: glibc 2.26 tcache path lacks a needed overflow check near SIZE_MAX, so malloc can return an undersized chunk and later writes trigger heap overflow. NVD
- CVE-2018-6485: glibc posix_memalign or memalign in 2.26 and earlier can overflow internal arithmetic, returning too-small heap memory and enabling heap corruption on use. NVD
- CVE-2018-6551: glibc malloc on powerpc 2.24 to 2.26 and i386 2.26 can mishandle near-SIZE_MAX allocations, returning smaller buffers and causing heap corruption. NVD
- CVE-2021-27502: TI-RTOS HeapMem_allocUnprotected can return a valid pointer for huge sizes after overflow, producing an undersized allocation and possible code execution. NVD
The 2021 CISA BadAlloc advisory documented 25 or more similar overflow bugs across RTOS allocator implementations. CISA ICSA-21-119-04
Timeline
| November 26, 2025 | Vulnerability identified by Maxim Masiutin; fix implemented across three commits (fa63fde, da01357, 5141af4); FastMM4-AVX v1.0.9 released |
|---|---|
| February 15, 2026 | GitHub Security Advisory GHSA-f6jf-6w84-w2h7 created |
| March 4, 2026 | Advisory published; CVE-2026-27123 assigned |
| March 6, 2026 | Developer advisory published at masiutin.net |
Credit
Discovered and fixed by Maxim Masiutin, maintainer of FastMM4-AVX.
Other FastMM4-AVX Security Advisories
| GHSA-3x29-6h9j-vcvm | FPU Stack Corruption in 32-bit Move Procedures (CWE-908, CWE-703, CWE-754). Fixed in v1.0.10. CVSS 4.0: 5.9 Medium. Advisory |
|---|
References
- NVD: CVE-2026-27123
- GitHub Security Advisory GHSA-f6jf-6w84-w2h7
- Fix Commit fa63fde: Primary overflow protection
- Fix Commit da01357: Pascal FastGetMem path
- Fix Commit 5141af4: MaxSafeLargeBlockSize threshold hardening
- FastMM4-AVX GitHub Repository
- Upstream FastMM4 (pleriche/FastMM4)
- CVE-2017-17426: glibc tcache integer overflow
- CVE-2018-6485: glibc posix_memalign integer overflow
- CVE-2018-6551: glibc malloc near-SIZE_MAX overflow
- CVE-2021-27502: TI-RTOS HeapMem integer overflow
- CISA BadAlloc Advisory ICSA-21-119-04
- CWE-190: Integer Overflow or Wraparound
- CWE-122: Heap-based Buffer Overflow
- SEI CERT MEM35-C: Allocate sufficient memory for an object