Ignore re-entrant form calls during passive FFI callbacks

Passive FFI callbacks (e.g. FFI_OutputSelectedRect, FFI_Invalidate)
are notifications invoked during internal operations such as painting.
Embedders must not re-entrantly execute form actions or load/close
pages during these callbacks.

Track passive callbacks using CPDFSDK_FormFillEnvironment's
in_passive_ffi_callback_ flag, and early-return from entry points
such as FORM_OnAfterLoadPage, FORM_OnBeforeClosePage, and
FORM_Do*Action when invoked re-entrantly.

Active retrieval callbacks such as FFI_GetPage remain unflagged, as
page loading is expected in those paths.

TAG=agy
CONV=9e87637a-cb01-4106-9c04-ad4da437fc61

Bug: 556535630
Change-Id: Id892141ce082cc8895b4ed5dc66af3edaf5ef740
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/156913
Reviewed-by: Lei Zhang <thestig@chromium.org>
Commit-Queue: Tom Sepez <tsepez@chromium.org>
diff --git a/fpdfsdk/cpdfsdk_formfillenvironment.cpp b/fpdfsdk/cpdfsdk_formfillenvironment.cpp
index 6c9b796..1568fc9 100644
--- a/fpdfsdk/cpdfsdk_formfillenvironment.cpp
+++ b/fpdfsdk/cpdfsdk_formfillenvironment.cpp
@@ -16,6 +16,7 @@
 #include "core/fpdfapi/parser/cpdf_array.h"
 #include "core/fpdfapi/parser/cpdf_dictionary.h"
 #include "core/fpdfdoc/cpdf_nametree.h"
+#include "core/fxcrt/autorestorer.h"
 #include "core/fxcrt/check.h"
 #include "core/fxcrt/containers/contains.h"
 #include "core/fxcrt/data_vector.h"
@@ -120,6 +121,9 @@
 
   CFX_PointF ptA = pFormField->PWLtoFFL(CFX_PointF(rect.left, rect.bottom));
   CFX_PointF ptB = pFormField->PWLtoFFL(CFX_PointF(rect.right, rect.top));
+
+  AutoRestorer<bool> ffi_restorer(&in_passive_ffi_callback_);
+  in_passive_ffi_callback_ = true;
   info_->FFI_OutputSelectedRect(info_, pPage, ptA.x, ptB.y, ptB.x, ptA.y);
 }
 
@@ -366,6 +370,8 @@
 void CPDFSDK_FormFillEnvironment::Invalidate(IPDF_Page* page,
                                              const FX_RECT& rect) {
   if (info_ && info_->FFI_Invalidate) {
+    AutoRestorer<bool> ffi_restorer(&in_passive_ffi_callback_);
+    in_passive_ffi_callback_ = true;
     info_->FFI_Invalidate(info_, FPDFPageFromIPDFPage(page), rect.left,
                           rect.top, rect.right, rect.bottom);
   }
@@ -374,6 +380,8 @@
 void CPDFSDK_FormFillEnvironment::SetCursor(
     IPWL_FillerNotify::CursorStyle nCursorType) {
   if (info_ && info_->FFI_SetCursor) {
+    AutoRestorer<bool> ffi_restorer(&in_passive_ffi_callback_);
+    in_passive_ffi_callback_ = true;
     info_->FFI_SetCursor(info_, static_cast<int>(nCursorType));
   }
 }
@@ -394,6 +402,8 @@
 
 void CPDFSDK_FormFillEnvironment::OnChange() {
   if (info_ && info_->FFI_OnChange) {
+    AutoRestorer<bool> ffi_restorer(&in_passive_ffi_callback_);
+    in_passive_ffi_callback_ = true;
     info_->FFI_OnChange(info_);
   }
 }
@@ -416,6 +426,8 @@
     size_t nCharacters = text.GetLength();
     ByteString bsUTFText = text.ToUTF16LE();
     auto* pBuffer = reinterpret_cast<const unsigned short*>(bsUTFText.c_str());
+    AutoRestorer<bool> ffi_restorer(&in_passive_ffi_callback_);
+    in_passive_ffi_callback_ = true;
     info_->FFI_SetTextFieldFocus(
         info_, pBuffer, pdfium::checked_cast<FPDF_DWORD>(nCharacters), bFocus);
   }
@@ -484,6 +496,8 @@
                                                double right,
                                                double bottom) {
   if (info_ && info_->version >= 2 && info_->FFI_DisplayCaret) {
+    AutoRestorer<bool> ffi_restorer(&in_passive_ffi_callback_);
+    in_passive_ffi_callback_ = true;
     info_->FFI_DisplayCaret(info_, FPDFPageFromIPDFPage(page), bVisible, left,
                             top, right, bottom);
   }
@@ -901,6 +915,8 @@
   FPDF_ANNOTATION fpdf_annot =
       FPDFAnnotationFromCPDFAnnotContext(focused_annot.get());
 
+  AutoRestorer<bool> ffi_restorer(&in_passive_ffi_callback_);
+  in_passive_ffi_callback_ = true;
   info_->FFI_OnFocusChange(info_, fpdf_annot, pPageView->GetPageIndex());
 }
 
