Mercurial > dovecot > original-hg > dovecot-1.2
changeset 7448:45884655c0c4 HEAD
DEBUG: Added buffer overflow checking to alloconly memory pools.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Tue, 01 Apr 2008 20:34:51 +0300 |
parents | 70cf4172af74 |
children | 4607141a6bdc |
files | src/lib/mempool-alloconly.c |
diffstat | 1 files changed, 60 insertions(+), 18 deletions(-) [+] |
line wrap: on
line diff
--- a/src/lib/mempool-alloconly.c Tue Apr 01 20:26:19 2008 +0300 +++ b/src/lib/mempool-alloconly.c Tue Apr 01 20:34:51 2008 +0300 @@ -40,10 +40,17 @@ #define SIZEOF_POOLBLOCK (MEM_ALIGN(sizeof(struct pool_block))) #define POOL_BLOCK_DATA(block) \ - ((char *) (block) + SIZEOF_POOLBLOCK) + ((unsigned char *) (block) + SIZEOF_POOLBLOCK) #define DEFAULT_BASE_SIZE MEM_ALIGN(sizeof(struct alloconly_pool)) +#ifdef DEBUG +# define CLEAR_CHR 0xde +# define SENTRY_COUNT (4*8) +#else +# define CLEAR_CHR 0 +#endif + static const char *pool_alloconly_get_name(pool_t pool); static void pool_alloconly_ref(pool_t pool); static void pool_alloconly_unref(pool_t *pool); @@ -79,17 +86,36 @@ }; #ifdef DEBUG -static void check_nuls(struct pool_block *block) +static void check_sentries(struct pool_block *block) { - const char *data = POOL_BLOCK_DATA(block); - size_t i; + const unsigned char *data = POOL_BLOCK_DATA(block); + size_t i, max_pos, alloc_size, used_size; + + used_size = block->size - block->left; + for (i = 0; i < used_size; ) { + alloc_size = *(size_t *)(data + i); + if (alloc_size == 0 || used_size - i < alloc_size) + i_panic("mempool-alloconly: saved alloc size broken"); + i += MEM_ALIGN(sizeof(alloc_size)); + max_pos = i + MEM_ALIGN(alloc_size + SENTRY_COUNT); + i += alloc_size; - for (i = block->size - block->left; i < block->size; i++) { + for (; i < max_pos; i++) { + if (data[i] != CLEAR_CHR) + i_panic("mempool-alloconly: buffer overflow"); + } + } + + if (i != used_size) + i_panic("mempool-alloconly: used_size wrong"); + + /* The unused data must be NULs */ + for (; i < block->size; i++) { if (data[i] != '\0') i_unreached(); } if (block->prev != NULL) - check_nuls(block->prev); + check_sentries(block->prev); } #endif @@ -153,10 +179,12 @@ /* destroy the last block */ block = apool->block; #ifdef DEBUG - safe_memset(block, 0xde, SIZEOF_POOLBLOCK + apool->block->size); + safe_memset(block, CLEAR_CHR, SIZEOF_POOLBLOCK + apool->block->size); #else - if (apool->clean_frees) - safe_memset(block, 0, SIZEOF_POOLBLOCK + apool->block->size); + if (apool->clean_frees) { + safe_memset(block, CLEAR_CHR, + SIZEOF_POOLBLOCK + apool->block->size); + } #endif #ifndef USE_GC @@ -238,22 +266,34 @@ { struct alloconly_pool *apool = (struct alloconly_pool *)pool; void *mem; + size_t alloc_size; if (unlikely(size == 0 || size > SSIZE_T_MAX)) i_panic("Trying to allocate %"PRIuSIZE_T" bytes", size); - size = MEM_ALIGN(size); +#ifndef DEBUG + alloc_size = MEM_ALIGN(size); +#else + alloc_size = MEM_ALIGN(sizeof(size)) + MEM_ALIGN(size + SENTRY_COUNT); +#endif - if (apool->block->left < size) { + if (apool->block->left < alloc_size) { /* we need a new block */ - block_alloc(apool, size + SIZEOF_POOLBLOCK); + block_alloc(apool, alloc_size + SIZEOF_POOLBLOCK); } mem = POOL_BLOCK_DATA(apool->block) + (apool->block->size - apool->block->left); - apool->block->left -= size; - apool->block->last_alloc_size = size; + apool->block->left -= alloc_size; + apool->block->last_alloc_size = alloc_size; +#ifdef DEBUG + memcpy(mem, &size, sizeof(size)); + mem = PTR_OFFSET(mem, MEM_ALIGN(sizeof(size))); + /* write CLEAR_CHRs to sentry */ + memset(PTR_OFFSET(mem, size), CLEAR_CHR, + MEM_ALIGN(size + SENTRY_COUNT) - size); +#endif return mem; } @@ -325,7 +365,7 @@ size_t base_size, avail_size; #ifdef DEBUG - check_nuls(apool->block); + check_sentries(apool->block); #endif /* destroy all blocks but the oldest, which contains the @@ -335,10 +375,12 @@ apool->block = block->prev; #ifdef DEBUG - safe_memset(block, 0xde, SIZEOF_POOLBLOCK + block->size); + safe_memset(block, CLEAR_CHR, SIZEOF_POOLBLOCK + block->size); #else - if (apool->clean_frees) - safe_memset(block, 0, SIZEOF_POOLBLOCK + block->size); + if (apool->clean_frees) { + safe_memset(block, CLEAR_CHR, + SIZEOF_POOLBLOCK + block->size); + } #endif #ifndef USE_GC free(block);