From 8e957baa851aed4b02511d04a66c0f95387d1e10 Mon Sep 17 00:00:00 2001 From: thestig Date: Thu, 28 Apr 2016 14:45:28 -0700 Subject: Fix stack overflow from nested arrays. BUG=pdfium:422 Review-Url: https://codereview.chromium.org/1930743003 --- core/fpdfapi/fpdf_page/fpdf_page_parser.cpp | 2 +- core/fpdfapi/fpdf_page/fpdf_page_parser_old.cpp | 101 +++++++++++++----------- core/fpdfapi/fpdf_page/pageint.h | 4 +- 3 files changed, 56 insertions(+), 51 deletions(-) diff --git a/core/fpdfapi/fpdf_page/fpdf_page_parser.cpp b/core/fpdfapi/fpdf_page/fpdf_page_parser.cpp index 93ea93dee7..7ed485c87c 100644 --- a/core/fpdfapi/fpdf_page/fpdf_page_parser.cpp +++ b/core/fpdfapi/fpdf_page/fpdf_page_parser.cpp @@ -604,7 +604,7 @@ void CPDF_StreamContentParser::Handle_BeginImage() { CFX_ByteString key((const FX_CHAR*)m_pSyntax->GetWordBuf() + 1, m_pSyntax->GetWordSize() - 1); std::unique_ptr> pObj( - m_pSyntax->ReadNextObject()); + m_pSyntax->ReadNextObject(false, 0)); if (!key.IsEmpty()) { uint32_t dwObjNum = pObj ? pObj->GetObjNum() : 0; if (dwObjNum) diff --git a/core/fpdfapi/fpdf_page/fpdf_page_parser_old.cpp b/core/fpdfapi/fpdf_page/fpdf_page_parser_old.cpp index 47c0336ea9..58ecb6c4d6 100644 --- a/core/fpdfapi/fpdf_page/fpdf_page_parser_old.cpp +++ b/core/fpdfapi/fpdf_page/fpdf_page_parser_old.cpp @@ -31,6 +31,14 @@ #include "core/fxcrt/include/fx_ext.h" #include "core/fxcrt/include/fx_safe_types.h" +namespace { + +const uint32_t kMaxNestedArrayLevel = 512; +const uint32_t kMaxWordBuffer = 256; +const FX_STRSIZE kMaxStringLength = 32767; + +} // namespace + CPDF_StreamParser::CPDF_StreamParser(const uint8_t* pData, uint32_t dwSize) { m_pBuf = pData; m_Size = dwSize; @@ -230,9 +238,6 @@ CPDF_Stream* CPDF_StreamParser::ReadInlineStream(CPDF_Document* pDoc, return new CPDF_Stream(pData, dwStreamSize, pDict); } -#define MAX_WORD_BUFFER 256 -#define MAX_STRING_LENGTH 32767 - CPDF_StreamParser::SyntaxType CPDF_StreamParser::ParseNextElement() { if (m_pLastObj) { m_pLastObj->Release(); @@ -268,12 +273,12 @@ CPDF_StreamParser::SyntaxType CPDF_StreamParser::ParseNextElement() { if (PDFCharIsDelimiter(ch) && ch != '/') { m_Pos--; - m_pLastObj = ReadNextObject(); + m_pLastObj = ReadNextObject(false, 0); return Others; } while (1) { - if (m_WordSize < MAX_WORD_BUFFER) + if (m_WordSize < kMaxWordBuffer) m_WordBuffer[m_WordSize++] = ch; if (!PDFCharIsNumeric(ch)) @@ -315,88 +320,90 @@ CPDF_StreamParser::SyntaxType CPDF_StreamParser::ParseNextElement() { return Keyword; } -CPDF_Object* CPDF_StreamParser::ReadNextObject(FX_BOOL bAllowNestedArray, - FX_BOOL bInArray) { +CPDF_Object* CPDF_StreamParser::ReadNextObject(bool bAllowNestedArray, + uint32_t dwInArrayLevel) { FX_BOOL bIsNumber; GetNextWord(bIsNumber); - if (m_WordSize == 0) { - return NULL; - } + if (!m_WordSize) + return nullptr; + if (bIsNumber) { m_WordBuffer[m_WordSize] = 0; return new CPDF_Number(CFX_ByteStringC(m_WordBuffer, m_WordSize)); } + int first_char = m_WordBuffer[0]; if (first_char == '/') { return new CPDF_Name( PDF_NameDecode(CFX_ByteStringC(m_WordBuffer + 1, m_WordSize - 1))); } - if (first_char == '(') { + + if (first_char == '(') return new CPDF_String(ReadString(), FALSE); - } + if (first_char == '<') { - if (m_WordSize == 1) { + if (m_WordSize == 1) return new CPDF_String(ReadHexString(), TRUE); - } + CPDF_Dictionary* pDict = new CPDF_Dictionary; while (1) { GetNextWord(bIsNumber); - if (m_WordSize == 0) { - pDict->Release(); - return nullptr; - } - if (m_WordSize == 2 && m_WordBuffer[0] == '>') { + if (m_WordSize == 2 && m_WordBuffer[0] == '>') break; - } - if (m_WordBuffer[0] != '/') { + + if (!m_WordSize || m_WordBuffer[0] != '/') { pDict->Release(); return nullptr; } + CFX_ByteString key = PDF_NameDecode(CFX_ByteStringC(m_WordBuffer + 1, m_WordSize - 1)); - CPDF_Object* pObj = ReadNextObject(TRUE); + CPDF_Object* pObj = ReadNextObject(true, 0); if (!pObj) { pDict->Release(); return nullptr; } - if (!key.IsEmpty()) { - pDict->SetAt(key, pObj); - } else { + + if (key.IsEmpty()) pObj->Release(); - } + else + pDict->SetAt(key, pObj); } return pDict; } + if (first_char == '[') { - if (!bAllowNestedArray && bInArray) { - return NULL; + if ((!bAllowNestedArray && dwInArrayLevel) || + dwInArrayLevel > kMaxNestedArrayLevel) { + return nullptr; } + CPDF_Array* pArray = new CPDF_Array; while (1) { - CPDF_Object* pObj = ReadNextObject(bAllowNestedArray, TRUE); + CPDF_Object* pObj = ReadNextObject(bAllowNestedArray, dwInArrayLevel + 1); if (pObj) { pArray->Add(pObj); continue; } - if (m_WordSize == 0 || m_WordBuffer[0] == ']') + if (!m_WordSize || m_WordBuffer[0] == ']') break; } return pArray; } + + if (m_WordSize == 5 && !memcmp(m_WordBuffer, "false", 5)) + return new CPDF_Boolean(FALSE); + if (m_WordSize == 4) { - if (memcmp(m_WordBuffer, "true", 4) == 0) { + if (memcmp(m_WordBuffer, "true", 4) == 0) return new CPDF_Boolean(TRUE); - } - if (memcmp(m_WordBuffer, "null", 4) == 0) { + + if (memcmp(m_WordBuffer, "null", 4) == 0) return new CPDF_Null; - } - } else if (m_WordSize == 5) { - if (memcmp(m_WordBuffer, "false", 5) == 0) { - return new CPDF_Boolean(FALSE); - } } - return NULL; + + return nullptr; } void CPDF_StreamParser::GetNextWord(FX_BOOL& bIsNumber) { @@ -439,7 +446,7 @@ void CPDF_StreamParser::GetNextWord(FX_BOOL& bIsNumber) { return; } - if (m_WordSize < MAX_WORD_BUFFER) + if (m_WordSize < kMaxWordBuffer) m_WordBuffer[m_WordSize++] = ch; } } else if (ch == '<') { @@ -463,7 +470,7 @@ void CPDF_StreamParser::GetNextWord(FX_BOOL& bIsNumber) { } while (1) { - if (m_WordSize < MAX_WORD_BUFFER) + if (m_WordSize < kMaxWordBuffer) m_WordBuffer[m_WordSize++] = ch; if (!PDFCharIsNumeric(ch)) bIsNumber = FALSE; @@ -492,8 +499,8 @@ CFX_ByteString CPDF_StreamParser::ReadString() { case 0: if (ch == ')') { if (parlevel == 0) { - if (buf.GetLength() > MAX_STRING_LENGTH) { - return CFX_ByteString(buf.GetBuffer(), MAX_STRING_LENGTH); + if (buf.GetLength() > kMaxStringLength) { + return CFX_ByteString(buf.GetBuffer(), kMaxStringLength); } return buf.AsStringC(); } @@ -571,8 +578,8 @@ CFX_ByteString CPDF_StreamParser::ReadString() { if (PositionIsInBounds()) ++m_Pos; - if (buf.GetLength() > MAX_STRING_LENGTH) { - return CFX_ByteString(buf.GetBuffer(), MAX_STRING_LENGTH); + if (buf.GetLength() > kMaxStringLength) { + return CFX_ByteString(buf.GetBuffer(), kMaxStringLength); } return buf.AsStringC(); } @@ -605,8 +612,8 @@ CFX_ByteString CPDF_StreamParser::ReadHexString() { if (!bFirst) buf.AppendChar((char)code); - if (buf.GetLength() > MAX_STRING_LENGTH) - return CFX_ByteString(buf.GetBuffer(), MAX_STRING_LENGTH); + if (buf.GetLength() > kMaxStringLength) + return CFX_ByteString(buf.GetBuffer(), kMaxStringLength); return buf.AsStringC(); } diff --git a/core/fpdfapi/fpdf_page/pageint.h b/core/fpdfapi/fpdf_page/pageint.h index 2dcf2e246f..01a28e3b96 100644 --- a/core/fpdfapi/fpdf_page/pageint.h +++ b/core/fpdfapi/fpdf_page/pageint.h @@ -53,8 +53,7 @@ class CPDF_StreamParser { } uint32_t GetPos() const { return m_Pos; } void SetPos(uint32_t pos) { m_Pos = pos; } - CPDF_Object* ReadNextObject(FX_BOOL bAllowNestedArray = FALSE, - FX_BOOL bInArray = FALSE); + CPDF_Object* ReadNextObject(bool bAllowNestedArray, uint32_t dwInArrayLevel); protected: friend class fpdf_page_parser_old_ReadHexString_Test; @@ -99,7 +98,6 @@ struct ContentParam { }; #define _FPDF_MAX_FORM_LEVEL_ 30 #define _FPDF_MAX_TYPE3_FORM_LEVEL_ 4 -#define _FPDF_MAX_OBJECT_STACK_SIZE_ 512 class CPDF_StreamContentParser { public: CPDF_StreamContentParser(CPDF_Document* pDoc, -- cgit v1.2.3