Chrome · PDF
CVE-2026-113212
Memory Corruption in PDF
Overview
High
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
Changed Functions
| Function | Change | Notes |
|---|---|---|
iffpdfsdk/cpdfsdk_formfillenvironment.cpp |
modified |
Files Changed
fpdfsdk/cpdfsdk_formfillenvironment.hfpdfsdk/cpdfsdk_formfillenvironment.cpp
Patch
From ac3cf1684db05bd68338acb84e3823e6feb72b5b Mon Sep 17 00:00:00 2001
From: Tom Sepez <tsepez@google.com>
Date: Wed, 14 Oct 2026 11:02:52 -0700
Subject: [PATCH] CHECK on FFE teardown if embedder is inside a callback.
This indicates a misbehaving embedder, so flag it with a CHECK()
while it is still active on the stack.
-- mass rename two hungarian length variables.
-- consistently name AutoRestorer local `restorer`
Bug: 572237007
Change-Id: Ice9212769e4072d76a427379aa13d02fa36be55d
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/160615
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 f6ce8cc..c882bfd 100644
--- a/fpdfsdk/cpdfsdk_formfillenvironment.cpp
+++ b/fpdfsdk/cpdfsdk_formfillenvironment.cpp
@@ -75,6 +75,8 @@
}
CPDFSDK_FormFillEnvironment::~CPDFSDK_FormFillEnvironment() {
+ CHECK(!in_active_ffi_callback_);
+ CHECK(!in_passive_ffi_callback_);
being_destroyed_ = true;
OnDetachFromDocument();
@@ -119,7 +121,7 @@
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_);
+ AutoRestorer<bool> restorer(&in_passive_ffi_callback_);
in_passive_ffi_callback_ = true;
info_->FFI_OutputSelectedRect(info_, pPage, ptA.x, ptB.y, ptB.x, ptA.y);
}
@@ -134,8 +136,10 @@
return pPage ? GetOrCreatePageView(pPage) : nullptr;
}
-IPDF_Page* CPDFSDK_FormFillEnvironment::GetCurrentPage() const {
+IPDF_Page* CPDFSDK_FormFillEnvironment::GetCurrentPage() {
if (info_ && info_->FFI_GetCurrentPage) {
+ AutoRestorer<bool> restorer(&in_active_ffi_callback_);
+ in_active_ffi_callback_ = true;
return IPDFPageFromFPDFPage(info_->FFI_GetCurrentPage(
info_, FPDFDocumentFromCPDFDocument(cpdfdoc_.Get())));
}
@@ -148,19 +152,29 @@
return WideString();
}
- int nRequiredLen = info_->FFI_GetLanguage(info_, nullptr, 0);
- if (nRequiredLen <= 0) {
+ int required_len;
+ {
+ AutoRestorer<bool> restorer(&in_active_ffi_callback_);
+ in_active_ffi_callback_ = true;
+ required_len = info_->FFI_GetLanguage(info_, nullptr, 0);
+ }
+ if (required_len <= 0) {
return WideString();
}
- DataVector<uint8_t> pBuff(nRequiredLen);
- int nActualLen = info_->FFI_GetLanguage(info_, pBuff.data(), nRequiredLen);
- if (nActualLen <= 0 || nActualLen > nRequiredLen) {
+ DataVector<uint8_t> pBuff(required_len);
+ int actual_len;
+ {
+ AutoRestorer<bool> restorer(&in_active_ffi_callback_);
+ in_active_ffi_callback_ = true;
+ actual_len = info_->FFI_GetLanguage(info_, pBuff.data(), required_len);
+ }
+ if (actual_len <= 0 || actual_len > required_len) {
return WideString();
}
return WideString::FromUTF16LE(
- pdfium::span(pBuff).first(static_cast<size_t>(nActualLen)));
+ pdfium::span(pBuff).first(static_cast<size_t>(actual_len)));
#else // PDF_ENABLE_XFA
return WideString();
#endif // PDF_ENABLE_XFA
@@ -172,19 +186,29 @@
return WideString();
}
- int nRequiredLen = info_->FFI_GetPlatform(info_, nullptr, 0);
- if (nRequiredLen <= 0) {
+ int required_len;
+ {
+ AutoRestorer<bool> restorer(&in_active_ffi_callback_);
+ in_active_ffi_callback_ = true;
+ required_len = info_->FFI_GetPlatform(info_, nullptr, 0);
+ }
+ if (required_len <= 0) {
return WideString();
}
- DataVector<uint8_t> pBuff(nRequiredLen);
- int nActualLen = info_->FFI_GetPlatform(info_, pBuff.data(), nRequiredLen);
- if (nActualLen <= 0 || nActualLen > nRequiredLen) {
+ DataVector<uint8_t> pBuff(required_len);
+ int actual_len;
+ {
+ AutoRestorer<bool> restorer(&in_active_ffi_callback_);
+ in_active_ffi_callback_ = true;
+ actual_len = info_->FFI_GetPlatform(info_, pBuff.data(), required_len);
+ }
+ if (actual_len <= 0 || actual_len > required_len) {
return WideString();
}
return WideString::FromUTF16LE(
- pdfium::span(pBuff).first(static_cast<size_t>(nActualLen)));
+ pdfium::span(pBuff).first(static_cast<size_t>(actual_len)));
#else // PDF_ENABLE_XFA
return WideString();
#endif // PDF_ENABLE_XFA
@@ -242,20 +266,20 @@
return WideString();
}
- const int nRequiredLen = js_platform->Field_browse(js_platform, nullptr, 0);
- if (nRequiredLen <= 0) {
+ const int required_len = js_platform->Field_browse(js_platform, nullptr, 0);
+ if (required_len <= 0) {
return WideString();
}
- DataVector<uint8_t> pBuff(nRequiredLen);
- const int nActualLen =
- js_platform->Field_browse(js_platform, pBuff.data(), nRequiredLen);
- if (nActualLen <= 0 || nActualLen > nRequiredLen) {
+ DataVector<uint8_t> pBuff(required_len);
+ const int actual_len =
+ js_platform->Field_browse(js_platform, pBuff.data(), required_len);
+ if (actual_len <= 0 || actual_len > required_len) {
return WideString();
}
// Don't include trailing NUL.
- pBuff.resize(nActualLen - 1);
+ pBuff.resize(actual_len - 1);
// Use FromDefANSI() per "local encoding" comment in fpdf_formfill.h.
return WideString::FromDefANSI(ByteStringView(pBuff));
@@ -323,21 +347,21 @@
return WideString();
}
- const int nRequiredLen =
+ const int required_len =
js_platform->Doc_getFilePath(js_platform, nullptr, 0);
- if (nRequiredLen <= 0) {
+ if (required_len <= 0) {
return WideString();
}
- DataVector<uint8_t> pBuff(nRequiredLen);
- const int nActualLen =
- js_platform->Doc_getFilePath(js_platform, pBuff.data(), nRequiredLen);
- if (nActualLen <= 0 || nActualLen > nRequiredLen) {
+ DataVector<uint8_t> pBuff(required_len);
+ const int actual_len =
+ js_platform->Doc_getFilePath(js_platform, pBuff.data(), required_len);
+ if (actual_len <= 0 || actual_len > required_len) {
return WideString();
}
// Don't include trailing NUL.
- pBuff.resize(nActualLen - 1);
+ pBuff.resize(actual_len - 1);
// Use FromDefANSI() per "local encoding" comment in fpdf_formfill.h.
return WideString::FromDefANSI(ByteStringView(pBuff));
@@ -378,7 +402,7 @@
void CPDFSDK_FormFillEnvironment::Invalidate(IPDF_Page* page,
const FX_RECT& rect) {
if (info_ && info_->FFI_Invalidate) {
- AutoRestorer<bool> ffi_restorer(&in_passive_ffi_callback_);
+ AutoRestorer<bool> restorer(&in_passive_ffi_callback_);
in_passive_ffi_callback_ = true;
info_->FFI_Invalidate(info_, FPDFPageFromIPDFPage(page), rect.left,
rect.top, rect.right, rect.bottom);
@@ -388,7 +412,7 @@
void CPDFSDK_FormFillEnvironment::SetCursor(
IPWL_FillerNotify::CursorStyle nCursorType) {
if (info_ && info_->FFI_SetCursor) {
- AutoRestorer<bool> ffi_restorer(&in_passive_ffi_callback_);
+ AutoRestorer<bool> restorer(&in_passive_ffi_callback_);
in_passive_ffi_callback_ = true;
info_->FFI_SetCursor(info_, static_cast<int>(nCursorType));
}
@@ -397,6 +421,8 @@
int CPDFSDK_FormFillEnvironment::SetTimer(int uElapse,
TimerCallback lpTimerFunc) {
if (info_ && info_->FFI_SetTimer) {
+ AutoRestorer<bool> restorer(&in_active_ffi_callback_);
+ in_active_ffi_callback_ = true;
return info_->FFI_SetTimer(info_, uElapse, lpTimerFunc);
}
return CFX_Timer::HandlerIface::kInvalidTimerID;
@@ -404,13 +430,15 @@
void CPDFSDK_FormFillEnvironment::KillTimer(int nTimerID) {
if (info_ && info_->FFI_KillTimer) {
+ AutoRestorer<bool> restorer(&in_active_ffi_callback_);
+ in_active_ffi_callback_ = true;
info_->FFI_KillTimer(info_, nTimerID);
}
}
void CPDFSDK_FormFillEnvironment::OnChange() {
if (info_ && info_->FFI_OnChange) {
- AutoRestorer<bool> ffi_restorer(&in_passive_ffi_callback_);
+ AutoRestorer<bool> restorer(&in_passive_ffi_callback_);
in_passive_ffi_callback_ = true;
info_->FFI_OnChange(info_);
}
@@ -419,6 +447,8 @@
void CPDFSDK_FormFillEnvironment::ExecuteNamedAction(
const ByteString& namedAction) {
if (info_ && info_->FFI_ExecuteNamedAction) {
+ AutoRestorer<bool> restorer(&in_active_ffi_callback_);
+ in_active_ffi_callback_ = true;
info_->FFI_ExecuteNamedAction(info_, namedAction.c_str());
}
}
@@ -434,7 +464,7 @@
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_);
+ AutoRestorer<bool> restorer(&in_passive_ffi_callback_);
in_passive_ffi_callback_ = true;
info_->FFI_SetTextFieldFocus(
info_, pBuffer, pdfium::checked_cast<FPDF_DWORD>(nCharacters), bFocus);
@@ -471,14 +501,16 @@
if (!info_) {
return;
}
-
if (info_->version >= 2 && info_->FFI_DoURIActionWithKeyboardModifier) {
+ AutoRestorer<bool> restorer(&in_active_ffi_callback_);
+ in_active_ffi_callback_ = true;
info_->FFI_DoURIActionWithKeyboardModifier(info_, bsURI.c_str(),
modifiers.UncheckedValue());
return;
}
-
if (info_->FFI_DoURIAction) {
+ AutoRestorer<bool> restorer(&in_active_ffi_callback_);
+ in_active_ffi_callback_ = true;
info_->FFI_DoURIAction(info_, bsURI.c_str());
}
}
@@ -487,6 +519,8 @@
int zoomMode,
pdfium::span<float> fPosArray) {
if (info_ && info_->FFI_DoGoToAction) {
+ AutoRestorer<bool> restorer(&in_active_ffi_callback_);
+ in_active_ffi_callback_ = true;
info_->FFI_DoGoToAction(info_, nPageIndex, zoomMode, fPosArray.data(),
fxcrt::CollectionSize<int>(fPosArray));
}
@@ -504,17 +538,19 @@
double right,
double bottom) {
if (info_ && info_->version >= 2 && info_->FFI_DisplayCaret) {
- AutoRestorer<bool> ffi_restorer(&in_passive_ffi_callback_);
+ AutoRestorer<bool> restorer(&in_passive_ffi_callback_);
in_passive_ffi_callback_ = true;
info_->FFI_DisplayCaret(info_, FPDFPageFromIPDFPage(page), bVisible, left,
top, right, bottom);
}
}
-int CPDFSDK_FormFillEnvironment::GetCurrentPageIndex() const {
+int CPDFSDK_FormFillEnvironment::GetCurrentPageIndex() {
if (!info_ || info_->version < 2 || !info_->FFI_GetCurrentPageIndex) {
return -1;
}
+ AutoRestorer<bool> restorer(&in_active_ffi_callback_);
+ in_active_ffi_callback_ = true;
return info_->FFI_GetCurrentPageIndex(
info_, FPDFDocumentFromCPDFDocument(cpdfdoc_.Get()));
}
@@ -523,6 +559,8 @@
if (!info_ || info_->version < 2 || !info_->FFI_SetCurrentPage) {
return;
}
+ AutoRestorer<bool> restorer(&in_active_ffi_callback_);
+ in_active_ffi_callback_ = true;
info_->FFI_SetCurrentPage(info_, FPDFDocumentFromCPDFDocument(cpdfdoc_.Get()),
iCurPage);
}
@@ -533,6 +571,8 @@
}
ByteString bsTo = wsURL.ToUTF16LE();
+ AutoRestorer<bool> restorer(&in_active_ffi_callback_);
+ in_active_ffi_callback_ = true;
info_->FFI_GotoURL(info_, FPDFDocumentFromCPDFDocument(cpdfdoc_.Get()),
AsFPDFWideString(&bsTo));
}
@@ -547,8 +587,12 @@
double top;
double right;
double bottom;
- info_->FFI_GetPageViewRect(info_, FPDFPageFromIPDFPage(page), &left, &top,
- &right, &bottom);
+ {
+ AutoRestorer<bool> restorer(&in_active_ffi_callback_);
+ in_active_ffi_callback_ = true;
+ info_->FFI_GetPageViewRect(info_, FPDFPageFromIPDFPage(page), &left, &top,
+ &right, &bottom);
+ }
rect.left = static_cast<float>(left);
rect.top = static_cast<float>(top);
@@ -560,9 +604,13 @@
bool CPDFSDK_FormFillEnvironment::PopupMenu(IPDF_Page* page,
int menuFlag,
const CFX_PointF& pt) {
- return info_ && info_->version >= 2 && info_->FFI_PopupMenu &&
- info_->FFI_PopupMenu(info_, FPDFPageFromIPDFPage(page), nullptr,
- menuFlag, pt.x, pt.y);
+ if (info_ && info_->version >= 2 && info_->FFI_PopupMenu) {
+ AutoRestorer<bool> restorer(&in_active_ffi_callback_);
+ in_active_ffi_callback_ = true;
+ return info_->FFI_PopupMenu(info_, FPDFPageFromIPDFPage(page), nullptr,
+ menuFlag, pt.x, pt.y);
+ }
+ return false;
}
void CPDFSDK_FormFillEnvironment::EmailTo(FPDF_FILEHANDLER* fileHandler,
@@ -572,6 +620,8 @@
FPDF_WIDESTRING pBcc,
FPDF_WIDESTRING pMsg) {
if (info_ && info_->version >= 2 && info_->FFI_EmailTo) {
+ AutoRestorer<bool> restorer(&in_active_ffi_callback_);
+ in_active_ffi_callback_ = true;
info_->FFI_EmailTo(info_, fileHandler, pTo, pSubject, pCC, pBcc, pMsg);
}
}
@@ -580,6 +630,8 @@
int fileFlag,
FPDF_WIDESTRING uploadTo) {
if (info_ && info_->version >= 2 && info_->FFI_UploadTo) {
+ AutoRestorer<bool> restorer(&in_active_ffi_callback_);
+ in_active_ffi_callback_ = true;
info_->FFI_UploadTo(info_, fileHandler, fileFlag, uploadTo);
}
}
@@ -588,6 +640,8 @@
FPDF_WIDESTRING wsURL,
const char* mode) {
if (info_ && info_->version >= 2 && info_->FFI_OpenFile) {
+ AutoRestorer<bool> restorer(&in_active_ffi_callback_);
+ in_active_ffi_callback_ = true;
return info_->FFI_OpenFile(info_, fileType, wsURL, mode);
}
return nullptr;
@@ -600,8 +654,13 @@
}
ByteString bstrURL = url.ToUTF16LE();
- FPDF_FILEHANDLER* file_handler =
- info_->FFI_DownloadFromURL(info_, AsFPDFWideString(&bstrURL));
+ FPDF_FILEHANDLER* file_handler;
+ {
+ AutoRestorer<bool> restorer(&in_active_ffi_callback_);
+ in_active_ffi_callback_ = true;
+ file_handler =
+ info_->FFI_DownloadFromURL(info_, AsFPDFWideString(&bstrURL));
+ }
if (!file_handler) {
return nullptr;
}
@@ -627,10 +686,14 @@
FPDF_BSTR response;
FPDF_BStr_Init(&response);
- info_->FFI_PostRequestURL(
- info_, AsFPDFWideString(&bsURL), AsFPDFWideString(&bsData),
- AsFPDFWideString(&bsContentType), AsFPDFWideString(&bsEncode),
- AsFPDFWideString(&bsHeader), &response);
+ {
+ AutoRestorer<bool> restorer(&in_active_ffi_callback_);
+ in_active_ffi_callback_ = true;
+ info_->FFI_PostRequestURL(
+ info_, AsFPDFWideString(&bsURL), AsFPDFWideString(&bsData),
+ AsFPDFWideString(&bsContentType), AsFPDFWideString(&bsEncode),
+ AsFPDFWideString(&bsHeader), &response);
... (file diff truncated)
Loading diff…
Original Bug Report
The reporter's bug is still restricted on the tracker. Chrome de-restricts security bugs ~30–90 days after the fix ships; a later run will backfill it here.
References
On This Page