dovecot-2.2: lib: test-data-stack - add some fatal tests.

dovecot at dovecot.org dovecot at dovecot.org
Wed Jul 30 12:04:02 UTC 2014


details:   http://hg.dovecot.org/dovecot-2.2/rev/8e990ad4db0e
changeset: 17672:8e990ad4db0e
user:      Phil Carmody <phil at dovecot.fi>
date:      Wed Jul 30 15:01:29 2014 +0300
description:
lib: test-data-stack - add some fatal tests.
Extra caution is necessary as data-stack is such a fundamental component.
All of the brokenness that we add must be undone as soon as possible, or
there will be an endless loop of catastrophic errors. In order to avoid
that, at least try to detect some issues, and abort as quickly as possible.

Alas, due to the reliance of these tests on DEBUG code, if that's not set,
this test is a no-op.

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

diffstat:

 src/lib/test-data-stack.c |  82 +++++++++++++++++++++++++++++++++++++++++++++++
 src/lib/test-lib.c        |   1 +
 src/lib/test-lib.h        |   1 +
 3 files changed, 84 insertions(+), 0 deletions(-)

diffs (111 lines):

diff -r 84ead9b26d59 -r 8e990ad4db0e src/lib/test-data-stack.c
--- a/src/lib/test-data-stack.c	Wed Jul 30 15:01:29 2014 +0300
+++ b/src/lib/test-data-stack.c	Wed Jul 30 15:01:29 2014 +0300
@@ -145,3 +145,85 @@
 	test_ds_realloc();
 	test_ds_recursive(20, 80);
 }
+
+enum fatal_test_state fatal_data_stack(int stage)
+{
+	/* If we abort, then we'll be left with a dangling t_push()
+	   keep a record of our temporary stack id, so we can clean up. */
+	static unsigned int t_id = 999999999;
+	static unsigned char *undo_ptr = NULL;
+	static unsigned char undo_data;
+	static bool things_are_messed_up = FALSE;
+	if (stage != 0) {
+		/* Presume that we need to clean up from the prior test:
+		   undo the evil write, then we will be able to t_pop cleanly,
+		   and finally we can end the test stanza. */
+		if (things_are_messed_up || undo_ptr == NULL || t_id == 999999999)
+			return FATAL_TEST_ABORT; /* abort, things are messed up with t_pop */
+		*undo_ptr = undo_data;
+		undo_ptr = NULL;
+		/* t_pop musn't abort, that would cause recursion */
+		things_are_messed_up = TRUE;
+		if (t_pop() != t_id)
+			return FATAL_TEST_ABORT; /* abort, things are messed up with us */
+		things_are_messed_up = FALSE;
+		t_id = 999999999;
+		test_end();
+	}
+
+	switch(stage) {
+#ifdef DEBUG
+	case 0: {
+		unsigned char *p;
+		test_begin("fatal data-stack underrun");
+		t_id = t_push_named("fatal_data_stack underrun");
+		size_t left = t_get_bytes_available();
+		p = t_malloc(left-80); /* will fit */
+		p = t_malloc(100); /* won't fit, will get new block */
+		int seek = 0;
+		/* Seek back for the canary, don't assume endianness */
+		while(seek > -60 &&
+		      ((p[seek+1] != 0xDB) ||
+		       ((p[seek]   != 0xBA || p[seek+2] != 0xAD) &&
+			(p[seek+2] != 0xBA || p[seek]   != 0xAD))))
+			seek--;
+		if (seek <= -60)
+			return FATAL_TEST_ABORT; /* abort, couldn't find header */
+		undo_ptr = p + seek;
+		undo_data = *undo_ptr;
+		*undo_ptr = '*';
+		/* t_malloc will panic block header corruption */
+		(void)t_malloc(10);
+		return FATAL_TEST_FAILURE;
+	}
+
+	case 1: case 2: {
+		test_begin(stage == 1 ? "fatal t_malloc overrun near" : "fatal t_malloc overrun far");
+		t_id = t_push_named(stage == 1 ? "fatal t_malloc overrun first" : "fatal t_malloc overrun far");
+		unsigned char *p = t_malloc(10);
+		undo_ptr = p + 10 + (stage == 1 ? 0 : 8*4-1); /* presumes sentry size */
+		undo_data = *undo_ptr;
+		*undo_ptr = '*';
+		/* t_pop will now fail */
+		(void)t_pop();
+		return FATAL_TEST_FAILURE;
+	}
+
+	case 3: case 4: {
+		test_begin(stage == 3 ? "fatal t_buffer_get overrun near" : "fatal t_buffer_get overrun far");
+		t_id = t_push_named(stage == 3 ? "fatal t_buffer overrun near" : "fatal t_buffer_get overrun far");
+		unsigned char *p = t_buffer_get(10);
+		undo_ptr = p + 10 + (stage == 3 ? 0 : 8*4-1);
+		undo_data = *undo_ptr;
+		*undo_ptr = '*';
+		/* t_pop will now fail */
+		(void)t_pop();
+		return FATAL_TEST_FAILURE;
+	}
+
+#endif
+	default:
+		things_are_messed_up = TRUE;
+		return FATAL_TEST_FINISHED;
+	}
+}
diff -r 84ead9b26d59 -r 8e990ad4db0e src/lib/test-lib.c
--- a/src/lib/test-lib.c	Wed Jul 30 15:01:29 2014 +0300
+++ b/src/lib/test-lib.c	Wed Jul 30 15:01:29 2014 +0300
@@ -48,6 +48,7 @@
 		NULL
 	};
 	static enum fatal_test_state (*fatal_functions[])(int) = {
+		fatal_data_stack,
 		fatal_mempool,
 		fatal_printf_format_fix,
 		NULL
diff -r 84ead9b26d59 -r 8e990ad4db0e src/lib/test-lib.h
--- a/src/lib/test-lib.h	Wed Jul 30 15:01:29 2014 +0300
+++ b/src/lib/test-lib.h	Wed Jul 30 15:01:29 2014 +0300
@@ -12,6 +12,7 @@
 void test_buffer(void);
 void test_crc32(void);
 void test_data_stack(void);
+enum fatal_test_state fatal_data_stack(int);
 void test_hash(void);
 void test_hash_format(void);
 void test_hash_method(void);


More information about the dovecot-cvs mailing list