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 <[email protected]> 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 <[email protected]> Commit-Queue: Tom Sepez <[email protected]> --- 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