UFM.FFM.MIGHT
Freed memory may be freed again
If memory is used or referenced after it's been freed, or if it's freed twice, results can be unpredictable. Memory reference problems can cause the use of unexpected values, which in turn can cause programs to crash or execute arbitrary code.
Use-after-free or double-free memory errors typically occur in error conditions or exceptions, unresolved race conditions, or when there's confusion of responsibility for memory between different parts of the program. The UFM checkers find instances of various use-after-free and double-free memory situations in code. The UFM.FFM.MIGHT checker flags situations in which already freed memory may be freed again.
Vulnerability and risk
Memory reference issues can prove to be critical problems. Using previously freed memory can result in corruption of valid data or execution of arbitrary code, depending on the specific situation. When memory is freed, its contents can remain intact and accessible if it isn't reallocated or recycled. The data at the freed location may seem to be valid, but it can change unexpectedly, and cause unintended code behavior.
If memory is allocated to another pointer at some time after it's been freed and the original pointer is used again, it can point to a location in the new allocation. As the data is changed, it can corrupt the validly used memory and result in undefined actions. If a function pointer is overwritten with an address to valid code, a malicious user can cause execution of arbitrary code.
When a program frees the same memory twice, the memory management data structures become corrupted, causing the program to crash or return the same pointer in two later function calls. In this case, an attacker can achieve control over the data that's written into the doubly-allocated memory, which then becomes vulnerable to a buffer overflow attack.
Mitigation and prevention
To avoid memory reference problems:
- Set pointers to null once they're freed.
- Make sure global variables are freed only once.
- Be particularly careful freeing memory in a loop or condiitonal statement, and when you're using the realloc function.
- Ensure that clean-up routines respect the state of memory allocation.
Vulnerable code example
#include <stdlib.h>
struct foo {
int s1;
};
int free_freed(void) {
int found;
int i;
struct foo *x;
x = (struct foo *) calloc(1, sizeof(struct foo));
if (x == NULL)
return 0;
found = rand();
if (found == 0) {
i = x->s1;
free(x);
} else {
found = x->s1;
}
free(x);
return 0;
}
Klocwork produces a report indicating that the memory pointed by 'x' is freed at line 21, after it was already freed at line 17. Typically, memory is allocated and freed at points further removed in the code than in this example, making it difficult to recognize the situation. In any case, the results of freeing already freed memory can be unpredictable and often critical.
Related checkers
External guidance
- CERT EXP54-CPP: Do not access an object outside of its lifetime
- CERT MEM00-C: Allocate and free memory in the same module, at the same level of abstraction
- CERT MEM30-C: Do not access freed memory
- CERT MEM50-CPP: Do not access freed memory
- CWE-415: Double Free
- CWE-416: Use After Free
- CWE-672: Operation on a Resource after Expiration or Release
Security training
Application security training materials provided by Secure Code Warrior.