summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlbert Astals Cid <aacid@kde.org>2024-04-22 10:17:03 +0200
committerAlbert Astals Cid <aacid@kde.org>2024-04-22 12:23:16 +0000
commit06e0b89c2f64580eaac5e09a729b52668b09c106 (patch)
tree5efc568e0f6b4d8f74d7e6422e4c48d365e2f0af
parentfd98a72b6a72bb6e395ef70ae2527477496db6f5 (diff)
Fix crash in broken files
oss-fuzz/57874
-rw-r--r--poppler/Object.h18
-rw-r--r--poppler/XRef.cc12
-rw-r--r--poppler/XRef.h4
3 files changed, 31 insertions, 3 deletions
diff --git a/poppler/Object.h b/poppler/Object.h
index 02209d8e..e70a9749 100644
--- a/poppler/Object.h
+++ b/poppler/Object.h
@@ -15,7 +15,7 @@
//
// Copyright (C) 2007 Julien Rebetez <julienr@svn.gnome.org>
// Copyright (C) 2008 Kees Cook <kees@outflux.net>
-// Copyright (C) 2008, 2010, 2017-2021, 2023 Albert Astals Cid <aacid@kde.org>
+// Copyright (C) 2008, 2010, 2017-2021, 2023, 2024 Albert Astals Cid <aacid@kde.org>
// Copyright (C) 2009 Jakub Wilk <jwilk@jwilk.net>
// Copyright (C) 2012 Fabio D'Urso <fabiodurso@hotmail.it>
// Copyright (C) 2013 Thomas Freitag <Thomas.Freitag@alfa.de>
@@ -132,10 +132,26 @@ struct RefRecursionChecker
return alreadySeenRefs.insert(ref.num).second;
}
+ void remove(Ref ref) { alreadySeenRefs.erase(ref.num); }
+
private:
std::set<int> alreadySeenRefs;
};
+struct RefRecursionCheckerRemover
+{
+ // Removes ref from c when this object is removed
+ RefRecursionCheckerRemover(RefRecursionChecker &c, Ref r) : checker(c), ref(r) { }
+ ~RefRecursionCheckerRemover() { checker.remove(ref); }
+
+ RefRecursionCheckerRemover(const RefRecursionCheckerRemover &) = delete;
+ RefRecursionCheckerRemover &operator=(const RefRecursionCheckerRemover &) = delete;
+
+private:
+ RefRecursionChecker &checker;
+ Ref ref;
+};
+
namespace std {
template<>
diff --git a/poppler/XRef.cc b/poppler/XRef.cc
index 903b3283..e97a00cc 100644
--- a/poppler/XRef.cc
+++ b/poppler/XRef.cc
@@ -15,7 +15,7 @@
//
// Copyright (C) 2005 Dan Sheridan <dan.sheridan@postman.org.uk>
// Copyright (C) 2005 Brad Hards <bradh@frogmouth.net>
-// Copyright (C) 2006, 2008, 2010, 2012-2014, 2016-2023 Albert Astals Cid <aacid@kde.org>
+// Copyright (C) 2006, 2008, 2010, 2012-2014, 2016-2024 Albert Astals Cid <aacid@kde.org>
// Copyright (C) 2007-2008 Julien Rebetez <julienr@svn.gnome.org>
// Copyright (C) 2007 Carlos Garcia Campos <carlosgc@gnome.org>
// Copyright (C) 2009, 2010 Ilya Gorenbein <igorenbein@finjan.com>
@@ -1187,6 +1187,16 @@ Object XRef::fetch(int num, int gen, int recursion, Goffset *endPos)
Object obj1, obj2, obj3;
xrefLocker();
+
+ const Ref ref = { num, gen };
+
+ if (!refsBeingFetched.insert(ref)) {
+ return Object(objNull);
+ }
+
+ // Will remove ref from refsBeingFetched once it's destroyed, i.e. the function returns
+ RefRecursionCheckerRemover remover(refsBeingFetched, ref);
+
// check for bogus ref - this can happen in corrupted PDF files
if (num < 0 || num >= size) {
goto err;
diff --git a/poppler/XRef.h b/poppler/XRef.h
index 8c401f55..739b87bb 100644
--- a/poppler/XRef.h
+++ b/poppler/XRef.h
@@ -14,7 +14,7 @@
// under GPL version 2 or later
//
// Copyright (C) 2005 Brad Hards <bradh@frogmouth.net>
-// Copyright (C) 2006, 2008, 2010-2013, 2017-2022 Albert Astals Cid <aacid@kde.org>
+// Copyright (C) 2006, 2008, 2010-2013, 2017-2022, 2024 Albert Astals Cid <aacid@kde.org>
// Copyright (C) 2007-2008 Julien Rebetez <julienr@svn.gnome.org>
// Copyright (C) 2007 Carlos Garcia Campos <carlosgc@gnome.org>
// Copyright (C) 2010 Ilya Gorenbein <igorenbein@finjan.com>
@@ -269,6 +269,8 @@ private:
mutable std::recursive_mutex mutex;
std::function<void()> xrefReconstructedCb;
+ RefRecursionChecker refsBeingFetched;
+
int reserve(int newSize);
int resize(int newSize);
bool readXRef(Goffset *pos, std::vector<Goffset> *followedXRefStm, std::vector<int> *xrefStreamObjsNum);