From 6557441870103cffbcc6191e7a1d1e702fd53438 Mon Sep 17 00:00:00 2001 From: Sandro Mani Date: Fri, 15 Jun 2018 21:55:01 +0200 Subject: [PATCH] Backport a ton of security fixes --- CVE-2017-5852.patch | 127 +++++++++++ CVE-2017-5853-and-CVE-2017-6844.patch | 77 +++++++ CVE-2017-5854.patch | 20 ++ CVE-2017-5855.patch | 27 +++ CVE-2017-5886-and-CVE-2018-8000.patch | 18 ++ ...-and-CVE-2017-6842-and-CVE-2017-6843.patch | 25 +++ CVE-2017-6845.patch | 27 +++ CVE-2017-6847-and-CVE-2017-6848.patch | 21 ++ CVE-2017-7378.patch | 38 ++++ CVE-2017-7379.patch | 28 +++ CVE-2017-738[0123].patch | 17 ++ CVE-2017-7994.patch | 103 +++++++++ CVE-2017-8054.patch | 206 ++++++++++++++++++ CVE-2017-8378.patch | 22 ++ CVE-2017-8787.patch | 20 ++ CVE-2018-5295.patch | 47 ++++ CVE-2018-5308.patch | 28 +++ podofo.spec | 30 ++- 18 files changed, 880 insertions(+), 1 deletion(-) create mode 100644 CVE-2017-5852.patch create mode 100644 CVE-2017-5853-and-CVE-2017-6844.patch create mode 100644 CVE-2017-5854.patch create mode 100644 CVE-2017-5855.patch create mode 100644 CVE-2017-5886-and-CVE-2018-8000.patch create mode 100644 CVE-2017-6840-and-CVE-2017-6842-and-CVE-2017-6843.patch create mode 100644 CVE-2017-6845.patch create mode 100644 CVE-2017-6847-and-CVE-2017-6848.patch create mode 100644 CVE-2017-7378.patch create mode 100644 CVE-2017-7379.patch create mode 100644 CVE-2017-738[0123].patch create mode 100644 CVE-2017-7994.patch create mode 100644 CVE-2017-8054.patch create mode 100644 CVE-2017-8378.patch create mode 100644 CVE-2017-8787.patch create mode 100644 CVE-2018-5295.patch create mode 100644 CVE-2018-5308.patch diff --git a/CVE-2017-5852.patch b/CVE-2017-5852.patch new file mode 100644 index 0000000..013edee --- /dev/null +++ b/CVE-2017-5852.patch @@ -0,0 +1,127 @@ +Description: CVE-2017-5852 + The part coming from the email is not (yet?) merged, it's there only to + prevent an ABI breakage and can be safely dropped at the next SONAME bump. +Acked-By: Mattia Rizzolo +Bug-Debian: https://bugs.debian.org/854600 +Origin: https://sourceforge.net/p/podofo/code/1838 +Origin: https://sourceforge.net/p/podofo/code/1835 +Origin: https://sourceforge.net/p/podofo/code/1841 +Origin: https://sourceforge.net/p/podofo/mailman/message/36084628/ +Last-Update: 2017-11-12 + +--- a/src/base/PdfError.cpp ++++ b/src/base/PdfError.cpp +@@ -222,6 +222,9 @@ + case ePdfError_InvalidEnumValue: + pszMsg = "ePdfError_InvalidEnumValue"; + break; ++ case ePdfError_BrokenFile: ++ pszMsg = "ePdfError_BrokenFile"; ++ break; + case ePdfError_PageNotFound: + pszMsg = "ePdfError_PageNotFound"; + break; +@@ -397,6 +400,9 @@ + case ePdfError_InvalidEnumValue: + pszMsg = "An invalid enum value was specified."; + break; ++ case ePdfError_BrokenFile: ++ pszMsg = "The file content is broken."; ++ break; + case ePdfError_PageNotFound: + pszMsg = "The requested page could not be found in the PDF."; + break; +--- a/src/base/PdfError.h ++++ b/src/base/PdfError.h +@@ -73,6 +73,7 @@ + ePdfError_ValueOutOfRange, /**< The specified memory is out of the allowed range. */ + ePdfError_InternalLogic, /**< An internal sanity check or assertion failed. */ + ePdfError_InvalidEnumValue, /**< An invalid enum value was specified. */ ++ ePdfError_BrokenFile, /**< The file content is broken. */ + + ePdfError_PageNotFound, /**< The requested page could not be found in the PDF. */ + +--- a/src/doc/PdfPage.cpp ++++ b/src/doc/PdfPage.cpp +@@ -214,6 +214,11 @@ + + const PdfObject* PdfPage::GetInheritedKeyFromObject( const char* inKey, const PdfObject* inObject ) const + { ++ return GetInheritedKeyFromObject( inKey, inObject, 0); ++} ++ ++const PdfObject* PdfPage::GetInheritedKeyFromObject( const char* inKey, const PdfObject* inObject, int depth ) const ++{ + const PdfObject* pObj = NULL; + + // check for it in the object itself +@@ -227,9 +232,29 @@ + // if we get here, we need to go check the parent - if there is one! + if( inObject->GetDictionary().HasKey( "Parent" ) ) + { ++ // CVE-2017-5852 - prevent stack overflow if Parent chain contains a loop, or is very long ++ // e.g. pObj->GetParent() == pObj or pObj->GetParent()->GetParent() == pObj ++ // default stack sizes ++ // Windows: 1 MB ++ // Linux: 2 MB ++ // macOS: 8 MB for main thread, 0.5 MB for secondary threads ++ // 0.5 MB is enough space for 1000 512 byte stack frames and 2000 256 byte stack frames ++ const int maxRecursionDepth = 1000; ++ ++ if ( depth > maxRecursionDepth ) ++ PODOFO_RAISE_ERROR( ePdfError_ValueOutOfRange ); ++ + pObj = inObject->GetIndirectKey( "Parent" ); ++ if( pObj == inObject ) ++ { ++ std::ostringstream oss; ++ oss << "Object " << inObject->Reference().ObjectNumber() << " " ++ << inObject->Reference().GenerationNumber() << " references itself as Parent"; ++ PODOFO_RAISE_ERROR_INFO( ePdfError_BrokenFile, oss.str().c_str() ); ++ } ++ + if( pObj ) +- pObj = GetInheritedKeyFromObject( inKey, pObj ); ++ pObj = GetInheritedKeyFromObject( inKey, pObj, depth + 1 ); + } + + return pObj; +@@ -523,6 +548,11 @@ + PdfObject* pParent = this->GetObject()->GetIndirectKey( "Parent" ); + PdfReference ref = this->GetObject()->Reference(); + ++ // CVE-2017-5852 - prevent infinite loop if Parent chain contains a loop ++ // e.g. pParent->GetIndirectKey( "Parent" ) == pParent or pParent->GetIndirectKey( "Parent" )->GetIndirectKey( "Parent" ) == pParent ++ const int maxRecursionDepth = 1000; ++ int depth = 0; ++ + while( pParent ) + { + PdfObject* pKids = pParent->GetIndirectKey( "Kids" ); +@@ -554,6 +584,12 @@ + + ref = pParent->Reference(); + pParent = pParent->GetIndirectKey( "Parent" ); ++ ++depth; ++ ++ if ( depth > maxRecursionDepth ) ++ { ++ PODOFO_RAISE_ERROR_INFO( ePdfError_BrokenFile, "Loop in Parent chain" ); ++ } + } + + return ++nPageNumber; +--- a/src/doc/PdfPage.h ++++ b/src/doc/PdfPage.h +@@ -291,7 +291,10 @@ + /** Method for getting a key value that could be inherited (such as the boxes, resources, etc.) + * \returns PdfObject - the result of the key fetching or NULL + */ +- const PdfObject* GetInheritedKeyFromObject( const char* inKey, const PdfObject* inObject ) const; ++ const PdfObject* GetInheritedKeyFromObject( const char* inKey, const PdfObject* inObject ) const; // wraps the next one ++ ++ // this is introduced by the fix for CVE-2017-5852, the depth param counts recursion depth, is checked against a max ++ const PdfObject* GetInheritedKeyFromObject( const char* inKey, const PdfObject* inObject, int depth ) const PODOFO_LOCAL; + + /** Get the annotations array. + * \param bCreate if true the annotations array is created diff --git a/CVE-2017-5853-and-CVE-2017-6844.patch b/CVE-2017-5853-and-CVE-2017-6844.patch new file mode 100644 index 0000000..e31dab3 --- /dev/null +++ b/CVE-2017-5853-and-CVE-2017-6844.patch @@ -0,0 +1,77 @@ +Description: CVE-2017-5853 and CVE-2017-6844 +Acked-By: Markus Koschany +Acked-By: Mattia Rizzolo +Last-Update: 2017-05-03 +Bug-Debian: https://bugs.debian.org/854601 +Bug-Debian: https://bugs.debian.org/861561 +Origin: https://sourceforge.net/p/podofo/code/1840 + +--- a/src/base/PdfParser.cpp ++++ b/src/base/PdfParser.cpp +@@ -748,21 +748,39 @@ + + void PdfParser::ReadXRefSubsection( pdf_int64 & nFirstObject, pdf_int64 & nNumObjects ) + { +- int count = 0; ++ pdf_int64 count = 0; + + #ifdef PODOFO_VERBOSE_DEBUG + PdfError::DebugMessage("Reading XRef Section: %" PDF_FORMAT_INT64 " with %" PDF_FORMAT_INT64 " Objects.\n", nFirstObject, nNumObjects ); + #endif // PODOFO_VERBOSE_DEBUG + +- if ( nFirstObject + nNumObjects > m_nNumObjects ) ++ if ( nFirstObject < 0 ) ++ PODOFO_RAISE_ERROR_INFO( ePdfError_ValueOutOfRange, "ReadXRefSubsection: nFirstObject is negative" ); ++ if ( nNumObjects < 0 ) ++ PODOFO_RAISE_ERROR_INFO( ePdfError_ValueOutOfRange, "ReadXRefSubsection: nNumObjects is negative" ); ++ ++ const pdf_int64 maxNum ++ = static_cast(PdfParser::s_nMaxObjects); ++ ++ // overflow guard, fixes CVE-2017-5853 (signed integer overflow) ++ // also fixes CVE-2017-6844 (buffer overflow) together with below size check ++ if( (maxNum >= nNumObjects) && (nFirstObject <= maxNum - nNumObjects) ) + { +- // Total number of xref entries to read is greater than the /Size +- // specified in the trailer if any. That's an error unless we're trying +- // to recover from a missing /Size entry. +- PdfError::LogMessage( eLogSeverity_Warning, +- "There are more objects (%" PDF_FORMAT_INT64 ") in this XRef table than " +- "specified in the size key of the trailer directory (%" PDF_FORMAT_INT64 ")!\n", +- nFirstObject + nNumObjects, m_nNumObjects ); ++ if( nFirstObject + nNumObjects > m_nNumObjects ) ++ { ++ // Total number of xref entries to read is greater than the /Size ++ // specified in the trailer if any. That's an error unless we're ++ // trying to recover from a missing /Size entry. ++ PdfError::LogMessage( eLogSeverity_Warning, ++ "There are more objects (%" PDF_FORMAT_INT64 ") in this XRef " ++ "table than specified in the size key of the trailer directory " ++ "(%" PDF_FORMAT_INT64 ")!\n", nFirstObject + nNumObjects, ++ static_cast( m_nNumObjects )); ++ } ++ ++ if ( static_cast( nFirstObject ) + static_cast( nNumObjects ) > static_cast( std::numeric_limits::max() ) ) ++ PODOFO_RAISE_ERROR_INFO( ePdfError_ValueOutOfRange, ++ "xref subsection's given entry numbers together too large" ); + + #ifdef _WIN32 + m_nNumObjects = static_cast(nFirstObject + nNumObjects); +@@ -771,7 +789,16 @@ + m_nNumObjects = nFirstObject + nNumObjects; + m_offsets.resize(nFirstObject+nNumObjects); + #endif // _WIN32 +- } ++ ++ } ++ else ++ { ++ PdfError::LogMessage( eLogSeverity_Error, "There are more objects (%" PDF_FORMAT_INT64 ++ " + %" PDF_FORMAT_INT64 " seemingly) in this XRef" ++ " table than supported by standard PDF, or it's inconsistent.\n", ++ nFirstObject, nNumObjects); ++ PODOFO_RAISE_ERROR( ePdfError_InvalidXRef ); ++ } + + // consume all whitespaces + int charcode; diff --git a/CVE-2017-5854.patch b/CVE-2017-5854.patch new file mode 100644 index 0000000..a9753c0 --- /dev/null +++ b/CVE-2017-5854.patch @@ -0,0 +1,20 @@ +Description: CVE-2017-5854 +Acked-By: Markus Koschany +Acked-By: Mattia Rizzolo +Last-Update: 2017-05-03 +Bug-Debian: https://bugs.debian.org/854602 +Origin: https://sourceforge.net/p/podofo/code/1836 + +--- a/tools/podofopdfinfo/pdfinfo.cpp ++++ b/tools/podofopdfinfo/pdfinfo.cpp +@@ -207,6 +207,10 @@ + for ( int pg=0; pgGetPage( pg ); ++ if( !curPage ) ++ { ++ PODOFO_RAISE_ERROR( PoDoFo::ePdfError_PageNotFound ); ++ } + rect = curPage->GetMediaBox(); + Format s( rect.GetWidth() - rect.GetLeft(), rect.GetHeight() - rect.GetBottom()); + sIt = sizes.find(s); diff --git a/CVE-2017-5855.patch b/CVE-2017-5855.patch new file mode 100644 index 0000000..641fbfa --- /dev/null +++ b/CVE-2017-5855.patch @@ -0,0 +1,27 @@ +Description: CVE-2017-5855 +Acked-By: Mattia Rizzolo +Last-Update: 2017-05-17 +Origin: https://sourceforge.net/p/podofo/code/1843 +Bug-Debian: https://bugs.debian.org/854603 + +--- a/src/base/PdfParser.cpp ++++ b/src/base/PdfParser.cpp +@@ -782,6 +782,7 @@ + PODOFO_RAISE_ERROR_INFO( ePdfError_ValueOutOfRange, + "xref subsection's given entry numbers together too large" ); + ++ try { + #ifdef _WIN32 + m_nNumObjects = static_cast(nFirstObject + nNumObjects); + m_offsets.resize(static_cast(nFirstObject+nNumObjects)); +@@ -789,7 +790,9 @@ + m_nNumObjects = nFirstObject + nNumObjects; + m_offsets.resize(nFirstObject+nNumObjects); + #endif // _WIN32 +- ++ } catch (std::bad_alloc &ex) { ++ PODOFO_RAISE_ERROR( ePdfError_OutOfMemory ); ++ } + } + else + { diff --git a/CVE-2017-5886-and-CVE-2018-8000.patch b/CVE-2017-5886-and-CVE-2018-8000.patch new file mode 100644 index 0000000..d1a76c7 --- /dev/null +++ b/CVE-2017-5886-and-CVE-2018-8000.patch @@ -0,0 +1,18 @@ +Description: CVE-2017-5886 +Acked-By: Markus Koschany +Acked-By: Mattia Rizzolo +Last-Update: 2017-05-03 +Bug-Debian: https://bugs.debian.org/854604 +Origin: https://sourceforge.net/p/podofo/code/1837 + +--- a/src/base/PdfTokenizer.cpp ++++ b/src/base/PdfTokenizer.cpp +@@ -239,7 +239,7 @@ + *peType = ePdfTokenType_Token; + + while( (c = m_device.Device()->Look()) != EOF +- && counter < static_cast(m_buffer.GetSize()) ) ++ && counter + 1 < static_cast(m_buffer.GetSize()) ) + { + // ignore leading whitespaces + if( !counter && IsWhitespace( c ) ) diff --git a/CVE-2017-6840-and-CVE-2017-6842-and-CVE-2017-6843.patch b/CVE-2017-6840-and-CVE-2017-6842-and-CVE-2017-6843.patch new file mode 100644 index 0000000..c9744d7 --- /dev/null +++ b/CVE-2017-6840-and-CVE-2017-6842-and-CVE-2017-6843.patch @@ -0,0 +1,25 @@ +Description: CVE-2017-6840 and CVE-2017-6842 and CVE-2017-6843 +Acked-By: Mattia Rizzolo +Last-UpdatE: 2017-05-17 +Origin: https://sourceforge.net/p/podofo/code/1844 +Origin: https://sourceforge.net/p/podofo/code/1845 +Bug-Debian: https://bugs.debian.org/861557 +Bug-Debian: https://bugs.debian.org/861559 +Bug-Debian: https://bugs.debian.org/861560 + +--- a/tools/podofocolor/colorchanger.cpp ++++ b/tools/podofocolor/colorchanger.cpp +@@ -181,6 +181,13 @@ + int nNumArgs = pInfo->nNumArguments; + EPdfColorSpace eColorSpace; + ++ if( pInfo->nNumArguments > 0 && args.size() != static_cast( pInfo->nNumArguments ) ) ++ { ++ std::ostringstream oss; ++ oss << "Expected " << pInfo->nNumArguments << " argument(s) for keyword '" << pszKeyword << "', but " << args.size() << " given instead."; ++ PODOFO_RAISE_ERROR_INFO( ePdfError_InvalidContentStream, oss.str().c_str() ); ++ } ++ + switch( pInfo->eKeywordType ) + { + case eKeyword_GraphicsStack_Push: diff --git a/CVE-2017-6845.patch b/CVE-2017-6845.patch new file mode 100644 index 0000000..c19ca96 --- /dev/null +++ b/CVE-2017-6845.patch @@ -0,0 +1,27 @@ +Description: CVE-2017-6845 +Acked-By: Mattia Rizzolo +Bug-Debian: https://bugs.debian.org/861562 +Origin: https://sourceforge.net/p/podofo/code/1892 + +--- a/src/base/PdfError.h ++++ b/src/base/PdfError.h +@@ -167,18 +167,8 @@ + * + * Evaluate `x' as a binary predicate and if it is true, raise a logic error with the + * info string `y' . +- * +- * This macro will be undefined when NDEBUG is set, so it's compiled out for release +- * builds. Use it for expensive or extremely frequent sanity checking. +- * +- * We define it then UNDEF it to help out doxygen. + */ +-#ifndef NDEBUG +- // Woo for double-negatives. We define PODOFO_RAISE_LOGIC_IF unless we've been told not to by NDEBUG. +- #define PODOFO_RAISE_LOGIC_IF( x, y ) { if (x) throw ::PoDoFo::PdfError( ePdfError_InternalLogic, __FILE__, __LINE__, y ); }; +-#else +- #define PODOFO_RAISE_LOGIC_IF( x, y ) {}; +-#endif ++#define PODOFO_RAISE_LOGIC_IF( x, y ) { if (x) throw ::PoDoFo::PdfError( ePdfError_InternalLogic, __FILE__, __LINE__, y ); }; + + class PODOFO_API PdfErrorInfo { + public: diff --git a/CVE-2017-6847-and-CVE-2017-6848.patch b/CVE-2017-6847-and-CVE-2017-6848.patch new file mode 100644 index 0000000..2b5a61a --- /dev/null +++ b/CVE-2017-6847-and-CVE-2017-6848.patch @@ -0,0 +1,21 @@ +Description: CVE-2017-6847 and CVE-2017-6848 +Acked-By: Mattia Rizzolo +Last-Update: 2017-05-17 +Origin: https://sourceforge.net/p/podofo/code/1846 +Bug-Debian: https://bugs.debian.org/861564 +Bug-Debian: https://bugs.debian.org/861565 + +--- a/src/doc/PdfXObject.cpp ++++ b/src/doc/PdfXObject.cpp +@@ -261,8 +261,10 @@ + + m_pResources = pObject->GetIndirectKey( "Resources" ); + m_Identifier = PdfName( out.str().c_str() ); +- m_rRect = PdfRect( this->GetObject()->GetIndirectKey( "BBox" )->GetArray() ); + m_Reference = this->GetObject()->Reference(); ++ ++ if( this->GetObject()->GetIndirectKey( "BBox" ) ) ++ m_rRect = PdfRect( this->GetObject()->GetIndirectKey( "BBox" )->GetArray() ); + } + + void PdfXObject::InitXObject( const PdfRect & rRect, const char* pszPrefix ) diff --git a/CVE-2017-7378.patch b/CVE-2017-7378.patch new file mode 100644 index 0000000..e55b8bc --- /dev/null +++ b/CVE-2017-7378.patch @@ -0,0 +1,38 @@ +Description: CVE-2017-7378 +Acked-By: Mattia Rizzolo +Last-Update: 2017-05-17 +Origin: https://sourceforge.net/p/podofo/code/1847 +Bug-Debian: https://bugs.debian.org/859330 + +--- a/src/doc/PdfPainter.cpp ++++ b/src/doc/PdfPainter.cpp +@@ -1938,16 +1938,27 @@ + const pdf_utf16be cTab = 0x0900; + const pdf_utf16be cSpace = 0x2000; + ++ if( lStringLen == -1 ) ++ lStringLen = rsString.GetCharacterLength(); ++ ++ if (lStringLen > rsString.GetCharacterLength()) ++ { ++ PdfError::DebugMessage( "Requested to expand tabs in string of %" PDF_FORMAT_INT64 " chars, while it has only %" PDF_FORMAT_INT64 "; correcting the value\n", ++ static_cast( lStringLen ), static_cast( rsString.GetCharacterLength() ) ); ++ ++ lStringLen = rsString.GetCharacterLength(); ++ } ++ + // count the number of tabs in the string + if( bUnicode ) + { +- for( i=0;i<=lStringLen;i++ ) ++ for( i=0;i +Acked-By: Mattia Rizzolo +Last-Update: 2017-05-03 +Bug-Debian: https://bugs.debian.org/859331 +Origin: https://sourceforge.net/p/podofo/code/1842 + +--- a/src/base/PdfEncoding.cpp ++++ b/src/base/PdfEncoding.cpp +@@ -45,6 +45,7 @@ + #include + #include + #include ++#include + #include + #include "PdfArray.h" + #include "doc/PdfDifferenceEncoding.h" +@@ -362,7 +363,9 @@ + void PdfSimpleEncoding::InitEncodingTable() + { + Util::PdfMutexWrapper wrapper( *m_mutex ); +- const long lTableLength = 0xffff; ++ // CVE-2017-7379 - previously lTableLength was 0xffff, but pdf_utf16be characters can be in range 0..0xffff so this ++ // caused out-by-one heap overflow when character 0xffff was encoded ++ const long lTableLength = std::numeric_limits::max() + 1; + const pdf_utf16be* cpUnicodeTable = this->GetToUnicodeTable(); + + if( !m_pEncodingTable ) // double check diff --git a/CVE-2017-738[0123].patch b/CVE-2017-738[0123].patch new file mode 100644 index 0000000..d6e843b --- /dev/null +++ b/CVE-2017-738[0123].patch @@ -0,0 +1,17 @@ +Description: CVE-2017-7380 and CVE-2017-7381 and CVE-2017-7382 and CVE-2017-7383 +Acked-By: Mattia Rizzolo +Last-Update: 2017-05-17 +Origin: https://sourceforge.net/p/podofo/code/1848 +Bug-Debian: https://bugs.debian.org/859329 + +--- a/src/doc/PdfPage.cpp ++++ b/src/doc/PdfPage.cpp +@@ -647,7 +647,7 @@ + // OC 15.08.2010 BugFix: Ghostscript creates here sometimes an indirect reference to a directory + // PdfObject* pType = m_pResources->GetDictionary().GetKey( rType ); + PdfObject* pType = m_pResources->GetIndirectKey( rType ); +- if( pType->IsDictionary() && pType->GetDictionary().HasKey( rKey ) ) ++ if( pType && pType->IsDictionary() && pType->GetDictionary().HasKey( rKey ) ) + { + const PdfReference & ref = pType->GetDictionary().GetKey( rKey )->GetReference(); + return this->GetObject()->GetOwner()->GetObject( ref ); diff --git a/CVE-2017-7994.patch b/CVE-2017-7994.patch new file mode 100644 index 0000000..d8d46eb --- /dev/null +++ b/CVE-2017-7994.patch @@ -0,0 +1,103 @@ +Description: CVE-2017-7994 +Acked-By: Mattia Rizzolo +Origin: https://sourceforge.net/p/podofo/code/1849 +Bug-Debian: https://bugs.debian.org/860930 +Last-Update: 2017-11-12 + +--- a/tools/podofotxtextract/TextExtractor.cpp ++++ b/tools/podofotxtextract/TextExtractor.cpp +@@ -72,10 +72,21 @@ + if( strcmp( pszToken, "l" ) == 0 || + strcmp( pszToken, "m" ) == 0 ) + { +- dCurPosX = stack.top().GetReal(); +- stack.pop(); +- dCurPosY = stack.top().GetReal(); +- stack.pop(); ++ if( stack.size() == 2 ) ++ { ++ dCurPosX = stack.top().GetReal(); ++ stack.pop(); ++ dCurPosY = stack.top().GetReal(); ++ stack.pop(); ++ } ++ else ++ { ++ fprintf( stderr, "WARNING: Token '%s' expects two arguments, but %" PDF_FORMAT_INT64 " given; ignoring\n", ++ pszToken, static_cast( stack.size() ) ); ++ ++ while( !stack.empty() ) ++ stack.pop(); ++ } + } + else if( strcmp( pszToken, "BT" ) == 0 ) + { +@@ -93,6 +104,13 @@ + { + if( strcmp( pszToken, "Tf" ) == 0 ) + { ++ if( stack.size() < 2 ) ++ { ++ fprintf( stderr, "WARNING: Expects two arguments for 'Tf', ignoring\n" ); ++ pCurFont = NULL; ++ continue; ++ } ++ + stack.pop(); + PdfName fontName = stack.top().GetName(); + PdfObject* pFont = pPage->GetFromResources( PdfName("Font"), fontName ); +@@ -102,21 +120,37 @@ + } + + pCurFont = pDocument->GetFont( pFont ); +- if( !pCurFont ) ++ if( !pCurFont ) + { +- fprintf( stderr, "WARNING: Unable to create font for object %i %i R\n", +- pFont->Reference().ObjectNumber(), +- pFont->Reference().GenerationNumber() ); ++ fprintf( stderr, "WARNING: Unable to create font for object %" PDF_FORMAT_INT64 " %" PDF_FORMAT_INT64 " R\n", ++ static_cast( pFont->Reference().ObjectNumber() ), ++ static_cast( pFont->Reference().GenerationNumber() ) ); + } + } + else if( strcmp( pszToken, "Tj" ) == 0 || + strcmp( pszToken, "'" ) == 0 ) + { ++ if( stack.size() < 1 ) ++ { ++ fprintf( stderr, "WARNING: Expects one argument for '%s', ignoring\n", pszToken ); ++ continue; ++ } ++ + AddTextElement( dCurPosX, dCurPosY, pCurFont, stack.top().GetString() ); + stack.pop(); + } + else if( strcmp( pszToken, "\"" ) == 0 ) + { ++ if( stack.size() < 3 ) ++ { ++ fprintf( stderr, "WARNING: Expects three arguments for '%s', ignoring\n", pszToken ); ++ ++ while( !stack.empty() ) ++ stack.pop(); ++ ++ continue; ++ } ++ + AddTextElement( dCurPosX, dCurPosY, pCurFont, stack.top().GetString() ); + stack.pop(); + stack.pop(); // remove char spacing from stack +@@ -124,6 +158,12 @@ + } + else if( strcmp( pszToken, "TJ" ) == 0 ) + { ++ if( stack.size() < 3 ) ++ { ++ fprintf( stderr, "WARNING: Expects one argument for '%s', ignoring\n", pszToken ); ++ continue; ++ } ++ + PdfArray array = stack.top().GetArray(); + stack.pop(); + diff --git a/CVE-2017-8054.patch b/CVE-2017-8054.patch new file mode 100644 index 0000000..1396bc4 --- /dev/null +++ b/CVE-2017-8054.patch @@ -0,0 +1,206 @@ +Description: CVE-2017-8054 +Acked-By: Mattia Rizzolo +Bug-Debian: https://bugs.debian.org/860995 +Origin: https://sourceforge.net/p/podofo/code/1872 +Origin: https://sourceforge.net/p/podofo/code/1881 +Origin: https://sourceforge.net/p/podofo/code/1882 +Origin: https://sourceforge.net/p/podofo/code/1883 + +--- a/src/base/PdfError.cpp ++++ b/src/base/PdfError.cpp +@@ -60,6 +60,12 @@ + { + } + ++PdfErrorInfo::PdfErrorInfo( int line, const char* pszFile, std::string sInfo ) ++ : m_nLine( line ), m_sFile( pszFile ? pszFile : "" ), m_sInfo( sInfo ) ++{ ++ ++} ++ + PdfErrorInfo::PdfErrorInfo( int line, const char* pszFile, const char* pszInfo ) + : m_nLine( line ), m_sFile( pszFile ? pszFile : "" ), m_sInfo( pszInfo ? pszInfo : "" ) + { +@@ -96,6 +102,12 @@ + } + + PdfError::PdfError( const EPdfError & eCode, const char* pszFile, int line, ++ std::string sInformation ) ++{ ++ this->SetError( eCode, pszFile, line, sInformation ); ++} ++ ++PdfError::PdfError( const EPdfError & eCode, const char* pszFile, int line, + const char* pszInformation ) + { + this->SetError( eCode, pszFile, line, pszInformation ); +--- a/src/base/PdfError.h ++++ b/src/base/PdfError.h +@@ -158,8 +158,8 @@ + /** \def PODOFO_RAISE_ERROR_INFO( x, y ) + * + * Set the value of the variable eCode (which has to exist in the current function) to x +- * and return the eCode. Additionally additional information on the error y is set. y has +- * to be an c-string. ++ * and return the eCode. Additionally additional information on the error y is set. ++ * y can be a C string, but can also be a C++ std::string. + */ + #define PODOFO_RAISE_ERROR_INFO( x, y ) throw ::PoDoFo::PdfError( x, __FILE__, __LINE__, y ); + +@@ -174,6 +174,7 @@ + public: + PdfErrorInfo(); + PdfErrorInfo( int line, const char* pszFile, const char* pszInfo ); ++ PdfErrorInfo( int line, const char* pszFile, std::string pszInfo ); + PdfErrorInfo( int line, const char* pszFile, const wchar_t* pszInfo ); + PdfErrorInfo( const PdfErrorInfo & rhs ); + +@@ -185,6 +186,7 @@ + inline const std::wstring & GetInformationW() const { return m_swInfo; } + + inline void SetInformation( const char* pszInfo ) { m_sInfo = pszInfo ? pszInfo : ""; } ++ inline void SetInformation( std::string pszInfo ) { m_sInfo = pszInfo; } + inline void SetInformation( const wchar_t* pszInfo ) { m_swInfo = pszInfo ? pszInfo : L""; } + + private: +@@ -242,12 +244,22 @@ + * Use the compiler macro __FILE__ to initialize the field. + * \param line the line in which the error has occured. + * Use the compiler macro __LINE__ to initialize the field. +- * \param pszInformation additional information on this error which mayy +- * be formatted like printf ++ * \param pszInformation additional information on this error + */ + PdfError( const EPdfError & eCode, const char* pszFile = NULL, int line = 0, + const char* pszInformation = NULL ); + ++ /** Create a PdfError object with a given error code. ++ * \param eCode the error code of this object ++ * \param pszFile the file in which the error has occured. ++ * Use the compiler macro __FILE__ to initialize the field. ++ * \param line the line in which the error has occured. ++ * Use the compiler macro __LINE__ to initialize the field. ++ * \param sInformation additional information on this error ++ */ ++ explicit PdfError( const EPdfError & eCode, const char* pszFile, int line, ++ std::string sInformation ); ++ + /** Copy constructor + * \param rhs copy the contents of rhs into this object + */ +@@ -309,6 +321,21 @@ + * \param line the line of source causing the error + * or 0. Typically you will use the gcc + * macro __LINE__ here. ++ * \param sInformation additional information on the error. ++ * e.g. how to fix the error. This string is intended to ++ * be shown to the user. ++ */ ++ inline void SetError( const EPdfError & eCode, const char* pszFile, int line, ++ std::string sInformation ); ++ ++ /** Set the error code of this object. ++ * \param eCode the error code of this object ++ * \param pszFile the filename of the source file causing ++ * the error or NULL. Typically you will use ++ * the gcc macro __FILE__ here. ++ * \param line the line of source causing the error ++ * or 0. Typically you will use the gcc ++ * macro __LINE__ here. + * \param pszInformation additional information on the error. + * e.g. how to fix the error. This string is intended to + * be shown to the user. +@@ -344,6 +371,21 @@ + */ + inline void AddToCallstack( const char* pszFile = NULL, int line = 0, const char* pszInformation = NULL ); + ++ /** Add callstack information to an error object. Always call this function ++ * if you get an error object but do not handle the error but throw it again. ++ * ++ * \param pszFile the filename of the source file causing ++ * the error or NULL. Typically you will use ++ * the gcc macro __FILE__ here. ++ * \param line the line of source causing the error ++ * or 0. Typically you will use the gcc ++ * macro __LINE__ here. ++ * \param sInformation additional information on the error. ++ * e.g. how to fix the error. This string is intended to ++ * be shown to the user. ++ */ ++ inline void AddToCallstack( const char* pszFile, int line, std::string sInformation ); ++ + /** \returns true if an error code was set + * and false if the error code is ePdfError_ErrOk + */ +@@ -478,6 +520,22 @@ + // ----------------------------------------------------- + // + // ----------------------------------------------------- ++void PdfError::SetError( const EPdfError & eCode, const char* pszFile, int line, std::string sInformation ) ++{ ++ m_error = eCode; ++ this->AddToCallstack( pszFile, line, sInformation ); ++} ++ ++// ----------------------------------------------------- ++// ++// ----------------------------------------------------- ++void PdfError::AddToCallstack( const char* pszFile, int line, std::string sInformation ) ++{ ++ m_callStack.push_front( PdfErrorInfo( line, pszFile, sInformation ) ); ++} ++// ----------------------------------------------------- ++// ++// ----------------------------------------------------- + void PdfError::SetErrorInformation( const char* pszInformation ) + { + if( m_callStack.size() ) +--- a/src/doc/PdfPagesTree.cpp ++++ b/src/doc/PdfPagesTree.cpp +@@ -34,6 +34,7 @@ + #include "PdfPagesTree.h" + + #include "base/PdfDefinesPrivate.h" ++#include + + #include "base/PdfArray.h" + #include "base/PdfDictionary.h" +@@ -478,7 +479,18 @@ + if( rVar.IsArray() ) + { + // Fixes some broken PDFs who have trees with 1 element kids arrays +- return GetPageNodeFromArray( 0, rVar.GetArray(), rLstParents ); ++ // Recursive call removed to prevent stack overflow (CVE-2017-8054) ++ // replaced by the following inside this conditional incl. continue ++ const PdfArray & rVarArray = rVar.GetArray(); ++ if (rVarArray.GetSize() == 0) ++ { ++ PdfError::LogMessage( eLogSeverity_Critical, "Trying to access" ++ " first page index of empty array" ); ++ return NULL; ++ } ++ PdfVariant rVarFirstEntry = rVarArray[0]; // avoids use-after-free ++ rVar = rVarFirstEntry; // in this line (rVar-ref'd array is freed) ++ continue; + } + else if( !rVar.IsReference() ) + { +@@ -502,6 +514,18 @@ + if( !pgObject->GetDictionary().HasKey( "Kids" ) ) + return NULL; + ++ if ( std::find( rLstParents.begin(), rLstParents.end(), pgObject ) ++ != rLstParents.end() ) // cycle in parent list detected, fend ++ { // off security vulnerability CVE-2017-8054 (infinite recursion) ++ std::ostringstream oss; ++ oss << "Cycle in page tree: child in /Kids array of object " ++ << ( *(rLstParents.rbegin()) )->Reference().ToString() ++ << " back-references to object " << pgObject->Reference() ++ .ToString() << " one of whose descendants the former is."; ++ ++ PODOFO_RAISE_ERROR_INFO( ePdfError_PageNotFound, oss.str() ); ++ } ++ + rLstParents.push_back( pgObject ); + rVar = *(pgObject->GetDictionary().GetKey( "Kids" )); + } else { diff --git a/CVE-2017-8378.patch b/CVE-2017-8378.patch new file mode 100644 index 0000000..e7d60f9 --- /dev/null +++ b/CVE-2017-8378.patch @@ -0,0 +1,22 @@ +Description: CVE-2017-8378 +Acked-By: Mattia Rizzolo +Bug-Debian: https://bugs.debian.org/861597 +Origin: https://sourceforge.net/p/podofo/code/1833 + +--- a/src/base/PdfParser.cpp ++++ b/src/base/PdfParser.cpp +@@ -981,6 +981,14 @@ + if( pEncrypt->IsReference() ) + { + i = pEncrypt->GetReference().ObjectNumber(); ++ if( i <= 0 || static_cast( i ) >= m_offsets.size () ) ++ { ++ std::ostringstream oss; ++ oss << "Encryption dictionary references a nonexistent object " << pEncrypt->GetReference().ObjectNumber() << " " ++ << pEncrypt->GetReference().GenerationNumber(); ++ PODOFO_RAISE_ERROR_INFO( ePdfError_InvalidEncryptionDict, oss.str().c_str() ); ++ } ++ + pObject = new PdfParserObject( m_vecObjects, m_device, m_buffer, m_offsets[i].lOffset ); + if( !pObject ) + PODOFO_RAISE_ERROR( ePdfError_OutOfMemory ); diff --git a/CVE-2017-8787.patch b/CVE-2017-8787.patch new file mode 100644 index 0000000..2763611 --- /dev/null +++ b/CVE-2017-8787.patch @@ -0,0 +1,20 @@ +Description: CVE-2017-8787 +Acked-By: Mattia Rizzolo +Origin: https://sourceforge.net/p/podofo/code/185 +Bug-Debian: https://bugs.debian.org/861738 +Last-Update: 2017-11-12 + +--- a/src/base/PdfXRefStreamParserObject.cpp ++++ b/src/base/PdfXRefStreamParserObject.cpp +@@ -124,6 +124,11 @@ + pdf_long lBufferLen; + const size_t entryLen = static_cast(nW[0] + nW[1] + nW[2]); + ++ if( nW[0] + nW[1] + nW[2] < 0 ) ++ { ++ PODOFO_RAISE_ERROR_INFO( ePdfError_NoXRef, "Invalid entry length in XRef stream" ); ++ } ++ + this->GetStream()->GetFilteredCopy( &pBuffer, &lBufferLen ); + + diff --git a/CVE-2018-5295.patch b/CVE-2018-5295.patch new file mode 100644 index 0000000..9e6688b --- /dev/null +++ b/CVE-2018-5295.patch @@ -0,0 +1,47 @@ +Description: CVE-2018-5295 +Acked-By: Mattia Rizzolo +Bug-Debian: https://bugs.debian.org/889511 +Origin: https://sourceforge.net/p/podofo/code/1889 + +--- a/src/base/PdfXRefStreamParserObject.cpp ++++ b/src/base/PdfXRefStreamParserObject.cpp +@@ -38,7 +38,7 @@ + #include "PdfStream.h" + #include "PdfVariant.h" + +-#include ++#include + + namespace PoDoFo { + +@@ -122,13 +122,27 @@ + { + char* pBuffer; + pdf_long lBufferLen; +- const size_t entryLen = static_cast(nW[0] + nW[1] + nW[2]); + +- if( nW[0] + nW[1] + nW[2] < 0 ) ++ for(pdf_int64 nLengthSum = 0, i = 0; i < W_ARRAY_SIZE; i++ ) + { +- PODOFO_RAISE_ERROR_INFO( ePdfError_NoXRef, "Invalid entry length in XRef stream" ); ++ if ( nW[i] < 0 ) ++ { ++ PODOFO_RAISE_ERROR_INFO( ePdfError_NoXRef, ++ "Negative field length in XRef stream" ); ++ } ++ if ( std::numeric_limits::max() - nLengthSum < nW[i] ) ++ { ++ PODOFO_RAISE_ERROR_INFO( ePdfError_NoXRef, ++ "Invalid entry length in XRef stream" ); ++ } ++ else ++ { ++ nLengthSum += nW[i]; ++ } + } + ++ const size_t entryLen = static_cast(nW[0] + nW[1] + nW[2]); ++ + this->GetStream()->GetFilteredCopy( &pBuffer, &lBufferLen ); + + diff --git a/CVE-2018-5308.patch b/CVE-2018-5308.patch new file mode 100644 index 0000000..df38ed2 --- /dev/null +++ b/CVE-2018-5308.patch @@ -0,0 +1,28 @@ +Description: CVE-2018-5308 +Acked-By: Mattia Rizzolo +Origin: https://sourceforge.net/p/podofo/code/1870 +Origin: https://sourceforge.net/p/podofo/code/1876 + +--- a/src/base/PdfOutputStream.cpp ++++ b/src/base/PdfOutputStream.cpp +@@ -85,6 +85,11 @@ + PdfMemoryOutputStream::PdfMemoryOutputStream( char* pBuffer, pdf_long lLen ) + : m_lLen( 0 ), m_bOwnBuffer( false ) + { ++ if( !pBuffer ) ++ { ++ PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); ++ } ++ + m_lSize = lLen; + m_pBuffer = pBuffer; + } +@@ -98,7 +103,7 @@ + + pdf_long PdfMemoryOutputStream::Write( const char* pBuffer, pdf_long lLen ) + { +- if( !m_pBuffer ) ++ if( !pBuffer ) + { + PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); + } diff --git a/podofo.spec b/podofo.spec index 237fb37..9c478e8 100644 --- a/podofo.spec +++ b/podofo.spec @@ -1,6 +1,6 @@ Name: podofo Version: 0.9.5 -Release: 8%{?dist} +Release: 9%{?dist} Summary: Tools and libraries to work with the PDF file format # The library is licensed under the LGPL. @@ -17,6 +17,26 @@ Patch1: podofo-0.9.4_build.patch # https://sourceforge.net/p/podofo/mailman/message/35649256/ Patch2: podofo-0.9.5_stdc++98.patch +# Backported security fixes +Patch100: CVE-2017-738[0123].patch +Patch101: CVE-2017-5852.patch +Patch102: CVE-2017-5853-and-CVE-2017-6844.patch +Patch103: CVE-2017-5854.patch +Patch104: CVE-2017-5855.patch +Patch105: CVE-2017-5886-and-CVE-2018-8000.patch +Patch106: CVE-2017-6840-and-CVE-2017-6842-and-CVE-2017-6843.patch +Patch107: CVE-2017-6845.patch +Patch108: CVE-2017-6847-and-CVE-2017-6848.patch +Patch109: CVE-2017-7378.patch +Patch110: CVE-2017-7379.patch +Patch111: CVE-2017-7994.patch +Patch112: CVE-2017-8054.patch +Patch113: CVE-2017-8378.patch +Patch114: CVE-2017-8787.patch +Patch115: CVE-2018-5295.patch +Patch116: CVE-2018-5308.patch + + BuildRequires: gcc-c++ %if %{?el7:1}%{!?el7:0} BuildRequires: cmake3 @@ -127,6 +147,14 @@ find doc/html -exec touch -r %{SOURCE0} {} \; %changelog +* Fri Jun 15 2018 Sandro Mani - 0.9.5-9 +- Backport security fixes (taken from debian package): + CVE-2017-7380, CVE-2017-7381, CVE-2017-7382, CVE-2017-7383, CVE-2017-5852, + CVE-2017-5853, CVE-2017-6844, CVE-2017-5854, CVE-2017-5855, CVE-2017-5886, + CVE-2018-8000, CVE-2017-6840, CVE-2017-6842, CVE-2017-6843, CVE-2017-6845, + CVE-2017-6847, CVE-2017-6848, CVE-2017-7378, CVE-2017-7379, CVE-2017-7994, + CVE-2017-8054, CVE-2017-8378, CVE-2017-8787, CVE-2018-5295, CVE-2018-5308 + * Wed May 16 2018 Kevin Fenzi - 0.9.5-8 - Rebuild for new libidn