dovecot: DEBUG: Make sure memory allocated from data stack doesn...
dovecot at dovecot.org
dovecot at dovecot.org
Sat Dec 22 03:05:35 EET 2007
details: http://hg.dovecot.org/dovecot/rev/8dc08ad6717c
changeset: 7026:8dc08ad6717c
user: Timo Sirainen <tss at iki.fi>
date: Sat Dec 22 03:01:35 2007 +0200
description:
DEBUG: Make sure memory allocated from data stack doesn't overflow the
buffer.
diffstat:
1 file changed, 103 insertions(+), 42 deletions(-)
src/lib/data-stack.c | 145 +++++++++++++++++++++++++++++++++++---------------
diffs (206 lines):
diff -r 984c05510dbc -r 8dc08ad6717c src/lib/data-stack.c
--- a/src/lib/data-stack.c Sat Dec 22 02:57:44 2007 +0200
+++ b/src/lib/data-stack.c Sat Dec 22 03:01:35 2007 +0200
@@ -29,6 +29,7 @@
#ifdef DEBUG
# define CLEAR_CHR 0xde
+# define SENTRY_COUNT (4*8)
#else
# define CLEAR_CHR 0
#endif
@@ -43,7 +44,7 @@ struct stack_block {
#define SIZEOF_MEMBLOCK MEM_ALIGN(sizeof(struct stack_block))
#define STACK_BLOCK_DATA(block) \
- ((char *) (block) + SIZEOF_MEMBLOCK)
+ ((unsigned char *) (block) + SIZEOF_MEMBLOCK)
/* current_frame_block contains last t_push()ed frames. After that new
stack_frame_block is created and it's ->prev is set to
@@ -153,6 +154,46 @@ static void free_blocks(struct stack_blo
}
}
+#ifdef DEBUG
+static void t_pop_verify(void)
+{
+ struct stack_block *block;
+ unsigned char *p;
+ size_t pos, max_pos, used_size, alloc_size;
+
+ block = current_frame_block->block[frame_pos];
+ pos = block->size - current_frame_block->block_space_used[frame_pos];
+ while (block != NULL) {
+ used_size = block->size - block->left;
+ p = STACK_BLOCK_DATA(block);
+ while (pos < used_size) {
+ alloc_size = *(size_t *)(p + pos);
+ if (used_size - pos < alloc_size)
+ i_panic("data stack: saved alloc size broken");
+ pos += MEM_ALIGN(sizeof(alloc_size));
+ max_pos = pos + MEM_ALIGN(alloc_size + SENTRY_COUNT);
+ pos += alloc_size;
+
+ for (; pos < max_pos; pos++) {
+ if (p[pos] != CLEAR_CHR)
+ i_panic("data stack: buffer overflow");
+ }
+ }
+
+ /* we could verify here that the rest of the buffer contains
+ CLEAR_CHRs, but it would slow us down a bit too much. */
+ max_pos = block->size - pos < SENTRY_COUNT ?
+ block->size - pos : SENTRY_COUNT;
+ for (; pos < max_pos; pos++) {
+ if (p[pos] != CLEAR_CHR)
+ i_panic("data stack: buffer overflow");
+ }
+ block = block->next;
+ pos = 0;
+ }
+}
+#endif
+
unsigned int t_pop(void)
{
struct stack_frame_block *frame_block;
@@ -161,14 +202,23 @@ unsigned int t_pop(void)
if (unlikely(frame_pos < 0))
i_panic("t_pop() called with empty stack");
+#ifdef DEBUG
+ t_pop_verify();
+#endif
+
/* update the current block */
current_block = current_frame_block->block[frame_pos];
+ if (clean_after_pop) {
+ size_t pos, used_size;
+
+ pos = current_block->size -
+ current_frame_block->block_space_used[frame_pos];
+ used_size = current_block->size - current_block->left;
+ memset(STACK_BLOCK_DATA(current_block) + pos, CLEAR_CHR,
+ used_size - pos);
+ }
current_block->left = current_frame_block->block_space_used[frame_pos];
- if (clean_after_pop) {
- memset(STACK_BLOCK_DATA(current_block) +
- (current_block->size - current_block->left), CLEAR_CHR,
- current_block->left);
- }
+
if (current_block->next != NULL) {
/* free unused blocks */
free_blocks(current_block->next);
@@ -225,13 +275,17 @@ static struct stack_block *mem_block_all
block->size = alloc_size;
block->next = NULL;
+#ifdef DEBUG
+ memset(STACK_BLOCK_DATA(block), CLEAR_CHR, alloc_size);
+#endif
return block;
}
static void *t_malloc_real(size_t size, bool permanent)
{
struct stack_block *block;
- void *ret;
+ void *ret;
+ size_t alloc_size;
#ifdef DEBUG
bool warn = FALSE;
#endif
@@ -251,48 +305,55 @@ static void *t_malloc_real(size_t size,
/* allocate only aligned amount of memory so alignment comes
always properly */
- size = MEM_ALIGN(size);
+#ifndef DEBUG
+ alloc_size = MEM_ALIGN(size);
+#else
+ alloc_size = MEM_ALIGN(sizeof(size)) + MEM_ALIGN(size + SENTRY_COUNT);
+#endif
/* used for t_try_realloc() */
- current_frame_block->last_alloc_size[frame_pos] = size;
-
- if (current_block->left >= size) {
+ current_frame_block->last_alloc_size[frame_pos] = alloc_size;
+
+ if (current_block->left >= alloc_size) {
/* enough space in current block, use it */
ret = STACK_BLOCK_DATA(current_block) +
(current_block->size - current_block->left);
if (permanent)
- current_block->left -= size;
- return ret;
- }
-
- /* current block is full, see if we can use the unused_block */
- if (unused_block != NULL && unused_block->size >= size) {
- block = unused_block;
- unused_block = NULL;
+ current_block->left -= alloc_size;
} else {
- block = mem_block_alloc(size);
-#ifdef DEBUG
- warn = TRUE;
-#endif
- }
-
- block->left = block->size;
- if (permanent)
- block->left -= size;
- block->next = NULL;
-
- current_block->next = block;
- current_block = block;
-
- ret = STACK_BLOCK_DATA(current_block);
-#ifdef DEBUG
- if (warn) {
- /* warn later, so that if i_warning() wants to allocate more
- memory we don't go to infinite loop */
- i_warning("Growing data stack with: %"PRIuSIZE_T, block->size);
- }
-#endif
-
+ /* current block is full, see if we can use the unused_block */
+ if (unused_block != NULL && unused_block->size >= alloc_size) {
+ block = unused_block;
+ unused_block = NULL;
+ } else {
+ block = mem_block_alloc(alloc_size);
+#ifdef DEBUG
+ warn = TRUE;
+#endif
+ }
+
+ block->left = block->size;
+ if (permanent)
+ block->left -= alloc_size;
+ block->next = NULL;
+
+ current_block->next = block;
+ current_block = block;
+
+ ret = STACK_BLOCK_DATA(current_block);
+#ifdef DEBUG
+ if (warn) {
+ /* warn after allocation, so if i_warning() wants to
+ allocate more memory we don't go to infinite loop */
+ i_warning("Growing data stack with: %"PRIuSIZE_T,
+ block->size);
+ }
+#endif
+ }
+#ifdef DEBUG
+ memcpy(ret, &size, sizeof(size));
+ ret = PTR_OFFSET(ret, MEM_ALIGN(sizeof(size)));
+#endif
return ret;
}
More information about the dovecot-cvs
mailing list