...
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
sizeof
oroffsetof
expression 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]\]
...