CWE-191, Integer Underflow (Wrap or Wraparound), is the subtraction twin of overflow. The product subtracts one value from another so that the result is less than the minimum allowable integer, producing a value that is not the correct result. MITRE notes this happens in both signed and unsigned cases.
With unsigned types, going below zero wraps to a very large number, which is the form that causes the most trouble in C, C++, Java and C#, the languages MITRE lists.
How it happens
A length minus a header size, with no check that the length is big enough:
// Vulnerable: if len < HEADER, payload_len wraps to a huge value
size_t payload_len = len - HEADER;
memcpy(out, data + HEADER, payload_len);
// Fixed
if (len < HEADER) {
return -1;
}
size_t payload_len = len - HEADER;
The record's examples are all malformed input cases: CVE-2004-0816 (integer underflow in a firewall via a malformed packet), CVE-2004-1002 (a packet with an invalid length), CVE-2005-0199 (long input causes an incorrect length calculation) and CVE-2005-1891 (a malformed icon causes an underflow in a loop counter variable).
What an attacker gains
MITRE lists crashes and resource consumption, including a likelihood of infinite loops when loop indexes are involved. It also lists memory corruption, and arbitrary code execution if the wrap leads to a buffer overflow, though MITRE notes this is usually outside the scope of a program's implicit security policy.
How to find it
MITRE says static analysis (SAST) can find some instances by modelling data flow. Add manual checks: find every subtraction involving a value that came from outside, and ask what stops the left side from being smaller than the right.
How to fix it
The record has no mitigations, so these are general steps.
- Compare before subtracting. Check that the minuend is at least the subtrahend.
- Use checked arithmetic helpers.
- Treat every length field from a packet or file as hostile until it is validated against the actual buffer.
Quick check
What happens to 3 minus 5 with unsigned integers?
It wraps to a very large number, which then looks like a valid, enormous length.