]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
imap-login: Limit the number of open IMAP parser lists
authorTimo Sirainen <timo.sirainen@open-xchange.com>
Fri, 6 Mar 2026 13:35:12 +0000 (15:35 +0200)
committerRebaser <foobar@foobar>
Thu, 26 Mar 2026 08:41:12 +0000 (08:41 +0000)
This prevents attackers from using a large number of '(' in a command to
grow memory usage excessively.

src/imap-login/imap-login-client.c
src/imap-login/imap-login-client.h
src/imap-login/imap-login-cmd-id.c

index 84e6a90db430260e7652bbc2e3da7186b55837a2..93966b2d155bc3d3e71f1d4ae15314562c016b61 100644 (file)
@@ -380,10 +380,13 @@ static int imap_client_create(struct client *client)
                return -1;
        }
 
+       struct imap_parser_params params = {
+               .list_count_limit = IMAP_LOGIN_LIST_COUNT_LIMIT,
+       };
        imap_client->parser =
                imap_parser_create(imap_client->common.input,
                                   imap_client->common.output,
-                                  IMAP_LOGIN_MAX_LINE_LENGTH, NULL);
+                                  IMAP_LOGIN_MAX_LINE_LENGTH, &params);
        struct settings_instance *set_instance = settings_instance_find(client->event);
        if (set_instance == NULL) {
                set_instance = settings_instance_new(
@@ -469,11 +472,14 @@ static void imap_client_starttls(struct client *client)
        struct imap_client *imap_client =
                container_of(client, struct imap_client, common);
 
+       struct imap_parser_params params = {
+               .list_count_limit = IMAP_LOGIN_LIST_COUNT_LIMIT,
+       };
        imap_parser_unref(&imap_client->parser);
        imap_client->parser =
                imap_parser_create(imap_client->common.input,
                                   imap_client->common.output,
-                                  IMAP_LOGIN_MAX_LINE_LENGTH, NULL);
+                                  IMAP_LOGIN_MAX_LINE_LENGTH, &params);
 
        /* CRLF is lost from buffer when streams are reopened. */
        imap_client->skip_line = FALSE;
index ffac6ec855030cc48360626ee91b5a48e4afd08a..1ff88015b2894b72570b13009fffc2eff5eb9c2b 100644 (file)
 /* maximum length for IMAP command line. */
 #define IMAP_LOGIN_MAX_LINE_LENGTH 8192
 
+/* Maximum number of '(' allowed in an IMAP command. Pre-login only uses
+   lists in the ID command. */
+#define IMAP_LOGIN_LIST_COUNT_LIMIT 1
+
 enum imap_client_id_state {
        IMAP_CLIENT_ID_STATE_LIST = 0,
        IMAP_CLIENT_ID_STATE_KEY,
index be2097f70b159d8ae5c61f3586a1cab968642c03..a07b1f8f562f3fa953d2459220c576e24a668606 100644 (file)
@@ -389,10 +389,14 @@ int cmd_id(struct imap_client *client)
                client->cmd_id = id = i_new(struct imap_client_cmd_id, 1);
                id->params = p_new(param_pool, struct imap_id_params, 1);
                id->params->pool = param_pool;
+
+               struct imap_parser_params params = {
+                       .list_count_limit = IMAP_LOGIN_LIST_COUNT_LIMIT,
+               };
                id->parser = imap_parser_create(client->common.input,
                                                client->common.output,
                                                IMAP_LOGIN_MAX_LINE_LENGTH,
-                                               NULL);
+                                               &params);
                id->log_reply = str_new(default_pool, 64);
                if (client->set->imap_literal_minus)
                        imap_parser_enable_literal_minus(id->parser);