File r1925-Fix-uncontrolled-memory-allocation-in-the-PdfParser-ReadXRefSubsection-CVE-2018-5296.patch of Package podofo.23799
------------------------------------------------------------------------
r1925 | domseichter | 2018-04-30 21:21:55 +0200 (lun, 30 abr 2018) | 1 line
FIXED: #6 based on the patch by Mark Rogers. Limit the maximum number of indirect objects by default to 2^23-1 as in the PDF reference Appendix C implementation limits
Index: src/base/PdfParser.cpp
===================================================================
--- src/base/PdfParser.cpp (revision 1924)
+++ src/base/PdfParser.cpp (revision 1925)
@@ -72,8 +72,10 @@
namespace PoDoFo {
-long PdfParser::s_nMaxObjects = std::numeric_limits<long>::max();
-
+const long nMaxNumIndirectObjects = (1L << 23) - 1L;
+long PdfParser::s_nMaxObjects = nMaxNumIndirectObjects;
+
+
# class PdfRecursionGuard
# {
# // RAII recursion guard ensures m_nRecursionDepth is always decremented
PdfParser::PdfParser( PdfVecObjects* pVecObjects )
: PdfTokenizer(), m_vecObjects( pVecObjects ), m_bStrictParsing( false )
@@ -352,13 +354,10 @@
m_nNumObjects = 0;
}
- // allow caller to specify a max object count to avoid very slow load times on large documents
- if (s_nMaxObjects != std::numeric_limits<long>::max()
- && m_nNumObjects > s_nMaxObjects)
- PODOFO_RAISE_ERROR_INFO( ePdfError_ValueOutOfRange, "m_nNumObjects is greater than m_nMaxObjects." );
-
if (m_nNumObjects > 0)
- m_offsets.resize(m_nNumObjects);
+ {
+ ResizeOffsets( m_nNumObjects );
+ }
if( m_pLinearization )
{
@@ -769,7 +768,7 @@
if( e == ePdfError_NoNumber || e == ePdfError_InvalidXRef || e == ePdfError_UnexpectedEOF )
break;
else
- {
+ {
e.AddToCallstack( __FILE__, __LINE__ );
throw e;
}
@@ -820,19 +819,22 @@
}
if ( static_cast<pdf_uint64>( nFirstObject ) + static_cast<pdf_uint64>( nNumObjects ) > static_cast<pdf_uint64>( std::numeric_limits<size_t>::max() ) )
+ {
PODOFO_RAISE_ERROR_INFO( ePdfError_ValueOutOfRange,
"xref subsection's given entry numbers together too large" );
-
+ }
+
if( nFirstObject + nNumObjects > m_nNumObjects )
{
try {
+
#ifdef _WIN32
- m_nNumObjects = static_cast<long>(nFirstObject + nNumObjects);
- m_offsets.resize(static_cast<long>(nFirstObject+nNumObjects));
+ m_nNumObjects = static_cast<long>(nFirstObject+nNumObjects);
#else
m_nNumObjects = nFirstObject + nNumObjects;
- m_offsets.resize(nFirstObject+nNumObjects);
#endif // _WIN32
+ ResizeOffsets(nFirstObject + nNumObjects);
+
} catch (std::exception &) {
// If m_nNumObjects*sizeof(TXRefEntry) > std::numeric_limits<size_t>::max() then
// resize() throws std::length_error, for smaller allocations that fail it may throw
@@ -1444,6 +1446,17 @@
}
+void PdfParser::ResizeOffsets( pdf_long nNewSize )
+{
+ // allow caller to specify a max object count to avoid very slow load times on large documents
+ if (nNewSize > s_nMaxObjects)
+ {
+ PODOFO_RAISE_ERROR_INFO( ePdfError_ValueOutOfRange, "nNewSize is greater than m_nMaxObjects." );
+ }
+
+ m_offsets.resize( nNewSize );
+}
+
void PdfParser::CheckEOFMarker()
{
// Check for the existence of the EOF marker
Index: src/base/PdfParser.h
===================================================================
--- src/base/PdfParser.h (revision 1924)
+++ src/base/PdfParser.h (revision 1925)
@@ -381,8 +381,7 @@
inline void SetIgnoreBrokenObjects( bool bBroken );
/**
- * \return maximum object count to read (default is LONG_MAX
- * which means no limit)
+ * \return maximum object count to read
*/
inline static long GetMaxObjectCount();
@@ -394,6 +393,10 @@
* working set and spend 15 mins in Load() before throwing
* an out of memory exception.
*
+ * By default, the maximum object count is set to 8388607
+ * which is the maximum number of indirect objects according
+ * to the PDF specification.
+ *
* \param nMaxObjects set max number of objects
*/
inline static void SetMaxObjectCount( long nMaxObjects );
@@ -564,6 +567,15 @@
*/
void UpdateDocumentVersion();
+
+ /** Resize the internal structure m_offsets in a safe manner.
+ * The limit for the maximum number of indirect objects in a PDF file is checked by this method.
+ * The maximum is 2^23-1 (8.388.607).
+ *
+ * \param nNewSize new size of the vector
+ */
+ void ResizeOffsets( pdf_long nNewSize );
+
private:
EPdfVersion m_ePdfVersion;
#@@ -594,7 +606,7 @@
# int m_nRecursionDepth;
#
# static long s_nMaxObjects;
#-
#+
# std::set<pdf_long> m_visitedXRefOffsets;
# };
#
Index: test/unit/BasicTypeTest.cpp
===================================================================
--- test/unit/BasicTypeTest.cpp (revision 1924)
+++ test/unit/BasicTypeTest.cpp (revision 1925)
@@ -40,3 +40,8 @@
{
CPPUNIT_ASSERT_MESSAGE("pdf_uint64 is big enough to hold an xref entry", std::numeric_limits<pdf_uint64>::max() >= PODOFO_ULL_LITERAL(9999999999) );
}
+
+void BasicTypeTest::testDefaultMaximumNumberOfObjects()
+{
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("PdfReference allows 8,388,607 indirect objects.", 8388607L, PdfParser::GetMaxObjectCount() );
+}
Index: test/unit/BasicTypeTest.h
===================================================================
--- test/unit/BasicTypeTest.h (revision 1924)
+++ test/unit/BasicTypeTest.h (revision 1925)
@@ -31,16 +31,18 @@
*/
class BasicTypeTest : public CppUnit::TestFixture
{
- CPPUNIT_TEST_SUITE( BasicTypeTest );
- CPPUNIT_TEST( testXrefOffsetTypeSize );
- CPPUNIT_TEST_SUITE_END();
-
+ CPPUNIT_TEST_SUITE( BasicTypeTest );
+ CPPUNIT_TEST( testXrefOffsetTypeSize );
+ CPPUNIT_TEST( testDefaultMaximumNumberOfObjects );
+ CPPUNIT_TEST_SUITE_END();
+
public:
- void setUp();
- void tearDown();
-
- void testXrefOffsetTypeSize();
-
+ void setUp();
+ void tearDown();
+
+ void testXrefOffsetTypeSize();
+ void testDefaultMaximumNumberOfObjects();
+
private:
};
------------------------------------------------------------------------