diff --git a/src/lib-sieve/Makefile.am b/src/lib-sieve/Makefile.am index bcb90071103228b06a6b26836f6f9a981823f9b4..e77e6c31817f689a2e4ab29f9bfb0c977fa414ef 100644 --- a/src/lib-sieve/Makefile.am +++ b/src/lib-sieve/Makefile.am @@ -57,6 +57,7 @@ libsieve_la_DEPENDENCIES = $(plugins) libsieve_la_LIBADD = $(plugins) libsieve_la_SOURCES = \ + sieve-limits.c \ sieve-message.c \ sieve-lexer.c \ sieve-script.c \ diff --git a/src/lib-sieve/sieve-limits.c b/src/lib-sieve/sieve-limits.c new file mode 100644 index 0000000000000000000000000000000000000000..624e702007cf0780689de5a8cf1838bb58da51a5 --- /dev/null +++ b/src/lib-sieve/sieve-limits.c @@ -0,0 +1,9 @@ +/* Copyright (c) 2002-2008 Dovecot Sieve authors, see the included COPYING file + */ + +#include "sieve-common.h" +#include "sieve-limits.h" + +unsigned int sieve_max_actions = SIEVE_DEFAULT_MAX_ACTIONS; +unsigned int sieve_max_redirects = SIEVE_DEFAULT_MAX_REDIRECTS; + diff --git a/src/lib-sieve/sieve-limits.h b/src/lib-sieve/sieve-limits.h index d5cceda1483e05cd0d4ce000d7e0c72864dec37f..375815afb96f5138c47f2173ee93e273dcf1c235 100644 --- a/src/lib-sieve/sieve-limits.h +++ b/src/lib-sieve/sieve-limits.h @@ -29,7 +29,10 @@ * Actions */ -#define SIEVE_DEFAULT_MAX_REDIRECTS 4 #define SIEVE_DEFAULT_MAX_ACTIONS 32 +#define SIEVE_DEFAULT_MAX_REDIRECTS 4 + +extern unsigned int sieve_max_actions; +extern unsigned int sieve_max_redirects; #endif /* __SIEVE_LIMITS_H */ diff --git a/src/lib-sieve/sieve-result.c b/src/lib-sieve/sieve-result.c index 22bd2360984d0b987276af784bcd021a294370c1..24d6f0b1e76d636cda2098f4263caff03b16b085 100644 --- a/src/lib-sieve/sieve-result.c +++ b/src/lib-sieve/sieve-result.c @@ -10,6 +10,7 @@ #include "str-sanitize.h" #include "sieve-common.h" +#include "sieve-limits.h" #include "sieve-script.h" #include "sieve-error.h" #include "sieve-interpreter.h" @@ -49,7 +50,7 @@ struct sieve_result_side_effect { struct sieve_result_side_effect *prev, *next; }; -struct sieve_result_implicit_side_effects { +struct sieve_result_action_context { const struct sieve_action *action; struct sieve_side_effects_list *seffects; }; @@ -68,10 +69,12 @@ struct sieve_result { struct sieve_error_handler *ehandler; struct sieve_action_exec_env action_env; + + unsigned int action_count; struct sieve_result_action *first_action; struct sieve_result_action *last_action; - struct hash_table *implicit_seffects; + struct hash_table *action_contexts; }; struct sieve_result *sieve_result_create @@ -92,10 +95,11 @@ struct sieve_result *sieve_result_create result->action_env.result = result; + result->action_count = 0; result->first_action = NULL; result->last_action = NULL; - result->implicit_seffects = NULL; + result->action_contexts = NULL; return result; } @@ -111,8 +115,8 @@ void sieve_result_unref(struct sieve_result **result) if (--(*result)->refcount != 0) return; - if ( (*result)->implicit_seffects != NULL ) - hash_destroy(&(*result)->implicit_seffects); + if ( (*result)->action_contexts != NULL ) + hash_destroy(&(*result)->action_contexts); sieve_error_handler_unref(&(*result)->ehandler); @@ -198,27 +202,27 @@ void sieve_result_add_implicit_side_effect (struct sieve_result *result, const struct sieve_action *to_action, const struct sieve_side_effect *seffect, void *context) { - struct sieve_result_implicit_side_effects *implseff = NULL; + struct sieve_result_action_context *actctx = NULL; - if ( result->implicit_seffects == NULL ) { - result->implicit_seffects = hash_create + if ( result->action_contexts == NULL ) { + result->action_contexts = hash_create (default_pool, result->pool, 0, NULL, NULL); } else { - implseff = (struct sieve_result_implicit_side_effects *) - hash_lookup(result->implicit_seffects, to_action); + actctx = (struct sieve_result_action_context *) + hash_lookup(result->action_contexts, to_action); } - if ( implseff == NULL ) { - implseff = p_new - (result->pool, struct sieve_result_implicit_side_effects, 1); - implseff->action = to_action; - implseff->seffects = sieve_side_effects_list_create(result); + if ( actctx == NULL ) { + actctx = p_new + (result->pool, struct sieve_result_action_context, 1); + actctx->action = to_action; + actctx->seffects = sieve_side_effects_list_create(result); - hash_insert(result->implicit_seffects, (void *) to_action, - (void *) implseff); + hash_insert(result->action_contexts, (void *) to_action, + (void *) actctx); } - sieve_side_effects_list_add(implseff->seffects, seffect, context); + sieve_side_effects_list_add(actctx->seffects, seffect, context); } int sieve_result_add_action @@ -260,6 +264,12 @@ int sieve_result_add_action } raction = raction->next; } + + /* Check policy limit on number of actions */ + if ( result->action_count >= sieve_max_actions ) { + sieve_runtime_error(renv, location, "number of actions exceeds policy limit"); + return -1; + } /* Create new action object */ raction = p_new(result->pool, struct sieve_result_action, 1); @@ -282,23 +292,24 @@ int sieve_result_add_action raction->prev = result->last_action; result->last_action = raction; raction->next = NULL; - } + } + result->action_count++; /* Apply any implicit side effects */ - if ( result->implicit_seffects != NULL ) { - struct sieve_result_implicit_side_effects *implseff; + if ( result->action_contexts != NULL ) { + struct sieve_result_action_context *actctx; /* Check for implicit side effects to this particular action */ - implseff = (struct sieve_result_implicit_side_effects *) - hash_lookup(result->implicit_seffects, action); + actctx = (struct sieve_result_action_context *) + hash_lookup(result->action_contexts, action); - if ( implseff != NULL ) { + if ( actctx != NULL ) { struct sieve_result_side_effect *iseff; /* Iterate through all implicit side effects and add those that are * missing. */ - iseff = implseff->seffects->first_effect; + iseff = actctx->seffects->first_effect; while ( iseff != NULL ) { struct sieve_result_side_effect *seff; bool exists = FALSE; @@ -438,20 +449,19 @@ bool sieve_result_implicit_keep ctx.folder = result->action_env.scriptenv->inbox; /* Also apply any implicit side effects if applicable */ - if ( !rollback && result->implicit_seffects != NULL ) { - struct sieve_result_implicit_side_effects *implseff; + if ( !rollback && result->action_contexts != NULL ) { + struct sieve_result_action_context *actctx; /* Check for implicit side effects to store action */ - implseff = (struct sieve_result_implicit_side_effects *) - hash_lookup(result->implicit_seffects, &act_store); + actctx = (struct sieve_result_action_context *) + hash_lookup(result->action_contexts, &act_store); - if ( implseff != NULL && implseff->seffects != NULL ) - rsef_first = implseff->seffects->first_effect; + if ( actctx != NULL && actctx->seffects != NULL ) + rsef_first = actctx->seffects->first_effect; } - success = act_store.start - (&act_store, &result->action_env, (void *) &ctx, &tr_context); + success = act_store.start(&act_store, &result->action_env, (void *) &ctx, &tr_context); rsef = rsef_first; while ( rsef != NULL ) { @@ -512,7 +522,7 @@ int sieve_result_execute /* * Transaction start - */ + */ rac = result->first_action; while ( success && rac != NULL ) { diff --git a/tests/execute/errors.svtest b/tests/execute/errors.svtest index 196d5fb9792b31511af575c886e239963c4847eb..60842f308747dfd6dd62270f41510d2063501f94 100644 --- a/tests/execute/errors.svtest +++ b/tests/execute/errors.svtest @@ -44,3 +44,21 @@ test "Action conflicts: reject <-> redirect" { test_fail "too many runtime errors reported"; } } + +test "Action limits" { + if not test_compile "errors/actions-limit.sieve" { + test_fail "compile failed"; + } + + if test_execute { + test_fail "execution should have failed"; + } + + if test_error :count "gt" :comparator "i;ascii-numeric" "1" { + test_fail "too many runtime errors reported"; + } + + if not test_error :index 1 :contains "number of actions exceeds policy limit"{ + test_fail "unexpected error reported"; + } +} diff --git a/tests/execute/errors/actions-limit.sieve b/tests/execute/errors/actions-limit.sieve new file mode 100644 index 0000000000000000000000000000000000000000..5f0421849846d6bb8d76ed524994296c2b740bf4 --- /dev/null +++ b/tests/execute/errors/actions-limit.sieve @@ -0,0 +1,35 @@ +require "fileinto"; + +fileinto "box1"; +fileinto "box2"; +fileinto "box3"; +fileinto "box4"; +fileinto "box5"; +fileinto "box6"; +fileinto "box7"; +fileinto "box8"; +fileinto "box9"; +fileinto "box10"; +fileinto "box11"; +fileinto "box12"; +fileinto "box13"; +fileinto "box14"; +fileinto "box15"; +fileinto "box16"; +redirect "address1@example.com"; +redirect "address2@example.com"; +redirect "address3@example.com"; +redirect "address4@example.com"; +redirect "address5@example.com"; +redirect "address6@example.com"; +redirect "address7@example.com"; +redirect "address8@example.com"; +redirect "address9@example.com"; +redirect "address10@example.com"; +redirect "address11@example.com"; +redirect "address12@example.com"; +redirect "address13@example.com"; +redirect "address14@example.com"; +redirect "address15@example.com"; +redirect "address16@example.com"; +keep;