]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
imapc: Fix potential assert-crash when selecting empty mailbox
authorTimo Sirainen <timo.sirainen@dovecot.fi>
Mon, 25 Jun 2018 09:10:55 +0000 (12:10 +0300)
committerTimo Sirainen <timo.sirainen@dovecot.fi>
Mon, 25 Jun 2018 09:10:55 +0000 (12:10 +0300)
imapc_mailbox_fetch_state_finish() should have been expunging all the mails,
but it didn't happen since UIDNEXT wasn't received yet at the time EXISTS
was sent, so sync_uid_next was always 0 when checking it. Fix this by
calling imapc_mailbox_fetch_state_finish() only after SELECT/EXAMINE tagged
reply is received.

This practically happened only when index files were used. It could also
happen without index files, if the session had received new mails after
opening the mailbox, then getting disconnected and before reconnect was
finished all the mails were externally expunged.

Fixes:
Panic: file imapc-sync.c: line 328 (imapc_initial_sync_check): assertion failed: (mail_index_is_expunged(view, lseq) || seq_range_exists(&ctx->mbox->delayed_expunged_uids, luid))

src/lib-storage/index/imapc/imapc-mailbox.c
src/lib-storage/index/imapc/imapc-storage.c
src/lib-storage/index/imapc/imapc-storage.h

index 7906fe40c2b97f10868e149db6a711dcda8a4cd6..b8b117cb53817bc5204229675da52164f6efb791 100644 (file)
@@ -234,6 +234,16 @@ imapc_mailbox_fetch_state_callback(const struct imapc_command_reply *reply,
        }
 }
 
+void imap_mailbox_select_finish(struct imapc_mailbox *mbox)
+{
+       if (mbox->exists_count == 0) {
+               /* no mails. expunge everything. */
+               mbox->sync_next_lseq = 1;
+               imapc_mailbox_init_delayed_trans(mbox);
+               imapc_mailbox_fetch_state_finish(mbox);
+       }
+}
+
 static void
 imapc_mailbox_fetch_state(struct imapc_mailbox *mbox, uint32_t first_uid)
 {
@@ -241,10 +251,9 @@ imapc_mailbox_fetch_state(struct imapc_mailbox *mbox, uint32_t first_uid)
 
        if (mbox->exists_count == 0) {
                /* empty mailbox - no point in fetching anything.
-                  just make sure everything is expunged in local index. */
-               mbox->sync_next_lseq = 1;
-               imapc_mailbox_init_delayed_trans(mbox);
-               imapc_mailbox_fetch_state_finish(mbox);
+                  just make sure everything is expunged in local index.
+                  Delay calling imapc_mailbox_fetch_state_finish() until
+                  SELECT finishes, so we see the updated UIDNEXT. */
                return;
        }
        if (mbox->state_fetching_uid1) {
index 3534017559c09ba7ee5adf47be04bf8cf90f3253..58d448e8c852ca212b537cb7081d0c8d210c9dde 100644 (file)
@@ -589,6 +589,7 @@ imapc_mailbox_reopen_callback(const struct imapc_command_reply *reply,
        if (reply->state != IMAPC_COMMAND_STATE_OK)
                errmsg = reply->text_full;
        else if (imapc_mailbox_verify_select(mbox, &errmsg)) {
+               imap_mailbox_select_finish(mbox);
                errmsg = NULL;
                mbox->selected = TRUE;
        }
@@ -661,6 +662,7 @@ imapc_mailbox_open_callback(const struct imapc_command_reply *reply,
                                "imapc: Opening mailbox failed: %s", error);
                        ctx->ret = -1;
                } else {
+                       imap_mailbox_select_finish(ctx->mbox);
                        ctx->mbox->selected = TRUE;
                        ctx->ret = 0;
                }
index 10d1ea4e2ad5d3672b7d5ed8777d6384375205b7..51d15a72e10317fa2c4be3db61145e392a351a83 100644 (file)
@@ -180,6 +180,7 @@ void imapc_mailbox_run(struct imapc_mailbox *mbox);
 void imapc_mailbox_run_nofetch(struct imapc_mailbox *mbox);
 void imapc_mail_cache_free(struct imapc_mail_cache *cache);
 int imapc_mailbox_select(struct imapc_mailbox *mbox);
+void imap_mailbox_select_finish(struct imapc_mailbox *mbox);
 
 bool imapc_mailbox_has_modseqs(struct imapc_mailbox *mbox);
 bool imap_resp_text_code_parse(const char *str, enum mail_error *error_r);