dovecot-2.2-pigeonhole: lib-sieve: interpreter: Improved robustn...

pigeonhole at rename-it.nl pigeonhole at rename-it.nl
Sun Nov 29 13:59:48 UTC 2015


details:   http://hg.rename-it.nl/dovecot-2.2-pigeonhole/rev/3e5d2ed2052b
changeset: 2146:3e5d2ed2052b
user:      Stephan Bosch <stephan at rename-it.nl>
date:      Sun Nov 29 14:58:20 2015 +0100
description:
lib-sieve: interpreter: Improved robustness of code loop handling against binary corruption.
When the program crosses the boundary of the current jump somehow, the program is terminated and a corruption error is returned.

diffstat:

 src/lib-sieve/plugins/mime/cmd-foreverypart.c |   8 +-
 src/lib-sieve/sieve-interpreter.c             |  68 +++++++++++++++++++++-----
 src/lib-sieve/sieve-interpreter.h             |   4 +-
 3 files changed, 60 insertions(+), 20 deletions(-)

diffs (234 lines):

diff -r 8b9147c83fd9 -r 3e5d2ed2052b src/lib-sieve/plugins/mime/cmd-foreverypart.c
--- a/src/lib-sieve/plugins/mime/cmd-foreverypart.c	Sun Nov 29 13:46:03 2015 +0100
+++ b/src/lib-sieve/plugins/mime/cmd-foreverypart.c	Sun Nov 29 14:58:20 2015 +0100
@@ -362,11 +362,9 @@
 	i_assert(fploop->part != NULL);
 	fploop->part = sieve_message_part_iter_next(&fploop->part_iter);
 	if ( fploop->part == NULL )
-		sieve_interpreter_loop_break(renv->interp, loop);
-	else
-		sieve_interpreter_loop_next(renv->interp, loop, loop_begin);
-	
-	return SIEVE_EXEC_OK;
+		return sieve_interpreter_loop_break(renv->interp, loop);
+
+	return sieve_interpreter_loop_next(renv->interp, loop, loop_begin);
 }
 
 
diff -r 8b9147c83fd9 -r 3e5d2ed2052b src/lib-sieve/sieve-interpreter.c
--- a/src/lib-sieve/sieve-interpreter.c	Sun Nov 29 13:46:03 2015 +0100
+++ b/src/lib-sieve/sieve-interpreter.c	Sun Nov 29 14:58:20 2015 +0100
@@ -512,12 +512,14 @@
 
 	i_assert( loop_end > interp->runenv.pc );
 
+	/* Check supplied end offset */
 	if ( loop_end > sieve_binary_block_get_size(renv->sblock) ) {
 		sieve_runtime_trace_error(renv,
 			"loop end offset out of range");
 		return SIEVE_EXEC_BIN_CORRUPT;
 	}
 
+	/* Trace */
 	if ( sieve_runtime_trace_active(renv, SIEVE_TRLVL_COMMANDS) ) {
 		unsigned int line =
 			sieve_runtime_get_source_location(renv, loop_end);
@@ -530,6 +532,7 @@
 		}
 	}
 
+	/* Check loop nesting limit */
 	if ( !array_is_created(&interp->loop_stack) )
 		p_array_init(&interp->loop_stack, interp->pool, 8);
 	if ( (interp->parent_loop_level + array_count(&interp->loop_stack))
@@ -542,12 +545,16 @@
 		return SIEVE_EXEC_FAILURE;
 	}
 
+	/* Create new loop */
 	loop = array_append_space(&interp->loop_stack);
 	loop->level = array_count(&interp->loop_stack)-1;
 	loop->ext_def = ext_def;
 	loop->begin = interp->runenv.pc;
 	loop->end = loop_end;
 	loop->pool =  pool_alloconly_create("sieve_interpreter", 128);
+
+	/* Set new loop limit */
+	interp->loop_limit = loop_end;
 	
 	*loop_r = loop;
 	return SIEVE_EXEC_OK;
@@ -573,7 +580,7 @@
 	return NULL;
 }
 
-void sieve_interpreter_loop_next(struct sieve_interpreter *interp,
+int sieve_interpreter_loop_next(struct sieve_interpreter *interp,
 	struct sieve_interpreter_loop *loop,
 	sieve_size_t loop_begin)
 {
@@ -581,6 +588,7 @@
 	struct sieve_interpreter_loop *loops;
 	unsigned int count;
 
+	/* Trace */
 	if ( sieve_runtime_trace_active(renv, SIEVE_TRLVL_COMMANDS) ) {
 		unsigned int line =
 			sieve_runtime_get_source_location(renv, loop_begin);
@@ -593,16 +601,24 @@
 		}
 	}
 
-	i_assert( loop->begin == loop_begin );
+	/* Check the code for corruption */
+	if ( loop->begin != loop_begin ) {
+		sieve_runtime_trace_error(renv,
+			"loop begin offset invalid");
+		return SIEVE_EXEC_BIN_CORRUPT;
+	}
 
+	/* Check invariants */
 	i_assert( array_is_created(&interp->loop_stack) );
 	loops = array_get_modifiable(&interp->loop_stack, &count);
 	i_assert( &loops[count-1] == loop );
 
+	/* Return to beginning */
 	interp->runenv.pc = loop_begin;
+	return SIEVE_EXEC_OK;
 }
 
