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..4f5d34ef2c777bbeec4cc1723eae14184ce7c262 100644 |
| --- a/core/src/fpdfapi/fpdf_parser/fpdf_parser_parser.cpp |
| +++ b/core/src/fpdfapi/fpdf_parser/fpdf_parser_parser.cpp |
| @@ -75,6 +75,12 @@ int32_t GetStreamFirst(CPDF_StreamAcc* pObjStream) { |
| return pObjStream->GetDict()->GetInteger(FX_BSTRC("First")); |
| } |
| +bool CanReadFromBitStream(const CFX_BitStream* hStream, |
|
jun_fang
2015/12/12 09:48:10
I don't think that we need to add an extra functio
|
| + const FX_SAFE_DWORD& num_bits) { |
| + return (num_bits.IsValid() && |
| + hStream->BitsRemaining() >= num_bits.ValueOrDie()); |
| +} |
| + |
| } // namespace |
| // TODO(thestig) Using unique_ptr with ReleaseDeleter is still not ideal. |
| @@ -4644,12 +4650,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 +4702,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 (!CanReadFromBitStream(hStream, required_bits)) |
|
jun_fang
2015/12/12 09:48:10
It means a failure if the return of CFX_BitStream:
Oliver Chang
2015/12/12 15:07:26
How do we distinguish between reading a value of 0
|
| + return FALSE; |
| for (int i = 0; i < nPages; ++i) { |
| FX_SAFE_DWORD safeDeltaObj = hStream->GetBits(dwDeltaObjectsBits); |
| safeDeltaObj += dwObjLeastNum; |
| @@ -4700,6 +4715,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 (!CanReadFromBitStream(hStream, required_bits)) |
| + return FALSE; |
| CFX_DWordArray dwPageLenArray; |
| for (int i = 0; i < nPages; ++i) { |
| FX_SAFE_DWORD safePageLen = hStream->GetBits(dwDeltaPageLenBits); |
| @@ -4739,41 +4759,64 @@ FX_BOOL CPDF_HintTables::ReadPageHintTable(CFX_BitStream* hStream) { |
| dwPageLenArray[nPages - 1]); |
| } |
| hStream->ByteAlign(); |
| + |
| // number of shared objects |
| + required_bits = dwSharedObjBits; |
| + required_bits *= pdfium::base::checked_cast<FX_DWORD>(nPages); |
| + if (!CanReadFromBitStream(hStream, required_bits)) |
| + 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 (!CanReadFromBitStream(hStream, required_bits)) |
| + return FALSE; |
| for (int j = 0; j < m_dwNSharedObjsArray[i]; j++) { |
| m_dwIdentifierArray.Add(hStream->GetBits(dwSharedIdBits)); |
| } |
| } |
| hStream->ByteAlign(); |
| + |
| for (int i = 0; i < nPages; i++) { |
| FX_SAFE_DWORD safeSize = m_dwNSharedObjsArray[i]; |
| safeSize *= dwSharedNumeratorBits; |
| - if (!safeSize.IsValid()) |
| + if (!CanReadFromBitStream(hStream, safeSize)) |
| 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 (!CanReadFromBitStream(hStream, safeTotalPageLen)) |
| return FALSE; |
| hStream->SkipBits(safeTotalPageLen.ValueOrDie()); |
|
jun_fang
2015/12/12 09:48:10
We should add a return value for SkipBits() like:
|
| 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 +4844,11 @@ 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 (!CanReadFromBitStream(hStream, required_bits)) |
|
jun_fang
2015/12/12 09:48:10
To check the return value of hStream->GetBits().
|
| + return FALSE; |
| + |
| for (int i = 0; i < dwSharedObjTotal; ++i) { |
| dwPrevObjLen = dwCurObjLen; |
| FX_SAFE_DWORD safeObjLen = hStream->GetBits(dwDeltaGroupLen); |
| @@ -4838,6 +4886,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); |
|
jun_fang
2015/12/12 09:48:10
To check the return value of SkipBits() after we a
|
| hStream->ByteAlign(); |
| return TRUE; |
| @@ -4899,6 +4949,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 +4972,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 +4980,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) { |
| 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) |