diff --git a/.vscode/settings.json b/.vscode/settings.json index e69b38ef..8bd5a6bf 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -68,6 +68,7 @@ "unordered_map": "cpp", "variant": "cpp", "algorithm": "cpp", - "tiffio.h": "c" + "tiffio.h": "c", + "utility": "cpp" } } \ No newline at end of file diff --git a/PDFWriter/PDFObjectParser.cpp b/PDFWriter/PDFObjectParser.cpp index 76812418..d6405f86 100644 --- a/PDFWriter/PDFObjectParser.cpp +++ b/PDFWriter/PDFObjectParser.cpp @@ -45,6 +45,8 @@ using namespace PDFHummus; +#define MAX_OBJECT_DEPTH 100 // While PDF does not explicitly define arrays and dicts depth...we do, due to call stack depth limit...and to avoid potential malarky. + PDFObjectParser::PDFObjectParser(void) { @@ -52,6 +54,7 @@ PDFObjectParser::PDFObjectParser(void) mDecryptionHelper = NULL; mOwnsStream = false; mStream = NULL; + mDepth = 0; } PDFObjectParser::~PDFObjectParser(void) @@ -79,6 +82,7 @@ void PDFObjectParser::ResetReadState() { mTokenBuffer.clear(); mTokenizer.ResetReadState(); + mDepth = 0; } void PDFObjectParser::ResetReadState(const PDFParserTokenizer& inExternalTokenizer) @@ -584,14 +588,40 @@ bool PDFObjectParser::IsArray(const std::string& inToken) return scLeftSquare == inToken; } +EStatusCode PDFObjectParser::IncreaseAndCheckDepth() { + ++mDepth; + if(mDepth > MAX_OBJECT_DEPTH) { + TRACE_LOG1("PDFObjectParser::IncreaseAndCeckDepth, reached maximum allowed depth of %d", MAX_OBJECT_DEPTH); + return eFailure; + } + + return eSuccess; +} + +EStatusCode PDFObjectParser::DecreaseAndCheckDepth() { + --mDepth; + if(mDepth < 0) { + TRACE_LOG("PDFObjectParser::DecreaseAndCheckDepth, anomaly. managed to get to negative depth"); + return eFailure; + } + + return eSuccess; +} + + static const std::string scRightSquare = "]"; PDFObject* PDFObjectParser::ParseArray() { - PDFArray* anArray = new PDFArray(); + PDFArray* anArray; bool arrayEndEncountered = false; std::string token; EStatusCode status = PDFHummus::eSuccess; + if(IncreaseAndCheckDepth() != eSuccess) + return NULL; + + anArray = new PDFArray(); + // easy one. just loop till you get to a closing bracket token and recurse while(GetNextToken(token) && PDFHummus::eSuccess == status) { @@ -612,6 +642,9 @@ PDFObject* PDFObjectParser::ParseArray() } } + if(DecreaseAndCheckDepth() != eSuccess) + status = eFailure; + if(arrayEndEncountered && PDFHummus::eSuccess == status) { return anArray; @@ -643,11 +676,16 @@ bool PDFObjectParser::IsDictionary(const std::string& inToken) static const std::string scDoubleRightAngle = ">>"; PDFObject* PDFObjectParser::ParseDictionary() { - PDFDictionary* aDictionary = new PDFDictionary(); + PDFDictionary* aDictionary; bool dictionaryEndEncountered = false; std::string token; EStatusCode status = PDFHummus::eSuccess; + if(IncreaseAndCheckDepth() != eSuccess) + return NULL; + + aDictionary = new PDFDictionary(); + while(GetNextToken(token) && PDFHummus::eSuccess == status) { dictionaryEndEncountered = (scDoubleRightAngle == token); @@ -681,6 +719,9 @@ PDFObject* PDFObjectParser::ParseDictionary() aDictionary->Insert(aKey.GetPtr(),aValue.GetPtr()); } + if(DecreaseAndCheckDepth() != eSuccess) + status = eFailure; + if(dictionaryEndEncountered && PDFHummus::eSuccess == status) { return aDictionary; diff --git a/PDFWriter/PDFObjectParser.h b/PDFWriter/PDFObjectParser.h index ff07e495..6d2c1ddf 100644 --- a/PDFWriter/PDFObjectParser.h +++ b/PDFWriter/PDFObjectParser.h @@ -78,6 +78,7 @@ class PDFObjectParser IPDFParserExtender* mParserExtender; DecryptionHelper* mDecryptionHelper; bool mOwnsStream; + int mDepth; bool GetNextToken(std::string& outToken); void SaveTokenToBuffer(std::string& inToken); @@ -112,5 +113,7 @@ class PDFObjectParser std::string MaybeDecryptString(const std::string& inString); + PDFHummus::EStatusCode IncreaseAndCheckDepth(); + PDFHummus::EStatusCode DecreaseAndCheckDepth(); }; diff --git a/PDFWriterTesting/Materials/fuzzing/errors/parseLastXrefPositionError_278.pdf b/PDFWriterTesting/Materials/fuzzing/errors/parseLastXrefPositionError_278.pdf new file mode 100644 index 00000000..5478f48a Binary files /dev/null and b/PDFWriterTesting/Materials/fuzzing/errors/parseLastXrefPositionError_278.pdf differ diff --git a/PDFWriterTesting/Materials/fuzzing/errors/parseLastXrefPositionError_279.pdf b/PDFWriterTesting/Materials/fuzzing/errors/parseLastXrefPositionError_279.pdf new file mode 100644 index 00000000..4089cec6 Binary files /dev/null and b/PDFWriterTesting/Materials/fuzzing/errors/parseLastXrefPositionError_279.pdf differ