From be8408f43bcfd69a74007a340a4c034004146c60 Mon Sep 17 00:00:00 2001 From: Oliver Chang Date: Mon, 14 Dec 2015 09:13:24 -0800 Subject: Fix hint table loading issues. BUG=566179 R=jun_fang@foxitsoftware.com, thestig@chromium.org Review URL: https://codereview.chromium.org/1523523002 . --- core/include/fxcrt/fx_basic.h | 6 ++ .../src/fpdfapi/fpdf_parser/fpdf_parser_parser.cpp | 65 +++++++++++++++++++--- core/src/fpdfapi/fpdf_parser/parser_int.h | 2 +- 3 files changed, 64 insertions(+), 9 deletions(-) diff --git a/core/include/fxcrt/fx_basic.h b/core/include/fxcrt/fx_basic.h index c5bb570fca..5d3fc33d6f 100644 --- a/core/include/fxcrt/fx_basic.h +++ b/core/include/fxcrt/fx_basic.h @@ -811,6 +811,12 @@ class CFX_BitStream { void Rewind() { m_BitPos = 0; } + FX_DWORD GetPos() { return m_BitPos; } + + FX_DWORD BitsRemaining() { + return m_BitSize >= m_BitPos ? m_BitSize - m_BitPos : 0; + } + protected: FX_DWORD m_BitPos; diff --git a/core/src/fpdfapi/fpdf_parser/fpdf_parser_parser.cpp b/core/src/fpdfapi/fpdf_parser/fpdf_parser_parser.cpp index 61d9749c8e..db9e177976 100644 --- a/core/src/fpdfapi/fpdf_parser/fpdf_parser_parser.cpp +++ b/core/src/fpdfapi/fpdf_parser/fpdf_parser_parser.cpp @@ -4643,12 +4643,16 @@ FX_DWORD CPDF_HintTables::GetItemLength(int index, return szArray[index + 1] - szArray[index]; } FX_BOOL CPDF_HintTables::ReadPageHintTable(CFX_BitStream* hStream) { - if (!hStream) + if (!hStream || hStream->IsEOF()) return FALSE; int nStreamOffset = ReadPrimaryHintStreamOffset(); int nStreamLen = ReadPrimaryHintStreamLength(); if (nStreamOffset < 0 || nStreamLen < 1) return FALSE; + + const FX_DWORD kHeaderSize = 288; + if (hStream->BitsRemaining() < kHeaderSize) + return FALSE; // Item 1: The least number of objects in a page. FX_DWORD dwObjLeastNum = hStream->GetBits(32); // Item 2: The location of the first page's page object. @@ -4691,6 +4695,11 @@ FX_BOOL CPDF_HintTables::ReadPageHintTable(CFX_BitStream* hStream) { int nPages = pPageNum ? pPageNum->GetInteger() : 0; if (nPages < 1) return FALSE; + FX_SAFE_DWORD required_bits = dwDeltaObjectsBits; + required_bits *= pdfium::base::checked_cast(nPages); + if (!required_bits.IsValid() || + hStream->BitsRemaining() < required_bits.ValueOrDie()) + return FALSE; for (int i = 0; i < nPages; ++i) { FX_SAFE_DWORD safeDeltaObj = hStream->GetBits(dwDeltaObjectsBits); safeDeltaObj += dwObjLeastNum; @@ -4699,6 +4708,11 @@ FX_BOOL CPDF_HintTables::ReadPageHintTable(CFX_BitStream* hStream) { m_dwDeltaNObjsArray.Add(safeDeltaObj.ValueOrDie()); } hStream->ByteAlign(); + required_bits = dwDeltaPageLenBits; + required_bits *= pdfium::base::checked_cast(nPages); + if (!required_bits.IsValid() || + hStream->BitsRemaining() < required_bits.ValueOrDie()) + return FALSE; CFX_DWordArray dwPageLenArray; for (int i = 0; i < nPages; ++i) { FX_SAFE_DWORD safePageLen = hStream->GetBits(dwDeltaPageLenBits); @@ -4739,12 +4753,22 @@ FX_BOOL CPDF_HintTables::ReadPageHintTable(CFX_BitStream* hStream) { } hStream->ByteAlign(); // number of shared objects + required_bits = dwSharedObjBits; + required_bits *= pdfium::base::checked_cast(nPages); + if (!required_bits.IsValid() || + hStream->BitsRemaining() < required_bits.ValueOrDie()) + return FALSE; for (int i = 0; i < nPages; i++) { m_dwNSharedObjsArray.Add(hStream->GetBits(dwSharedObjBits)); } hStream->ByteAlign(); // array of identifier, sizes = nshared_objects for (int i = 0; i < nPages; i++) { + required_bits = dwSharedIdBits; + required_bits *= m_dwNSharedObjsArray[i]; + if (!required_bits.IsValid() || + hStream->BitsRemaining() < required_bits.ValueOrDie()) + return FALSE; for (int j = 0; j < m_dwNSharedObjsArray[i]; j++) { m_dwIdentifierArray.Add(hStream->GetBits(dwSharedIdBits)); } @@ -4753,26 +4777,38 @@ FX_BOOL CPDF_HintTables::ReadPageHintTable(CFX_BitStream* hStream) { for (int i = 0; i < nPages; i++) { FX_SAFE_DWORD safeSize = m_dwNSharedObjsArray[i]; safeSize *= dwSharedNumeratorBits; - if (!safeSize.IsValid()) + if (!safeSize.IsValid() || hStream->BitsRemaining() < safeSize.ValueOrDie()) return FALSE; hStream->SkipBits(safeSize.ValueOrDie()); } hStream->ByteAlign(); FX_SAFE_DWORD safeTotalPageLen = pdfium::base::checked_cast(nPages); safeTotalPageLen *= dwDeltaPageLenBits; - if (!safeTotalPageLen.IsValid()) + if (!safeTotalPageLen.IsValid() || + hStream->BitsRemaining() < safeTotalPageLen.ValueOrDie()) return FALSE; hStream->SkipBits(safeTotalPageLen.ValueOrDie()); hStream->ByteAlign(); return TRUE; } -FX_BOOL CPDF_HintTables::ReadSharedObjHintTable(CFX_BitStream* hStream) { - if (!hStream) +FX_BOOL CPDF_HintTables::ReadSharedObjHintTable(CFX_BitStream* hStream, + FX_DWORD offset) { + if (!hStream || hStream->IsEOF()) return FALSE; int nStreamOffset = ReadPrimaryHintStreamOffset(); int nStreamLen = ReadPrimaryHintStreamLength(); if (nStreamOffset < 0 || nStreamLen < 1) return FALSE; + + FX_SAFE_DWORD bit_offset = offset; + bit_offset *= 8; + if (!bit_offset.IsValid() || hStream->GetPos() > bit_offset.ValueOrDie()) + return FALSE; + hStream->SkipBits(bit_offset.ValueOrDie() - hStream->GetPos()); + + const FX_DWORD kHeaderSize = 192; + if (hStream->BitsRemaining() < kHeaderSize) + return FALSE; // Item 1: The object number of the first object in the shared objects // section. FX_DWORD dwFirstSharedObjNum = hStream->GetBits(32); @@ -4800,6 +4836,12 @@ FX_BOOL CPDF_HintTables::ReadSharedObjHintTable(CFX_BitStream* hStream) { return FALSE; FX_DWORD dwPrevObjLen = 0; FX_DWORD dwCurObjLen = 0; + FX_SAFE_DWORD required_bits = dwSharedObjTotal; + required_bits *= dwDeltaGroupLen; + if (!required_bits.IsValid() || + hStream->BitsRemaining() < required_bits.ValueOrDie()) + return FALSE; + for (int i = 0; i < dwSharedObjTotal; ++i) { dwPrevObjLen = dwCurObjLen; FX_SAFE_DWORD safeObjLen = hStream->GetBits(dwDeltaGroupLen); @@ -4837,6 +4879,8 @@ FX_BOOL CPDF_HintTables::ReadSharedObjHintTable(CFX_BitStream* hStream) { m_szSharedObjOffsetArray.Add(safeLoc.ValueOrDie()); } hStream->ByteAlign(); + if (hStream->BitsRemaining() < dwSharedObjTotal) + return FALSE; hStream->SkipBits(dwSharedObjTotal); hStream->ByteAlign(); return TRUE; @@ -4898,6 +4942,8 @@ int32_t CPDF_HintTables::CheckPage(int index, IFX_DownloadHints* pHints) { FX_DWORD dwObjNum = 0; for (int j = 0; j < m_dwNSharedObjsArray[index]; ++j) { dwIndex = m_dwIdentifierArray[offset + j]; + if (dwIndex >= m_dwSharedObjNumArray.GetSize()) + return IPDF_DataAvail::DataNotAvailable; dwObjNum = m_dwSharedObjNumArray[dwIndex]; if (dwObjNum >= nFirstPageObjNum && dwObjNum < nFirstPageObjNum + m_nFirstPageSharedObjs) { @@ -4919,6 +4965,7 @@ FX_BOOL CPDF_HintTables::LoadHintStream(CPDF_Stream* pHintStream) { CPDF_Object* pOffset = pDict ? pDict->GetElement(FX_BSTRC("S")) : nullptr; if (!pOffset || pOffset->GetType() != PDFOBJ_NUMBER) return FALSE; + int shared_hint_table_offset = pOffset->GetInteger(); CPDF_StreamAcc acc; acc.LoadAllData(pHintStream); FX_DWORD size = acc.GetSize(); @@ -4926,13 +4973,15 @@ FX_BOOL CPDF_HintTables::LoadHintStream(CPDF_Stream* pHintStream) { // The header section of shared object hint table is 24 bytes. // Hint table has at least 60 bytes. const FX_DWORD MIN_STREAM_LEN = 60; - if (size < MIN_STREAM_LEN || size < pOffset->GetInteger() || - !pOffset->GetInteger()) { + if (size < MIN_STREAM_LEN || shared_hint_table_offset < 0 || + size < shared_hint_table_offset || !shared_hint_table_offset) { return FALSE; } CFX_BitStream bs; bs.Init(acc.GetData(), size); - return ReadPageHintTable(&bs) && ReadSharedObjHintTable(&bs); + return ReadPageHintTable(&bs) && + ReadSharedObjHintTable(&bs, pdfium::base::checked_cast( + shared_hint_table_offset)); } int CPDF_HintTables::ReadPrimaryHintStreamOffset() const { if (!m_pLinearizedDict) diff --git a/core/src/fpdfapi/fpdf_parser/parser_int.h b/core/src/fpdfapi/fpdf_parser/parser_int.h index fba6663238..c7f240384f 100644 --- a/core/src/fpdfapi/fpdf_parser/parser_int.h +++ b/core/src/fpdfapi/fpdf_parser/parser_int.h @@ -34,7 +34,7 @@ class CPDF_HintTables { protected: FX_BOOL ReadPageHintTable(CFX_BitStream* hStream); - FX_BOOL ReadSharedObjHintTable(CFX_BitStream* hStream); + FX_BOOL ReadSharedObjHintTable(CFX_BitStream* hStream, FX_DWORD offset); FX_DWORD GetItemLength(int index, const CFX_FileSizeArray& szArray); private: -- cgit v1.2.3