This security snippet deals with CWE-190 “Integer Overflow or Wraparound” described in https://cwe.mitre.org/data/definitions/190.html
The problem description for this weakness enumeration states:
An integer overflow or wraparound occurs when an integer value is incremented to a value that is too large to store in the associated representation. When this occurs, the value may wrap to become a very small or negative number. While this may be intended behavior in circumstances that rely on wrapping, it can have security consequences if the wrap is unexpected. This is especially the case if the integer overflow can be triggered using user-supplied inputs. This becomes security-critical when the result is used to control looping, make a security decision, or determine the offset or size in behaviors such as memory allocation, copying, concatenation, etc.
This problem is prevalent in languages exhibiting structural type definitions rather than nominative type definitions for numeric types[1]. Languages such as C which use structural type definitions provide implicit type conversions between numeric types. Furthermore, structural type definitions of numeric types do not allow the programmer to define a type with a programmer-defined range of valid values. Integer types, for instance, generally come in 8 bit, 16 bit, 32 bit and 64 bit types. There are no provisions in C to define an 8 bit type with a range of -10 through 10. The closest one can do is use a signed char type which provides a range of values from -128 through 127. Furthermore, since C uses only structural information to determine a numeric type integer types experience wrap-around when overflowing or underflowing values.
Using nominative types for numeric data types also allows the specification of a particular data range for a type. Thus, two different types using the same bit representation, such as 8 bits, can be kept separate.
The following example of C code is given in CWE-190 as an example of wrap-around issues:
#define JAN 1
#define FEB 2
#define MAR 3
short getMonthlySales(int month) {...}
float calculateRevenueForQuarter(short quarterSold) {...}
int determineFirstQuarterRevenue() {
// Variable for sales revenue for the quarter
float quarterRevenue = 0.0f;
short JanSold = getMonthlySales(JAN); /* Get sales in January */
short FebSold = getMonthlySales(FEB); /* Get sales in February */
short MarSold = getMonthlySales(MAR); /* Get sales in March */
// Calculate quarterly total
short quarterSold = JanSold + FebSold + MarSold;
// Calculate the total revenue for the quarter
quarterRevenue = calculateRevenueForQuarter(quarterSold);
saveFirstQuarterRevenue(quarterRevenue);
return 0;
}
|
This code actually exhibits many faults, as well as a potential wrap-around.
· The macros defining JAN, FEB, and MAR evaluate to integer values which are interpreted as month numbers by the function getMonthlySales. There is no assurance that a value greater than 12 cannot be passed to the function, resulting in erroneous behavior.
· Each month’s sales are limited to a maximum of 32767 which may be too small for the monthly revenue for a business. Furthermore, the total of three months sales numbers is also restricted to a maximum of 32767.
A more correct implementation using Ada, which provides nominative numeric types is:
type Months is (Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec);
type Sales_Count is range 0..2**31;
function getMonthlySales(Month : Months)return Sales_Count;
function calculateRevenueForQuarter(Count : Sales_Count) return float;
procedure determineFirstQuarterRevenue is
JanSold : Sales_Count := getMonthlySales(Jan);
FebSold : Sales_Count := getMonthlySales(Feb);
MarSold : Sales_Count := getMonthlySales(Mar);
Quarter_Sold : Sales_Count;
begin
Quarter_Sold := JanSold + FebSold + MarSold;
saveFirstQuarterRevenue(calulateRevenueForQuarter(Quarter_Sold));
end determineFirstQuarterRevenue;
|
The Ada version implementation shown above defines values for all months and requires the function getMonthlySales to use a parameter of the enumeration type Months, not simply an integer. The C version allows any int value to be passed to the function.
The type Sales_Count is defined to hold any value from 0 through 2^31 (2,147,483,648). Note that this also ensures that a negative sales count cannot be reported. The type Sales_Count will not exhibit wrap-around.
Use of enumerations in C will not provide the same benefits as the Ada enumerated type in the example above. Ada enumerated types are a separate type not implicitly convertible to an integer type, while C enums are simply aliases for int values. The parameter type for the function must still be an int, which does not restrict the parameter values to a set of valid values.
No comments:
Post a Comment