poppler: fix CVE-2025-52886

Poppler is a PDF rendering library. Versions prior to 25.06.0
use `std::atomic_int` for reference counting. Because
`std::atomic_int` is only 32 bits, it is possible to overflow
the reference count and trigger a use-after-free. Version 25.06.0
patches the issue.

CVE-2025-52886-0001 and CVE-2025-52886-0002 are dependent commits
while rest are actual CVE fixes.

References:
https://nvd.nist.gov/vuln/detail/CVE-2025-52886
https://security-tracker.debian.org/tracker/CVE-2025-52886

Upstream patches:
https://gitlab.freedesktop.org/poppler/poppler/-/commit/d35e11a8f84d396a9d9ef43ef852d377adc3830a
https://gitlab.freedesktop.org/poppler/poppler/-/commit/af3e1e1a3577c4e1c66cbe69ebdc6a632038e299
https://gitlab.freedesktop.org/poppler/poppler/-/commit/3449a16d3b1389870eb3e20795e802c6ae8bc04f
https://gitlab.freedesktop.org/poppler/poppler/-/commit/ac36affcc8486de38e8905a8d6547a3464ff46e5

Signed-off-by: Yogita Urade <yogita.urade@windriver.com>
Signed-off-by: Gyorgy Sarvari <skandigraun@gmail.com>
This commit is contained in:
Yogita Urade
2025-09-05 15:45:50 +05:30
committed by Gyorgy Sarvari
parent f8c52b138b
commit 110e57abb5
5 changed files with 4707 additions and 0 deletions
@@ -0,0 +1,318 @@
From d35e11a8f84d396a9d9ef43ef852d377adc3830a Mon Sep 17 00:00:00 2001
From: Albert Astals Cid <aacid@kde.org>
Date: Fri, 1 Apr 2022 16:26:25 +0200
Subject: [PATCH] Annots: Just return the std::vector instead of two getters
Simpler code to use and solves the int vs size_t mismatch by not having a
type involved at all
CVE: CVE-2025-52886
Upstream-Status: Backport [https://gitlab.freedesktop.org/poppler/poppler/-/commit/d35e11a8f84d396a9d9ef43ef852d377adc3830a]
Signed-off-by: Yogita Urade <yogita.urade@windriver.com>
---
glib/poppler-page.cc | 5 +----
poppler/Annot.cc | 4 ++--
poppler/Annot.h | 5 ++---
poppler/FontInfo.cc | 4 ++--
poppler/Form.cc | 7 +++----
poppler/JSInfo.cc | 14 +++++++-------
poppler/Link.cc | 3 +--
poppler/PSOutputDev.cc | 4 ++--
poppler/Page.cc | 17 ++++-------------
qt5/src/poppler-annotation.cc | 10 ++--------
qt6/src/poppler-annotation.cc | 10 ++--------
utils/pdfdetach.cc | 4 +---
12 files changed, 29 insertions(+), 58 deletions(-)
diff --git a/glib/poppler-page.cc b/glib/poppler-page.cc
index d075502..f0b7245 100644
--- a/glib/poppler-page.cc
+++ b/glib/poppler-page.cc
@@ -1285,7 +1285,6 @@ GList *poppler_page_get_annot_mapping(PopplerPage *page)
{
GList *map_list = nullptr;
double width, height;
- gint i;
Annots *annots;
const PDFRectangle *crop_box;
@@ -1299,14 +1298,12 @@ GList *poppler_page_get_annot_mapping(PopplerPage *page)
poppler_page_get_size(page, &width, &height);
crop_box = page->page->getCropBox();
- for (i = 0; i < annots->getNumAnnots(); i++) {
+ for (Annot *annot : annots->getAnnots()) {
PopplerAnnotMapping *mapping;
PopplerRectangle rect;
- Annot *annot;
gboolean flag_no_rotate;
gint rotation = 0;
- annot = annots->getAnnot(i);
flag_no_rotate = annot->getFlags() & Annot::flagNoRotate;
/* Create the mapping */
diff --git a/poppler/Annot.cc b/poppler/Annot.cc
index 60c023d..366e7de 100644
--- a/poppler/Annot.cc
+++ b/poppler/Annot.cc
@@ -1087,8 +1087,8 @@ void AnnotAppearance::removeStream(Ref refToStream)
continue;
}
Annots *annots = page->getAnnots();
- for (int i = 0; i < annots->getNumAnnots(); ++i) {
- AnnotAppearance *annotAp = annots->getAnnot(i)->getAppearStreams();
+ for (Annot *annot : annots->getAnnots()) {
+ AnnotAppearance *annotAp = annot->getAppearStreams();
if (annotAp && annotAp != this && annotAp->referencesStream(refToStream)) {
return; // Another annotation points to the stream -> Don't delete it
}
diff --git a/poppler/Annot.h b/poppler/Annot.h
index 9ae274d..8d1f18b 100644
--- a/poppler/Annot.h
+++ b/poppler/Annot.h
@@ -1766,9 +1766,8 @@ public:
Annots(const Annots &) = delete;
Annots &operator=(const Annots &) = delete;
- // Iterate through list of annotations.
- int getNumAnnots() const { return annots.size(); }
- Annot *getAnnot(int i) { return annots[i]; }
+ const std::vector<Annot *> &getAnnots() { return annots; }
+
void appendAnnot(Annot *annot);
bool removeAnnot(Annot *annot);
diff --git a/poppler/FontInfo.cc b/poppler/FontInfo.cc
index 23425f6..309ec6d 100644
--- a/poppler/FontInfo.cc
+++ b/poppler/FontInfo.cc
@@ -82,8 +82,8 @@ std::vector<FontInfo *> FontInfoScanner::scan(int nPages)
delete resDict;
}
annots = page->getAnnots();
- for (int i = 0; i < annots->getNumAnnots(); ++i) {
- Object obj1 = annots->getAnnot(i)->getAppearanceResDict();
+ for (Annot *annot : annots->getAnnots()) {
+ Object obj1 = annot->getAppearanceResDict();
if (obj1.isDict()) {
scanFonts(xrefA.get(), obj1.getDict(), &result);
}
diff --git a/poppler/Form.cc b/poppler/Form.cc
index 97b5be0..b88972a 100644
--- a/poppler/Form.cc
+++ b/poppler/Form.cc
@@ -2732,14 +2732,13 @@ FormPageWidgets::FormPageWidgets(Annots *annots, unsigned int page, Form *form)
widgets = nullptr;
size = 0;
- if (annots && annots->getNumAnnots() > 0 && form) {
- size = annots->getNumAnnots();
+ if (annots && !annots->getAnnots().empty() > 0 && form) {
+ size = annots->getAnnots().size();
widgets = (FormWidget **)greallocn(widgets, size, sizeof(FormWidget *));
/* For each entry in the page 'Annots' dict, try to find
a matching form field */
- for (int i = 0; i < size; ++i) {
- Annot *annot = annots->getAnnot(i);
+ for (Annot *annot : annots->getAnnots()) {
if (annot->getType() != Annot::typeWidget) {
continue;
diff --git a/poppler/JSInfo.cc b/poppler/JSInfo.cc
index 6607085..eaef33e 100644
--- a/poppler/JSInfo.cc
+++ b/poppler/JSInfo.cc
@@ -191,15 +191,15 @@ void JSInfo::scan(int nPages)
}
// annotation actions (links, screen, widget)
annots = page->getAnnots();
- for (int i = 0; i < annots->getNumAnnots(); ++i) {
- if (annots->getAnnot(i)->getType() == Annot::typeLink) {
- AnnotLink *annot = static_cast<AnnotLink *>(annots->getAnnot(i));
+ for (Annot *a : annots->getAnnots()) {
+ if (a->getType() == Annot::typeLink) {
+ AnnotLink *annot = static_cast<AnnotLink *>(a);
scanLinkAction(annot->getAction(), "Link Annotation Activated");
if (onlyFirstJS && hasJS) {
return;
}
- } else if (annots->getAnnot(i)->getType() == Annot::typeScreen) {
- AnnotScreen *annot = static_cast<AnnotScreen *>(annots->getAnnot(i));
+ } else if (a->getType() == Annot::typeScreen) {
+ AnnotScreen *annot = static_cast<AnnotScreen *>(a);
scanLinkAction(annot->getAction(), "Screen Annotation Activated");
scanLinkAction(annot->getAdditionalAction(Annot::actionCursorEntering).get(), "Screen Annotation Cursor Enter");
scanLinkAction(annot->getAdditionalAction(Annot::actionCursorLeaving).get(), "Screen Annotation Cursor Leave");
@@ -215,8 +215,8 @@ void JSInfo::scan(int nPages)
if (onlyFirstJS && hasJS) {
return;
}
- } else if (annots->getAnnot(i)->getType() == Annot::typeWidget) {
- AnnotWidget *annot = static_cast<AnnotWidget *>(annots->getAnnot(i));
+ } else if (a->getType() == Annot::typeWidget) {
+ AnnotWidget *annot = static_cast<AnnotWidget *>(a);
scanLinkAction(annot->getAction(), "Widget Annotation Activated");
scanLinkAction(annot->getAdditionalAction(Annot::actionCursorEntering).get(), "Widget Annotation Cursor Enter");
scanLinkAction(annot->getAdditionalAction(Annot::actionCursorLeaving).get(), "Widget Annotation Cursor Leave");
diff --git a/poppler/Link.cc b/poppler/Link.cc
index b2e48cb..8aca0b9 100644
--- a/poppler/Link.cc
+++ b/poppler/Link.cc
@@ -890,8 +890,7 @@ Links::Links(Annots *annots)
return;
}
- for (int i = 0; i < annots->getNumAnnots(); ++i) {
- Annot *annot = annots->getAnnot(i);
+ for (Annot *annot : annots->getAnnots()) {
if (annot->getType() != Annot::typeLink) {
continue;
diff --git a/poppler/PSOutputDev.cc b/poppler/PSOutputDev.cc
index 111b472..9db6229 100644
--- a/poppler/PSOutputDev.cc
+++ b/poppler/PSOutputDev.cc
@@ -1745,8 +1745,8 @@ void PSOutputDev::writeDocSetup(Catalog *catalog, const std::vector<int> &pageLi
setupResources(resDict);
}
annots = page->getAnnots();
- for (int i = 0; i < annots->getNumAnnots(); ++i) {
- Object obj1 = annots->getAnnot(i)->getAppearanceResDict();
+ for (Annot *annot : annots->getAnnots()) {
+ Object obj1 = annot->getAppearanceResDict();
if (obj1.isDict()) {
setupResources(obj1.getDict());
}
diff --git a/poppler/Page.cc b/poppler/Page.cc
index 727dd28..6b33500 100644
--- a/poppler/Page.cc
+++ b/poppler/Page.cc
@@ -367,16 +367,9 @@ void Page::replaceXRef(XRef *xrefA)
/* Loads standalone fields into Page, should be called once per page only */
void Page::loadStandaloneFields(Annots *annotations, Form *form)
{
- const int numAnnots = annotations ? annotations->getNumAnnots() : 0;
-
- if (numAnnots < 1) {
- return;
- }
-
/* Look for standalone annots, identified by being: 1) of type Widget
* 2) not referenced from the Catalog's Form Field array */
- for (int i = 0; i < numAnnots; ++i) {
- Annot *annot = annotations->getAnnot(i);
+ for (Annot *annot : annots->getAnnots()) {
if (annot->getType() != Annot::typeWidget || !annot->getHasRef()) {
continue;
@@ -564,7 +557,6 @@ void Page::displaySlice(OutputDev *out, double hDPI, double vDPI, int rotate, bo
{
Gfx *gfx;
Annots *annotList;
- int i;
if (!out->checkPageSlice(this, hDPI, vDPI, rotate, useMediaBox, crop, sliceX, sliceY, sliceW, sliceH, printing, abortCheckCbk, abortCheckCbkData, annotDisplayDecideCbk, annotDisplayDecideCbkData)) {
return;
@@ -591,14 +583,13 @@ void Page::displaySlice(OutputDev *out, double hDPI, double vDPI, int rotate, bo
// draw annotations
annotList = getAnnots();
- if (annotList->getNumAnnots() > 0) {
+ if (!annotList->getAnnots().empty()) {
if (globalParams->getPrintCommands()) {
printf("***** Annotations\n");
}
- for (i = 0; i < annotList->getNumAnnots(); ++i) {
- Annot *annot = annotList->getAnnot(i);
+ for (Annot *annot : annots->getAnnots()) {
if ((annotDisplayDecideCbk && (*annotDisplayDecideCbk)(annot, annotDisplayDecideCbkData)) || !annotDisplayDecideCbk) {
- annotList->getAnnot(i)->draw(gfx, printing);
+ annot->draw(gfx, printing);
}
}
out->dump();
diff --git a/qt5/src/poppler-annotation.cc b/qt5/src/poppler-annotation.cc
index ab45673..cdf25da 100644
--- a/qt5/src/poppler-annotation.cc
+++ b/qt5/src/poppler-annotation.cc
@@ -438,10 +438,6 @@ AnnotPath *AnnotationPrivate::toAnnotPath(const QLinkedList<QPointF> &list) cons
QList<Annotation *> AnnotationPrivate::findAnnotations(::Page *pdfPage, DocumentData *doc, const QSet<Annotation::SubType> &subtypes, int parentID)
{
Annots *annots = pdfPage->getAnnots();
- const uint numAnnotations = annots->getNumAnnots();
- if (numAnnotations == 0) {
- return QList<Annotation *>();
- }
const bool wantTextAnnotations = subtypes.isEmpty() || subtypes.contains(Annotation::AText);
const bool wantLineAnnotations = subtypes.isEmpty() || subtypes.contains(Annotation::ALine);
@@ -459,11 +455,9 @@ QList<Annotation *> AnnotationPrivate::findAnnotations(::Page *pdfPage, Document
// Create Annotation objects and tie to their native Annot
QList<Annotation *> res;
- for (uint k = 0; k < numAnnotations; k++) {
- // get the j-th annotation
- Annot *ann = annots->getAnnot(k);
+ for (Annot *ann : annots->getAnnots()) {
if (!ann) {
- error(errInternal, -1, "Annot {0:ud} is null", k);
+ error(errInternal, -1, "Annot is null");
continue;
}
diff --git a/qt6/src/poppler-annotation.cc b/qt6/src/poppler-annotation.cc
index b92b76b..5770be6 100644
--- a/qt6/src/poppler-annotation.cc
+++ b/qt6/src/poppler-annotation.cc
@@ -360,10 +360,6 @@ AnnotPath *AnnotationPrivate::toAnnotPath(const QVector<QPointF> &list) const
std::vector<std::unique_ptr<Annotation>> AnnotationPrivate::findAnnotations(::Page *pdfPage, DocumentData *doc, const QSet<Annotation::SubType> &subtypes, int parentID)
{
Annots *annots = pdfPage->getAnnots();
- const uint numAnnotations = annots->getNumAnnots();
- if (numAnnotations == 0) {
- return std::vector<std::unique_ptr<Annotation>>();
- }
const bool wantTextAnnotations = subtypes.isEmpty() || subtypes.contains(Annotation::AText);
const bool wantLineAnnotations = subtypes.isEmpty() || subtypes.contains(Annotation::ALine);
@@ -381,11 +377,9 @@ std::vector<std::unique_ptr<Annotation>> AnnotationPrivate::findAnnotations(::Pa
// Create Annotation objects and tie to their native Annot
std::vector<std::unique_ptr<Annotation>> res;
- for (uint k = 0; k < numAnnotations; k++) {
- // get the j-th annotation
- Annot *ann = annots->getAnnot(k);
+ for (Annot *ann : annots->getAnnots()) {
if (!ann) {
- error(errInternal, -1, "Annot {0:ud} is null", k);
+ error(errInternal, -1, "Annot is null");
continue;
}
diff --git a/utils/pdfdetach.cc b/utils/pdfdetach.cc
index 61c3728..247c2c1 100644
--- a/utils/pdfdetach.cc
+++ b/utils/pdfdetach.cc
@@ -85,7 +85,6 @@ int main(int argc, char *argv[])
int nFiles, nPages, n, i, j;
Page *page;
Annots *annots;
- Annot *annot;
const GooString *s1;
Unicode u;
bool isUnicode;
@@ -151,8 +150,7 @@ int main(int argc, char *argv[])
break;
}
- for (j = 0; j < annots->getNumAnnots(); ++j) {
- annot = annots->getAnnot(j);
+ for (Annot *annot : annots->getAnnots()) {
if (annot->getType() != Annot::typeFileAttachment) {
continue;
}
--
2.40.0
@@ -0,0 +1,108 @@
From af3e1e1a3577c4e1c66cbe69ebdc6a632038e299 Mon Sep 17 00:00:00 2001
From: Albert Astals Cid <aacid@kde.org>
Date: Fri, 1 Apr 2022 16:03:46 +0200
Subject: [PATCH] Link: Just return the std::vector instead of two getters
Simpler code to use and solves the int vs size_t mismatch by not having a
type involved at all
CVE: CVE-2025-52886
Upstream-Status: Backport [https://gitlab.freedesktop.org/poppler/poppler/-/commit/af3e1e1a3577c4e1c66cbe69ebdc6a632038e299]
Signed-off-by: Yogita Urade <yogita.urade@windriver.com>
---
glib/poppler-page.cc | 5 +----
poppler/Link.h | 4 +---
poppler/Page.cc | 4 ++--
utils/HtmlOutputDev.cc | 4 ++--
utils/pdfinfo.cc | 3 +--
5 files changed, 7 insertions(+), 13 deletions(-)
diff --git a/glib/poppler-page.cc b/glib/poppler-page.cc
index f0b7245..a9515f3 100644
--- a/glib/poppler-page.cc
+++ b/glib/poppler-page.cc
@@ -1119,7 +1119,6 @@ static void poppler_page_init(PopplerPage *page) { }
GList *poppler_page_get_link_mapping(PopplerPage *page)
{
GList *map_list = nullptr;
- gint i;
Links *links;
double width, height;
@@ -1133,13 +1132,11 @@ GList *poppler_page_get_link_mapping(PopplerPage *page)
poppler_page_get_size(page, &width, &height);
- for (i = 0; i < links->getNumLinks(); i++) {
+ for (AnnotLink *link : links->getLinks()) {
PopplerLinkMapping *mapping;
PopplerRectangle rect;
LinkAction *link_action;
- AnnotLink *link;
- link = links->getLink(i);
link_action = link->getAction();
/* Create the mapping */
diff --git a/poppler/Link.h b/poppler/Link.h
index 0c4677c..204207b 100644
--- a/poppler/Link.h
+++ b/poppler/Link.h
@@ -555,9 +555,7 @@ public:
Links(const Links &) = delete;
Links &operator=(const Links &) = delete;
- // Iterate through list of links.
- int getNumLinks() const { return links.size(); }
- AnnotLink *getLink(int i) const { return links[i]; }
+ const std::vector<AnnotLink *> &getLinks() const { return links; }
private:
std::vector<AnnotLink *> links;
diff --git a/poppler/Page.cc b/poppler/Page.cc
index 6b33500..c256d39 100644
--- a/poppler/Page.cc
+++ b/poppler/Page.cc
@@ -778,8 +778,8 @@ void Page::makeBox(double hDPI, double vDPI, int rotate, bool useMediaBox, bool
void Page::processLinks(OutputDev *out)
{
std::unique_ptr<Links> links = getLinks();
- for (int i = 0; i < links->getNumLinks(); ++i) {
- out->processLink(links->getLink(i));
+ for (AnnotLink *link : links->getLinks()) {
+ out->processLink(link);
}
}
diff --git a/utils/HtmlOutputDev.cc b/utils/HtmlOutputDev.cc
index 71fe672..2056188 100644
--- a/utils/HtmlOutputDev.cc
+++ b/utils/HtmlOutputDev.cc
@@ -1247,8 +1247,8 @@ void HtmlOutputDev::startPage(int pageNumA, GfxState *state, XRef *xref)
void HtmlOutputDev::endPage()
{
std::unique_ptr<Links> linksList = docPage->getLinks();
- for (int i = 0; i < linksList->getNumLinks(); ++i) {
- doProcessLink(linksList->getLink(i));
+ for (AnnotLink *link : linksList->getLinks()) {
+ doProcessLink(link);
}
pages->conv();
diff --git a/utils/pdfinfo.cc b/utils/pdfinfo.cc
index 4b9166f..5f96b41 100644
--- a/utils/pdfinfo.cc
+++ b/utils/pdfinfo.cc
@@ -415,8 +415,7 @@ static void printUrlList(PDFDoc *doc)
Page *page = doc->getPage(pg);
if (page) {
std::unique_ptr<Links> links = page->getLinks();
- for (int i = 0; i < links->getNumLinks(); i++) {
- AnnotLink *annot = links->getLink(i);
+ for (AnnotLink *annot : links->getLinks()) {
LinkAction *action = annot->getAction();
if (action->getKind() == actionURI) {
LinkURI *linkUri = dynamic_cast<LinkURI *>(action);
--
2.40.0
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,58 @@
From ac36affcc8486de38e8905a8d6547a3464ff46e5 Mon Sep 17 00:00:00 2001
From: Sune Vuorela <sune@vuorela.dk>
Date: Tue, 3 Jun 2025 00:35:19 +0200
Subject: [PATCH] Limit ammount of annots per document/page
CVE: CVE-2025-52886
Upstream-Status: Backport [https://gitlab.freedesktop.org/poppler/poppler/-/commit/ac36affcc8486de38e8905a8d6547a3464ff46e5]
Signed-off-by: Yogita Urade <yogita.urade@windriver.com>
---
poppler/Annot.cc | 4 ++++
poppler/Page.cc | 16 ++++++++++++++++
2 files changed, 20 insertions(+)
diff --git a/poppler/Annot.cc b/poppler/Annot.cc
index 19ec824..9b5145c 100644
--- a/poppler/Annot.cc
+++ b/poppler/Annot.cc
@@ -7253,6 +7253,10 @@ Annots::Annots(PDFDoc *docA, int page, Object *annotsObj)
const Object &obj2 = annotsObj->arrayGetNF(i);
std::shared_ptr<Annot> annot = createAnnot(std::move(obj1), &obj2);
if (annot) {
+ if (annot.use_count() > 100000) {
+ error(errSyntaxError, -1, "Annotations likely malformed. Too many references. Stopping processing annots on page {0:d}", page);
+ break;
+ }
if (annot->isOk()) {
annot->setPage(page, false); // Don't change /P
appendAnnot(annot);
diff --git a/poppler/Page.cc b/poppler/Page.cc
index b27c90d..8b5da2f 100644
--- a/poppler/Page.cc
+++ b/poppler/Page.cc
@@ -289,6 +289,22 @@ Page::Page(PDFDoc *docA, int numA, Object &&pageDict, Ref pageRefA, PageAttrs *a
goto err2;
}
+ if (annotsObj.isArray() && annotsObj.arrayGetLength() > 10000) {
+ error(errSyntaxError, -1, "Page annotations object (page {0:d}) is likely malformed. Too big: ({1:d})", num, annotsObj.arrayGetLength());
+ goto err2;
+ }
+ if (annotsObj.isRef()) {
+ auto resolvedObj = getAnnotsObject();
+ if (resolvedObj.isArray() && resolvedObj.arrayGetLength() > 10000) {
+ error(errSyntaxError, -1, "Page annotations object (page {0:d}) is likely malformed. Too big: ({1:d})", num, resolvedObj.arrayGetLength());
+ goto err2;
+ }
+ if (!resolvedObj.isArray() && !resolvedObj.isNull()) {
+ error(errSyntaxError, -1, "Page annotations object (page {0:d}) is wrong type ({1:s})", num, resolvedObj.getTypeName());
+ goto err2;
+ }
+ }
+
// contents
contents = pageObj.dictLookupNF("Contents").copy();
if (!(contents.isRef() || contents.isArray() || contents.isNull())) {
--
2.40.0
@@ -15,6 +15,10 @@ SRC_URI = "http://poppler.freedesktop.org/${BP}.tar.xz \
file://CVE-2025-32365.patch \
file://CVE-2025-43903.patch \
file://CVE-2025-50420.patch \
file://CVE-2025-52886-0001.patch \
file://CVE-2025-52886-0002.patch \
file://CVE-2025-52886-0003.patch \
file://CVE-2025-52886-0004.patch \
"
SRC_URI[sha256sum] = "813fb4b90e7bda63df53205c548602bae728887a60f4048aae4dbd9b1927deff"