Versions Compared

Key

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

...

In cases where the memory allocation functions return a non-null pointer, using this pointer results in undefined behavior. Typically the pointer refers to a zero-length block of memory consisting entirely of control structures. Overwriting these control structures will damage the data structures used by the memory manager.

malloc()

Non-Compliant Code Example

The result of calling malloc(0) to allocate 0 bytes is implementation-defined. In this example, a dynamic array of integers is allocated to store size elements. However, if size is zero, the call to malloc(size) may return a reference to a block of memory of size 0 rather than NULL. When data is copied to this location, a heap-buffer overflow occurs.

Code Block
bgColor#FFcccc
list = malloc(size);
if (list == NULL) {
  /* Handle Allocation Error */
}
/* Continue Processing list */

Compliant Code Example

To ensure that zero is never passed as a size argument to malloc(), size is checked to ensure it has a positive value.

Code Block
bgColor#ccccff
if (size <= 0) {
  /* Handle Error */
}
list = malloc(size);
if (list == NULL) {
  /* Handle Allocation Error */
}
/* Continue Processing list */

realloc()

Non-Compliant Code Example

The realloc() function deallocates the old object and returns a pointer to a new object of a specified size. If memory for the new object cannot be allocated, the realloc() function does not deallocate the old object and its value is unchanged. If the realloc() function returns NULL, failing to free the original memory will result in a memory leak. As a result, the following idiom is often recommended for reallocating memory:

...

However, this commonly recommended idiom has problems with zero-length allocations. If the value of nsize in this example is 0, the standard allows the option of either returning a null pointer or returning a pointer to an invalid (e.g., zero-length) object. In cases where the realloc() function frees the memory but returns a null pointer, execution of the code in this example results in a double free.

Implementation Details

If this non-compliant code is compiled with gcc 3.4.6 and linked with libc 2.3.4, invoking realloc(p, 0) returns a non-null pointer to a zero-sized object (the same as malloc(0)). However, if the same code is compiled with either Microsoft Visual Studio Version 7.1 or gcc version 4.1.0 , realloc(p, 0) returns a null pointer, resulting in a double-free vulnerability.

Compliant Code Example

Do not pass a size argument of zero to the realloc() function.

Code Block
bgColor#ccccff
char *p2;
char *p = (char *)malloc(100);
/* ... */
if ( (nsize == 0) || (p2 = (char *)realloc(p, nsize)) == NULL) {
  free(p);
  p = NULL;
  return NULL;
}
p = p2;

Risk Assessment

Assuming that allocating zero bytes results in an error can lead to buffer overflows when zero bytes are allocated. Buffer overflows can be exploited by an attacker to run arbitrary code with the permissions of the vulnerable process.

Recommendation

Severity

Likelihood

Remediation Cost

Priority

Level

MEM04-A

3 (high)

2 (probable)

2 (medium)

P12

L1

Related Vulnerabilities

Search for vulnerabilities resulting from the violation of this rule on the CERT website.

References

Wiki Markup
\[[ISO/IEC 9899-1999|AA. C References#ISO/IEC 9899-1999]\] Section 7.20.3, "Memory Management Functions"
\[[Seacord 05|AA. C References#Seacord 05]\] Chapter 4, "Dynamic Memory Management"

...