File r1872-Fix-CVE-2017-8054-Detect-cycles-in-PdfPagesTree.patch of Package podofo.34526
------------------------------------------------------------------------
r1872 | mc-zyx | 2018-01-26 07:30:27 +0100 (vie, 26 ene 2018) | 2 lines
Fix by Matthias Brinke: CVE-2017-8054 - Detect cycles in PdfPagesTree
Index: src/base/PdfError.cpp
===================================================================
--- src/base/PdfError.cpp (revision 1871)
+++ src/base/PdfError.cpp (revision 1872)
@@ -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 );
Index: src/base/PdfError.h
===================================================================
--- src/base/PdfError.h (revision 1871)
+++ src/base/PdfError.h (revision 1872)
@@ -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 );
@@ -184,6 +184,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 );
PdfErrorInfo( const PdfErrorInfo & rhs );
@@ -195,6 +196,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:
@@ -252,12 +254,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
*/
@@ -319,6 +331,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.
@@ -354,6 +381,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
*/
@@ -488,6 +530,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() )
Index: src/doc/PdfPagesTree.cpp
===================================================================
--- src/doc/PdfPagesTree.cpp (revision 1871)
+++ src/doc/PdfPagesTree.cpp (revision 1872)
@@ -34,6 +34,7 @@
#include "PdfPagesTree.h"
#include "base/PdfDefinesPrivate.h"
+#include <algorithm>
#include "base/PdfArray.h"
#include "base/PdfDictionary.h"
@@ -478,7 +479,17 @@
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, replaced by:
+ // all the following inside this conditional, plus restart looping
+ const PdfArray & rVarArray = rVar.GetArray();
+ if (rVarArray.GetSize() == 0)
+ {
+ PdfError::LogMessage( eLogSeverity_Critical, "Trying to access"
+ " first page index of empty array" );
+ return NULL;
+ }
+ rVar = rVarArray[0];
+ continue;
}
else if( !rVar.IsReference() )
{
@@ -502,6 +513,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 {
------------------------------------------------------------------------