209 lines
8.8 KiB
XML
209 lines
8.8 KiB
XML
<?xml version='1.0' encoding='utf-8' ?>
|
|
<!DOCTYPE section PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
|
]>
|
|
<section id="sect-Defensive_Coding-C-Allocators">
|
|
<title>Memory allocators</title>
|
|
|
|
<section>
|
|
<title><function>malloc</function> and related functions</title>
|
|
<para>
|
|
The C library interfaces for memory allocation are provided by
|
|
<function>malloc</function>, <function>free</function> and
|
|
<function>realloc</function>, and the
|
|
<function>calloc</function> function. In addition to these
|
|
generic functions, there are derived functions such as
|
|
<function>strdup</function> which perform allocation using
|
|
<function>malloc</function> internally, but do not return
|
|
untyped heap memory (which could be used for any object).
|
|
</para>
|
|
<para>
|
|
The C compiler knows about these functions and can use their
|
|
expected behavior for optimizations. For instance, the compiler
|
|
assumes that an existing pointer (or a pointer derived from an
|
|
existing pointer by arithmetic) will not point into the memory
|
|
area returned by <function>malloc</function>.
|
|
</para>
|
|
<para>
|
|
If the allocation fails, <function>realloc</function> does not
|
|
free the old pointer. Therefore, the idiom <literal>ptr =
|
|
realloc(ptr, size);</literal> is wrong because the memory
|
|
pointed to by <literal>ptr</literal> leaks in case of an error.
|
|
</para>
|
|
<section id="sect-Defensive_Coding-C-Use-After-Free">
|
|
<title>Use-after-free errors</title>
|
|
<para>
|
|
After <function>free</function>, the pointer is invalid.
|
|
Further pointer dereferences are not allowed (and are usually
|
|
detected by <application>valgrind</application>). Less obvious
|
|
is that any <emphasis>use</emphasis> of the old pointer value is
|
|
not allowed, either. In particular, comparisons with any other
|
|
pointer (or the null pointer) are undefined according to the C
|
|
standard.
|
|
</para>
|
|
<para>
|
|
The same rules apply to <function>realloc</function> if the
|
|
memory area cannot be enlarged in-place. For instance, the
|
|
compiler may assume that a comparison between the old and new
|
|
pointer will always return false, so it is impossible to detect
|
|
movement this way.
|
|
</para>
|
|
</section>
|
|
<section>
|
|
<title>Handling memory allocation errors</title>
|
|
<para>
|
|
Recovering from out-of-memory errors is often difficult or even
|
|
impossible. In these cases, <function>malloc</function> and
|
|
other allocation functions return a null pointer. Dereferencing
|
|
this pointer lead to a crash. Such dereferences can even be
|
|
exploitable for code execution if the dereference is combined
|
|
with an array subscript.
|
|
</para>
|
|
<para>
|
|
In general, if you cannot check all allocation calls and
|
|
handle failure, you should abort the program on allocation
|
|
failure, and not rely on the null pointer dereference to
|
|
terminate the process. See
|
|
<xref
|
|
linkend="sect-Defensive_Coding-Tasks-Serialization-Decoders"/>
|
|
for related memory allocation concerns.
|
|
</para>
|
|
</section>
|
|
</section>
|
|
|
|
<section id="sect-Defensive_Coding-C-Allocators-alloca">
|
|
<title><function>alloca</function> and other forms of stack-based
|
|
allocation</title>
|
|
<para>
|
|
Allocation on the stack is risky because stack overflow checking
|
|
is implicit. There is a guard page at the end of the memory
|
|
area reserved for the stack. If the program attempts to read
|
|
from or write to this guard page, a <literal>SIGSEGV</literal>
|
|
signal is generated and the program typically terminates.
|
|
</para>
|
|
<para>
|
|
This is sufficient for detecting typical stack overflow
|
|
situations such as unbounded recursion, but it fails when the
|
|
stack grows in increments larger than the size of the guard
|
|
page. In this case, it is possible that the stack pointer ends
|
|
up pointing into a memory area which has been allocated for a
|
|
different purposes. Such misbehavior can be exploitable.
|
|
</para>
|
|
<para>
|
|
A common source for large stack growth are calls to
|
|
<function>alloca</function> and related functions such as
|
|
<function>strdupa</function>. These functions should be avoided
|
|
because of the lack of error checking. (They can be used safely
|
|
if the allocated size is less than the page size (typically,
|
|
4096 bytes), but this case is relatively rare.) Additionally,
|
|
relying on <function>alloca</function> makes it more difficult
|
|
to reorgnize the code because it is not allowed to use the
|
|
pointer after the function calling <function>alloca</function>
|
|
has returned, even if this function has been inlined into its
|
|
caller.
|
|
</para>
|
|
<para>
|
|
Similar concerns apply to <emphasis>variable-length
|
|
arrays</emphasis> (VLAs), a feature of the C99 standard which
|
|
started as a GNU extension. For large objects exceeding the
|
|
page size, there is no error checking, either.
|
|
</para>
|
|
<para>
|
|
In both cases, negative or very large sizes can trigger a
|
|
stack-pointer wraparound, and the stack pointer and end up
|
|
pointing into caller stack frames, which is fatal and can be
|
|
exploitable.
|
|
</para>
|
|
<para>
|
|
If you want to use <function>alloca</function> or VLAs for
|
|
performance reasons, consider using a small on-stack array (less
|
|
than the page size, large enough to fulfill most requests). If
|
|
the requested size is small enough, use the on-stack array.
|
|
Otherwise, call <function>malloc</function>. When exiting the
|
|
function, check if <function>malloc</function> had been called,
|
|
and free the buffer as needed.
|
|
</para>
|
|
</section>
|
|
|
|
<section id="sect-Defensive_Coding-C-Allocators-Arrays">
|
|
<title>Array allocation</title>
|
|
<para>
|
|
When allocating arrays, it is important to check for overflows.
|
|
The <function>calloc</function> function performs such checks.
|
|
</para>
|
|
<para>
|
|
If <function>malloc</function> or <function>realloc</function>
|
|
is used, the size check must be written manually. For instance,
|
|
to allocate an array of <literal>n</literal> elements of type
|
|
<literal>T</literal>, check that the requested size is not
|
|
greater than <literal>((size_t) -1) / sizeof(T)</literal>. See
|
|
<xref linkend="sect-Defensive_Coding-C-Arithmetic"/>.
|
|
</para>
|
|
</section>
|
|
|
|
<section id="sect-Defensive_Coding-C-Allocators-Custom">
|
|
<title>Custom memory allocators</title>
|
|
<para>
|
|
Custom memory allocates come in two forms: replacements for
|
|
<function>malloc</function>, and completely different interfaces
|
|
for memory management. Both approaches can reduce the
|
|
effectiveness of <application>valgrind</application> and similar
|
|
tools, and the heap corruption detection provided by GNU libc, so
|
|
they should be avoided.
|
|
</para>
|
|
<para>
|
|
Memory allocators are difficult to write and contain many
|
|
performance and security pitfalls.
|
|
</para>
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para>
|
|
When computing array sizes or rounding up allocation
|
|
requests (to the next allocation granularity, or for
|
|
alignment purposes), checks for arithmetic overflow are
|
|
required.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
Size computations for array allocations need overflow
|
|
checking. See <xref
|
|
linkend="sect-Defensive_Coding-C-Allocators-Arrays"/>.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
It can be difficult to beat well-tuned general-purpose
|
|
allocators. In micro-benchmarks, pool allocators can show
|
|
huge wins, and size-specific pools can reduce internal
|
|
fragmentation. But often, utilization of individual pools
|
|
is poor, and external fragmentation increases the overall
|
|
memory usage.
|
|
</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
</section>
|
|
|
|
<section>
|
|
<title>Conservative garbage collection</title>
|
|
<para>
|
|
Garbage collection can be an alternative to explicit memory
|
|
management using <function>malloc</function> and
|
|
<function>free</function>. The Boehm-Dehmers-Weiser allocator
|
|
can be used from C programs, with minimal type annotations.
|
|
Performance is competitive with <function>malloc</function> on
|
|
64-bit architectures, especially for multi-threaded programs.
|
|
The stop-the-world pauses may be problematic for some real-time
|
|
applications, though.
|
|
</para>
|
|
<para>
|
|
However, using a conservative garbage collector may reduce
|
|
opertunities for code reduce because once one library in a
|
|
program uses garbage collection, the whole process memory needs
|
|
to be subject to it, so that no pointers are missed. The
|
|
Boehm-Dehmers-Weiser collector also reserves certain signals for
|
|
internal use, so it is not fully transparent to the rest of the
|
|
program.
|
|
</para>
|
|
</section>
|
|
</section>
|
|
|