...
Noncompliant Code Example
In this noncompliant code example, integer values returned by {{Wiki Markup parseint(getdata())}} are stored into an array of {{INTBUFSIZE}} elements of type {{int}} called {{buf}} \ [[Dowd 2006|AA. Bibliography#Dowd 06]\]. If data is available for insertion into {{buf}} (which is indicated by {{havedata()}}) and {{buf_ptr}} has not been incremented past {{buf + sizeof(buf)}}, an integer value is stored at the address referenced by {{buf_ptr}}. However, the {{sizeof}} operator returns the total number of bytes in {{buf}}, which is typically a multiple of the number of elements in {{buf}}. This value is scaled to the size of an integer and added to {{buf}}. As a result, the check to make sure integers are not written past the end of {{buf}} is incorrect and a buffer overflow is possible.
| Code Block | ||||
|---|---|---|---|---|
| ||||
int buf[INTBUFSIZE];
int *buf_ptr = buf;
while (havedata() && buf_ptr < (buf + sizeof(buf))) {
*buf_ptr++ = parseint(getdata());
}
|
...
| Code Block | ||||
|---|---|---|---|---|
| ||||
int buf[INTBUFSIZE];
int *buf_ptr = buf;
while (havedata() && buf_ptr < &buf[INTBUFSIZE] {
*buf_ptr++ = parseint(getdata());
}
|
This works because C99 guarantees the address of {{Wiki Markup buf\[INTBUFSIZE\]}} even though no such element exists.
Noncompliant Code Example
...
| Code Block | ||||
|---|---|---|---|---|
| ||||
struct big {
unsigned long long ull_1; /* typically 8 bytes */
unsigned long long ull_2; /* typically 8 bytes */
unsigned long long ull_3; /* typically 8 bytes */
int si_4; /* typically 4 bytes */
int si_5; /* typically 4 bytes */
};
/* ... */
size_t skip = offsetof(struct big, ull_2);
struct big *s = (struct big *)malloc(sizeof(struct big));
if (!s) {
/* Handle malloc() error */
}
memset(s + skip, 0, sizeof(struct big) - skip);
/* ... */
free(s);
s = NULL;
|
A similar situation occurred in OpenBSD's {{Wiki Markup make}} command \[ [Murenin 2007|AA. Bibliography#Murenin 07]\].
Compliant Solution
To correct this example, the struct big pointer is cast as a char *. This causes skip to be scaled by a factor of 1.
...
Recommendation | Severity | Likelihood | Remediation Cost | Priority | Level |
|---|---|---|---|---|---|
EXP08-C | high | probable | high | P6 | L2 |
Automated Detection
Tool | Version | Checker | Description | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
|
|
...
- A pointer to a 'foo' object has 'foo' as the unit.
- A pointer to
char *has unit 'byte'. - Any
sizeoforoffsetofexpression also has unit 'byte'.unmigrated-wiki-markup - Any variable used in an index to an array of {{
foo}} objects (eg {{foo\[variable\]}}) has '{{foo}}' as the unit.
In addition to pointer arithmetic expressions, one can also hunt for array index expressions, as {{Wiki Markup array\[index\]}} is merely shorthand for '{{array + index}}'.
Related Vulnerabilities
Search for vulnerabilities resulting from the violation of this rule on the CERT website.
...
MITRE CWE: CWE-468, "Incorrect Pointer Scaling"
Bibliography
\[[Dowd 2006|AA. Bibliography#Dowd 06]\] Chapter 6, "C Language Issues"
\Wiki Markup
[[Murenin 2007|AA. Bibliography#Murenin 07]\]
...