...
Code Block | ||||
---|---|---|---|---|
| ||||
#include <stdlib.h> static int *table = NULL; static size_t size = 0; int insert_in_table(size_t pos, int value) { if (size < pos) { int *tmp; size = pos + 1; tmp = (int *)realloc(table, sizeof(*table) * size); if (tmp == NULL) { return -1; /* Failure */ } table = tmp; } table[pos] = value; return 0; } |
Compliant Solution
The following compliant solution correctly validates the index pos
by using the <=
operator and avoids modifying size
until it has verified that the call to realloc()
was successful:
Code Block | ||||
---|---|---|---|---|
| ||||
#include <realloc.h>
static int *table = NULL;
static size_t size = 0;
int insert_in_table(size_t pos, int value) {
if (size <= pos) {
int *tmp = (int *)realloc(table, sizeof(*table) *
(pos + 1));
if (tmp == NULL) {
return -1; /* Failure */
}
/* Modify size only after realloc succeeds. */
size = pos + 1;
table = tmp;
}
table[pos] = value;
return 0;
}
|
...
In the following noncompliant code example, the function find()
attempts to iterate over the elements of the flexible array member buf
, starting with the second element. However, because function g()
does not allocate any storage for the member, the expression first++
in find()
attempts to form a pointer just past the end of buf
when there are no elements. This attempt results in undefined behavior 62 .
Code Block | ||||
---|---|---|---|---|
| ||||
#include <stddef.h> struct S { size_t len; char buf[]; /* flexibleFlexible array member */ }; char *find(const struct S *s, int c) { char *first = s->buf; char *last = s->buf + s->len; while (first++ != last) { /* undefinedUndefined behavior */ if (*first == (unsigned char)c) { return first; } } return NULL; } |
...
Code Block | ||||
---|---|---|---|---|
| ||||
struct S { size_t len; char buf[]; /* flexibleFlexible array member */ }; char *find(const struct S *s, int c) { char *first = s->buf; char *last = s->buf + s->len; while (first != last) { /* Avoid incrementing here. */ if (*++first == (unsigned char)c) { return first; } } return NULL; } |
...
In the following noncompliant code example, the function f()
calls fread()
to read nitems
of type wchar_t
, each size
bytes in size, into an array of BUFSIZ
elements, wbuf
. However, the expression used to compute the value of nitems
fails to account for the fact that, unlike the size of char
, the size of wchar_t
may be greater than 1. Thus, fread()
could attempt to form pointers past the end of wbuf
and use them to assign values to nonexisting nonexistent elements of the array. Such an attempt results in undefined behavior 109 . A likely manifestation of this undefined behavior is a classic buffer overflow, which is often exploitable by code injection attacks.
...
Risk Assessment
Accessing out-of-range pointers or array subscripts for writing can result in a buffer overflow and the execution of arbitrary code with the permissions of the vulnerable process or unintended information disclosure.
...
Tool | Version | Checker | Description | ||||||
---|---|---|---|---|---|---|---|---|---|
Compass/ROSE | Could be configured to catch violations of this rule. The way to catch the noncompliant code example is to first hunt for example code that follows this pattern: for (LPWSTR pwszTemp = pwszPath + 2; *pwszTemp != L'\\'; In particular, the iteration variable is a pointer, it gets incremented, and the loop condition does not set an upper bound on the pointer. Once this case is handled, we ROSE can handle cases like the real noncompliant code example, which is effectively the same semantics, just different syntax | ||||||||
| ARRAY_VS_SINGLETON NEGATIVE_RETURNS OVERRUN_STATIC OVERRUN_DYNAMIC | Can detect the access of memory past the end of a memory buffer/array Can detect when the loop bound may become negative Can detect the out-of-bound read/write to array allocated statically or dynamically | |||||||
| ABV.ITERATOR SV.TAINTED.LOOP_BOUND | ||||||||
LDRA tool suite |
| 47 S | Partially implemented | ||||||
PRQA QA-C |
| 3680 3681 3682 3683 3685 (U) 3686 3688 3689 (U) 3690 3692 | Partially implemented |
...
CVE-2008-1517 results from a violation of this rule. Before Mac OSX version 10.5.7, the xnu kernel accessed an array at an unverified , user-input index, allowing an attacker to execute arbitrary code by passing an index greater than the length of the array and therefore accessing outside memory [xorl 2009].
...
ISO/IEC TR 24772:2013 | Arithmetic Wrap-around Error [FIF] Unchecked Array Indexing [XYZ] |
ISO/IEC TS 17961 (Draft) | Forming or using out-of-bounds pointers or array subscripts [invptr] |
MITRE CWE | CWE-119, Failure to constrain operations within the bounds of a memory buffer CWE-121, Stack-based buffer overflow CWE-122, Heap-based buffer overflow CWE-129, Unchecked array indexing CWE-788, Access of memory location after end of buffer CWE-805, Buffer access with incorrect length value |
...