diff -Nru dovecot-2.3.4.1/debian/changelog dovecot-2.3.4.1/debian/changelog --- dovecot-2.3.4.1/debian/changelog 2019-08-28 18:47:43.000000000 +0000 +++ dovecot-2.3.4.1/debian/changelog 2020-05-13 13:32:58.000000000 +0000 @@ -1,3 +1,14 @@ +dovecot (1:2.3.4.1-5ubuntu3.1) eoan-security; urgency=medium + + * SECURITY UPDATE: Multiple security issues + - debian/patches/CVE-2020-109xx/*.patch: add patches provided by + upstream to fix issues. + - CVE-2020-10957 + - CVE-2020-10958 + - CVE-2020-10967 + + -- Marc Deslauriers Wed, 13 May 2020 09:32:58 -0400 + dovecot (1:2.3.4.1-5ubuntu3) eoan; urgency=medium * SECURITY UPDATE: The IMAP protocol parser does not properly handled diff -Nru dovecot-2.3.4.1/debian/patches/CVE-2020-109xx/0001-lib-smtp-smtp-server-cmd-vrfy-Restructure-parameter-.patch dovecot-2.3.4.1/debian/patches/CVE-2020-109xx/0001-lib-smtp-smtp-server-cmd-vrfy-Restructure-parameter-.patch --- dovecot-2.3.4.1/debian/patches/CVE-2020-109xx/0001-lib-smtp-smtp-server-cmd-vrfy-Restructure-parameter-.patch 1970-01-01 00:00:00.000000000 +0000 +++ dovecot-2.3.4.1/debian/patches/CVE-2020-109xx/0001-lib-smtp-smtp-server-cmd-vrfy-Restructure-parameter-.patch 2020-05-13 13:30:46.000000000 +0000 @@ -0,0 +1,40 @@ +From 4a530313b8376aa4a2153143cd1a9b3a82791555 Mon Sep 17 00:00:00 2001 +From: Stephan Bosch +Date: Tue, 24 Mar 2020 21:05:17 +0100 +Subject: [PATCH 01/17] lib-smtp: smtp-server-cmd-vrfy - Restructure parameter + parsing. + +--- + src/lib-smtp/smtp-server-cmd-vrfy.c | 16 +++++++--------- + 1 file changed, 7 insertions(+), 9 deletions(-) + +diff --git a/src/lib-smtp/smtp-server-cmd-vrfy.c b/src/lib-smtp/smtp-server-cmd-vrfy.c +index 7f750b82cb..5642604757 100644 +--- a/src/lib-smtp/smtp-server-cmd-vrfy.c ++++ b/src/lib-smtp/smtp-server-cmd-vrfy.c +@@ -17,15 +17,13 @@ void smtp_server_cmd_vrfy(struct smtp_server_cmd_ctx *cmd, + int ret; + + /* vrfy = "VRFY" SP String CRLF */ +- if ((ret=smtp_string_parse(params, ¶m, &error)) <= 0) { +- if (ret < 0) { +- smtp_server_reply(cmd, +- 501, "5.5.4", +- "Invalid string parameter: %s", error); +- } else { +- smtp_server_reply(cmd, +- 501, "5.5.4", "Invalid parameters"); +- } ++ ret = smtp_string_parse(params, ¶m, &error); ++ if (ret < 0) { ++ smtp_server_reply(cmd, 501, "5.5.4", ++ "Invalid string parameter: %s", error); ++ return; ++ } else if (ret == 0) { ++ smtp_server_reply(cmd, 501, "5.5.4", "Invalid parameters"); + return; + } + +-- +2.11.0 + diff -Nru dovecot-2.3.4.1/debian/patches/CVE-2020-109xx/0002-lib-smtp-smtp-syntax-Do-not-allow-NULL-return-parame.patch dovecot-2.3.4.1/debian/patches/CVE-2020-109xx/0002-lib-smtp-smtp-syntax-Do-not-allow-NULL-return-parame.patch --- dovecot-2.3.4.1/debian/patches/CVE-2020-109xx/0002-lib-smtp-smtp-syntax-Do-not-allow-NULL-return-parame.patch 1970-01-01 00:00:00.000000000 +0000 +++ dovecot-2.3.4.1/debian/patches/CVE-2020-109xx/0002-lib-smtp-smtp-syntax-Do-not-allow-NULL-return-parame.patch 2020-05-13 13:30:46.000000000 +0000 @@ -0,0 +1,63 @@ +From 3d24d1eee0422e9a5c865268ed6dee8d49d7bff9 Mon Sep 17 00:00:00 2001 +From: Stephan Bosch +Date: Tue, 24 Mar 2020 20:57:03 +0100 +Subject: [PATCH 02/17] lib-smtp: smtp-syntax - Do not allow NULL return + parameters for smtp_string_parse(). + +--- + src/lib-smtp/smtp-server-cmd-noop.c | 8 ++++++-- + src/lib-smtp/smtp-syntax.c | 9 +++++---- + 2 files changed, 11 insertions(+), 6 deletions(-) + +diff --git a/src/lib-smtp/smtp-server-cmd-noop.c b/src/lib-smtp/smtp-server-cmd-noop.c +index 1a10e1ab79..19ea9560ee 100644 +--- a/src/lib-smtp/smtp-server-cmd-noop.c ++++ b/src/lib-smtp/smtp-server-cmd-noop.c +@@ -13,11 +13,15 @@ void smtp_server_cmd_noop(struct smtp_server_cmd_ctx *cmd, + struct smtp_server_connection *conn = cmd->conn; + struct smtp_server_command *command = cmd->cmd; + const struct smtp_server_callbacks *callbacks = conn->callbacks; ++ const char *param, *error; + int ret; + + /* "NOOP" [ SP String ] CRLF */ +- if (*params != '\0' && smtp_string_parse(params, NULL, NULL) < 0) { +- smtp_server_reply(cmd, 501, "5.5.4", "Invalid parameters"); ++ ret = smtp_string_parse(params, ¶m, &error); ++ if (ret < 0) { ++ smtp_server_reply(cmd, 501, "5.5.4", ++ "Invalid string parameter: %s", ++ error); + return; + } + +diff --git a/src/lib-smtp/smtp-syntax.c b/src/lib-smtp/smtp-syntax.c +index 9088184d85..0f0c0ba0fc 100644 +--- a/src/lib-smtp/smtp-syntax.c ++++ b/src/lib-smtp/smtp-syntax.c +@@ -17,7 +17,9 @@ int smtp_string_parse(const char *string, + const char **value_r, const char **error_r) + { + struct smtp_parser parser; +- int ret; ++ ++ *value_r = NULL; ++ *error_r = NULL; + + if (string == NULL || *string == '\0') { + *value_r = ""; +@@ -26,9 +28,8 @@ int smtp_string_parse(const char *string, + + smtp_parser_init(&parser, pool_datastack_create(), string); + +- if ((ret=smtp_parser_parse_string(&parser, value_r)) < 0) { +- if (error_r != NULL) +- *error_r = parser.error; ++ if (smtp_parser_parse_string(&parser, value_r) < 0) { ++ *error_r = parser.error; + return -1; + } + if (parser.cur < parser.end) { +-- +2.11.0 + diff -Nru dovecot-2.3.4.1/debian/patches/CVE-2020-109xx/0003-lib-smtp-smtp-syntax-Do-not-allow-NULL-return-parame.patch dovecot-2.3.4.1/debian/patches/CVE-2020-109xx/0003-lib-smtp-smtp-syntax-Do-not-allow-NULL-return-parame.patch --- dovecot-2.3.4.1/debian/patches/CVE-2020-109xx/0003-lib-smtp-smtp-syntax-Do-not-allow-NULL-return-parame.patch 1970-01-01 00:00:00.000000000 +0000 +++ dovecot-2.3.4.1/debian/patches/CVE-2020-109xx/0003-lib-smtp-smtp-syntax-Do-not-allow-NULL-return-parame.patch 2020-05-13 13:30:46.000000000 +0000 @@ -0,0 +1,54 @@ +From bdfdb27aad8fbdeefac2fd02be921f8fc6989918 Mon Sep 17 00:00:00 2001 +From: Stephan Bosch +Date: Tue, 24 Mar 2020 21:11:01 +0100 +Subject: [PATCH 03/17] lib-smtp: smtp-syntax - Do not allow NULL return + parameters for smtp_xtext_parse(). + +--- + src/lib-smtp/smtp-syntax.c | 15 +++++++-------- + 1 file changed, 7 insertions(+), 8 deletions(-) + +diff --git a/src/lib-smtp/smtp-syntax.c b/src/lib-smtp/smtp-syntax.c +index 0f0c0ba0fc..23b5d5a4bd 100644 +--- a/src/lib-smtp/smtp-syntax.c ++++ b/src/lib-smtp/smtp-syntax.c +@@ -86,20 +86,20 @@ int smtp_xtext_parse(const char *xtext, + { + struct smtp_parser parser; + string_t *value = NULL; +- int ret; ++ ++ *value_r = NULL; ++ *error_r = NULL; + + if (xtext == NULL || *xtext == '\0') { + *value_r = ""; + return 1; + } + +- if (value_r != NULL) +- value = t_str_new(256); ++ value = t_str_new(256); + smtp_parser_init(&parser, pool_datastack_create(), xtext); + +- if ((ret=smtp_parser_parse_xtext(&parser, value)) < 0) { +- if (error_r != NULL) +- *error_r = parser.error; ++ if (smtp_parser_parse_xtext(&parser, value) < 0) { ++ *error_r = parser.error; + return -1; + } + if (parser.cur < parser.end) { +@@ -110,8 +110,7 @@ int smtp_xtext_parse(const char *xtext, + if (value_r != NULL) { + *value_r = str_c(value); + if (strlen(*value_r) != str_len(value)) { +- if (*error_r != NULL) +- *error_r = "Encountered NUL character in xtext"; ++ *error_r = "Encountered NUL character in xtext"; + return -1; + } + } +-- +2.11.0 + diff -Nru dovecot-2.3.4.1/debian/patches/CVE-2020-109xx/0004-lib-smtp-syntax-Fix-smtp_ehlo_line_parse-to-also-rec.patch dovecot-2.3.4.1/debian/patches/CVE-2020-109xx/0004-lib-smtp-syntax-Fix-smtp_ehlo_line_parse-to-also-rec.patch --- dovecot-2.3.4.1/debian/patches/CVE-2020-109xx/0004-lib-smtp-syntax-Fix-smtp_ehlo_line_parse-to-also-rec.patch 1970-01-01 00:00:00.000000000 +0000 +++ dovecot-2.3.4.1/debian/patches/CVE-2020-109xx/0004-lib-smtp-syntax-Fix-smtp_ehlo_line_parse-to-also-rec.patch 2020-05-13 13:30:46.000000000 +0000 @@ -0,0 +1,26 @@ +From f78dbaca924bd7e950052a6dcfd9e3edc6c30193 Mon Sep 17 00:00:00 2001 +From: Stephan Bosch +Date: Mon, 3 Dec 2018 18:45:17 +0100 +Subject: [PATCH 04/17] lib-smtp: syntax: Fix smtp_ehlo_line_parse() to also + record the last parameter. + +--- + src/lib-smtp/smtp-syntax.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/src/lib-smtp/smtp-syntax.c b/src/lib-smtp/smtp-syntax.c +index 23b5d5a4bd..bf8a3f6904 100644 +--- a/src/lib-smtp/smtp-syntax.c ++++ b/src/lib-smtp/smtp-syntax.c +@@ -229,6 +229,8 @@ static int smtp_parse_ehlo_line(struct smtp_parser *parser, + } + + if (params_r != NULL) { ++ param = p_strdup_until(parser->pool, pbegin, parser->cur); ++ array_append(¶ms, ¶m, 1); + array_append_zero(¶ms); + *params_r = array_idx(¶ms, 0); + } +-- +2.11.0 + diff -Nru dovecot-2.3.4.1/debian/patches/CVE-2020-109xx/0005-lib-smtp-smtp-syntax-Do-not-allow-NULL-return-parame.patch dovecot-2.3.4.1/debian/patches/CVE-2020-109xx/0005-lib-smtp-smtp-syntax-Do-not-allow-NULL-return-parame.patch --- dovecot-2.3.4.1/debian/patches/CVE-2020-109xx/0005-lib-smtp-smtp-syntax-Do-not-allow-NULL-return-parame.patch 1970-01-01 00:00:00.000000000 +0000 +++ dovecot-2.3.4.1/debian/patches/CVE-2020-109xx/0005-lib-smtp-smtp-syntax-Do-not-allow-NULL-return-parame.patch 2020-05-13 13:30:46.000000000 +0000 @@ -0,0 +1,98 @@ +From d1834eae1c177dc241a0f996ba2483ccb450bf21 Mon Sep 17 00:00:00 2001 +From: Stephan Bosch +Date: Tue, 24 Mar 2020 21:14:34 +0100 +Subject: [PATCH 05/17] lib-smtp: smtp-syntax - Do not allow NULL return + parameters for smtp_ehlo_line_parse(). + +--- + src/lib-smtp/smtp-syntax.c | 38 ++++++++++++++++---------------------- + 1 file changed, 16 insertions(+), 22 deletions(-) + +diff --git a/src/lib-smtp/smtp-syntax.c b/src/lib-smtp/smtp-syntax.c +index bf8a3f6904..683b2014e4 100644 +--- a/src/lib-smtp/smtp-syntax.c ++++ b/src/lib-smtp/smtp-syntax.c +@@ -193,12 +193,10 @@ static int smtp_parse_ehlo_line(struct smtp_parser *parser, + (i_isalnum(*parser->cur) || *parser->cur == '-')) + parser->cur++; + +- if (key_r != NULL) +- *key_r = p_strdup_until(parser->pool, pbegin, parser->cur); ++ *key_r = p_strdup_until(parser->pool, pbegin, parser->cur); + + if (parser->cur >= parser->end) { +- if (params_r != NULL) +- *params_r = p_new(parser->pool, const char *, 1); ++ *params_r = p_new(parser->pool, const char *, 1); + return 1; + } + if (*parser->cur != ' ') { +@@ -208,18 +206,15 @@ static int smtp_parse_ehlo_line(struct smtp_parser *parser, + parser->cur++; + + pbegin = parser->cur; +- if (params_r != NULL) +- p_array_init(¶ms, parser->pool, 32); ++ p_array_init(¶ms, parser->pool, 32); + while (parser->cur < parser->end) { + if (*parser->cur == ' ') { + if (parser->cur+1 >= parser->end || *(parser->cur+1) == ' ') { + parser->error = "Missing EHLO parameter after ' '"; + return -1; + } +- if (params_r != NULL) { +- param = p_strdup_until(parser->pool, pbegin, parser->cur); +- array_append(¶ms, ¶m, 1); +- } ++ param = p_strdup_until(parser->pool, pbegin, parser->cur); ++ array_append(¶ms, ¶m, 1); + pbegin = parser->cur + 1; + } else if (!smtp_char_is_ehlo_param(*parser->cur)) { + parser->error = "Unexpected character in EHLO parameter"; +@@ -228,12 +223,10 @@ static int smtp_parse_ehlo_line(struct smtp_parser *parser, + parser->cur++; + } + +- if (params_r != NULL) { +- param = p_strdup_until(parser->pool, pbegin, parser->cur); +- array_append(¶ms, ¶m, 1); +- array_append_zero(¶ms); +- *params_r = array_idx(¶ms, 0); +- } ++ param = p_strdup_until(parser->pool, pbegin, parser->cur); ++ array_append(¶ms, ¶m, 1); ++ array_append_zero(¶ms); ++ *params_r = array_idx(¶ms, 0); + return 1; + } + +@@ -241,19 +234,20 @@ int smtp_ehlo_line_parse(const char *ehlo_line, const char **key_r, + const char *const **params_r, const char **error_r) + { + struct smtp_parser parser; +- int ret; ++ ++ *key_r = NULL; ++ *params_r = NULL; ++ *error_r = NULL; + + if (ehlo_line == NULL || *ehlo_line == '\0') { +- if (error_r != NULL) +- *error_r = "Parameter is empty"; ++ *error_r = "Parameter is empty"; + return -1; + } + + smtp_parser_init(&parser, pool_datastack_create(), ehlo_line); + +- if ((ret=smtp_parse_ehlo_line(&parser, key_r, params_r)) <= 0) { +- if (error_r != NULL) +- *error_r = parser.error; ++ if (smtp_parse_ehlo_line(&parser, key_r, params_r) <= 0) { ++ *error_r = parser.error; + return -1; + } + return 1; +-- +2.11.0 + diff -Nru dovecot-2.3.4.1/debian/patches/CVE-2020-109xx/0006-lib-smtp-smtp-syntax-Return-0-for-smtp_string_parse-.patch dovecot-2.3.4.1/debian/patches/CVE-2020-109xx/0006-lib-smtp-smtp-syntax-Return-0-for-smtp_string_parse-.patch --- dovecot-2.3.4.1/debian/patches/CVE-2020-109xx/0006-lib-smtp-smtp-syntax-Return-0-for-smtp_string_parse-.patch 1970-01-01 00:00:00.000000000 +0000 +++ dovecot-2.3.4.1/debian/patches/CVE-2020-109xx/0006-lib-smtp-smtp-syntax-Return-0-for-smtp_string_parse-.patch 2020-05-13 13:30:46.000000000 +0000 @@ -0,0 +1,27 @@ +From 934387b185074170654f87e34fe494a898732af7 Mon Sep 17 00:00:00 2001 +From: Stephan Bosch +Date: Tue, 24 Mar 2020 22:42:15 +0100 +Subject: [PATCH 06/17] lib-smtp: smtp-syntax - Return 0 for + smtp_string_parse() with empty input. + +This is what the current users of this function actually expect. +--- + src/lib-smtp/smtp-syntax.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/lib-smtp/smtp-syntax.c b/src/lib-smtp/smtp-syntax.c +index 683b2014e4..04fff9fc8c 100644 +--- a/src/lib-smtp/smtp-syntax.c ++++ b/src/lib-smtp/smtp-syntax.c +@@ -23,7 +23,7 @@ int smtp_string_parse(const char *string, + + if (string == NULL || *string == '\0') { + *value_r = ""; +- return 1; ++ return 0; + } + + smtp_parser_init(&parser, pool_datastack_create(), string); +-- +2.11.0 + diff -Nru dovecot-2.3.4.1/debian/patches/CVE-2020-109xx/0007-lib-smtp-Add-tests-for-smtp_string_parse-and-smtp_st.patch dovecot-2.3.4.1/debian/patches/CVE-2020-109xx/0007-lib-smtp-Add-tests-for-smtp_string_parse-and-smtp_st.patch --- dovecot-2.3.4.1/debian/patches/CVE-2020-109xx/0007-lib-smtp-Add-tests-for-smtp_string_parse-and-smtp_st.patch 1970-01-01 00:00:00.000000000 +0000 +++ dovecot-2.3.4.1/debian/patches/CVE-2020-109xx/0007-lib-smtp-Add-tests-for-smtp_string_parse-and-smtp_st.patch 2020-05-13 13:30:46.000000000 +0000 @@ -0,0 +1,194 @@ +From fe20f28677f1dccf9b9f28cd6578a7ae00a2ac9f Mon Sep 17 00:00:00 2001 +From: Stephan Bosch +Date: Tue, 24 Mar 2020 22:24:20 +0100 +Subject: [PATCH 07/17] lib-smtp: Add tests for smtp_string_parse() and + smtp_string_write(). + +--- + src/lib-smtp/Makefile.am | 5 ++ + src/lib-smtp/test-smtp-syntax.c | 150 ++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 155 insertions(+) + create mode 100644 src/lib-smtp/test-smtp-syntax.c + +diff --git a/src/lib-smtp/Makefile.am b/src/lib-smtp/Makefile.am +index 381d4fefe3..0ecc359876 100644 +--- a/src/lib-smtp/Makefile.am ++++ b/src/lib-smtp/Makefile.am +@@ -71,6 +71,7 @@ pkginc_libdir=$(pkgincludedir) + pkginc_lib_HEADERS = $(headers) + + test_programs = \ ++ test-smtp-syntax \ + test-smtp-address \ + test-smtp-params \ + test-smtp-reply-parser \ +@@ -111,6 +112,10 @@ test_deps = \ + ../lib-test/libtest.la \ + ../lib/liblib.la + ++test_smtp_syntax_SOURCES = test-smtp-syntax.c ++test_smtp_syntax_LDADD = $(test_libs) ++test_smtp_syntax_DEPENDENCIES = $(test_deps) ++ + test_smtp_address_SOURCES = test-smtp-address.c + test_smtp_address_LDFLAGS = -export-dynamic + test_smtp_address_LDADD = $(test_libs) +diff --git a/src/lib-smtp/test-smtp-syntax.c b/src/lib-smtp/test-smtp-syntax.c +new file mode 100644 +index 0000000000..735cd01220 +--- /dev/null ++++ b/src/lib-smtp/test-smtp-syntax.c +@@ -0,0 +1,150 @@ ++/* Copyright (c) 2020 Dovecot authors, see the included COPYING file */ ++ ++#include "lib.h" ++#include "str.h" ++#include "str-sanitize.h" ++#include "test-common.h" ++#include "smtp-syntax.h" ++ ++/* ++ * Valid string parse tests ++ */ ++ ++struct valid_string_parse_test { ++ const char *input, *parsed, *output; ++}; ++ ++static const struct valid_string_parse_test ++valid_string_parse_tests[] = { ++ { ++ .input = "", ++ .parsed = "", ++ }, ++ { ++ .input = "atom", ++ .parsed = "atom", ++ }, ++ { ++ .input = "abcdefghijklmnopqrstuvwxyz" ++ "ABCDEFGHIJKLMNOPQRSTUVWXYZ" ++ "0123456789!#$%&'*+-/=?^_`{|}~", ++ .parsed = "abcdefghijklmnopqrstuvwxyz" ++ "ABCDEFGHIJKLMNOPQRSTUVWXYZ" ++ "0123456789!#$%&'*+-/=?^_`{|}~", ++ }, ++ { ++ .input = "\"quoted-string\"", ++ .parsed = "quoted-string", ++ .output = "quoted-string", ++ }, ++ { ++ .input = "\"quoted \\\"string\\\"\"", ++ .parsed = "quoted \"string\"", ++ }, ++ { ++ .input = "\"quoted \\\\string\\\\\"", ++ .parsed = "quoted \\string\\", ++ }, ++}; ++ ++static const unsigned int valid_string_parse_test_count = ++ N_ELEMENTS(valid_string_parse_tests); ++ ++static void test_smtp_string_parse_valid(void) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < valid_string_parse_test_count; i++) T_BEGIN { ++ const struct valid_string_parse_test *test = ++ &valid_string_parse_tests[i]; ++ const char *parsed, *error = NULL; ++ int ret; ++ ++ ret = smtp_string_parse(test->input, &parsed, &error); ++ ++ test_begin(t_strdup_printf("smtp string valid [%d]", i)); ++ test_out_reason(t_strdup_printf("parse(\"%s\")", test->input), ++ ret >= 0, error); ++ test_assert(ret != 0 || *test->input == '\0'); ++ ++ if (!test_has_failed()) { ++ string_t *encoded; ++ const char *output; ++ ++ test_out(t_strdup_printf("parsed = \"%s\"", parsed), ++ null_strcmp(parsed, test->parsed) == 0); ++ ++ encoded = t_str_new(255); ++ smtp_string_write(encoded, parsed); ++ output = (test->output == NULL ? ++ test->input : test->output); ++ test_out(t_strdup_printf("write() = \"%s\"", ++ str_c(encoded)), ++ strcmp(str_c(encoded), output) == 0); ++ } ++ test_end(); ++ } T_END; ++} ++ ++/* ++ * Invalid string parse tests ++ */ ++ ++struct invalid_string_parse_test { ++ const char *input; ++}; ++ ++static const struct invalid_string_parse_test ++invalid_string_parse_tests[] = { ++ { ++ .input = " ", ++ }, ++ { ++ .input = "\\", ++ }, ++ { ++ .input = "\"", ++ }, ++ { ++ .input = "\"aa", ++ }, ++ { ++ .input = "aa\"", ++ }, ++}; ++ ++static const unsigned int invalid_string_parse_test_count = ++ N_ELEMENTS(invalid_string_parse_tests); ++ ++static void test_smtp_string_parse_invalid(void) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < invalid_string_parse_test_count; i++) T_BEGIN { ++ const struct invalid_string_parse_test *test = ++ &invalid_string_parse_tests[i]; ++ const char *parsed, *error; ++ int ret; ++ ++ ret = smtp_string_parse(test->input, &parsed, &error); ++ ++ test_begin(t_strdup_printf("smtp string invalid [%d]", i)); ++ test_out_reason(t_strdup_printf("parse(\"%s\")", test->input), ++ ret < 0, error); ++ test_end(); ++ } T_END; ++} ++ ++/* ++ * Tests ++ */ ++ ++int main(void) ++{ ++ static void (*test_functions[])(void) = { ++ test_smtp_string_parse_valid, ++ test_smtp_string_parse_invalid, ++ NULL ++ }; ++ return test_run(test_functions); ++} +-- +2.11.0 + diff -Nru dovecot-2.3.4.1/debian/patches/CVE-2020-109xx/0008-lib-smtp-test-smtp-server-errors-Add-tests-for-VRFY-.patch dovecot-2.3.4.1/debian/patches/CVE-2020-109xx/0008-lib-smtp-test-smtp-server-errors-Add-tests-for-VRFY-.patch --- dovecot-2.3.4.1/debian/patches/CVE-2020-109xx/0008-lib-smtp-test-smtp-server-errors-Add-tests-for-VRFY-.patch 1970-01-01 00:00:00.000000000 +0000 +++ dovecot-2.3.4.1/debian/patches/CVE-2020-109xx/0008-lib-smtp-test-smtp-server-errors-Add-tests-for-VRFY-.patch 2020-05-13 13:30:46.000000000 +0000 @@ -0,0 +1,343 @@ +From 38988b2e355898f734ac37a259a916229c4d974f Mon Sep 17 00:00:00 2001 +From: Stephan Bosch +Date: Tue, 24 Mar 2020 22:33:45 +0100 +Subject: [PATCH 08/17] lib-smtp: test-smtp-server-errors - Add tests for VRFY + and NOOP commands with invalid parameters. + +--- + src/lib-smtp/test-smtp-server-errors.c | 312 +++++++++++++++++++++++++++++++++ + 1 file changed, 312 insertions(+) + +diff --git a/src/lib-smtp/test-smtp-server-errors.c b/src/lib-smtp/test-smtp-server-errors.c +index 24af2aae3f..43ddb63016 100644 +--- a/src/lib-smtp/test-smtp-server-errors.c ++++ b/src/lib-smtp/test-smtp-server-errors.c +@@ -1270,6 +1270,316 @@ static void test_bad_rcpt(void) + } + + /* ++ * Bad VRFY ++ */ ++ ++/* client */ ++ ++struct _bad_vrfy_client { ++ struct smtp_reply_parser *parser; ++ unsigned int reply; ++ ++ bool replied:1; ++}; ++ ++static void ++test_bad_vrfy_client_input(struct client_connection *conn) ++{ ++ struct _bad_vrfy_client *ctx = conn->context; ++ struct smtp_reply *reply; ++ const char *error; ++ int ret; ++ ++ while ((ret = smtp_reply_parse_next(ctx->parser, FALSE, ++ &reply, &error)) > 0) { ++ if (debug) ++ i_debug("REPLY: %s", smtp_reply_log(reply)); ++ ++ switch (ctx->reply++) { ++ case 0: /* greeting */ ++ i_assert(reply->status == 220); ++ break; ++ case 1: /* bad command reply */ ++ switch (client_index) { ++ case 0: case 1: case 2: ++ i_assert(reply->status == 501); ++ break; ++ case 3: ++ i_assert(smtp_reply_is_success(reply)); ++ break; ++ default: ++ i_unreached(); ++ } ++ ctx->replied = TRUE; ++ io_loop_stop(ioloop); ++ connection_disconnect(&conn->conn); ++ return; ++ default: ++ i_unreached(); ++ } ++ } ++ ++ i_assert(ret == 0); ++} ++ ++static void ++test_bad_vrfy_client_connected(struct client_connection *conn) ++{ ++ struct _bad_vrfy_client *ctx; ++ ++ ctx = p_new(conn->pool, struct _bad_vrfy_client, 1); ++ ctx->parser = smtp_reply_parser_init(conn->conn.input, (size_t)-1); ++ conn->context = ctx; ++ ++ switch (client_index) { ++ case 0: ++ o_stream_nsend_str(conn->conn.output, ++ "VRFY\r\n"); ++ break; ++ case 1: ++ o_stream_nsend_str(conn->conn.output, ++ "VRFY \"hendrik\r\n"); ++ break; ++ case 2: ++ o_stream_nsend_str(conn->conn.output, ++ "VRFY hen\"drik\r\n"); ++ break; ++ case 3: ++ o_stream_nsend_str(conn->conn.output, ++ "VRFY \"hendrik\"\r\n"); ++ break; ++ default: ++ i_unreached(); ++ } ++} ++ ++static void ++test_bad_vrfy_client_deinit(struct client_connection *conn) ++{ ++ struct _bad_vrfy_client *ctx = conn->context; ++ ++ i_assert(ctx->replied); ++ smtp_reply_parser_deinit(&ctx->parser); ++} ++ ++static void test_client_bad_vrfy(unsigned int index) ++{ ++ test_client_input = test_bad_vrfy_client_input; ++ test_client_connected = test_bad_vrfy_client_connected; ++ test_client_deinit = test_bad_vrfy_client_deinit; ++ test_client_run(index); ++} ++ ++/* server */ ++ ++static void ++test_server_bad_vrfy_disconnect(void *context ATTR_UNUSED, const char *reason) ++{ ++ if (debug) ++ i_debug("Disconnect: %s", reason); ++} ++ ++static int ++test_server_bad_vrfy_rcpt(void *conn_ctx ATTR_UNUSED, ++ struct smtp_server_cmd_ctx *cmd ATTR_UNUSED, ++ struct smtp_server_cmd_rcpt *data ATTR_UNUSED) ++{ ++ test_assert(FALSE); ++ return 1; ++} ++ ++static int ++test_server_bad_vrfy_data_begin( ++ void *conn_ctx ATTR_UNUSED, struct smtp_server_cmd_ctx *cmd ATTR_UNUSED, ++ struct smtp_server_transaction *trans ATTR_UNUSED, ++ struct istream *data_input ATTR_UNUSED) ++{ ++ test_assert(FALSE); ++ return 1; ++} ++ ++static void ++test_server_bad_vrfy(const struct smtp_server_settings *server_set) ++{ ++ server_callbacks.conn_disconnect = test_server_bad_vrfy_disconnect; ++ ++ server_callbacks.conn_cmd_rcpt = test_server_bad_vrfy_rcpt; ++ server_callbacks.conn_cmd_data_begin = test_server_bad_vrfy_data_begin; ++ test_server_run(server_set); ++} ++ ++/* test */ ++ ++static void test_bad_vrfy(void) ++{ ++ struct smtp_server_settings smtp_server_set; ++ ++ test_server_defaults(&smtp_server_set); ++ smtp_server_set.max_client_idle_time_msecs = 1000; ++ ++ test_begin("bad VRFY"); ++ test_run_client_server(&smtp_server_set, ++ test_server_bad_vrfy, ++ test_client_bad_vrfy, 4); ++ test_end(); ++} ++ ++/* ++ * Bad NOOP ++ */ ++ ++/* client */ ++ ++struct _bad_noop_client { ++ struct smtp_reply_parser *parser; ++ unsigned int reply; ++ ++ bool replied:1; ++}; ++ ++static void ++test_bad_noop_client_input(struct client_connection *conn) ++{ ++ struct _bad_noop_client *ctx = conn->context; ++ struct smtp_reply *reply; ++ const char *error; ++ int ret; ++ ++ while ((ret = smtp_reply_parse_next(ctx->parser, FALSE, ++ &reply, &error)) > 0) { ++ if (debug) ++ i_debug("REPLY: %s", smtp_reply_log(reply)); ++ ++ switch (ctx->reply++) { ++ case 0: /* greeting */ ++ i_assert(reply->status == 220); ++ break; ++ case 1: /* bad command reply */ ++ switch (client_index) { ++ case 1: case 2: ++ i_assert(reply->status == 501); ++ break; ++ case 0: case 3: ++ i_assert(smtp_reply_is_success(reply)); ++ break; ++ default: ++ i_unreached(); ++ } ++ ctx->replied = TRUE; ++ io_loop_stop(ioloop); ++ connection_disconnect(&conn->conn); ++ return; ++ default: ++ i_unreached(); ++ } ++ } ++ ++ i_assert(ret == 0); ++} ++ ++static void ++test_bad_noop_client_connected(struct client_connection *conn) ++{ ++ struct _bad_noop_client *ctx; ++ ++ ctx = p_new(conn->pool, struct _bad_noop_client, 1); ++ ctx->parser = smtp_reply_parser_init(conn->conn.input, (size_t)-1); ++ conn->context = ctx; ++ ++ switch (client_index) { ++ case 0: ++ o_stream_nsend_str(conn->conn.output, ++ "NOOP\r\n"); ++ break; ++ case 1: ++ o_stream_nsend_str(conn->conn.output, ++ "NOOP \"frop\r\n"); ++ break; ++ case 2: ++ o_stream_nsend_str(conn->conn.output, ++ "NOOP fr\"op\r\n"); ++ break; ++ case 3: ++ o_stream_nsend_str(conn->conn.output, ++ "NOOP \"frop\"\r\n"); ++ break; ++ default: ++ i_unreached(); ++ } ++} ++ ++static void ++test_bad_noop_client_deinit(struct client_connection *conn) ++{ ++ struct _bad_noop_client *ctx = conn->context; ++ ++ i_assert(ctx->replied); ++ smtp_reply_parser_deinit(&ctx->parser); ++} ++ ++static void test_client_bad_noop(unsigned int index) ++{ ++ test_client_input = test_bad_noop_client_input; ++ test_client_connected = test_bad_noop_client_connected; ++ test_client_deinit = test_bad_noop_client_deinit; ++ test_client_run(index); ++} ++ ++/* server */ ++ ++static void ++test_server_bad_noop_disconnect(void *context ATTR_UNUSED, const char *reason) ++{ ++ if (debug) ++ i_debug("Disconnect: %s", reason); ++} ++ ++static int ++test_server_bad_noop_rcpt(void *conn_ctx ATTR_UNUSED, ++ struct smtp_server_cmd_ctx *cmd ATTR_UNUSED, ++ struct smtp_server_cmd_rcpt *data ATTR_UNUSED) ++{ ++ test_assert(FALSE); ++ return 1; ++} ++ ++static int ++test_server_bad_noop_data_begin( ++ void *conn_ctx ATTR_UNUSED, struct smtp_server_cmd_ctx *cmd ATTR_UNUSED, ++ struct smtp_server_transaction *trans ATTR_UNUSED, ++ struct istream *data_input ATTR_UNUSED) ++{ ++ test_assert(FALSE); ++ return 1; ++} ++ ++static void ++test_server_bad_noop(const struct smtp_server_settings *server_set) ++{ ++ server_callbacks.conn_disconnect = test_server_bad_noop_disconnect; ++ ++ server_callbacks.conn_cmd_rcpt = test_server_bad_noop_rcpt; ++ server_callbacks.conn_cmd_data_begin = test_server_bad_noop_data_begin; ++ test_server_run(server_set); ++} ++ ++/* test */ ++ ++static void test_bad_noop(void) ++{ ++ struct smtp_server_settings smtp_server_set; ++ ++ test_server_defaults(&smtp_server_set); ++ smtp_server_set.max_client_idle_time_msecs = 1000; ++ ++ test_begin("bad NOOP"); ++ test_run_client_server(&smtp_server_set, ++ test_server_bad_noop, ++ test_client_bad_noop, 4); ++ test_end(); ++} ++ ++/* + * MAIL workarounds + */ + +@@ -2024,6 +2334,8 @@ static void (*const test_functions[])(void) = { + test_bad_ehlo, + test_bad_mail, + test_bad_rcpt, ++ test_bad_vrfy, ++ test_bad_noop, + test_mail_workarounds, + test_rcpt_workarounds, + test_too_many_recipients, +-- +2.11.0 + diff -Nru dovecot-2.3.4.1/debian/patches/CVE-2020-109xx/0009-lib-smtp-server-command-Move-core-of-smtp_server_com.patch dovecot-2.3.4.1/debian/patches/CVE-2020-109xx/0009-lib-smtp-server-command-Move-core-of-smtp_server_com.patch --- dovecot-2.3.4.1/debian/patches/CVE-2020-109xx/0009-lib-smtp-server-command-Move-core-of-smtp_server_com.patch 1970-01-01 00:00:00.000000000 +0000 +++ dovecot-2.3.4.1/debian/patches/CVE-2020-109xx/0009-lib-smtp-server-command-Move-core-of-smtp_server_com.patch 2020-05-13 13:30:46.000000000 +0000 @@ -0,0 +1,91 @@ +From 62dcd47377f6a79785ba5df6b4a0a47a14adbe54 Mon Sep 17 00:00:00 2001 +From: Stephan Bosch +Date: Thu, 1 Nov 2018 00:44:10 +0100 +Subject: [PATCH 09/17] lib-smtp: server: command: Move core of + smtp_server_command_submit_reply() into a separate function. + +Makes the next changes easier. +--- + src/lib-smtp/smtp-server-command.c | 53 ++++++++++++++++++++++---------------- + 1 file changed, 31 insertions(+), 22 deletions(-) + +diff --git a/src/lib-smtp/smtp-server-command.c b/src/lib-smtp/smtp-server-command.c +index cdc7b1b5b3..5cfa5786b7 100644 +--- a/src/lib-smtp/smtp-server-command.c ++++ b/src/lib-smtp/smtp-server-command.c +@@ -391,6 +391,36 @@ void smtp_server_command_completed(struct smtp_server_command *cmd) + } + } + ++static bool ++smtp_server_command_handle_reply(struct smtp_server_command *cmd) ++{ ++ struct smtp_server_connection *conn = cmd->context.conn; ++ ++ smtp_server_command_replied(cmd); ++ ++ /* submit reply */ ++ smtp_server_connection_ref(conn); ++ switch (cmd->state) { ++ case SMTP_SERVER_COMMAND_STATE_NEW: ++ case SMTP_SERVER_COMMAND_STATE_PROCESSING: ++ if (!smtp_server_command_is_complete(cmd)) { ++ smtp_server_command_debug(&cmd->context, ++ "Not ready to reply"); ++ cmd->state = SMTP_SERVER_COMMAND_STATE_SUBMITTED_REPLY; ++ break; ++ } ++ smtp_server_command_ready_to_reply(cmd); ++ break; ++ case SMTP_SERVER_COMMAND_STATE_READY_TO_REPLY: ++ case SMTP_SERVER_COMMAND_STATE_ABORTED: ++ break; ++ default: ++ i_unreached(); ++ } ++ ++ return smtp_server_connection_unref(&conn); ++} ++ + void smtp_server_command_submit_reply(struct smtp_server_command *cmd) + { + struct smtp_server_connection *conn = cmd->context.conn; +@@ -422,34 +452,13 @@ void smtp_server_command_submit_reply(struct smtp_server_command *cmd) + cmd->hook_next = NULL; + cmd->context.hook_next = NULL; + +- smtp_server_command_replied(cmd); +- + /* limit number of consecutive bad commands */ + if (is_bad) + conn->bad_counter++; + else if (cmd->replies_submitted == cmd->replies_expected) + conn->bad_counter = 0; + +- /* submit reply */ +- smtp_server_connection_ref(conn); +- switch (cmd->state) { +- case SMTP_SERVER_COMMAND_STATE_NEW: +- case SMTP_SERVER_COMMAND_STATE_PROCESSING: +- if (!smtp_server_command_is_complete(cmd)) { +- smtp_server_command_debug(&cmd->context, +- "Not ready to reply"); +- cmd->state = SMTP_SERVER_COMMAND_STATE_SUBMITTED_REPLY; +- break; +- } +- smtp_server_command_ready_to_reply(cmd); +- break; +- case SMTP_SERVER_COMMAND_STATE_READY_TO_REPLY: +- case SMTP_SERVER_COMMAND_STATE_ABORTED: +- break; +- default: +- i_unreached(); +- } +- if (!smtp_server_connection_unref(&conn)) ++ if (!smtp_server_command_handle_reply(cmd)) + return; + + if (conn != NULL && conn->bad_counter > conn->set.max_bad_commands) { +-- +2.11.0 + diff -Nru dovecot-2.3.4.1/debian/patches/CVE-2020-109xx/0010-lib-smtp-smtp-server-command-Assign-cmd-reg-immediat.patch dovecot-2.3.4.1/debian/patches/CVE-2020-109xx/0010-lib-smtp-smtp-server-command-Assign-cmd-reg-immediat.patch --- dovecot-2.3.4.1/debian/patches/CVE-2020-109xx/0010-lib-smtp-smtp-server-command-Assign-cmd-reg-immediat.patch 1970-01-01 00:00:00.000000000 +0000 +++ dovecot-2.3.4.1/debian/patches/CVE-2020-109xx/0010-lib-smtp-smtp-server-command-Assign-cmd-reg-immediat.patch 2020-05-13 13:30:46.000000000 +0000 @@ -0,0 +1,64 @@ +From 15e7c36612ad1bf3f1e41f6215212338045dfa8a Mon Sep 17 00:00:00 2001 +From: Stephan Bosch +Date: Tue, 17 Mar 2020 11:58:52 +0100 +Subject: [PATCH 10/17] lib-smtp: smtp-server-command - Assign cmd->reg + immediately. + +--- + src/lib-smtp/smtp-server-command.c | 13 ++++++------- + 1 file changed, 6 insertions(+), 7 deletions(-) + +diff --git a/src/lib-smtp/smtp-server-command.c b/src/lib-smtp/smtp-server-command.c +index 5cfa5786b7..b63fbb1b00 100644 +--- a/src/lib-smtp/smtp-server-command.c ++++ b/src/lib-smtp/smtp-server-command.c +@@ -175,13 +175,13 @@ smtp_server_command_new(struct smtp_server_connection *conn, + const char *name, const char *params) + { + struct smtp_server *server = conn->server; +- const struct smtp_server_command_reg *cmd_reg; + struct smtp_server_command *cmd; + + cmd = smtp_server_command_alloc(conn); + cmd->context.name = p_strdup(cmd->context.pool, name); ++ cmd->reg = smtp_server_command_find(server, name); + +- if ((cmd_reg=smtp_server_command_find(server, name)) == NULL) { ++ if (cmd->reg == NULL) { + /* RFC 5321, Section 4.2.4: Reply Code 502 + + Questions have been raised as to when reply code 502 (Command +@@ -194,7 +194,7 @@ smtp_server_command_new(struct smtp_server_connection *conn, + 500, "5.5.1", "Unknown command"); + + } else if (!conn->ssl_secured && conn->set.tls_required && +- (cmd_reg->flags & SMTP_SERVER_CMD_FLAG_PRETLS) == 0) { ++ (cmd->reg->flags & SMTP_SERVER_CMD_FLAG_PRETLS) == 0) { + /* RFC 3207, Section 4: + + A SMTP server that is not publicly referenced may choose to +@@ -213,7 +213,7 @@ smtp_server_command_new(struct smtp_server_connection *conn, + 530, "5.7.0", "TLS required."); + + } else if (!conn->authenticated && !conn->set.auth_optional && +- (cmd_reg->flags & SMTP_SERVER_CMD_FLAG_PREAUTH) == 0) { ++ (cmd->reg->flags & SMTP_SERVER_CMD_FLAG_PREAUTH) == 0) { + /* RFC 4954, Section 6: Status Codes + + 530 5.7.0 Authentication required +@@ -229,10 +229,9 @@ smtp_server_command_new(struct smtp_server_connection *conn, + } else { + struct smtp_server_command *tmp_cmd = cmd; + +- i_assert(cmd_reg->func != NULL); ++ i_assert(cmd->reg->func != NULL); + smtp_server_command_ref(tmp_cmd); +- tmp_cmd->reg = cmd_reg; +- cmd_reg->func(&tmp_cmd->context, params); ++ cmd->reg->func(&tmp_cmd->context, params); + if (tmp_cmd->state == SMTP_SERVER_COMMAND_STATE_NEW) + tmp_cmd->state = SMTP_SERVER_COMMAND_STATE_PROCESSING; + if (!smtp_server_command_unref(&tmp_cmd)) +-- +2.11.0 + diff -Nru dovecot-2.3.4.1/debian/patches/CVE-2020-109xx/0011-lib-smtp-smtp-server-command-Guarantee-that-non-dest.patch dovecot-2.3.4.1/debian/patches/CVE-2020-109xx/0011-lib-smtp-smtp-server-command-Guarantee-that-non-dest.patch --- dovecot-2.3.4.1/debian/patches/CVE-2020-109xx/0011-lib-smtp-smtp-server-command-Guarantee-that-non-dest.patch 1970-01-01 00:00:00.000000000 +0000 +++ dovecot-2.3.4.1/debian/patches/CVE-2020-109xx/0011-lib-smtp-smtp-server-command-Guarantee-that-non-dest.patch 2020-05-13 13:30:46.000000000 +0000 @@ -0,0 +1,27 @@ +From c4ca98650cc71e0aa51de78de93ee9245717f704 Mon Sep 17 00:00:00 2001 +From: Stephan Bosch +Date: Tue, 24 Mar 2020 12:13:43 +0100 +Subject: [PATCH 11/17] lib-smtp: smtp-server-command - Guarantee that + non-destroy hooks aren't called for an ended command. + +--- + src/lib-smtp/smtp-server-command.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/src/lib-smtp/smtp-server-command.c b/src/lib-smtp/smtp-server-command.c +index b63fbb1b00..0ee9986aae 100644 +--- a/src/lib-smtp/smtp-server-command.c ++++ b/src/lib-smtp/smtp-server-command.c +@@ -316,6 +316,9 @@ void smtp_server_command_next_to_reply(struct smtp_server_command *cmd) + + smtp_server_command_debug(&cmd->context, "Next to reply"); + ++ if (cmd->state >= SMTP_SERVER_COMMAND_STATE_FINISHED) ++ return; ++ + /* execute private hook_next */ + if (cmd->hook_next != NULL) { + smtp_server_cmd_func_t *hook_next = cmd->hook_next; +-- +2.11.0 + diff -Nru dovecot-2.3.4.1/debian/patches/CVE-2020-109xx/0012-lib-smtp-smtp-server-command-Perform-initial-command.patch dovecot-2.3.4.1/debian/patches/CVE-2020-109xx/0012-lib-smtp-smtp-server-command-Perform-initial-command.patch --- dovecot-2.3.4.1/debian/patches/CVE-2020-109xx/0012-lib-smtp-smtp-server-command-Perform-initial-command.patch 1970-01-01 00:00:00.000000000 +0000 +++ dovecot-2.3.4.1/debian/patches/CVE-2020-109xx/0012-lib-smtp-smtp-server-command-Perform-initial-command.patch 2020-05-13 13:30:46.000000000 +0000 @@ -0,0 +1,83 @@ +From e996b3978e179dc6f3ef8a8e7d9552a924449239 Mon Sep 17 00:00:00 2001 +From: Stephan Bosch +Date: Tue, 24 Mar 2020 12:23:32 +0100 +Subject: [PATCH 12/17] lib-smtp: smtp-server-command - Perform initial command + execution in separate function. + +--- + src/lib-smtp/smtp-server-command.c | 11 +++++++++-- + src/lib-smtp/smtp-server-connection.c | 3 ++- + src/lib-smtp/smtp-server-private.h | 7 +++++-- + 3 files changed, 16 insertions(+), 5 deletions(-) + +diff --git a/src/lib-smtp/smtp-server-command.c b/src/lib-smtp/smtp-server-command.c +index 0ee9986aae..4523e988df 100644 +--- a/src/lib-smtp/smtp-server-command.c ++++ b/src/lib-smtp/smtp-server-command.c +@@ -172,7 +172,7 @@ smtp_server_command_alloc(struct smtp_server_connection *conn) + + struct smtp_server_command * + smtp_server_command_new(struct smtp_server_connection *conn, +- const char *name, const char *params) ++ const char *name) + { + struct smtp_server *server = conn->server; + struct smtp_server_command *cmd; +@@ -181,6 +181,14 @@ smtp_server_command_new(struct smtp_server_connection *conn, + cmd->context.name = p_strdup(cmd->context.pool, name); + cmd->reg = smtp_server_command_find(server, name); + ++ return cmd; ++} ++ ++void smtp_server_command_execute(struct smtp_server_command *cmd, ++ const char *params) ++{ ++ struct smtp_server_connection *conn = cmd->context.conn; ++ + if (cmd->reg == NULL) { + /* RFC 5321, Section 4.2.4: Reply Code 502 + +@@ -237,7 +245,6 @@ smtp_server_command_new(struct smtp_server_connection *conn, + if (!smtp_server_command_unref(&tmp_cmd)) + cmd = NULL; + } +- return cmd; + } + + void smtp_server_command_ref(struct smtp_server_command *cmd) +diff --git a/src/lib-smtp/smtp-server-connection.c b/src/lib-smtp/smtp-server-connection.c +index ff705fba58..036b2f6103 100644 +--- a/src/lib-smtp/smtp-server-connection.c ++++ b/src/lib-smtp/smtp-server-connection.c +@@ -325,7 +325,8 @@ smtp_server_connection_handle_command(struct smtp_server_connection *conn, + struct smtp_server_command *cmd; + + smtp_server_connection_ref(tmp_conn); +- cmd = smtp_server_command_new(tmp_conn, cmd_name, cmd_params); ++ cmd = smtp_server_command_new(tmp_conn, cmd_name); ++ smtp_server_command_execute(cmd, cmd_params); + if (!smtp_server_connection_unref(&tmp_conn)) { + /* the command start callback managed to get this connection + destroyed */ +diff --git a/src/lib-smtp/smtp-server-private.h b/src/lib-smtp/smtp-server-private.h +index 58972646ca..25d31e2de8 100644 +--- a/src/lib-smtp/smtp-server-private.h ++++ b/src/lib-smtp/smtp-server-private.h +@@ -226,8 +226,11 @@ void smtp_server_command_debug(struct smtp_server_cmd_ctx *cmd, + struct smtp_server_command * + smtp_server_command_alloc(struct smtp_server_connection *conn); + struct smtp_server_command * +-smtp_server_command_new(struct smtp_server_connection *conn, +- const char *name, const char *params); ++smtp_server_command_new(struct smtp_server_connection *conn, const char *name); ++ ++void smtp_server_command_execute(struct smtp_server_command *cmd, ++ const char *params); ++ + void smtp_server_command_ref(struct smtp_server_command *cmd); + bool smtp_server_command_unref(struct smtp_server_command **_cmd); + void smtp_server_command_abort(struct smtp_server_command **_cmd); +-- +2.11.0 + diff -Nru dovecot-2.3.4.1/debian/patches/CVE-2020-109xx/0013-lib-smtp-smtp-server-connection-Hold-a-command-refer.patch dovecot-2.3.4.1/debian/patches/CVE-2020-109xx/0013-lib-smtp-smtp-server-connection-Hold-a-command-refer.patch --- dovecot-2.3.4.1/debian/patches/CVE-2020-109xx/0013-lib-smtp-smtp-server-connection-Hold-a-command-refer.patch 1970-01-01 00:00:00.000000000 +0000 +++ dovecot-2.3.4.1/debian/patches/CVE-2020-109xx/0013-lib-smtp-smtp-server-connection-Hold-a-command-refer.patch 2020-05-13 13:30:46.000000000 +0000 @@ -0,0 +1,51 @@ +From 75562ab36126594969b7c5c65b848317eeaa5e75 Mon Sep 17 00:00:00 2001 +From: Stephan Bosch +Date: Tue, 24 Mar 2020 12:25:03 +0100 +Subject: [PATCH 13/17] lib-smtp: smtp-server-connection - Hold a command + reference while executing a command. + +This fixes a use-after-free problem at the end of +smtp_server_connection_handle_command(). +--- + src/lib-smtp/smtp-server-connection.c | 13 ++++++++++--- + 1 file changed, 10 insertions(+), 3 deletions(-) + +diff --git a/src/lib-smtp/smtp-server-connection.c b/src/lib-smtp/smtp-server-connection.c +index 036b2f6103..8bd595557a 100644 +--- a/src/lib-smtp/smtp-server-connection.c ++++ b/src/lib-smtp/smtp-server-connection.c +@@ -323,21 +323,28 @@ smtp_server_connection_handle_command(struct smtp_server_connection *conn, + { + struct smtp_server_connection *tmp_conn = conn; + struct smtp_server_command *cmd; ++ bool finished; + +- smtp_server_connection_ref(tmp_conn); + cmd = smtp_server_command_new(tmp_conn, cmd_name); ++ ++ smtp_server_command_ref(cmd); ++ ++ smtp_server_connection_ref(tmp_conn); + smtp_server_command_execute(cmd, cmd_params); + if (!smtp_server_connection_unref(&tmp_conn)) { + /* the command start callback managed to get this connection + destroyed */ ++ smtp_server_command_unref(&cmd); + return FALSE; + } + +- if (cmd != NULL && conn->command_queue_head == cmd) ++ if (conn->command_queue_head == cmd) + smtp_server_command_next_to_reply(cmd); + + smtp_server_connection_timeout_update(conn); +- return (cmd == NULL || !cmd->input_locked); ++ ++ finished = !cmd->input_locked; ++ return (!smtp_server_command_unref(&cmd) || finished); + } + + int smtp_server_connection_ssl_init(struct smtp_server_connection *conn) +-- +2.11.0 + diff -Nru dovecot-2.3.4.1/debian/patches/CVE-2020-109xx/0014-lib-smtp-test-smtp-server-errors-Add-tests-for-large.patch dovecot-2.3.4.1/debian/patches/CVE-2020-109xx/0014-lib-smtp-test-smtp-server-errors-Add-tests-for-large.patch --- dovecot-2.3.4.1/debian/patches/CVE-2020-109xx/0014-lib-smtp-test-smtp-server-errors-Add-tests-for-large.patch 1970-01-01 00:00:00.000000000 +0000 +++ dovecot-2.3.4.1/debian/patches/CVE-2020-109xx/0014-lib-smtp-test-smtp-server-errors-Add-tests-for-large.patch 2020-05-13 13:30:46.000000000 +0000 @@ -0,0 +1,200 @@ +From 07946bc3ccc93cee11f680c834209d4d26be15aa Mon Sep 17 00:00:00 2001 +From: Stephan Bosch +Date: Tue, 24 Mar 2020 12:59:15 +0100 +Subject: [PATCH 14/17] lib-smtp: test-smtp-server-errors - Add tests for large + series of empty and bad commands. + +--- + src/lib-smtp/test-smtp-server-errors.c | 169 +++++++++++++++++++++++++++++++++ + 1 file changed, 169 insertions(+) + +diff --git a/src/lib-smtp/test-smtp-server-errors.c b/src/lib-smtp/test-smtp-server-errors.c +index 43ddb63016..f3cd2c401d 100644 +--- a/src/lib-smtp/test-smtp-server-errors.c ++++ b/src/lib-smtp/test-smtp-server-errors.c +@@ -570,6 +570,174 @@ static void test_bad_command(void) + } + + /* ++ * Many bad commands ++ */ ++ ++/* client */ ++ ++struct _many_bad_commands_client { ++ struct smtp_reply_parser *parser; ++ unsigned int reply; ++ bool replied:1; ++}; ++ ++static void ++test_many_bad_commands_client_input(struct client_connection *conn) ++{ ++ struct _many_bad_commands_client *ctx = conn->context; ++ struct smtp_reply *reply; ++ const char *error; ++ int ret; ++ ++ while ((ret=smtp_reply_parse_next(ctx->parser, FALSE, ++ &reply, &error)) > 0) { ++ if (debug) ++ i_debug("REPLY: %s", smtp_reply_log(reply)); ++ ++ switch (ctx->reply++) { ++ /* greeting */ ++ case 0: ++ i_assert(reply->status == 220); ++ break; ++ /* bad command reply */ ++ case 1: case 2: case 3: case 4: case 5: ++ case 6: case 7: case 8: case 9: case 10: ++ i_assert(reply->status == 500); ++ break; ++ case 11: ++ i_assert(reply->status == 421); ++ ctx->replied = TRUE; ++ io_loop_stop(ioloop); ++ connection_disconnect(&conn->conn); ++ return; ++ default: ++ i_unreached(); ++ } ++ } ++ ++ i_assert(ret >= 0); ++} ++ ++static void ++test_many_bad_commands_client_connected(struct client_connection *conn) ++{ ++ struct _many_bad_commands_client *ctx; ++ ++ ctx = p_new(conn->pool, struct _many_bad_commands_client, 1); ++ ctx->parser = smtp_reply_parser_init(conn->conn.input, (size_t)-1); ++ conn->context = ctx; ++ ++ switch (client_index) { ++ case 0: ++ o_stream_nsend_str(conn->conn.output, ++ "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"); ++ break; ++ case 1: ++ o_stream_nsend_str(conn->conn.output, ++ "a\r\nb\r\nc\r\nd\r\ne\r\nf\r\ng\r\nh\r\n" ++ "i\r\nj\r\nk\r\nl\r\nm\r\nn\r\no\r\np\r\n"); ++ break; ++ default: ++ i_unreached(); ++ } ++} ++ ++static void ++test_many_bad_commands_client_deinit(struct client_connection *conn) ++{ ++ struct _many_bad_commands_client *ctx = conn->context; ++ ++ i_assert(ctx->replied); ++ smtp_reply_parser_deinit(&ctx->parser); ++} ++ ++static void test_client_many_bad_commands(unsigned int index) ++{ ++ test_client_input = test_many_bad_commands_client_input; ++ test_client_connected = test_many_bad_commands_client_connected; ++ test_client_deinit = test_many_bad_commands_client_deinit; ++ test_client_run(index); ++} ++ ++/* server */ ++ ++struct _many_bad_commands { ++ struct istream *payload_input; ++ struct io *io; ++ ++ bool serviced:1; ++}; ++ ++static void ++test_server_many_bad_commands_disconnect(void *context ATTR_UNUSED, ++ const char *reason) ++{ ++ if (debug) ++ i_debug("Disconnect: %s", reason); ++ io_loop_stop(ioloop); ++} ++ ++static int ++test_server_many_bad_commands_helo( ++ void *conn_ctx ATTR_UNUSED, struct smtp_server_cmd_ctx *cmd ATTR_UNUSED, ++ struct smtp_server_cmd_helo *data ATTR_UNUSED) ++{ ++ test_assert(FALSE); ++ return 1; ++} ++ ++static int ++test_server_many_bad_commands_rcpt( ++ void *conn_ctx ATTR_UNUSED, struct smtp_server_cmd_ctx *cmd ATTR_UNUSED, ++ struct smtp_server_cmd_rcpt *data ATTR_UNUSED) ++{ ++ test_assert(FALSE); ++ return 1; ++} ++ ++static int ++test_server_many_bad_commands_data_begin( ++ void *conn_ctx ATTR_UNUSED, struct smtp_server_cmd_ctx *cmd ATTR_UNUSED, ++ struct smtp_server_transaction *trans ATTR_UNUSED, ++ struct istream *data_input ATTR_UNUSED) ++{ ++ test_assert(FALSE); ++ return 1; ++} ++ ++static void test_server_many_bad_commands ++(const struct smtp_server_settings *server_set) ++{ ++ server_callbacks.conn_disconnect = ++ test_server_many_bad_commands_disconnect; ++ ++ server_callbacks.conn_cmd_helo = ++ test_server_many_bad_commands_helo; ++ server_callbacks.conn_cmd_rcpt = ++ test_server_many_bad_commands_rcpt; ++ server_callbacks.conn_cmd_data_begin = ++ test_server_many_bad_commands_data_begin; ++ test_server_run(server_set); ++} ++ ++/* test */ ++ ++static void test_many_bad_commands(void) ++{ ++ struct smtp_server_settings smtp_server_set; ++ ++ test_server_defaults(&smtp_server_set); ++ smtp_server_set.max_client_idle_time_msecs = 1000; ++ smtp_server_set.max_bad_commands = 10; ++ ++ test_begin("many bad commands"); ++ test_run_client_server(&smtp_server_set, ++ test_server_many_bad_commands, ++ test_client_many_bad_commands, 2); ++ test_end(); ++} ++ ++/* + * Long command + */ + +@@ -2329,6 +2497,7 @@ static void (*const test_functions[])(void) = { + test_slow_client, + test_hanging_command_payload, + test_bad_command, ++ test_many_bad_commands, + test_long_command, + test_big_data, + test_bad_ehlo, +-- +2.11.0 + diff -Nru dovecot-2.3.4.1/debian/patches/CVE-2020-109xx/0015-lib-smtp-smtp-address-Don-t-return-NULL-from-smtp_ad.patch dovecot-2.3.4.1/debian/patches/CVE-2020-109xx/0015-lib-smtp-smtp-address-Don-t-return-NULL-from-smtp_ad.patch --- dovecot-2.3.4.1/debian/patches/CVE-2020-109xx/0015-lib-smtp-smtp-address-Don-t-return-NULL-from-smtp_ad.patch 1970-01-01 00:00:00.000000000 +0000 +++ dovecot-2.3.4.1/debian/patches/CVE-2020-109xx/0015-lib-smtp-smtp-address-Don-t-return-NULL-from-smtp_ad.patch 2020-05-13 13:30:46.000000000 +0000 @@ -0,0 +1,64 @@ +From d4d48764ca9e77e5e7a2eaeae526b4120807737b Mon Sep 17 00:00:00 2001 +From: Stephan Bosch +Date: Sun, 22 Mar 2020 18:14:44 +0100 +Subject: [PATCH 15/17] lib-smtp: smtp-address - Don't return NULL from + smtp_address_clone*() unless the input is NULL. + +--- + src/lib-smtp/smtp-address.c | 20 ++++++++++++-------- + 1 file changed, 12 insertions(+), 8 deletions(-) + +diff --git a/src/lib-smtp/smtp-address.c b/src/lib-smtp/smtp-address.c +index bb31d34a67..c55e1a432b 100644 +--- a/src/lib-smtp/smtp-address.c ++++ b/src/lib-smtp/smtp-address.c +@@ -617,17 +617,19 @@ struct smtp_address * + smtp_address_clone(pool_t pool, const struct smtp_address *src) + { + struct smtp_address *new; +- size_t size, lpsize, dsize = 0; +- char *data, *localpart, *domain = NULL; ++ size_t size, lpsize = 0, dsize = 0; ++ char *data, *localpart = NULL, *domain = NULL; + +- if (smtp_address_isnull(src)) ++ if (src == NULL) + return NULL; + + /* @UNSAFE */ + + size = sizeof(struct smtp_address); +- lpsize = strlen(src->localpart) + 1; +- size = MALLOC_ADD(size, lpsize); ++ if (!smtp_address_isnull(src)) { ++ lpsize = strlen(src->localpart) + 1; ++ size = MALLOC_ADD(size, lpsize); ++ } + if (src->domain != NULL) { + dsize = strlen(src->domain) + 1; + size = MALLOC_ADD(size, dsize); +@@ -635,8 +637,10 @@ smtp_address_clone(pool_t pool, const struct smtp_address *src) + + data = p_malloc(pool, size); + new = (struct smtp_address *)data; +- localpart = PTR_OFFSET(data, sizeof(*new)); +- memcpy(localpart, src->localpart, lpsize); ++ if (lpsize > 0) { ++ localpart = PTR_OFFSET(data, sizeof(*new)); ++ memcpy(localpart, src->localpart, lpsize); ++ } + if (dsize > 0) { + domain = PTR_OFFSET(data, sizeof(*new) + lpsize); + memcpy(domain, src->domain, dsize); +@@ -677,7 +681,7 @@ smtp_address_clone_temp(const struct smtp_address *src) + { + struct smtp_address *new; + +- if (smtp_address_isnull(src)) ++ if (src == NULL) + return NULL; + + new = t_new(struct smtp_address, 1); +-- +2.11.0 + diff -Nru dovecot-2.3.4.1/debian/patches/CVE-2020-109xx/0016-lib-smtp-smtp-address-Don-t-recognize-an-address-wit.patch dovecot-2.3.4.1/debian/patches/CVE-2020-109xx/0016-lib-smtp-smtp-address-Don-t-recognize-an-address-wit.patch --- dovecot-2.3.4.1/debian/patches/CVE-2020-109xx/0016-lib-smtp-smtp-address-Don-t-recognize-an-address-wit.patch 1970-01-01 00:00:00.000000000 +0000 +++ dovecot-2.3.4.1/debian/patches/CVE-2020-109xx/0016-lib-smtp-smtp-address-Don-t-recognize-an-address-wit.patch 2020-05-13 13:30:46.000000000 +0000 @@ -0,0 +1,29 @@ +From c2a64b7a075d6d96e29b18f7fb11b0bab4e30073 Mon Sep 17 00:00:00 2001 +From: Stephan Bosch +Date: Fri, 20 Mar 2020 13:35:19 +0100 +Subject: [PATCH 16/17] lib-smtp: smtp-address - Don't recognize an address + with empty localpart as <>. + +Depending on context, the addresses <""@domain.tld> and <""> are potentially +valid non-null addresses. +--- + src/lib-smtp/smtp-address.h | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/src/lib-smtp/smtp-address.h b/src/lib-smtp/smtp-address.h +index 2556e4feab..6d8ccde52d 100644 +--- a/src/lib-smtp/smtp-address.h ++++ b/src/lib-smtp/smtp-address.h +@@ -122,8 +122,7 @@ smtp_address_equals(const struct smtp_address *address1, + static inline bool ATTR_NULL(1) ATTR_PURE + smtp_address_isnull(const struct smtp_address *address) + { +- return (address == NULL || address->localpart == NULL || +- *address->localpart == '\0'); ++ return (address == NULL || address->localpart == NULL); + } + + #endif +-- +2.11.0 + diff -Nru dovecot-2.3.4.1/debian/patches/CVE-2020-109xx/0017-lmtp-lmtp-commands-Explicity-prohibit-empty-RCPT-pat.patch dovecot-2.3.4.1/debian/patches/CVE-2020-109xx/0017-lmtp-lmtp-commands-Explicity-prohibit-empty-RCPT-pat.patch --- dovecot-2.3.4.1/debian/patches/CVE-2020-109xx/0017-lmtp-lmtp-commands-Explicity-prohibit-empty-RCPT-pat.patch 1970-01-01 00:00:00.000000000 +0000 +++ dovecot-2.3.4.1/debian/patches/CVE-2020-109xx/0017-lmtp-lmtp-commands-Explicity-prohibit-empty-RCPT-pat.patch 2020-05-13 13:30:46.000000000 +0000 @@ -0,0 +1,38 @@ +From 5f0bfc627883695eff48f92e8b57cc220f1ae596 Mon Sep 17 00:00:00 2001 +From: Stephan Bosch +Date: Fri, 20 Mar 2020 13:38:41 +0100 +Subject: [PATCH 17/17] lmtp: lmtp-commands - Explicity prohibit empty RCPT + path. + +The empty path <""> will yield an empty username. +--- + src/lmtp/commands.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/src/lmtp/commands.c b/src/lmtp/commands.c +index 76d367e14e..17e8ee470a 100644 +--- a/src/lmtp/commands.c ++++ b/src/lmtp/commands.c +@@ -51,9 +51,19 @@ int cmd_rcpt(void *conn_ctx, struct smtp_server_cmd_ctx *cmd, + char delim = '\0'; + int ret; + ++ i_assert(!smtp_address_isnull(data->path)); ++ if (*data->path->localpart == '\0' && data->path->domain == NULL) { ++ smtp_server_reply(cmd, 550, "5.1.1", "<%s> " ++ "Unacceptable TO: Empty path not allowed", ++ smtp_address_encode(data->path)); ++ return -1; ++ } ++ + smtp_address_detail_parse_temp( + client->unexpanded_lda_set->recipient_delimiter, + data->path, &username, &delim, &detail); ++ i_assert(*username != '\0'); ++ + if (client->lmtp_set->lmtp_proxy) { + /* proxied? */ + if ((ret=lmtp_proxy_rcpt(client, cmd, data, +-- +2.11.0 + diff -Nru dovecot-2.3.4.1/debian/patches/series dovecot-2.3.4.1/debian/patches/series --- dovecot-2.3.4.1/debian/patches/series 2019-08-28 18:47:43.000000000 +0000 +++ dovecot-2.3.4.1/debian/patches/series 2020-05-13 13:32:43.000000000 +0000 @@ -18,3 +18,20 @@ CVE-2019-11500-2.patch CVE-2019-11500-3.patch CVE-2019-11500-4.patch +CVE-2020-109xx/0001-lib-smtp-smtp-server-cmd-vrfy-Restructure-parameter-.patch +CVE-2020-109xx/0002-lib-smtp-smtp-syntax-Do-not-allow-NULL-return-parame.patch +CVE-2020-109xx/0003-lib-smtp-smtp-syntax-Do-not-allow-NULL-return-parame.patch +CVE-2020-109xx/0004-lib-smtp-syntax-Fix-smtp_ehlo_line_parse-to-also-rec.patch +CVE-2020-109xx/0005-lib-smtp-smtp-syntax-Do-not-allow-NULL-return-parame.patch +CVE-2020-109xx/0006-lib-smtp-smtp-syntax-Return-0-for-smtp_string_parse-.patch +CVE-2020-109xx/0007-lib-smtp-Add-tests-for-smtp_string_parse-and-smtp_st.patch +CVE-2020-109xx/0008-lib-smtp-test-smtp-server-errors-Add-tests-for-VRFY-.patch +CVE-2020-109xx/0009-lib-smtp-server-command-Move-core-of-smtp_server_com.patch +CVE-2020-109xx/0010-lib-smtp-smtp-server-command-Assign-cmd-reg-immediat.patch +CVE-2020-109xx/0011-lib-smtp-smtp-server-command-Guarantee-that-non-dest.patch +CVE-2020-109xx/0012-lib-smtp-smtp-server-command-Perform-initial-command.patch +CVE-2020-109xx/0013-lib-smtp-smtp-server-connection-Hold-a-command-refer.patch +CVE-2020-109xx/0014-lib-smtp-test-smtp-server-errors-Add-tests-for-large.patch +CVE-2020-109xx/0015-lib-smtp-smtp-address-Don-t-return-NULL-from-smtp_ad.patch +CVE-2020-109xx/0016-lib-smtp-smtp-address-Don-t-recognize-an-address-wit.patch +CVE-2020-109xx/0017-lmtp-lmtp-commands-Explicity-prohibit-empty-RCPT-pat.patch