Memory Management in C
Vulnerabilities, Attacks, and Mitigations
|
Prof. David Bernstein
James Madison University
|
|
Computer Science Department |
bernstdh@jmu.edu |
|
Initialization Vulnerabilities
- Recall:
-
free()
does not necessarily initialize memory
(for performance reasons)
-
malloc()
does not necessarily initialize memory
(for performance reasons)
- The programmer needs to initialize memory when it is
appropriate to do so
- A Detail:
- It is common to use
memset()
to clear memory,
but optimizing compilers may remove this call if the memory
isn't accessed following the write
Initialization Vulnerabilities (cont.)
- Potential Harm:
- Confidentiality - leakage of information that was
formerly at that location
- Mitigation:
- Clear sensitive information stored in reusable
resources (e.g., clear sensitive information
before calling
free()
)
- Use
memset_s()
(C11)
- Configure
malloc()
to use randomization
Heap Exhaustion Vulnerabilities
- Definition:
-
Heap exhaustion occurs when the memory manager
is unable to respond to an allocation request
- Consumers of Memory:
- Active data structures
- Leaks
Heap Exhaustion Vulnerabilities (cont.)
- Processes Involved:
- Memory might be used by other processes
- Memory is certainly being used by the process of interest
- A Note About Dereferencing:
- The result of applying
*
(i.e., the unary derefernce
operator) to an invalid address is undefined (i.e.,
it typically results in a segmentation fault but not always)
- A Note About Non-Conforming Implementations:
- A request for a block in excess of the amount available
does not fail; the process is killed when it attempts to
access that memory
Heap Exhaustion Vulnerabilities (cont.)
- Threats:
- Memory Corruption
- Arbitrary Memory Writes - dereferencing an offset from
NULL
might not crash the program but, instead,
give an attacker the ability to write a value into an
arbitrary location in memory
- Corrupted Function Pointers
- Potential Harm:
- Availability (e.g.,
malloc()
returns
NULL
but the program doesn't check and crashes)
when the pointer is dereferenced
- Other (e.g., some embedded systems have a register mapped
at address 0 and some ARM chips uses address 0 for the
exception table and other kinds of harm may be caused
in these cases)
- Mitigation:
- Always check return values
Dangling Pointer Vulnerabilities
- Definition:
- Memory is freed but the pointer to it remains
- A Note:
- Since
free()
is passed a void*
not a void**
it can't reset the pointer
it is passed
- Potential Harm:
- Confidentiality - reading from freed memory results in
undefined behavior but doesn't usually fail
- Integrity - a write to freed memory could write to
memory that has been recycled
Multiple-Free Vulnerabilities
- Defined:
-
free()
is called multiple times
for the same block of memory (i.e., being passed the same
pointer)
- Mitigation:
- Use a single, consistent design (e.g., Caller Allocates/Caller
Frees; Callee Allocates/Caller Frees;
Callee Allocates/Callee Frees)
- Always have
create()
and destroy()
functions
- Always assign
NULL
to pointers after calling free (and
remember that there can be multiple pointers to the
same memory)
- Use
phkmalloc
(which can determine whether a
pointer passed to free()
or realloc()
is valid without dereferencing it)
General Mitigation Strategies
- Have a List of Standard Practices:
- Use Run-Time Analysis Tools During Testing:
- They (e.g., Purify, Valgrind, Insure++, Application
Verifier) may be too slow for production but are very
useful during testing