Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

Code Block
bgColor#ffcccc
langc
#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
bgColor#ccccff
langc
#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
bgColor#ffcccc
langc
#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
bgColor#ccccff
langc
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'\\';
*pwszTemp++;)

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

Coverity

Include Page
Coverity_V
Coverity_V

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

Klocwork

Include Page
Klocwork_V
Klocwork_V

ABV.ITERATOR SV.TAINTED.LOOP_BOUND

 
LDRA tool suite 
Include Page
LDRA_V
LDRA_V

47 S
476 S
64 X
68 X
69 X

 Partially implemented
PRQA QA-C
Include Page
PRQA_V
PRQA_V
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:2013Arithmetic 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 CWECWE-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

...