CWE-197, Numeric Truncation Error, occurs when a primitive is cast to a smaller primitive and data is lost. The high order bits of the larger value disappear, and what remains may be nothing like the original. It affects C, C++, Java and C#.
How it happens
MITRE notes the truncated value may be needed as an index into a buffer, a loop iterator, or state data. Whatever its role, it can no longer be trusted and the system is in an undefined state. Truncation to isolate low bits is a legitimate technique, but MITRE says that is rare, and truncation usually implies an implementation error.
// Vulnerable: 64 bit length truncated to 32 bits
uint64_t len = input_length; // 0x100000010
uint32_t n = (uint32_t)len; // 16
char *buf = malloc(n);
memcpy(buf, input, len); // copies far more than allocated
// Fixed
if (len > UINT32_MAX) {
return -1;
}
uint32_t n = (uint32_t)len;
The record's examples show how this plays out. CVE-2020-17087 is a chain where integer truncation caused a small buffer allocation, leading to an out of bounds write in kernel pool, exploited in the wild per CISA KEV. CVE-2009-0231 is integer truncation of a length value leading to a heap based buffer overflow. CVE-2008-3282 involved a type whose size changes on 64 bit platforms, causing truncation in a document processor and an incorrect index.
The last one is a reminder to retest when you move to a new architecture.
What an attacker gains
MITRE lists integrity: the true value of the data is lost and corrupted data is used. The chains above show the practical end result, memory corruption.
How to find it
MITRE lists fuzzing and automated static analysis (SAST). Fuzzing with very large inputs is especially useful, since truncation shows up only when a value is bigger than the narrow type. Compiler warnings for narrowing conversions help in review.
How to fix it
The record has no mitigations, so these are general steps.
- Use one wide enough type end to end for sizes and lengths.
- Range check before any narrowing cast.
- Use fixed width types so a change of platform does not change sizes.
- Test with inputs at and beyond the narrow type's limit.
Quick check
Why do truncation bugs show up after a move to 64 bit?
Some types change size. Code that used to fit may now be narrowed in places the developer never considered.