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) |