File poppler-CVE-2025-11896.patch of Package poppler
From 998c6a79571af968ba90af57a0c5dcbb5a53763c Mon Sep 17 00:00:00 2001
From: Sune Vuorela <sune@vuorela.dk>
Date: Mon, 13 Oct 2025 15:13:14 +0200
Subject: [PATCH] Limit recursion in cmap parsing
fixes #1632
---
poppler/CMap.cc | 18 +++++++++++-------
poppler/CMap.h | 13 +++++++------
2 files changed, 18 insertions(+), 13 deletions(-)
diff --git a/poppler/CMap.cc b/poppler/CMap.cc
index c71667f1c5..23e8240131 100644
--- a/poppler/CMap.cc
+++ b/poppler/CMap.cc
@@ -66,7 +66,7 @@ static int getCharFromStream(void *data)
//------------------------------------------------------------------------
-std::shared_ptr<CMap> CMap::parse(CMapCache *cache, const std::string &collectionA, Object *obj)
+std::shared_ptr<CMap> CMap::parse(CMapCache *cache, const std::string &collectionA, Object *obj, const std::shared_ptr<RefRecursionChecker> &recursion)
{
std::shared_ptr<CMap> cMap;
@@ -76,7 +76,7 @@ std::shared_ptr<CMap> CMap::parse(CMapCache *cache, const std::string &collectio
error(errSyntaxError, -1, "Unknown CMap '{0:t}' for character collection '{1:s}'", &cMapNameA, collectionA.c_str());
}
} else if (obj->isStream()) {
- if (!(cMap = CMap::parse(nullptr, collectionA, obj->getStream()))) {
+ if (!(cMap = CMap::parse(nullptr, collectionA, obj->getStream(), recursion))) {
error(errSyntaxError, -1, "Invalid CMap in Type 0 font");
}
} else {
@@ -112,12 +112,16 @@ std::shared_ptr<CMap> CMap::parse(CMapCache *cache, const std::string &collectio
return cMap;
}
-std::shared_ptr<CMap> CMap::parse(CMapCache *cache, const std::string &collectionA, Stream *str)
+std::shared_ptr<CMap> CMap::parse(CMapCache *cache, const std::string &collectionA, Stream *str, const std::shared_ptr<RefRecursionChecker> &recursion)
{
auto cMap = std::shared_ptr<CMap>(new CMap(std::make_unique<GooString>(collectionA), nullptr));
- Object obj1 = str->getDict()->lookup("UseCMap");
+ Ref ref;
+ Object obj1 = str->getDict()->lookup("UseCMap", &ref);
+ if (!recursion->insert(ref)) {
+ return nullptr;
+ }
if (!obj1.isNull()) {
- cMap->useCMap(cache, &obj1);
+ cMap->useCMap(cache, &obj1, recursion);
}
if (str->reset()) {
@@ -233,9 +237,9 @@ void CMap::useCMap(CMapCache *cache, const char *useName)
}
}
-void CMap::useCMap(CMapCache *cache, Object *obj)
+void CMap::useCMap(CMapCache *cache, Object *obj, const std::shared_ptr<RefRecursionChecker> &recursion)
{
- std::shared_ptr<CMap> subCMap = CMap::parse(cache, collection->toStr(), obj);
+ std::shared_ptr<CMap> subCMap = CMap::parse(cache, collection->toStr(), obj, recursion);
if (!subCMap) {
return;
}
diff --git a/poppler/CMap.h b/poppler/CMap.h
index 6856b52c46..1b8cc764af 100644
--- a/poppler/CMap.h
+++ b/poppler/CMap.h
@@ -30,6 +30,7 @@
#include <atomic>
#include <memory>
+#include "Object.h"
#include "poppler-config.h"
#include "CharTypes.h"
@@ -46,16 +47,12 @@ class CMap
public:
// Parse a CMap from <obj>, which can be a name or a stream. Sets
// the initial reference count to 1. Returns NULL on failure.
- static std::shared_ptr<CMap> parse(CMapCache *cache, const std::string &collectionA, Object *obj);
+ static std::shared_ptr<CMap> parse(CMapCache *cache, const std::string &collectionA, Object *obj, const std::shared_ptr<RefRecursionChecker> &recursion = std::make_shared<RefRecursionChecker>());
// Create the CMap specified by <collection> and <cMapName>. Sets
// the initial reference count to 1. Returns NULL on failure.
static std::shared_ptr<CMap> parse(CMapCache *cache, const std::string &collectionA, const std::string &cMapNameA);
- // Parse a CMap from <str>. Sets the initial reference count to 1.
- // Returns NULL on failure.
- static std::shared_ptr<CMap> parse(CMapCache *cache, const std::string &collectionA, Stream *str);
-
~CMap();
CMap(const CMap &) = delete;
@@ -81,11 +78,15 @@ public:
void setReverseMap(unsigned int *rmap, unsigned int rmapSize, unsigned int ncand);
private:
+ // Parse a CMap from <str>. Sets the initial reference count to 1.
+ // Returns NULL on failure.
+ static std::shared_ptr<CMap> parse(CMapCache *cache, const std::string &collectionA, Stream *str, const std::shared_ptr<RefRecursionChecker> &recursion);
+
void parse2(CMapCache *cache, int (*getCharFunc)(void *), void *data);
CMap(std::unique_ptr<GooString> &&collectionA, std::unique_ptr<GooString> &&cMapNameA);
CMap(std::unique_ptr<GooString> &&collectionA, std::unique_ptr<GooString> &&cMapNameA, int wModeA);
void useCMap(CMapCache *cache, const char *useName);
- void useCMap(CMapCache *cache, Object *obj);
+ void useCMap(CMapCache *cache, Object *obj, const std::shared_ptr<RefRecursionChecker> &recursion);
void copyVector(CMapVectorEntry *dest, CMapVectorEntry *src);
void addCIDs(unsigned int start, unsigned int end, unsigned int nBytes, CID firstCID);
void freeCMapVector(CMapVectorEntry *vec);
--
GitLab