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
This commit is contained in:
Ben Campbell 2024-02-22 12:10:04 +00:00
Родитель 837252e6bc
Коммит 7b417d1700
1 изменённых файлов: 31 добавлений и 6 удалений

Просмотреть файл

@ -79,7 +79,7 @@
#include "nsMsgLineBuffer.h" #include "nsMsgLineBuffer.h"
#include "mozilla/Logging.h" #include "mozilla/Logging.h"
#include "mozilla/Attributes.h" #include "mozilla/Attributes.h"
#include "mozilla/SlicedInputStream.h" #include "mozilla/ScopeExit.h"
#include "nsStringStream.h" #include "nsStringStream.h"
#include "nsIStreamListener.h" #include "nsIStreamListener.h"
#include "nsITimer.h" #include "nsITimer.h"
@ -2725,6 +2725,7 @@ NS_IMETHODIMP nsImapMailFolder::UpdateImapMailboxStatus(
return NS_OK; return NS_OK;
} }
// nsIImapMailFolderSink.parseMsgHdrs()
NS_IMETHODIMP nsImapMailFolder::ParseMsgHdrs( NS_IMETHODIMP nsImapMailFolder::ParseMsgHdrs(
nsIImapProtocol* aProtocol, nsIImapHeaderXferInfo* aHdrXferInfo) { nsIImapProtocol* aProtocol, nsIImapHeaderXferInfo* aHdrXferInfo) {
NS_ENSURE_ARG_POINTER(aHdrXferInfo); NS_ENSURE_ARG_POINTER(aHdrXferInfo);
@ -2781,6 +2782,7 @@ NS_IMETHODIMP nsImapMailFolder::ParseMsgHdrs(
return rv; return rv;
} }
// Helper for ParseMsgHdrs().
nsresult nsImapMailFolder::SetupHeaderParseStream( nsresult nsImapMailFolder::SetupHeaderParseStream(
uint32_t aSize, const nsACString& content_type, nsIMailboxSpec* boxSpec) { uint32_t aSize, const nsACString& content_type, nsIMailboxSpec* boxSpec) {
if (!mDatabase) GetDatabase(); if (!mDatabase) GetDatabase();
@ -2797,6 +2799,7 @@ nsresult nsImapMailFolder::SetupHeaderParseStream(
return m_msgParser->SetState(nsIMsgParseMailMsgState::ParseHeadersState); return m_msgParser->SetState(nsIMsgParseMailMsgState::ParseHeadersState);
} }
// Helper for ParseMsgHdrs().
nsresult nsImapMailFolder::ParseAdoptedHeaderLine(const char* aMessageLine, nsresult nsImapMailFolder::ParseAdoptedHeaderLine(const char* aMessageLine,
nsMsgKey aMsgKey) { nsMsgKey aMsgKey) {
// we can get blocks that contain more than one line, // we can get blocks that contain more than one line,
@ -2824,12 +2827,15 @@ nsresult nsImapMailFolder::ParseAdoptedHeaderLine(const char* aMessageLine,
return NS_OK; return NS_OK;
} }
// Helper for ParseMsgHdrs().
nsresult nsImapMailFolder::NormalEndHeaderParseStream( nsresult nsImapMailFolder::NormalEndHeaderParseStream(
nsIImapProtocol* aProtocol, nsIImapUrl* imapUrl) { nsIImapProtocol* aProtocol, nsIImapUrl* imapUrl) {
nsCOMPtr<nsIMsgDBHdr> newMsgHdr; nsCOMPtr<nsIMsgDBHdr> newMsgHdr;
nsresult rv; nsresult rv;
NS_ENSURE_TRUE(m_msgParser, NS_ERROR_NULL_POINTER); NS_ENSURE_TRUE(m_msgParser, NS_ERROR_NULL_POINTER);
auto uidClear = mozilla::MakeScopeExit([&] { m_curMsgUid = 0; });
nsMailboxParseState parseState; nsMailboxParseState parseState;
m_msgParser->GetState(&parseState); m_msgParser->GetState(&parseState);
if (parseState == nsIMsgParseMailMsgState::ParseHeadersState) if (parseState == nsIMsgParseMailMsgState::ParseHeadersState)
@ -3034,10 +3040,11 @@ nsresult nsImapMailFolder::NormalEndHeaderParseStream(
return NS_OK; return NS_OK;
} }
// From nsIImapMailFolderSink.
NS_IMETHODIMP nsImapMailFolder::AbortHeaderParseStream( NS_IMETHODIMP nsImapMailFolder::AbortHeaderParseStream(
nsIImapProtocol* aProtocol) { nsIImapProtocol* aProtocol) {
nsresult rv = NS_ERROR_FAILURE; m_curMsgUid = 0;
return rv; return NS_OK;
} }
NS_IMETHODIMP nsImapMailFolder::BeginCopy() { NS_IMETHODIMP nsImapMailFolder::BeginCopy() {
@ -4298,15 +4305,26 @@ nsImapMailFolder::ParseAdoptedMsgLine(const char* adoptedMessageLine,
NS_ENSURE_ARG_POINTER(aImapUrl); NS_ENSURE_ARG_POINTER(aImapUrl);
uint32_t count = 0; uint32_t count = 0;
nsresult rv; nsresult rv;
// remember the uid of the message we're downloading.
m_curMsgUid = uidOfMessage;
if (!m_offlineHeader) { 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)); rv = GetMessageHeader(uidOfMessage, getter_AddRefs(m_offlineHeader));
if (NS_SUCCEEDED(rv) && !m_offlineHeader) rv = NS_ERROR_UNEXPECTED; if (NS_SUCCEEDED(rv) && !m_offlineHeader) rv = NS_ERROR_UNEXPECTED;
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
rv = StartNewOfflineMessage(); rv = StartNewOfflineMessage();
NS_ENSURE_SUCCESS(rv, rv); 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, // adoptedMessageLine is actually a string with a lot of message lines,
// separated by native line terminators we need to count the number of // separated by native line terminators we need to count the number of
// MSG_LINEBREAK's to determine how much to increment m_numOfflineMsgLines by. // MSG_LINEBREAK's to determine how much to increment m_numOfflineMsgLines by.
@ -4340,6 +4358,9 @@ NS_IMETHODIMP
nsImapMailFolder::NormalEndMsgWriteStream(nsMsgKey uidOfMessage, bool markRead, nsImapMailFolder::NormalEndMsgWriteStream(nsMsgKey uidOfMessage, bool markRead,
nsIImapUrl* imapUrl, nsIImapUrl* imapUrl,
int32_t updatedMessageSize) { int32_t updatedMessageSize) {
NS_WARNING_ASSERTION((uidOfMessage == m_curMsgUid), "Interleaved messages?");
auto uidClear = mozilla::MakeScopeExit([&] { m_curMsgUid = 0; });
if (updatedMessageSize != -1) { if (updatedMessageSize != -1) {
// retrieve the message header to update size, if we don't already have it // retrieve the message header to update size, if we don't already have it
nsCOMPtr<nsIMsgDBHdr> msgHeader = m_offlineHeader; nsCOMPtr<nsIMsgDBHdr> msgHeader = m_offlineHeader;
@ -4416,8 +4437,12 @@ nsImapMailFolder::NormalEndMsgWriteStream(nsMsgKey uidOfMessage, bool markRead,
NS_IMETHODIMP NS_IMETHODIMP
nsImapMailFolder::AbortMsgWriteStream() { nsImapMailFolder::AbortMsgWriteStream() {
if (m_offlineHeader) {
EndNewOfflineMessage(NS_ERROR_ABORT);
}
m_offlineHeader = nullptr; m_offlineHeader = nullptr;
return NS_ERROR_FAILURE; m_curMsgUid = 0;
return NS_OK;
} }
// message move/copy related methods // message move/copy related methods