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:
 };
 

------------------------------------------------------------------------
openSUSE Build Service is sponsored by