Versions Compared

Key

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

...

In this noncompliant code example, integer values returned by parseint(getdata()) are stored into an array of INTBUFSIZE elements of type int called buf [Dowd 2006]. 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
bgColor#FFCCCC
langc
int buf[INTBUFSIZE];
int *buf_ptr = buf;

while (havedata() && buf_ptr < (buf + sizeof(buf))) {
    *buf_ptr++ = parseint(getdata());
}

...

Code Block
bgColor#CCCCFF
langc
int buf[INTBUFSIZE];
int *buf_ptr = buf;

while (havedata() && buf_ptr < &buf[INTBUFSIZE] {
  *buf_ptr++ = parseint(getdata());
}

This solution works because the C standard guarantees Standard guarantees the address of buf[INTBUFSIZE] even though no such element exists.

...

The following example is based on a flaw in the OpenBSD operating system. An integer, skip, is added as an offset to a pointer of type struct big. The adjusted pointer is then used as a destination address in a call to memset(). However, when skip is added to the struct big pointer, it is automatically scaled by the size of struct big, which is 32 bytes (assuming 4-byte integers, 8-byte long long integers, and no structure padding). This scaling results in the call to memset() writing to unintended memory.

Code Block
bgColor#FFCCCC
langc
struct big {
  unsigned long long ull_1; /* typicallyTypically 8 bytes */
  unsigned long long ull_2; /* typicallyTypically 8 bytes */
  unsigned long long ull_3; /* typicallyTypically 8 bytes */
  int si_4; /* typicallyTypically 4 bytes */
  int si_5; /* typicallyTypically 4 bytes */
};
/* ... */
 
int f(void) {
  size_t skip = offsetof(struct big, ull_2);
  struct big *s = (struct big *)malloc(sizeof(struct big));
  if (!s) {
   return -1; /* Indicate malloc() failure */
  }

  memset(s + skip, 0, sizeof(struct big) - skip);
  /* ... */
  free(s);
  s = NULL;

  
  return 0;
}

A similar situation occurred in OpenBSD's make command [Murenin 2007].

...

Code Block
bgColor#CCCCFF
langc
struct big {
  unsigned long long ull_1; /* typicallyTypically 8 bytes */
  unsigned long long ull_2; /* typicallyTypically 8 bytes */
  unsigned long long ull_3; /* typicallyTypically 8 bytes */
  int si_4; /* typicallyTypically 4 bytes */
  int si_5; /* typicallyTypically 4 bytes */
};
/* ... */
 
int f(void) {
  size_t skip = offsetof(struct big, ull_2);
  struct big *s = (struct big *)malloc(sizeof(struct big));
  if (!s) {
    return -1; /* Indicate malloc() failure */
  }

  memset((char *)s + skip, 0, sizeof(struct big) - skip);
/* ... */
  free(s);
  s = NULL;

 
  return 0;
}

Risk Assessment

...