sys_heap: perform cheap overflow detection on freed memory

Make the LEFT_SIZE field first and SIZE_AND_USED field last (for an
allocated chunk) so they sit right next to the allocated memory. The
current chunk's SIZE_AND_USED field points to the next (right) chunk,
and from there the LEFT_SIZE field should point back to the current
chunk. Many trivial memory overflows should trip that test.

One way to make this test more robust could involve xor'ing the values
within respective accessor pairs. But at least the fact that the size
value is shifted by one bit already prevent fooling the test with a
same-byte corruption.

Signed-off-by: Nicolas Pitre <npitre@baylibre.com>
This commit is contained in:
Nicolas Pitre 2019-09-26 15:55:50 -04:00 committed by Carles Cufí
parent cb3d460a2c
commit 74fbca412a
2 changed files with 15 additions and 1 deletions

View file

@ -112,6 +112,20 @@ void sys_heap_free(struct sys_heap *heap, void *mem)
chunkid_t c = ((uint8_t *)mem - chunk_header_bytes(h)
- (uint8_t *)chunk_buf(h)) / CHUNK_UNIT;
/*
* This should catch many double-free cases.
* This is cheap enough so let's do it all the time.
*/
__ASSERT(chunk_used(h, c),
"unexpected heap state (double-free?) for memory at %p", mem);
/*
* It is easy to catch many common memory overflow cases with
* a quick check on this and next chunk header fields that are
* immediately before and after the freed memory.
*/
__ASSERT(left_chunk(h, right_chunk(h, c)) == c,
"corrupted heap bounds (buffer overflow?) for memory at %p", mem);
/* Merge with right chunk? We can just absorb it. */
if (!chunk_used(h, right_chunk(h, c))) {
chunkid_t rc = right_chunk(h, c);

View file

@ -51,7 +51,7 @@ typedef size_t chunkid_t;
typedef struct { char bytes[CHUNK_UNIT]; } chunk_unit_t;
enum chunk_fields { SIZE_AND_USED, LEFT_SIZE, FREE_PREV, FREE_NEXT };
enum chunk_fields { LEFT_SIZE, SIZE_AND_USED, FREE_PREV, FREE_NEXT };
struct z_heap_bucket {
chunkid_t next;