Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: updated realloc stuff

...

In this noncompliant example, a diagnostic is required because realloc() may free c_str1 when it returns a null pointer, resulting in c_str1 being freed twice.  The committee response to Defect Report #400 makes it implementation-defined whether the old object is deallocated if size is zero and memory for the new object is not allocated, and the current implementation of realloc() in glibc will free c_str1 and return a null pointer for zero byte allocations.  Freeing a pointer twice can result in a potentially exploitable vulnerability commonly referred to as a "double-free exploit" [Seacord 2013].

Code Block
bgColor#FFCCCC
langc
#include <stdlib.h>
 
void f(char *c_str1, size_t size) {
  char *c_str2 = (char *)realloc(c_str1, size);
  if (c_str2 == NULL) {
    free(c_str1); // diagnostic required
    return;
  }
}

Compliant Solution

This compliant solution does not pass a size argument of zero to the realloc() function, eliminating the possibility of c_str1 being freed twice. 

Code Block
bgColor#ccccff
langc
#include <stdlib.h>
 
void f(char *c_str1, size_t size) {
  if (size != 0) {
    char *c_str2 = (char *)realloc(c_str1, size); 
    if (c_str2 == NULL) {
      free(c_str1); 
    }
  }
  return;
}

Noncompliant Code Example

In this noncompliant example (CVE-2009-1364) from libwmf version 0.2.8.4, the return value of gdRealloc (a simple wrapper around realloc that reallocates space pointed to by im->clip->list) is set to more. However, the value of im->clip->list is used directly afterwards in the code, and the C Standard specifies that if realloc moves the area pointed to, then the original is freed. An attacker can then execute arbitrary code by forcing a reallocation (with a sufficient im->clip->count) and accessing freed memory [xorl 2009].

Code Block
bgColor#FFCCCC
langc
void gdClipSetAdd(gdImagePtr im,gdClipRectanglePtr rect) {
  gdClipRectanglePtr more;
  if (im->clip == 0) {
   /* ... */
  }
  if (im->clip->count == im->clip->max) {
    more = gdRealloc (im->clip->list,(im->clip->max + 8) *
                      sizeof (gdClipRectangle));
    /*
     * If the realloc fails, then we have not lost the
     * im->clip->list value.
     */
    if (more == 0) return; 
    im->clip->max += 8;
  }
  im->clip->list[im->clip->count] = (*rect);
  im->clip->count++;

Compliant Solution

The compliant solution simply reassigns im->clip->list to the value of more after the call to realloc:

Code Block
bgColor#ccccff
langc
void gdClipSetAdd(gdImagePtr im,gdClipRectanglePtr rect) {
  gdClipRectanglePtr more;
  if (im->clip == 0) {
    /* ... */
  }
  if (im->clip->count == im->clip->max) {
    more = gdRealloc (im->clip->list,(im->clip->max + 8) *
                      sizeof (gdClipRectangle));
    if (more == 0) return;
    im->clip->max += 8;
    im->clip->list = more;
  }
  im->clip->list[im->clip->count] = (*rect);
  im->clip->count++;

Noncompliant Code Example

In this example, an object is referred to outside of its lifetime:

Code Block
bgColor#FFCCCC
langc
int *get_ptr(void) {
  int obj = 12;
  return &obj;
}
 
void func(void) {
  int *ptr = get_ptr();
  *ptr = 42;
}

Compliant Solution

In this compliant solution, allocated storage is used instead of automatic storage for the pointer:

...