If an integer expression is compared to, or assigned to, a larger integer size, that integer expression should be evaluated in that larger size by explicitly casting one of the operands.
This code example is non-compliant on systems where size_t is an unsigned 32-bit value and long long is a 64-bit value. In this example, the programmer tests for integer overflow by comparing SIZE_MAX to length + BLOCK_HEADER_SIZE. Because length is declared as size_t, the addition is performed as a 32-bit operation and can result in an integer overflow. The comparison with SIZE_MAX in this example will always test false. If an overflow occurs, malloc() will allocate insufficient space for mBlock, which can lead to a subsequent buffer overflow.
enum { BLOCK_HEADER_SIZE = 16 };
void *AllocateBlock(size_t length) {
struct memBlock *mBlock;
if (length + BLOCK_HEADER_SIZE > (unsigned long long) SIZE_MAX) return NULL;
mBlock
= (struct memBlock *)malloc(length + BLOCK_HEADER_SIZE);
if (!mBlock) return NULL;
/* fill in block header and return data portion */
return mBlock;
}
|
GCC 3.4.4 produces a warning for this non-compliant code example.
In this compliant solution, the length operand is upcast to unsigned long long, ensuring that the addition takes place in this size.
enum { BLOCK_HEADER_SIZE = 16 };
void *AllocateBlock(size_t length) {
struct memBlock *mBlock;
if ((unsigned long long)length + BLOCK_HEADER_SIZE > SIZE_MAX)
return NULL;
mBlock
= (struct memBlock *)malloc(length + BLOCK_HEADER_SIZE);
if (!mBlock) return NULL;
/* fill in block header and return data portion */
return mBlock;
}
|
This test for integer overflow is only effective when the sizeof(unsigned long long) > sizeof(size_t). If both size_t and unsigned long long types are represented as a 64-bit unsigned value, the result of the addition operation may not be representable as an unsigned long long value.
In this compliant solution, the length operand is subtracted from SIZE_MAX, this ensures that no overflow can occur (see INT30-C. Ensure that unsigned integer operations do not wrap).
enum { BLOCK_HEADER_SIZE = 16 };
void *AllocateBlock(size_t length) {
struct memBlock *mBlock;
if (SIZE_MAX - length < BLOCK_HEADER_SIZE) return NULL;
mBlock
= (struct memBlock *)malloc(length + BLOCK_HEADER_SIZE);
if (!mBlock) return NULL;
/* fill in block header and return data portion */
return mBlock;
}
|
In this non-compliant code example, the programmer attempts to prevent integer overflow by allocating an unsigned long long integer called alloc and assigning it the result from cBlocks * 16.
unsigned long long max = UINT_MAX;
/* ... */
void* AllocBlocks(size_t cBlocks) {
if (cBlocks == 0) return NULL;
unsigned long long alloc = cBlocks * 16;
return (alloc < UINT_MAX) ? malloc(cBlocks * 16) : NULL;
}
|
There are two separate problems with this non-compliant code example. The first problem is that this code assumes an implementation where unsigned long long has a least four more bits than size_t. The second problem, assuming an implementation where size_t is a 32-bit value and unsigned long long is represented by a 64-bit value, is that to be compliant with C99, multiplying two 32-bit numbers in this context must yield a 32-bit result. Any integer overflow resulting from this multiplication will remain undetected by this code, and the expression alloc < UINT_MAX will always be true.
In this compliant solution, the cBlocks operand is upcast to unsigned long long, ensuring that the multiplication takes place in this size.
void* AllocBlocks(size_t cBlocks) {
if (cBlocks == 0) return NULL;
unsigned long long alloc = (unsigned long long)cBlocks * 16;
return (alloc < UINT_MAX) ? malloc(cBlocks * 16) : NULL;
}
|
Note that this code does not prevent overflows unless the unsigned long long type is at least four bits larger than size_t.
Failure to cast integers before comparing or assigning them to a larger integer size can result in software vulnerabilities that can allow the execution of arbitrary code by an attacker with the permissions of the vulnerable process.
Rule |
Severity |
Likelihood |
Remediation Cost |
Priority |
Level |
|---|---|---|---|---|---|
INT35-C |
high |
likely |
medium |
P18 |
L1 |
Fortify SCA Version 5.0 with CERT C Rule Pack can detect violations of this rule.
Search for vulnerabilities resulting from the violation of this rule on the CERT website.
\[[Dowd 06|AA. C References#Dowd 06]\] Chapter 6, "C Language Issues" \[[ISO/IEC 9899:1999|AA. C References#ISO/IEC 9899-1999]\] Section 6.3.1, "Arithmetic operands" \[[ISO/IEC PDTR 24772|AA. C References#ISO/IEC PDTR 24772]\] "FLC Numeric Conversion Errors" \[[Seacord 05a|AA. C References#Seacord 05a]\] Chapter 5, "Integer Security" |
INT34-C. Do not shift a negative number of bits or more bits than exist in the operand 04. Integers (INT) 05. Floating Point (FLP)