
...
Noncompliant Code Example
This noncompliant code noncompliant code example demonstrates how performing bitwise operations on integer types smaller than int
may have unexpected results:
...
In this example, a bitwise complement of port
is first computed and then shifted 4 bits to the right. If both of these operations are performed on an 8-bit unsigned integer, then result_8
will have the value 0x0a
. However, port
is first promoted to a signed int
, with the following results (on a typical architecture where type int
is 32 bits wide):
Expression | Type | Value | Notes |
---|---|---|---|
|
|
|
|
|
|
|
|
| Whether or not value is negative is implementation-defined |
|
|
|
Compliant Solution
In this compliant solution, the bitwise complement of port
is converted back to 8 bits. Consequently, result_8
is assigned the expected value of 0x0aU
.
Code Block | ||||
---|---|---|---|---|
| ||||
uint8_t port = 0x5a; uint8_t result_8 = (uint8_t) (~port) >> 4; |
Risk Assessment
Misunderstanding integer conversion rules can lead to errors, which in turn can lead to exploitable vulnerabilities. The major risks occur when narrowing the type (which requires a specific cast or assignment), converting from unsigned to signed, or converting from negative to unsigned.
Recommendation | Severity | Likelihood | Remediation Cost | Priority | Level |
---|---|---|---|---|---|
INT02-C | Medium | Probable | Medium | P8 | L2 |
Automated Detection
Noncompliant Code Example
In this example, a character is iterated from 0 to CHAR_MAX
. However, on a platform where char is signed (such as 32-bit x86), max
is set to 0x80
while i
increments from 0x79
to {{0xffffff80} (aka -127):
Code Block | ||||
---|---|---|---|---|
| ||||
#include <limits.h>
unsigned char max = CHAR_MAX + 1;
for (char i = 0; i < max; ++i) {
printf("i=0x%08x max=0x%08x\n", i, max);
} |
Compliant Solution
There are several ways to rectify this example. One way is to treat both chars as unsigned, which prevents wraparound:
Code Block | ||||
---|---|---|---|---|
| ||||
#include <limits.h>
unsigned char max = CHAR_MAX + 1;
for (unsigned char i = 0; i < max; ++i) {
printf("i=0x%08x max=0x%08x\n", i, max);
} |
Noncompliant Code Example
This noncompliant code example, adapted from the Cryptography Services blog, demonstrates how signed overflow can occur even when it seems that only unsigned types are in use:
Code Block | ||||
---|---|---|---|---|
| ||||
unsigned short x = 45000, y = 50000;
unsigned int z = x * y; |
On implementations where short
is 16 bits wide and int
is 32 bits wide, the program results in undefined behavior due to signed overflow. This is because the unsigned short
s become signed when they are automatically promoted to integer, and their mathematical product (2250000000) is greater than the largest signed 32-bit integer (231 - 1, which is 2147483647).
Compliant Solution
In this compliant solution, by manually casting one of the operands to unsigned int
, the multiplication will be unsigned and so will not result in undefined behavior:
Code Block | ||||
---|---|---|---|---|
| ||||
unsigned short x = 45000, y = 50000;
unsigned int z = x * (unsigned int)y; |
Risk Assessment
Misunderstanding integer conversion rules can lead to errors, which in turn can lead to exploitable vulnerabilities. The major risks occur when narrowing the type (which requires a specific cast or assignment), converting from unsigned to signed, or converting from negative to unsigned.
Recommendation | Severity | Likelihood | Detectable | Repairable | Priority | Level |
---|---|---|---|---|---|---|
INT02-C | Medium | Probable | No | No | P4 | L3 |
Automated Detection
Tool | Version | Checker | Description | ||||||
---|---|---|---|---|---|---|---|---|---|
Astrée |
| Supported | |||||||
CodeSonar |
| ALLOC.SIZE.TRUNC LANG.CAST.COERCE LANG.CAST.VALUE MISC.MEM.SIZE.TRUNC | Truncation of Allocation Size Coercion Alters Value Cast Alters Value Truncation of Size | ||||||
| CC2.INT02 | Fully implemented | |||||||
Helix QAC |
| C1250, C1251, C1252, C1253, C1256, C1257, C1260, C1263, C1266, C1274, C1290, C1291, C1292, C1293, C1294, C1295, C1296, C1297, C1298, C1299, C1800, C1802, C1803, C1804, C1810, C1811, C1812, C1813, C1820, C1821, C1822, C1823, C1824, C1830, C1831, C1832, C1833, C1834, C1840, C1841, C1842, C1843, C1844, C1850, C1851, C1852, C1853, C1854, C1860, C1861, C1862, C1863, C1864, C1880, C1881, C1882, C2100, C2101, C2102, C2103, C2104, C2105, C2106, C2107, C2109, C2110, C2111, C2112, C2113, C2114, C2115, C2116, C2117, C2118, C2119, C2120, C2122, C2124, C2130, C2132, C2134, C4401, C4402, C4403, C4404, C4405, C4410, C4412, C4413, C4414, C4415, C4420, C4421, C4422, C4423, C4424, C4425, C4430, C4431, C4432, C4434, C4435, C4436, C4437, C4440, C4441, C4442, C4443, C4445, C4446, C4447, C4460, C4461, C4463, C4464, C4470, C4471, C4480, C4481 | |||||||
Klocwork |
| MISRA.CAST.INT MISRA.CAST.UNSIGNED_BITS MISRA.CONV.INT.SIGN MISRA.CVALUE.IMPL.CAST MISRA.UMINUS.UNSIGNED PRECISION.LOSS | |||||||
LDRA tool suite |
| 52 S, 93 S, 96 S, 101 S, 107 S, 332 S, 334 S, 433 S, 434 S, 446 S, 452 S, 457 S, 458 S | Fully implemented | ||||||
Parasoft C/C++test |
| CERT_C-INT02-a | Implicit conversions from wider to narrower integral type which may result in a loss of information shall not be used | ||||||
PC-lint Plus |
| 501, 502, 569, 570, 573, | Partially supported | ||||||
Polyspace Bug Finder |
| Checks for sign change integer conversion overflow (rec. fully supported) | |||||||
PVS-Studio |
| V555, V605, V673, V5006 |
Tool
Version
Checker
Description
ALLOC.SIZE.TRUNC
LANG.CAST.COERCE
LANG.CAST.VALUE
MISC.MEM.SIZE.TRUNC
Truncation of Allocation Size
Coercion Alters Value
Cast Alters Value
Truncation of Size
CC2.INT02
Fully implemented
52 S
93 S
96 S
101 S
332 S
334 S
433 S
434 S
442 S
443 S
446 S
452 S
457 S
458 S
491 S
Fully implemented
4402,4403,4404,4405,4410,4412,4413,4414,4415,4420,4421,4422,4423,4424,4425,4430,
4431,4432,4434,4435,4436,4437,4440,4441,4442,4443,4445,4446,4447,
4460,4461,4463,4464,4470,4471,4480,4481,
1250,1251,1252,1253,1260,1263,1274,1800,1802,1803,1804,1810,1811,1812,
1813,1820,1821,1822,1823,1824,1830,1831,1832,1833,1834,1840,1841,1842,
1843,1844,1850,1851,1852,1853,1854,1860,1861,1862,1863,1864,1880,1881,1882,
2100,2101,2102,2103,2104,2105,2106,2107,2109,2110,2111,2112,2113,2114,
2115,2116,2117,2118,2119,2120,2122,2124,2130,2132,2134
Related Vulnerabilities
This vulnerability in Adobe Flash arises because Flash passes a signed integer to calloc()
. An attacker has control over this integer and can send negative numbers. Because calloc()
takes size_t
, which is unsigned, the negative number is converted to a very large number, which is generally too big to allocate, and as a result, calloc()
returns NULL
, causing the vulnerability to exist.
Search for vulnerabilities resulting from the violation of this rule on the CERT website.
Related Guidelines
SEI CERT C++ Coding Standard | VOID INT02-CPP. Understand integer conversion rules |
ISO/IEC TR 24772:2013 | Numeric Conversion Errors [FLC] |
MISRA C:2012 | Rule 10.1 (required) Rule 10.3 (required) Rule 10.4 (required) Rule 10.6 (required) Rule 10.7 (required) Rule 10.8 (required) |
MITRE CWE | CWE-192, Integer coercion error CWE-197, Numeric truncation error |
Bibliography
[Dowd 2006] | Chapter 6, "C Language Issues" ("Type Conversions," pp. 223–270) |
[Seacord 2013] | Chapter 5, "Integer Security" |
...
...