From: Timo Sirainen Date: Mon, 25 Jun 2018 09:10:55 +0000 (+0300) Subject: imapc: Fix potential assert-crash when selecting empty mailbox X-Git-Tag: 2.3.9~1684 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=5985a8b02df58c90fdb155dbed14fe879d2ae7d6;p=thirdparty%2Fdovecot%2Fcore.git imapc: Fix potential assert-crash when selecting empty mailbox 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)) --- diff --git a/src/lib-storage/index/imapc/imapc-mailbox.c b/src/lib-storage/index/imapc/imapc-mailbox.c index 7906fe40c2..b8b117cb53 100644 --- a/src/lib-storage/index/imapc/imapc-mailbox.c +++ b/src/lib-storage/index/imapc/imapc-mailbox.c @@ -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) { diff --git a/src/lib-storage/index/imapc/imapc-storage.c b/src/lib-storage/index/imapc/imapc-storage.c index 3534017559..58d448e8c8 100644 --- a/src/lib-storage/index/imapc/imapc-storage.c +++ b/src/lib-storage/index/imapc/imapc-storage.c @@ -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; } diff --git a/src/lib-storage/index/imapc/imapc-storage.h b/src/lib-storage/index/imapc/imapc-storage.h index 10d1ea4e2a..51d15a72e1 100644 --- a/src/lib-storage/index/imapc/imapc-storage.h +++ b/src/lib-storage/index/imapc/imapc-storage.h @@ -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);