How to Mitigate Integer Overflow and Underflow Vulnerabilities
Introduction to Integer Overflows and Underflows
Integer overflow and underflow vulnerabilities are simple but extremely powerful vulnerabilities. They exist when the value stored within a variable lies outside of the range of values that it is capable of storing. Under these circumstances, the value may be interpreted differently than was intended.
One of the biggest challenges with dealing with integer overflow and underflow vulnerabilities is that they can occur for a wide variety of different reasons. User-controlled values may (intentionally or accidentally) fall outside of the range of acceptable values for a variable. Alternatively, a mismatch between variable types used in an operation can result in an implicit typecast and the incorrect interpretation of a value.
Mitigating Integer Overflow and Underflow Vulnerabilities
Integer overflow and underflow vulnerabilities occur when an application tries to place a value into a variable where it doesn’t fit. As a result, a variable may be interpreted as larger or smaller than it originally was.
This typically becomes a major issue when a variable is interpreted one way in one location and another way in a different location. For example, a variable may be used as a signed int for memory allocation and an unsigned int when copying over data to the newly-allocated memory block. Since unsigned ints can hold larger values than signed ones, it is possible that more data is copied than space is allocated for (even if the bits used in both values are identical).
Different interpretations of values occur when a variable is typecast from one type to another (either explicitly or implicitly). For this reason, it is vital to ensure that a value can be correctly interpreted within a target variable type before casting it over to that type.
The code samples shown above demonstrate safe and unsafe casts between signed and unsigned integers. The value of a in the main function can be safely stored in an unsigned int but not in a signed one. In contrast, a value of -5 can be stored in a signed int but not an unsigned one.
In the vulnerable code on the left, these variables are unsafely cast to the opposite signedness. As a result, when the same value is printed twice – interpreted once as signed and once as unsigned – two different results are produced.
The code on the right is designed to manage typecasting safely. Before typecasting a value, the code checks to ensure that it can actually fit in the target type. If not, the application prints an error message and terminates. This protects the application from unsafely using a value that it has interpreted incorrectly.
Avoiding Integer Overflows and Underflows
Integer overflow and underflow issues typically occur when an application performs unsafe typecasting, whether explicitly or implicitly. Applications should be designed to perform value checks before explicit typecasts and to avoid implicit typecasts – such as comparing variables of different types or passing a signed variable to a function expecting an unsigned one – when possible. This helps to avoid integer overflow or underflow vulnerabilities that could be exploited by an attacker or result in a user accidentally breaking the application.