Chromium Code Reviews| Index: core/src/fpdfapi/fpdf_parser/fpdf_parser_parser.cpp |
| diff --git a/core/src/fpdfapi/fpdf_parser/fpdf_parser_parser.cpp b/core/src/fpdfapi/fpdf_parser/fpdf_parser_parser.cpp |
| index bc5d3edc2bbc6bcacd66680a15110eaf64899e14..7339caf88ad727b99bc17e413ff7709820bd1f85 100644 |
| --- a/core/src/fpdfapi/fpdf_parser/fpdf_parser_parser.cpp |
| +++ b/core/src/fpdfapi/fpdf_parser/fpdf_parser_parser.cpp |
| @@ -4644,12 +4644,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. |
| @@ -4692,6 +4696,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<FX_DWORD>(nPages); |
| + if (!required_bits.IsValid() || |
| + hStream->BitsRemaining() < required_bits.ValueOrDie()) |
|
Lei Zhang
2015/12/12 01:38:12
braces, ditto below. Maybe make a helper function?
Oliver Chang
2015/12/12 02:37:14
Made a helper. A lot cleaner now.
|
| + return FALSE; |
| for (int i = 0; i < nPages; ++i) { |
| FX_SAFE_DWORD safeDeltaObj = hStream->GetBits(dwDeltaObjectsBits); |
| safeDeltaObj += dwObjLeastNum; |
| @@ -4700,6 +4709,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<FX_DWORD>(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); |
| @@ -4740,12 +4754,22 @@ FX_BOOL CPDF_HintTables::ReadPageHintTable(CFX_BitStream* hStream) { |
| } |
| hStream->ByteAlign(); |
| // number of shared objects |
| + required_bits = dwSharedObjBits; |
| + required_bits *= pdfium::base::checked_cast<FX_DWORD>(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)); |
| } |
| @@ -4754,26 +4778,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<FX_DWORD>(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); |
| @@ -4801,6 +4837,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); |
| @@ -4838,6 +4880,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; |
| @@ -4899,6 +4943,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) { |
| @@ -4920,6 +4966,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(); |
| @@ -4927,13 +4974,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<FX_DWORD>( |
| + shared_hint_table_offset)); |
| } |
| int CPDF_HintTables::ReadPrimaryHintStreamOffset() const { |
| if (!m_pLinearizedDict) |