Versions Compared

Key

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

...

This non-compliant code example shows a double-free vulnerability resulting from memory being allocated and freed at differing levels of abstraction. In this example, memory for the list array is allocatd in the process_list() function. The array is then passed to the verify_list() function that performs error checking on the size of the list. If the size of the list is below a minimum size, the memory allocated to the list is freed and the function returns to the caller. The calling function then frees this same memory again, resulting in a double-free and potentially exploitable vulnerability.

Code Block
bgColor#FFcccc
enum { MIN_SIZE_ALLOWED = 32 };

int verify_size(char *list, size_t size) {
  if (size < MIN_SIZE_ALLOWED) {
    /* Handle Error Condition */
    free(list);
    return -1;
  }
  return 0;
}

void process_list(size_t number) {
  char *list = (char *)malloc(number);

  if (list == NULL) {
    /* Handle Allocation Error */
  }

  if (verify_size(list, number) == -1) {
      free(list);
      return;
  }

  /* Continue Processing list */

  free(list);
}

...

To correct this problem, the the error handling code in verify_list() is modified so that it no longer frees list. This change ensures that list is freed only once, at the same level of abstraction, in the process_list() function.

Code Block
bgColor#ccccff

enum { MIN_SIZE_ALLOWED = 32 };

int verify_size(char const *list, size_t size) {
  if (size < MIN_SIZE_ALLOWED) {
    /* Handle Error Condition */
    return -1;
  }
  return 0;
}

void process_list(size_t number) {
  char *list = (char *)malloc(number);

  if (list == NULL) {
    /* Handle Allocation Error */
  }

  if (verify_size(list, number) == -1) {
      free(list);
      return;
  }

  /* Continue Processing list */

  free(list);
}

...