You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
128 lines
5.2 KiB
128 lines
5.2 KiB
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 <mattia@debian.org>
|
|
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
|