File CVE-2021-33515.patch of Package dovecot23.20135
commit 321c339756f9b2b98fb7326359d1333adebb5295
Author: Stephan Bosch <stephan.bosch@open-xchange.com>
Date: Sat May 22 00:16:38 2021 +0200
lib-smtp: smtp-server-connection - Fix STARTTLS command injection vulnerability.
The input handler kept reading more commands even though the input was locked by
the STARTTLS command, thereby causing it to read the command pipelined beyond
STARTTLS. This causes a STARTTLS command injection vulerability.
diff --git a/src/lib-smtp/smtp-server-cmd-starttls.c b/src/lib-smtp/smtp-server-cmd-starttls.c
index ed1687e6b8..de53b39a38 100644
--- a/src/lib-smtp/smtp-server-cmd-starttls.c
+++ b/src/lib-smtp/smtp-server-cmd-starttls.c
@@ -37,6 +37,13 @@ static int cmd_starttls_start(struct smtp_server_connection *conn)
return -1;
}
+ /* The command queue must be empty at this point. If anything were to be
+ queued somehow, this connection is vulnerable to STARTTLS command
+ insertion.
+ */
+ i_assert(conn->command_queue_count == 0 &&
+ conn->command_queue_head == NULL);
+
/* RFC 3207, Section 4.2:
Upon completion of the TLS handshake, the SMTP protocol is reset to
@@ -107,6 +114,13 @@ cmd_starttls_next(struct smtp_server_cmd_ctx *cmd, void *context ATTR_UNUSED)
const struct smtp_server_callbacks *callbacks = conn->callbacks;
int ret;
+ /* The command queue can only contain the STARTTLS command at this
+ point. If anything beyond the STARTTLS were queued somehow, this
+ connection is vulnerable to STARTTLS command insertion.
+ */
+ i_assert(conn->command_queue_count == 1 &&
+ conn->command_queue_tail == command);
+
smtp_server_connection_set_state(conn, SMTP_SERVER_STATE_STARTTLS,
NULL);
diff --git a/src/lib-smtp/smtp-server-connection.c b/src/lib-smtp/smtp-server-connection.c
index bdca2d0717..fc42d1ba53 100644
--- a/src/lib-smtp/smtp-server-connection.c-orig 2021-06-17 15:57:49.357852126 +0200
+++ b/src/lib-smtp/smtp-server-connection.c 2021-06-17 15:59:56.829098475 +0200
@@ -419,7 +419,7 @@
/* parse commands */
ret = 1;
- while (!conn->closing && ret != 0) {
+ while (!conn->closing && !conn->input_locked && ret != 0) {
while ((ret = smtp_command_parse_next(conn->smtp_parser,
&cmd_name, &cmd_params, &error_code, &error)) > 0) {
@@ -443,6 +443,10 @@
if (conn->disconnected)
return;
+ /* Last command locked the input; stop trying to read
+ more. */
+ if (conn->input_locked)
+ break;
/* client indicated it will close after this command;
stop trying to read more. */
if (conn->closing)