-void sieve_interpreter_loop_break(struct sieve_interpreter *interp,
+int sieve_interpreter_loop_break(struct sieve_interpreter *interp,
 	struct sieve_interpreter_loop *loop)
 {
 	const struct sieve_runtime_env *renv = &interp->runenv;
@@ -610,27 +626,38 @@
 	sieve_size_t loop_end = loop->end;
 	unsigned int count, i;
 
+	/* Find the loop */
 	i_assert( array_is_created(&interp->loop_stack) );
 	loops = array_get_modifiable(&interp->loop_stack, &count);
 	for ( i = count; i > 0 && &loops[i-1] != loop; i-- )
 		pool_unref(&loops[i-1].pool);
 	i_assert( i > 0 && &loops[i-1] == loop );
 
+	/* Delete it and all deeper loops */
 	array_delete(&interp->loop_stack, i-1, count - (i-1));
 
+	/* Set new loop limit */
+	if ( --i > 0 )
+		interp->loop_limit = loops[i-1].end;
+	else
+		interp->loop_limit =- 0;
+
+	/* Trace */
 	if ( sieve_runtime_trace_active(renv, SIEVE_TRLVL_COMMANDS) ) {
 		unsigned int jmp_line =
 			sieve_runtime_get_source_location(renv, loop_end);
 
 		if ( sieve_runtime_trace_hasflag(renv, SIEVE_TRFLG_ADDRESSES) ) {
-			sieve_runtime_trace(renv, 0, "ending loop at line %d [%08llx]",
+			sieve_runtime_trace(renv, 0, "exiting loops at line %d [%08llx]",
 				jmp_line, (long long unsigned int) loop_end);
 		} else {
-			sieve_runtime_trace(renv, 0, "ending loop at line %d", jmp_line);
+			sieve_runtime_trace(renv, 0, "exiting loops at line %d", jmp_line);
 		}
 	}
 
+	/* Exit loop */
 	interp->runenv.pc = loop->end;
+	return SIEVE_EXEC_OK;
 }
 
 struct sieve_interpreter_loop *sieve_interpreter_loop_get_surrounding
@@ -700,6 +727,8 @@
 	const struct sieve_runtime_env *renv = &interp->runenv;
 	sieve_size_t *address = &(interp->runenv.pc);
 	sieve_size_t jmp_start = *address;
+	sieve_size_t jmp_limit = ( interp->loop_limit == 0 ?
+		sieve_binary_block_get_size(renv->sblock) : interp->loop_limit );
 	sieve_offset_t jmp_offset;
 
 	if ( !sieve_binary_read_offset(renv->sblock, address, &jmp_offset) )
@@ -708,7 +737,7 @@
 		return SIEVE_EXEC_BIN_CORRUPT;
 	}
 
-	if ( jmp_start + jmp_offset <= sieve_binary_block_get_size(renv->sblock) &&
+	if ( (jmp_start + jmp_offset) <= jmp_limit &&
 		jmp_start + jmp_offset > 0 )
 	{
 		if ( jump ) {
@@ -734,7 +763,13 @@
 		return SIEVE_EXEC_OK;
 	}
 
-	sieve_runtime_trace_error(renv, "jump offset out of range");
+	if ( interp->loop_limit != 0 ) {
+		sieve_runtime_trace_error(renv,
+			"jump offset crosses loop boundary");
+	} else {
+		sieve_runtime_trace_error(renv,
+			"jump offset out of range");
+	}
 	return SIEVE_EXEC_BIN_CORRUPT;
 }
 
@@ -796,24 +831,31 @@
 int sieve_interpreter_continue
 (struct sieve_interpreter *interp, bool *interrupted)
 {
+	const struct sieve_runtime_env *renv = &interp->runenv;
 	sieve_size_t *address = &(interp->runenv.pc);
 	int ret = SIEVE_EXEC_OK;
 
-	sieve_result_ref(interp->runenv.result);
+	sieve_result_ref(renv->result);
 	interp->interrupted = FALSE;
 
 	if ( interrupted != NULL )
 		*interrupted = FALSE;
 
 	while ( ret == SIEVE_EXEC_OK && !interp->interrupted &&
-		*address < sieve_binary_block_get_size(interp->runenv.sblock) ) {
+		*address < sieve_binary_block_get_size(renv->sblock) ) {
+		if ( interp->loop_limit != 0 && *address > interp->loop_limit ) {
+			sieve_runtime_trace_error(renv,
+				"program crossed loop boundary");
+			ret = SIEVE_EXEC_BIN_CORRUPT;
+			break;
+		}
 
 		ret = sieve_interpreter_operation_execute(interp);
+	}
 
-		if ( ret != SIEVE_EXEC_OK ) {
-			sieve_runtime_trace(&interp->runenv, SIEVE_TRLVL_NONE,
-				"[[EXECUTION ABORTED]]");
-		}
+	if ( ret != SIEVE_EXEC_OK ) {
+		sieve_runtime_trace(&interp->runenv, SIEVE_TRLVL_NONE,
+			"[[EXECUTION ABORTED]]");
 	}
 
 	if ( interrupted != NULL )
diff -r 8b9147c83fd9 -r 3e5d2ed2052b src/lib-sieve/sieve-interpreter.h
--- a/src/lib-sieve/sieve-interpreter.h	Sun Nov 29 13:46:03 2015 +0100
+++ b/src/lib-sieve/sieve-interpreter.h	Sun Nov 29 14:58:20 2015 +0100
@@ -66,11 +66,11 @@
 struct sieve_interpreter_loop *sieve_interpreter_loop_get
 	(struct sieve_interpreter *interp, sieve_size_t loop_end,
 		const struct sieve_extension_def *ext_def);
-void sieve_interpreter_loop_next
+int sieve_interpreter_loop_next
 	(struct sieve_interpreter *interp,
 		struct sieve_interpreter_loop *loop,
 		sieve_size_t loop_begin);
-void sieve_interpreter_loop_break
+int sieve_interpreter_loop_break
 	(struct sieve_interpreter *interp,
 		struct sieve_interpreter_loop *loop);
 


More information about the dovecot-cvs mailing list