From 309ddf3970408bb3cf21a2eeee31104452bddc67 Mon Sep 17 00:00:00 2001 From: Peter Van der Beken Date: Tue, 21 Dec 2021 17:56:02 +0000 (2021-12-22) Subject: [PATCH] CVE-2022-22755 --- dom/xslt/xslt/txExecutionState.cpp | 7 +- dom/xslt/xslt/txExecutionState.h | 5 +- dom/xslt/xslt/txMozillaXSLTProcessor.cpp | 101 ++++++++++++++++++++++- dom/xslt/xslt/txXSLTProcessor.cpp | 25 ++++-- 4 files changed, 126 insertions(+), 12 deletions(-) diff --git a/dom/xslt/xslt/txExecutionState.cpp b/dom/xslt/xslt/txExecutionState.cpp index a4e7609dfc..8d849886ac 100644 --- a/dom/xslt/xslt/txExecutionState.cpp +++ b/dom/xslt/xslt/txExecutionState.cpp @@ -417,7 +417,12 @@ txExecutionState::TemplateRule* txExecutionState::getCurrentTemplateRule() { return &mTemplateRules[mTemplateRules.Length() - 1]; } -txInstruction* txExecutionState::getNextInstruction() { +mozilla::Result +txExecutionState::getNextInstruction() { + if (mStopProcessing) { + return mozilla::Err(NS_ERROR_FAILURE); + } + txInstruction* instr = mNextInstruction; if (instr) { mNextInstruction = instr->mNext.get(); diff --git a/dom/xslt/xslt/txExecutionState.h b/dom/xslt/xslt/txExecutionState.h index 7d91df704e..c4b15edd60 100644 --- a/dom/xslt/xslt/txExecutionState.h +++ b/dom/xslt/xslt/txExecutionState.h @@ -17,6 +17,7 @@ #include "txStylesheet.h" #include "txXPathTreeWalker.h" #include "nsTArray.h" +#include "mozilla/Result.h" class txAOutputHandlerFactory; class txAXMLEventHandler; @@ -115,13 +116,14 @@ class txExecutionState : public txIMatchContext { } // state-modification functions - txInstruction* getNextInstruction(); + mozilla::Result getNextInstruction(); nsresult runTemplate(txInstruction* aInstruction); nsresult runTemplate(txInstruction* aInstruction, txInstruction* aReturnTo); void gotoInstruction(txInstruction* aNext); void returnFromTemplate(); nsresult bindVariable(const txExpandedName& aName, txAExprResult* aValue); void removeVariable(const txExpandedName& aName); + void stopProcessing() { mStopProcessing = true; } txAXMLEventHandler* mOutputHandler; txAXMLEventHandler* mResultHandler; @@ -156,6 +158,7 @@ class txExecutionState : public txIMatchContext { txKeyHash mKeyHash; RefPtr mRecycler; bool mDisableLoads; + bool mStopProcessing = false; static const int32_t kMaxRecursionDepth; }; diff --git a/dom/xslt/xslt/txMozillaXSLTProcessor.cpp b/dom/xslt/xslt/txMozillaXSLTProcessor.cpp index 1b22b1caf0..5d810471b6 100644 --- a/dom/xslt/xslt/txMozillaXSLTProcessor.cpp +++ b/dom/xslt/xslt/txMozillaXSLTProcessor.cpp @@ -538,6 +538,80 @@ already_AddRefed txMozillaXSLTProcessor::TransformToDocument( return doc.forget(); } +class XSLTProcessRequest final : public nsIRequest { + public: + explicit XSLTProcessRequest(txExecutionState* aState) : mState(aState) {} + + NS_DECL_ISUPPORTS + NS_DECL_NSIREQUEST + + void Done() { mState = nullptr; } + + private: + ~XSLTProcessRequest() {} + txExecutionState* mState; +}; +NS_IMPL_ISUPPORTS(XSLTProcessRequest, nsIRequest) + +NS_IMETHODIMP +XSLTProcessRequest::GetName(nsACString& aResult) { + aResult.AssignLiteral("about:xslt-load-blocker"); + return NS_OK; +} + +NS_IMETHODIMP +XSLTProcessRequest::IsPending(bool* _retval) { + *_retval = true; + return NS_OK; +} + +NS_IMETHODIMP +XSLTProcessRequest::GetStatus(nsresult* status) { + *status = NS_OK; + return NS_OK; +} + +NS_IMETHODIMP +XSLTProcessRequest::Cancel(nsresult status) { + mState->stopProcessing(); + return NS_OK; +} + +NS_IMETHODIMP +XSLTProcessRequest::Suspend(void) { return NS_OK; } + +NS_IMETHODIMP +XSLTProcessRequest::Resume(void) { return NS_OK; } + +NS_IMETHODIMP +XSLTProcessRequest::GetLoadGroup(nsILoadGroup** aLoadGroup) { + *aLoadGroup = nullptr; + return NS_OK; +} + +NS_IMETHODIMP +XSLTProcessRequest::SetLoadGroup(nsILoadGroup* aLoadGroup) { return NS_OK; } + +NS_IMETHODIMP +XSLTProcessRequest::GetLoadFlags(nsLoadFlags* aLoadFlags) { + *aLoadFlags = nsIRequest::LOAD_NORMAL; + return NS_OK; +} + +NS_IMETHODIMP +XSLTProcessRequest::SetLoadFlags(nsLoadFlags aLoadFlags) { return NS_OK; } + +NS_IMETHODIMP +XSLTProcessRequest::GetTRRMode(nsIRequest::TRRMode* aTRRMode) { + return GetTRRModeImpl(aTRRMode); +} + +NS_IMETHODIMP +XSLTProcessRequest::SetTRRMode(nsIRequest::TRRMode aTRRMode) { + return SetTRRModeImpl(aTRRMode); +} + + nsresult txMozillaXSLTProcessor::TransformToDoc(Document** aResult, bool aCreateDataDocument) { UniquePtr sourceNode( @@ -548,11 +622,31 @@ nsresult txMozillaXSLTProcessor::TransformToDoc(Document** aResult, txExecutionState es(mStylesheet, IsLoadDisabled()); + Document* sourceDoc = mSource->OwnerDoc(); + nsCOMPtr loadGroup = sourceDoc->GetDocumentLoadGroup(); + if (!loadGroup) { + nsCOMPtr win = do_QueryInterface(mOwner); + if (win && win->IsCurrentInnerWindow()) { + Document* doc = win->GetDoc(); + if (doc) { + loadGroup = doc->GetDocumentLoadGroup(); + } + } + + if (!loadGroup) { + return NS_ERROR_FAILURE; + } + } + + RefPtr xsltProcessRequest = new XSLTProcessRequest(&es); + loadGroup->AddRequest(xsltProcessRequest, nullptr); + + // XXX Need to add error observers // If aResult is non-null, we're a data document - txToDocHandlerFactory handlerFactory(&es, mSource->OwnerDoc(), mObserver, - aCreateDataDocument); + txToDocHandlerFactory handlerFactory(&es, sourceDoc, mObserver, + aCreateDataDocument); es.mOutputHandlerFactory = &handlerFactory; nsresult rv = es.init(*sourceNode, &mVariables); @@ -562,6 +656,9 @@ nsresult txMozillaXSLTProcessor::TransformToDoc(Document** aResult, rv = txXSLTProcessor::execute(es); } + xsltProcessRequest->Done(); + loadGroup->RemoveRequest(xsltProcessRequest, nullptr, NS_OK); + nsresult endRv = es.end(rv); if (NS_SUCCEEDED(rv)) { rv = endRv; diff --git a/dom/xslt/xslt/txXSLTProcessor.cpp b/dom/xslt/xslt/txXSLTProcessor.cpp index dfcdeb5595..4a5117efcf 100644 --- a/dom/xslt/xslt/txXSLTProcessor.cpp +++ b/dom/xslt/xslt/txXSLTProcessor.cpp @@ -31,12 +31,21 @@ void txXSLTProcessor::shutdown() { txHandlerTable::shutdown(); } /* static */ nsresult txXSLTProcessor::execute(txExecutionState& aEs) { - nsresult rv = NS_OK; - txInstruction* instr; - while ((instr = aEs.getNextInstruction())) { - rv = instr->execute(aEs); - NS_ENSURE_SUCCESS(rv, rv); - } - - return NS_OK; + + nsresult rv; + do { + mozilla::Result result = aEs.getNextInstruction(); + if (result.isErr()) { + return result.unwrapErr(); + } + + txInstruction* instr = result.unwrap(); + if (!instr) { + return NS_OK; + } + + rv = instr->execute(aEs); + } while (NS_SUCCEEDED(rv)); + + return rv; } -- 2.27.0