Detecting Memory Corruption

One of the
primary debugging facilities of the allocator is that it includes algorithms
to recognize data corruption quickly. When corruption is detected, the allocator
immediately panics the system.

This section describes how the allocator recognizes data corruption;
you must understand this to be able to debug these problems. Memory abuse
typically falls into one of the following categories:

Writing past the end of a buffer

Accessing uninitialized data

Continuing to use a freed buffer

Corrupting kernel memory

Keep these problems in mind as you read the next three sections. They
will help you to understand the allocator's design, and enable you to diagnose
problems more efficiently.

Freed Buffer Checking: 0xdeadbeef

When
the KMF_DEADBEEF (0x2) bit is set in the flags field of
a kmem_cache, the allocator tries to make memory corruption
easy to detect by writing a special pattern into all freed buffers. This
pattern is 0xdeadbeef. Since a typical region of memory
contains both allocated and freed memory, sections of each kind of block will
be interspersed; here is an example from the "kmem_alloc_24" cache:

The buffer beginning at 0x70a9add8 is filled with
the 0xdeadbeef pattern, which is an immediate indication
that the buffer is currently free. At 0x70a9ae28 another
free buffer begins; at 0x70a9ae00 an allocated buffer is
located between them.

Note -

You might have observed that there are some holes on this picture,
and that 3 24-byte regions should occupy only 72 bytes of memory, instead
of the 120 bytes shown here. This discrepancy is explained in the next section "Redzone: 0xfeedface".

Redzone: 0xfeedface

The pattern 0xfeedface appears frequently in the buffer above. This pattern is known
as the "redzone" indicator. It enables the allocator (and a programmer
debugging a problem) to determine if the boundaries of a buffer have been
violated by "buggy" code. Following the redzone is some additional
information. The contents of that data depends upon other factors (see "Memory Allocation Logging"). The redzone and its suffix are collectively called
the buftag region.Figure 6-1 summarizes this information.

Figure 6-1 The Redzone

The buftag is appended to each buffer in a cache when any of the KMF_AUDIT, KMF_DEADBEEF, KMF_REDZONE, or KMF_CONTENTS flags are set in that buffer's
cache. The contents of the buftag depend on whether KMF_AUDIT
is set.

Decomposing the memory region presented above into distinct buffers
is now simple:

In the free buffers at 0x70a9add8 and 0x70a9ae28, the redzone is filled with 0xfeedfacefeedface.
This a convenient way of determining that a buffer is free.

In the allocated buffer beginning at 0x70a9ae00,
the situation is different. Recall from "Allocator Basics" that
there are two allocation types:

1) The client requested memory using kmem_cache_alloc(),
in which case the size of the requested buffer is equal to the bufsize of
the cache.

2) The client requested memory using kmem_alloc(9F), in which
case the size of the requested buffer is less than or equal to the bufsize
of the cache. For example, a request for 20 bytes will be fulfilled from
the kmem_alloc_24 cache. The allocator enforces the
buffer boundary by placing a marker, the redzone byte,
immediately following the client data:

0xfeedface at 0x70a9ae18 is followed
by a 32-bit word containing what seems to be a random value. This number
is actually an encoded representation of the size of the buffer. To decode
this number and find the size of the allocated buffer, use the formula:

size = redzone_value / (UINT_MAX / KMEM_MAXBUF)

The value of KMEM_MAXBUF is 16384,
and the value of UINT_MAX is 4294967295. So, in this
example,

size = 0x4fffed / (4294967295 / 16384) = 20 bytes.

This indicates that the buffer requested was of size 20 bytes. The
allocator performs this decoding operation and finds that the redzone byte
should be at offset 20. The redzone byte is the hex pattern 0xbb, which is present at 0x729084e4 (0x729084d0 + 0t20)
as expected.

Figure 6-2 Sample kmem_alloc(9F) Buffer

Figure 6-3 Redzone Byte

If the allocation size is the same as the bufsize of the cache, the
redzone byte overwrites the first byte of the redzone itself, as shown in Figure 6-4.

Figure 6-4 Redzone Byte at the Beginning of the Redzone

This overwriting results in the first 32-bit word of the redzone being 0xbbedface, or 0xfeedfabb depending on the endianness
of the hardware on which the system is running.

Note -

Why is the allocation size encoded this way? To encode the size, the
allocator uses the formula ((UINT_MAX / KMEM_MAXBUF) * size + 1). When the
size decode occurs, the integer division discards the remainder of '+1'.
However, the addition of 1 is valuable because the allocator can check whether
the size is valid by testing whether (size % (UINT_MAX / KMEM_MAXBUF) == 1).
In this way, the allocator defends against corruption of the redzone byte
index.

Uninitialized Data: 0xbaddcafe

You might be wondering
what the suspicious 0xbbddcafe at address 0x729084d4 was before the redzone byte got placed over
the first byte in the word. It was 0xbaddcafe. When the KMF_DEADBEEF flag is set in the cache, allocated but uninitialized memory is filled with the 0xbaddcafe
pattern. When the allocator performs an allocation, it loops across the words
of the buffer and verifies that each word contains 0xdeadbeef,
then fills that word with 0xbaddcafe.

The allocator was able to detect this case because it tried to validate
that the buffer in question was filled with 0xdeadbeef.
At offset 0x30, this condition was not met. Since this
condition indicates memory corruption, the allocator panicked the system.

Another example failure message is:

kernel memory allocator: redzone violation: write past end of buffer

The allocator was able to detect this case because it tried to validate
that the redzone byte (0xbb) was in the location it determined
from the redzone size encoding. It failed to find the signature byte in the
correct location. Since this indicates memory corruption, the allocator panicked
the system. Other allocator panic messages are discussed later.