Prevent an UAF in CPDFSDK_AnnotHandlerMgr::GetNextAnnot().
Calling CXFA_FFPageView::CreateWidgetIterator() can trigger JS and
invalidate CPDFSDK_Annot objects. Use ObservedPtr to check for
CPDFSDK_Annot destruction to catch this.
Bug: chromium:980161
Change-Id: Ifdb926be75c129d7b4a05c3b1fb8c747ef352e71
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/58171
Reviewed-by: Tom Sepez <tsepez@chromium.org>
Commit-Queue: Tom Sepez <tsepez@chromium.org>
diff --git a/AUTHORS b/AUTHORS
index 8fe2b46..bd3e4bd 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -20,6 +20,7 @@
Finnur Thorarinsson <finnur@chromium.org>
GiWan Go <gogil@stealien.com>
Henrique Nakashima <hnakashima@chromium.org>
+Huy Ngo <huyna89@gmail.com>
Jiang Jiang <jiangj@opera.com>
Jochen Eisinger <jochen@chromium.org>
John Abd-El-Malek <jam@chromium.org>
diff --git a/fpdfsdk/cpdfsdk_annothandlermgr.cpp b/fpdfsdk/cpdfsdk_annothandlermgr.cpp
index a16aeba..b1a31fe 100644
--- a/fpdfsdk/cpdfsdk_annothandlermgr.cpp
+++ b/fpdfsdk/cpdfsdk_annothandlermgr.cpp
@@ -229,7 +229,7 @@
CPDFSDK_FormFillEnvironment::IsALTKeyDown(nFlag)) {
return GetAnnotHandler(pAnnot)->OnKeyDown(pAnnot, nKeyCode, nFlag);
}
-
+ ObservedPtr<CPDFSDK_Annot> pObservedAnnot(pAnnot);
CPDFSDK_PageView* pPage = pAnnot->GetPageView();
CPDFSDK_Annot* pFocusAnnot = pPage->GetFocusAnnot();
if (pFocusAnnot && (nKeyCode == FWL_VKEY_Tab)) {
@@ -241,6 +241,10 @@
}
}
+ // Check |pAnnot| again because JS may have destroyed it in |GetNextAnnot|
+ if (!pObservedAnnot)
+ return false;
+
return GetAnnotHandler(pAnnot)->OnKeyDown(pAnnot, nKeyCode, nFlag);
}
@@ -310,6 +314,7 @@
CPDFSDK_Annot* CPDFSDK_AnnotHandlerMgr::GetNextAnnot(CPDFSDK_Annot* pSDKAnnot,
bool bNext) {
#ifdef PDF_ENABLE_XFA
+ ObservedPtr<CPDFSDK_Annot> pObservedAnnot(pSDKAnnot);
CPDFSDK_PageView* pPageView = pSDKAnnot->GetPageView();
CPDFXFA_Page* pPage = pPageView->GetPDFXFAPage();
if (pPage && !pPage->AsPDFPage()) {
@@ -319,7 +324,9 @@
XFA_TRAVERSEWAY_Tranvalse, XFA_WidgetStatus_Visible |
XFA_WidgetStatus_Viewable |
XFA_WidgetStatus_Focused));
- if (!pWidgetIterator)
+
+ // Check |pSDKAnnot| again because JS may have destroyed it
+ if (!pObservedAnnot || !pWidgetIterator)
return nullptr;
if (pWidgetIterator->GetCurrentWidget() != pSDKAnnot->GetXFAWidget())
pWidgetIterator->SetCurrentWidget(pSDKAnnot->GetXFAWidget());