]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
imap: Fixed infinite loop / memory eating with SEARCHRES + pipelining $.
authorTimo Sirainen <tss@iki.fi>
Tue, 22 Feb 2011 09:59:57 +0000 (11:59 +0200)
committerTimo Sirainen <tss@iki.fi>
Tue, 22 Feb 2011 09:59:57 +0000 (11:59 +0200)
If SEARCH RETURN (SAVE) command was running long enough so that Dovecot
started executing the next command, and if that command used $ in
messageset, Dovecot went into infinite function recursion.

src/imap/imap-client.c
src/imap/imap-client.h

index 7305d295aaaccbc436bd3476fc7936b78866280c..adb137b1bdd31140929c41f250bc57cc409a9ecc 100644 (file)
@@ -432,7 +432,7 @@ client_command_find_with_flags(struct client_command_context *new_cmd,
        return NULL;
 }
 
-static bool client_command_check_ambiguity(struct client_command_context *cmd)
+static bool client_command_is_ambiguous(struct client_command_context *cmd)
 {
        enum command_flags flags;
        enum client_command_state max_state =
@@ -443,6 +443,17 @@ static bool client_command_check_ambiguity(struct client_command_context *cmd)
            !imap_sync_is_allowed(cmd->client))
                return TRUE;
 
+       if (cmd->search_save_result_used) {
+               /* if there are pending commands that update the search
+                  save result, wait */
+               struct client_command_context *old_cmd = cmd->next;
+
+               for (; old_cmd != NULL; old_cmd = old_cmd->next) {
+                       if (old_cmd->search_save_result)
+                               return TRUE;
+               }
+       }
+
        if ((cmd->cmd_flags & COMMAND_FLAG_BREAKS_MAILBOX) ==
            COMMAND_FLAG_BREAKS_MAILBOX) {
                /* there must be no other command running that uses the
@@ -578,11 +589,11 @@ void client_continue_pending_input(struct client *client)
 
                /* the command is waiting for existing ambiguity causing
                   commands to finish. */
-               if (client_command_check_ambiguity(cmd)) {
+               if (client_command_is_ambiguous(cmd)) {
                        /* we could be waiting for existing sync to finish */
                        if (!cmd_sync_delayed(client))
                                return;
-                       if (client_command_check_ambiguity(cmd))
+                       if (client_command_is_ambiguous(cmd))
                                return;
                }
                cmd->state = CLIENT_COMMAND_STATE_WAIT_INPUT;
@@ -690,7 +701,7 @@ static bool client_command_input(struct client_command_context *cmd)
        } else if ((command = command_find(cmd->name)) != NULL) {
                cmd->func = command->func;
                cmd->cmd_flags = command->flags;
-               if (client_command_check_ambiguity(cmd)) {
+               if (client_command_is_ambiguous(cmd)) {
                        /* do nothing until existing commands are finished */
                        i_assert(cmd->state == CLIENT_COMMAND_STATE_WAIT_INPUT);
                        cmd->state = CLIENT_COMMAND_STATE_WAIT_UNAMBIGUITY;
@@ -907,6 +918,7 @@ bool client_handle_search_save_ambiguity(struct client_command_context *cmd)
        i_assert(cmd->state == CLIENT_COMMAND_STATE_WAIT_INPUT);
        cmd->client->input_lock = cmd;
        cmd->state = CLIENT_COMMAND_STATE_WAIT_UNAMBIGUITY;
+       cmd->search_save_result_used = TRUE;
        io_remove(&cmd->client->io);
        return TRUE;
 }
index 57fc7470556f92a9a3894ce199dc7b500c0c970d..b332a8a2770bf03f205d2b3af2bd6d10794a1cf0 100644 (file)
@@ -82,6 +82,7 @@ struct client_command_context {
        unsigned int cancel:1; /* command is wanted to be cancelled */
        unsigned int param_error:1;
        unsigned int search_save_result:1; /* search result is being updated */
+       unsigned int search_save_result_used:1; /* command uses search save */
        unsigned int temp_executed:1; /* temporary execution state tracking */
 };