diff --git a/fpdfsdk/cpdfsdk_formfillenvironment.h b/fpdfsdk/cpdfsdk_formfillenvironment.h
index 56613dc..74efbd8 100644
--- a/fpdfsdk/cpdfsdk_formfillenvironment.h
+++ b/fpdfsdk/cpdfsdk_formfillenvironment.h
@@ -85,6 +85,8 @@
   bool HasPermissions(uint32_t flags) const override;
   void OnChange() override;
 
+  bool InPassiveFFICallback() const { return in_passive_ffi_callback_; }
+
   CPDFSDK_PageView* GetPageViewAtIndex(int nIndex);
   void RemovePageView(IPDF_Page* pUnderlyingPage);
   void UpdateAllViews(CPDFSDK_Annot* pAnnot);
@@ -287,6 +289,7 @@
   std::unique_ptr<CFFL_InteractiveFormFiller> interactive_form_filler_;
   bool change_mask_ = false;
   bool being_destroyed_ = false;
+  bool in_passive_ffi_callback_ = false;
 
   // Holds the list of focusable annot types.
   // Annotations of type WIDGET are by default focusable.
diff --git a/fpdfsdk/fpdf_formfill.cpp b/fpdfsdk/fpdf_formfill.cpp
index 451cdd5..d05882b 100644
--- a/fpdfsdk/fpdf_formfill.cpp
+++ b/fpdfsdk/fpdf_formfill.cpp
@@ -850,6 +850,12 @@
 
 FPDF_EXPORT void FPDF_CALLCONV FORM_OnAfterLoadPage(FPDF_PAGE page,
                                                     FPDF_FORMHANDLE hHandle) {
+  CPDFSDK_FormFillEnvironment* pFormFillEnv =
+      CPDFSDKFormFillEnvironmentFromFPDFFormHandle(hHandle);
+  if (!pFormFillEnv || pFormFillEnv->InPassiveFFICallback()) {
+    return;
+  }
+
   if (CPDFSDK_PageView* pPageView = FormHandleToPageView(hHandle, page)) {
     pPageView->SetValid(true);
   }
@@ -859,7 +865,7 @@
                                                       FPDF_FORMHANDLE hHandle) {
   CPDFSDK_FormFillEnvironment* pFormFillEnv =
       CPDFSDKFormFillEnvironmentFromFPDFFormHandle(hHandle);
-  if (!pFormFillEnv) {
+  if (!pFormFillEnv || pFormFillEnv->InPassiveFFICallback()) {
     return;
   }
 
@@ -880,7 +886,11 @@
 FORM_DoDocumentJSAction(FPDF_FORMHANDLE hHandle) {
   CPDFSDK_FormFillEnvironment* pFormFillEnv =
       CPDFSDKFormFillEnvironmentFromFPDFFormHandle(hHandle);
-  if (pFormFillEnv && pFormFillEnv->IsJSPlatformPresent()) {
+  if (!pFormFillEnv || pFormFillEnv->InPassiveFFICallback()) {
+    return;
+  }
+
+  if (pFormFillEnv->IsJSPlatformPresent()) {
     pFormFillEnv->ProcJavascriptAction();
   }
 }
@@ -889,16 +899,18 @@
 FORM_DoDocumentOpenAction(FPDF_FORMHANDLE hHandle) {
   CPDFSDK_FormFillEnvironment* pFormFillEnv =
       CPDFSDKFormFillEnvironmentFromFPDFFormHandle(hHandle);
-  if (pFormFillEnv) {
-    pFormFillEnv->ProcOpenAction();
+  if (!pFormFillEnv || pFormFillEnv->InPassiveFFICallback()) {
+    return;
   }
+
+  pFormFillEnv->ProcOpenAction();
 }
 
 FPDF_EXPORT void FPDF_CALLCONV FORM_DoDocumentAAction(FPDF_FORMHANDLE hHandle,
                                                       int aaType) {
   CPDFSDK_FormFillEnvironment* pFormFillEnv =
       CPDFSDKFormFillEnvironmentFromFPDFFormHandle(hHandle);
-  if (!pFormFillEnv) {
+  if (!pFormFillEnv || pFormFillEnv->InPassiveFFICallback()) {
     return;
   }
 
@@ -920,7 +932,7 @@
                                                   int aaType) {
   CPDFSDK_FormFillEnvironment* pFormFillEnv =
       CPDFSDKFormFillEnvironmentFromFPDFFormHandle(hHandle);
-  if (!pFormFillEnv) {
+  if (!pFormFillEnv || pFormFillEnv->InPassiveFFICallback()) {
     return;
   }