From 8d6d9e9fd7118c625e1eaee81c6e9e9bf4e0a38c Mon Sep 17 00:00:00 2001
From: Stephan Bosch <stephan.bosch@open-xchange.com>
Date: Fri, 4 Dec 2020 12:19:28 +0100
Subject: [PATCH] lib-sieve: sieve-types - Add SIEVE_EXEC_RESOURCE_LIMIT exit
 code.

It indicates that script execution exceeded a resource limit (currently only CPU
time limit).
---
 src/lib-sieve/sieve-interpreter.c                 |  5 ++++-
 src/lib-sieve/sieve-types.h                       | 11 ++++++-----
 src/plugins/imap-filter-sieve/imap-filter-sieve.c |  8 ++++++++
 src/plugins/imapsieve/imap-sieve.c                |  8 ++++++++
 src/plugins/lda-sieve/lda-sieve-plugin.c          |  2 ++
 src/sieve-tools/sieve-filter.c                    |  3 +++
 src/sieve-tools/sieve-test.c                      |  4 ++++
 src/testsuite/testsuite.c                         |  4 ++++
 8 files changed, 39 insertions(+), 6 deletions(-)

diff --git a/src/lib-sieve/sieve-interpreter.c b/src/lib-sieve/sieve-interpreter.c
index 42f6ea1c6..47ece8810 100644
--- a/src/lib-sieve/sieve-interpreter.c
+++ b/src/lib-sieve/sieve-interpreter.c
@@ -953,7 +953,7 @@ int sieve_interpreter_continue(struct sieve_interpreter *interp,
 			sieve_runtime_error(
 				renv, NULL,
 				"execution exceeded CPU time limit");
-			ret = SIEVE_EXEC_FAILURE;
+			ret = SIEVE_EXEC_RESOURCE_LIMIT;
 			break;
 		}
 		if (interp->loop_limit != 0 && *address > interp->loop_limit) {
@@ -998,6 +998,9 @@ int sieve_interpreter_continue(struct sieve_interpreter *interp,
 		case SIEVE_EXEC_BIN_CORRUPT:
 			e->add_str("error", "Binary corrupt");
 			break;
+		case SIEVE_EXEC_RESOURCE_LIMIT:
+			e->add_str("error", "Resource limit exceeded");
+			break;
 		case SIEVE_EXEC_KEEP_FAILED:
 			/* Not supposed to occur at runtime */
 			i_unreached();
diff --git a/src/lib-sieve/sieve-types.h b/src/lib-sieve/sieve-types.h
index 5ab027e29..f2e64a4cd 100644
--- a/src/lib-sieve/sieve-types.h
+++ b/src/lib-sieve/sieve-types.h
@@ -290,11 +290,12 @@ struct sieve_exec_status {
  */
 
 enum sieve_execution_exitcode {
-	SIEVE_EXEC_OK           = 1,
-	SIEVE_EXEC_FAILURE      = 0,
-	SIEVE_EXEC_TEMP_FAILURE = -1,
-	SIEVE_EXEC_BIN_CORRUPT  = -2,
-	SIEVE_EXEC_KEEP_FAILED  = -3
+	SIEVE_EXEC_OK         	        = 1,
+	SIEVE_EXEC_FAILURE              = 0,
+	SIEVE_EXEC_TEMP_FAILURE         = -1,
+	SIEVE_EXEC_BIN_CORRUPT          = -2,
+	SIEVE_EXEC_KEEP_FAILED          = -3,
+	SIEVE_EXEC_RESOURCE_LIMIT       = -4,
 };
 
 #endif
diff --git a/src/plugins/imap-filter-sieve/imap-filter-sieve.c b/src/plugins/imap-filter-sieve/imap-filter-sieve.c
index f3e33017f..26369541f 100644
--- a/src/plugins/imap-filter-sieve/imap-filter-sieve.c
+++ b/src/plugins/imap-filter-sieve/imap-filter-sieve.c
@@ -728,6 +728,14 @@ imap_sieve_filter_handle_exec_status(struct imap_filter_sieve_context *sctx,
 		*fatal_r = TRUE;
 		ret = -1;
 		break;
+	case SIEVE_EXEC_RESOURCE_LIMIT:
+		e_error(sieve_get_event(svinst),
+			"Execution of script %s was aborted "
+			"due to excessive resource usage",
+			sieve_script_location(script));
+		*fatal_r = TRUE;
+		ret = -1;
+		break;
 	case SIEVE_EXEC_KEEP_FAILED:
 		e_log(sieve_get_event(svinst), log_level,
 		      "Execution of script %s failed "
diff --git a/src/plugins/imapsieve/imap-sieve.c b/src/plugins/imapsieve/imap-sieve.c
index 74d66eb7b..3ed19ea8f 100644
--- a/src/plugins/imapsieve/imap-sieve.c
+++ b/src/plugins/imapsieve/imap-sieve.c
@@ -636,6 +636,14 @@ imap_sieve_handle_exec_status(struct imap_sieve_run *isrun,
 		*fatal_r = TRUE;
 		ret = -1;
 		break;
+	case SIEVE_EXEC_RESOURCE_LIMIT:
+		e_error(sieve_get_event(svinst),
+			"Execution of script %s was aborted "
+			"due to excessive resource usage",
+			sieve_script_location(script));
+		*fatal_r = TRUE;
+		ret = -1;
+		break;
 	case SIEVE_EXEC_KEEP_FAILED:
 		e_log(sieve_get_event(svinst), log_level,
 		      "Execution of script %s failed "
diff --git a/src/plugins/lda-sieve/lda-sieve-plugin.c b/src/plugins/lda-sieve/lda-sieve-plugin.c
index 0fa323de1..175b76ac2 100644
--- a/src/plugins/lda-sieve/lda-sieve-plugin.c
+++ b/src/plugins/lda-sieve/lda-sieve-plugin.c
@@ -564,6 +564,8 @@ lda_sieve_execute_script(struct lda_sieve_run_context *srctx,
 		if (mstatus != SIEVE_EXEC_BIN_CORRUPT)
 			lda_sieve_binary_save(srctx, sbin, script);
 	}
+	if (ret == 0 && mstatus == SIEVE_EXEC_RESOURCE_LIMIT)
+		ret = -1;
 
 	sieve_close(&sbin);
 
diff --git a/src/sieve-tools/sieve-filter.c b/src/sieve-tools/sieve-filter.c
index d71f4bcad..deaae6abd 100644
--- a/src/sieve-tools/sieve-filter.c
+++ b/src/sieve-tools/sieve-filter.c
@@ -237,6 +237,9 @@ static int filter_message(struct sieve_filter_context *sfctx, struct mail *mail)
 	switch (ret) {
 	case SIEVE_EXEC_OK:
 		break;
+	case SIEVE_EXEC_RESOURCE_LIMIT:
+		sieve_error(ehandler, NULL, "sieve resource limit exceeded");
+		return -1;
 	case SIEVE_EXEC_BIN_CORRUPT:
 		sieve_error(ehandler, NULL, "sieve script binary is corrupt");
 		return -1;
diff --git a/src/sieve-tools/sieve-test.c b/src/sieve-tools/sieve-test.c
index b623b6714..c553ace89 100644
--- a/src/sieve-tools/sieve-test.c
+++ b/src/sieve-tools/sieve-test.c
@@ -452,6 +452,10 @@ int main(int argc, char **argv)
 		case SIEVE_EXEC_OK:
 			i_info("final result: success");
 			break;
+		case SIEVE_EXEC_RESOURCE_LIMIT:
+			i_info("resource limit exceeded");
+			exit_status = EXIT_FAILURE;
+			break;
 		case SIEVE_EXEC_BIN_CORRUPT:
 			i_info("corrupt binary deleted.");
 			i_unlink_if_exists(sieve_binary_path(sbin));
diff --git a/src/testsuite/testsuite.c b/src/testsuite/testsuite.c
index 4cd4ba722..2a6b82eb4 100644
--- a/src/testsuite/testsuite.c
+++ b/src/testsuite/testsuite.c
@@ -222,6 +222,10 @@ int main(int argc, char **argv)
 			testsuite_testcase_fail(
 				"compiled test script binary is corrupt");
 			break;
+		case SIEVE_EXEC_RESOURCE_LIMIT:
+			testsuite_testcase_fail(
+				"resource limit exceeded");
+			break;
 		}
 
 		sieve_close(&sbin);
-- 
GitLab