From 225cd9dac27d685833156dfc249838cda11cd2ef Mon Sep 17 00:00:00 2001 From: Jay Berkenbilt Date: Wed, 21 Aug 2019 12:50:36 -0400 Subject: Protect against coding error of re-entrant parsing --- include/qpdf/QPDF.hh | 27 +++++++++++++++++++++++++++ libqpdf/QPDF.cc | 15 +++++++++++++++ libqpdf/QPDFObjectHandle.cc | 6 +++++- 3 files changed, 47 insertions(+), 1 deletion(-) diff --git a/include/qpdf/QPDF.hh b/include/qpdf/QPDF.hh index f052cb33..5fae5a57 100644 --- a/include/qpdf/QPDF.hh +++ b/include/qpdf/QPDF.hh @@ -657,6 +657,31 @@ class QPDF }; friend class Warner; + // ParseGuard class allows QPDFObjectHandle to detect re-entrant + // resolution + class ParseGuard + { + friend class QPDFObjectHandle; + private: + ParseGuard(QPDF* qpdf) : + qpdf(qpdf) + { + if (qpdf) + { + qpdf->inParse(true); + } + } + ~ParseGuard() + { + if (qpdf) + { + qpdf->inParse(false); + } + } + QPDF* qpdf; + }; + friend class ParseGuard; + // Pipe class is restricted to QPDF_Stream class Pipe { @@ -816,6 +841,7 @@ class QPDF friend class ResolveRecorder; void parse(char const* password); + void inParse(bool); void warn(QPDFExc const& e); void setTrailer(QPDFObjectHandle obj); void read_xref(qpdf_offset_t offset); @@ -1352,6 +1378,7 @@ class QPDF bool reconstructed_xref; bool fixed_dangling_refs; bool immediate_copy_from; + bool in_parse; // Linearization data qpdf_offset_t first_xref_item_offset; // actual value from file diff --git a/libqpdf/QPDF.cc b/libqpdf/QPDF.cc index 068630d1..1d54ef44 100644 --- a/libqpdf/QPDF.cc +++ b/libqpdf/QPDF.cc @@ -150,6 +150,7 @@ QPDF::Members::Members() : reconstructed_xref(false), fixed_dangling_refs(false), immediate_copy_from(false), + in_parse(false), first_xref_item_offset(0), uncompressed_after_compressed(false) { @@ -416,6 +417,20 @@ QPDF::parse(char const* password) findAttachmentStreams(); } +void +QPDF::inParse(bool v) +{ + if (this->m->in_parse == v) + { + // This happens of QPDFObjectHandle::parseInternal tries to + // resolve an indirect object while it is parsing. + throw std::logic_error( + "QPDF: re-entrant parsing detected. This is a qpdf bug." + " Please report at https://github.com/qpdf/qpdf/issues."); + } + this->m->in_parse = v; +} + void QPDF::warn(QPDFExc const& e) { diff --git a/libqpdf/QPDFObjectHandle.cc b/libqpdf/QPDFObjectHandle.cc index 1b3b64b0..6240395d 100644 --- a/libqpdf/QPDFObjectHandle.cc +++ b/libqpdf/QPDFObjectHandle.cc @@ -1714,7 +1714,11 @@ QPDFObjectHandle::parseInternal(PointerHolder input, // This method must take care not to resolve any objects. Don't // check the type of any object without first ensuring that it is // a direct object. Otherwise, doing so may have the side effect - // of reading the object and changing the file pointer. + // of reading the object and changing the file pointer. If you do + // this, it will cause a logic error to be thrown from + // QPDF::inParse(). + + QPDF::ParseGuard pg(context); empty = false; -- cgit v1.2.3-54-g00ecf