From 7b417d17001b9c2699ee8065d1ba34cb790db4a0 Mon Sep 17 00:00:00 2001 From: Ben Campbell Date: Thu, 22 Feb 2024 12:10:04 +0000 Subject: [PATCH] Bug 1872849 - Add protection against interleaved message writes to nsImapMailFolder. r=mkmelin Differential Revision: https://phabricator.services.mozilla.com/D202197 --HG-- extra : moz-landing-system : lando --- mailnews/imap/src/nsImapMailFolder.cpp | 37 +++++++++++++++++++++----- 1 file changed, 31 insertions(+), 6 deletions(-) diff --git a/mailnews/imap/src/nsImapMailFolder.cpp b/mailnews/imap/src/nsImapMailFolder.cpp index df43cefb2a..a60483011b 100644 --- a/mailnews/imap/src/nsImapMailFolder.cpp +++ b/mailnews/imap/src/nsImapMailFolder.cpp @@ -79,7 +79,7 @@ #include "nsMsgLineBuffer.h" #include "mozilla/Logging.h" #include "mozilla/Attributes.h" -#include "mozilla/SlicedInputStream.h" +#include "mozilla/ScopeExit.h" #include "nsStringStream.h" #include "nsIStreamListener.h" #include "nsITimer.h" @@ -2725,6 +2725,7 @@ NS_IMETHODIMP nsImapMailFolder::UpdateImapMailboxStatus( return NS_OK; } +// nsIImapMailFolderSink.parseMsgHdrs() NS_IMETHODIMP nsImapMailFolder::ParseMsgHdrs( nsIImapProtocol* aProtocol, nsIImapHeaderXferInfo* aHdrXferInfo) { NS_ENSURE_ARG_POINTER(aHdrXferInfo); @@ -2781,6 +2782,7 @@ NS_IMETHODIMP nsImapMailFolder::ParseMsgHdrs( return rv; } +// Helper for ParseMsgHdrs(). nsresult nsImapMailFolder::SetupHeaderParseStream( uint32_t aSize, const nsACString& content_type, nsIMailboxSpec* boxSpec) { if (!mDatabase) GetDatabase(); @@ -2797,6 +2799,7 @@ nsresult nsImapMailFolder::SetupHeaderParseStream( return m_msgParser->SetState(nsIMsgParseMailMsgState::ParseHeadersState); } +// Helper for ParseMsgHdrs(). nsresult nsImapMailFolder::ParseAdoptedHeaderLine(const char* aMessageLine, nsMsgKey aMsgKey) { // we can get blocks that contain more than one line, @@ -2824,12 +2827,15 @@ nsresult nsImapMailFolder::ParseAdoptedHeaderLine(const char* aMessageLine, return NS_OK; } +// Helper for ParseMsgHdrs(). nsresult nsImapMailFolder::NormalEndHeaderParseStream( nsIImapProtocol* aProtocol, nsIImapUrl* imapUrl) { nsCOMPtr newMsgHdr; nsresult rv; NS_ENSURE_TRUE(m_msgParser, NS_ERROR_NULL_POINTER); + auto uidClear = mozilla::MakeScopeExit([&] { m_curMsgUid = 0; }); + nsMailboxParseState parseState; m_msgParser->GetState(&parseState); if (parseState == nsIMsgParseMailMsgState::ParseHeadersState) @@ -3034,10 +3040,11 @@ nsresult nsImapMailFolder::NormalEndHeaderParseStream( return NS_OK; } +// From nsIImapMailFolderSink. NS_IMETHODIMP nsImapMailFolder::AbortHeaderParseStream( nsIImapProtocol* aProtocol) { - nsresult rv = NS_ERROR_FAILURE; - return rv; + m_curMsgUid = 0; + return NS_OK; } NS_IMETHODIMP nsImapMailFolder::BeginCopy() { @@ -4298,15 +4305,26 @@ nsImapMailFolder::ParseAdoptedMsgLine(const char* adoptedMessageLine, NS_ENSURE_ARG_POINTER(aImapUrl); uint32_t count = 0; nsresult rv; - // remember the uid of the message we're downloading. - m_curMsgUid = uidOfMessage; if (!m_offlineHeader) { + // Starting a new message. + if (m_curMsgUid) { + NS_WARNING("ParseAdoptedMsgLine: already processing a message"); + return NS_ERROR_ABORT; + } rv = GetMessageHeader(uidOfMessage, getter_AddRefs(m_offlineHeader)); if (NS_SUCCEEDED(rv) && !m_offlineHeader) rv = NS_ERROR_UNEXPECTED; NS_ENSURE_SUCCESS(rv, rv); rv = StartNewOfflineMessage(); NS_ENSURE_SUCCESS(rv, rv); + m_curMsgUid = uidOfMessage; + } else { + // Continuing an existing message. + if (uidOfMessage != m_curMsgUid) { + NS_WARNING("ParseAdoptedMsgLine: preventing interleaved messages"); + return NS_ERROR_ABORT; + } } + // adoptedMessageLine is actually a string with a lot of message lines, // separated by native line terminators we need to count the number of // MSG_LINEBREAK's to determine how much to increment m_numOfflineMsgLines by. @@ -4340,6 +4358,9 @@ NS_IMETHODIMP nsImapMailFolder::NormalEndMsgWriteStream(nsMsgKey uidOfMessage, bool markRead, nsIImapUrl* imapUrl, int32_t updatedMessageSize) { + NS_WARNING_ASSERTION((uidOfMessage == m_curMsgUid), "Interleaved messages?"); + auto uidClear = mozilla::MakeScopeExit([&] { m_curMsgUid = 0; }); + if (updatedMessageSize != -1) { // retrieve the message header to update size, if we don't already have it nsCOMPtr msgHeader = m_offlineHeader; @@ -4416,8 +4437,12 @@ nsImapMailFolder::NormalEndMsgWriteStream(nsMsgKey uidOfMessage, bool markRead, NS_IMETHODIMP nsImapMailFolder::AbortMsgWriteStream() { + if (m_offlineHeader) { + EndNewOfflineMessage(NS_ERROR_ABORT); + } m_offlineHeader = nullptr; - return NS_ERROR_FAILURE; + m_curMsgUid = 0; + return NS_OK; } // message move/copy related methods