diff --git a/ChangeLog b/ChangeLog index 4a59b6a7..b217b8f3 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2020-10-22 Jay Berkenbilt + + * Fix loop detection problem when traversing page thumbnails + during optimization (fuzz issue 23172). + 2020-10-21 Jay Berkenbilt * Bug fix: properly handle copying foreign streams that have diff --git a/TODO b/TODO index 3f4e0976..a2854a2e 100644 --- a/TODO +++ b/TODO @@ -65,7 +65,6 @@ Fuzz Errors * https://bugs.chromium.org/p/oss-fuzz/issues/detail?id= * New: - * 23172: stack overflow (https://oss-fuzz.com/testcase-detail/5719543787028480) * 23599: integer overflow: https://oss-fuzz.com/testcase?key=6290807920525312 * 23642: leak: https://oss-fuzz.com/testcase-detail/4906569690251264 diff --git a/fuzz/qpdf_extra/23172.fuzz b/fuzz/qpdf_extra/23172.fuzz new file mode 100644 index 00000000..802711cb Binary files /dev/null and b/fuzz/qpdf_extra/23172.fuzz differ diff --git a/include/qpdf/QPDF.hh b/include/qpdf/QPDF.hh index 720c1bc8..2482b232 100644 --- a/include/qpdf/QPDF.hh +++ b/include/qpdf/QPDF.hh @@ -1341,7 +1341,8 @@ class QPDF std::set& visited); void updateObjectMaps(ObjUser const& ou, QPDFObjectHandle oh); void updateObjectMapsInternal(ObjUser const& ou, QPDFObjectHandle oh, - std::set& visited, bool top); + std::set& visited, bool top, + int depth); void filterCompressedObjects(std::map const& object_stream_data); // Type conversion helper methods diff --git a/libqpdf/QPDF_optimization.cc b/libqpdf/QPDF_optimization.cc index afa7ccbd..05cac415 100644 --- a/libqpdf/QPDF_optimization.cc +++ b/libqpdf/QPDF_optimization.cc @@ -354,12 +354,13 @@ void QPDF::updateObjectMaps(ObjUser const& ou, QPDFObjectHandle oh) { std::set visited; - updateObjectMapsInternal(ou, oh, visited, true); + updateObjectMapsInternal(ou, oh, visited, true, 0); } void QPDF::updateObjectMapsInternal(ObjUser const& ou, QPDFObjectHandle oh, - std::set& visited, bool top) + std::set& visited, bool top, + int depth) { // Traverse the object tree from this point taking care to avoid // crossing page boundaries. @@ -397,7 +398,8 @@ QPDF::updateObjectMapsInternal(ObjUser const& ou, QPDFObjectHandle oh, int n = oh.getArrayNItems(); for (int i = 0; i < n; ++i) { - updateObjectMapsInternal(ou, oh.getArrayItem(i), visited, false); + updateObjectMapsInternal( + ou, oh.getArrayItem(i), visited, false, 1 + depth); } } else if (oh.isDictionary() || oh.isStream()) @@ -417,8 +419,9 @@ QPDF::updateObjectMapsInternal(ObjUser const& ou, QPDFObjectHandle oh, { // Traverse page thumbnail dictionaries as a special // case. - updateObjectMaps(ObjUser(ObjUser::ou_thumb, ou.pageno), - dict.getKey(key)); + updateObjectMapsInternal( + ObjUser(ObjUser::ou_thumb, ou.pageno), + dict.getKey(key), visited, false, 1 + depth); } else if (is_page_node && (key == "/Parent")) { @@ -426,8 +429,8 @@ QPDF::updateObjectMapsInternal(ObjUser const& ou, QPDFObjectHandle oh, } else { - updateObjectMapsInternal(ou, dict.getKey(key), - visited, false); + updateObjectMapsInternal( + ou, dict.getKey(key), visited, false, 1 + depth); } } }