dovecot-2.2: lib: data-stack - enable tighter sanity checks on s...

dovecot at dovecot.org dovecot at dovecot.org
Mon Jul 28 13:54:27 UTC 2014


details:   http://hg.dovecot.org/dovecot-2.2/rev/b4eec0a20bba
changeset: 17639:b4eec0a20bba
user:      Phil Carmody <phil at dovecot.fi>
date:      Mon Jul 28 16:45:33 2014 +0300
description:
lib: data-stack - enable tighter sanity checks on stack_block allocations
The canary doesn't have to be NULL. That's only effective if it will be read
and dereferenced as a pointer. If used as an integer, it's a perfectly boring
one, and not likely to draw attention to itself.

Once the canary is in place, at least in debug mode, we can check it in
every function as a sanity check.

Make our poison stand out from other poison used elsewhere in the code.

Signed-off-by: Phil Carmody <phil at dovecot.fi>

diffstat:

 src/lib/data-stack.c |  18 ++++++++++++++----
 1 files changed, 14 insertions(+), 4 deletions(-)

diffs (87 lines):

diff -r a5f479be46b9 -r b4eec0a20bba src/lib/data-stack.c
--- a/src/lib/data-stack.c	Mon Jul 28 16:45:33 2014 +0300
+++ b/src/lib/data-stack.c	Mon Jul 28 16:45:33 2014 +0300
@@ -22,19 +22,23 @@
 #endif
 
 #ifdef DEBUG
-#  define CLEAR_CHR 0xde
+#  define CLEAR_CHR 0xD5               /* D5 is mnemonic for "Data 5tack" */
 #  define SENTRY_COUNT (4*8)
+#  define BLOCK_CANARY ((void *)0xBADBADD5BADBADD5)      /* contains 'D5' */
+#  define BLOCK_CANARY_CHECK(block) i_assert((block)->canary == BLOCK_CANARY)
 #else
 #  define CLEAR_CHR 0
+#  define BLOCK_CANARY NULL
+#  define BLOCK_CANARY_CHECK(block) do { ; } while(0)
 #endif
 
 struct stack_block {
 	struct stack_block *next;
 
 	size_t size, left, lowwater;
-	/* always NULL and here just in case something accesses
+	/* NULL or a poison value, just in case something accesses
 	   the memory in front of an allocated area */
-	char *nullpad;
+	void *canary;
 	/* unsigned char data[]; */
 };
 
@@ -192,6 +196,7 @@
 	/* free all the blocks, except if any of them is bigger than
 	   unused_block, replace it */
 	while (block != NULL) {
+		BLOCK_CANARY_CHECK(block);
 		next = block->next;
 
 		if (clean_after_pop)
@@ -223,6 +228,7 @@
 	block = current_frame_block->block[frame_pos];
 	pos = block->size - current_frame_block->block_space_used[frame_pos];
 	while (block != NULL) {
+		BLOCK_CANARY_CHECK(block);
 		used_size = block->size - block->left;
 		p = STACK_BLOCK_DATA(block);
 		while (pos < used_size) {
@@ -264,6 +270,7 @@
 
 	/* update the current block */
 	current_block = current_frame_block->block[frame_pos];
+	BLOCK_CANARY_CHECK(current_block);
 	if (clean_after_pop) {
 		size_t pos, used_size;
 
@@ -332,7 +339,7 @@
 	block->left = 0;
 	block->lowwater = block->size;
 	block->next = NULL;
-	block->nullpad = NULL;
+	block->canary = BLOCK_CANARY;
 
 #ifdef DEBUG
 	memset(STACK_BLOCK_DATA(block), CLEAR_CHR, alloc_size);
@@ -357,6 +364,7 @@
 		/* kludgy, but allow this before initialization */
 		data_stack_init();
 	}
+	BLOCK_CANARY_CHECK(current_block);
 
 	/* allocate only aligned amount of memory so alignment comes
 	   always properly */
@@ -456,6 +464,7 @@
 
 	if (unlikely(size == 0 || size > SSIZE_T_MAX))
 		i_panic("Trying to allocate %"PRIuSIZE_T" bytes", size);
+	BLOCK_CANARY_CHECK(current_block);
 
 	last_alloc_size = current_frame_block->last_alloc_size[frame_pos];
 
@@ -484,6 +493,7 @@
 	const unsigned int extra = MEM_ALIGN_SIZE-1 + SENTRY_COUNT +
 		MEM_ALIGN(sizeof(size_t));
 #endif
+	BLOCK_CANARY_CHECK(current_block);
 	return current_block->left < extra ? current_block->left :
 		current_block->left - extra;
 }


More information about the dovecot-cvs mailing list