]> granicus.if.org Git - neomutt/commitdiff
Fix use after free of ctx->last_tag. (closes #3775)
authorKevin McCarthy <kevin@8t8.us>
Sun, 6 Sep 2015 14:40:06 +0000 (07:40 -0700)
committerKevin McCarthy <kevin@8t8.us>
Sun, 6 Sep 2015 14:40:06 +0000 (07:40 -0700)
When using imap to access gmail, tagging and saving messages to "all
mail" and pressing <sync-mailbox> can result in the call path:
  mx_check_mailbox()
    imap_check_mailbox()
      imap_cmd_finish()
        imap_expunge_mailbox()
          mx_update_tables()
followed by:
  mx_sync_mailbox()

The HEADER pointed to by ctx->last_tag will be removed and FREE'ed in
mx_update_tables(), but will subsequently be accessed in mx_sync_mailbox().

This patch simply sets ctx->last_tag=NULL if it is freed inside mx_update_tables().

Thanks to Peter Lekensteyn for the bug report and ASAN report.

mx.c

diff --git a/mx.c b/mx.c
index 4c5cb07de423f740385da227f5e144a7463044a2..62a5d5f3cf7be652689d70f34c86e461253ebd83 100644 (file)
--- a/mx.c
+++ b/mx.c
@@ -1058,6 +1058,13 @@ void mx_update_tables(CONTEXT *ctx, int committing)
        hash_delete (ctx->subj_hash, ctx->hdrs[i]->env->real_subj, ctx->hdrs[i], NULL);
       if (ctx->id_hash && ctx->hdrs[i]->env->message_id)
        hash_delete (ctx->id_hash, ctx->hdrs[i]->env->message_id, ctx->hdrs[i], NULL);
+      /* The path mx_check_mailbox() -> imap_check_mailbox() ->
+       *          imap_expunge_mailbox() -> mx_update_tables()
+       * can occur before a call to mx_sync_mailbox(), resulting in
+       * last_tag being stale if it's not reset here.
+       */
+      if (ctx->last_tag == ctx->hdrs[i])
+        ctx->last_tag = NULL;
       mutt_free_header (&ctx->hdrs[i]);
     }
   }