From 414eb4b0da85f49941ed859db906162ead2be839 Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Sat, 1 Feb 2020 16:06:00 +0100 Subject: [PATCH] GDALDefaultOverviews::OverviewScan(): avoid very long processing time on corrupted files. Fixes https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=20407 --- gdal/gcore/gdaldefaultoverviews.cpp | 62 +++++++++++++++++++++++++---- gdal/port/cpl_multiproc.h | 1 + 2 files changed, 55 insertions(+), 8 deletions(-) diff --git a/gdal/gcore/gdaldefaultoverviews.cpp b/gdal/gcore/gdaldefaultoverviews.cpp index 20597a8b0c68..df256da2f5fe 100644 --- a/gdal/gcore/gdaldefaultoverviews.cpp +++ b/gdal/gcore/gdaldefaultoverviews.cpp @@ -29,12 +29,14 @@ ****************************************************************************/ #include "cpl_port.h" +#include "cpl_multiproc.h" #include "gdal_priv.h" #include #include #include +#include #include #include @@ -180,6 +182,46 @@ void GDALDefaultOverviews::TransferSiblingFiles( char** papszSiblingFiles ) papszInitSiblingFiles = papszSiblingFiles; } + +namespace { +// Prevent infinite recursion. +struct AntiRecursionStruct +{ + int nRecLevel = 0; + std::set oSetFiles{}; +}; +} + +static void FreeAntiRecursion( void* pData ) +{ + delete static_cast(pData); +} + +static AntiRecursionStruct& GetAntiRecursion() +{ + static AntiRecursionStruct dummy; + int bMemoryErrorOccurred = false; + void* pData = CPLGetTLSEx(CTLS_GDALDEFAULTOVR_ANTIREC, &bMemoryErrorOccurred); + if( bMemoryErrorOccurred ) + { + return dummy; + } + if( pData == nullptr) + { + auto pAntiRecursion = new AntiRecursionStruct(); + CPLSetTLSWithFreeFuncEx( CTLS_GDALDEFAULTOVR_ANTIREC, + pAntiRecursion, + FreeAntiRecursion, &bMemoryErrorOccurred ); + if( bMemoryErrorOccurred ) + { + delete pAntiRecursion; + return dummy; + } + return *pAntiRecursion; + } + return *static_cast(pData); +} + /************************************************************************/ /* OverviewScan() */ /* */ @@ -196,21 +238,23 @@ void GDALDefaultOverviews::OverviewScan() return; bCheckedForOverviews = true; + if( pszInitName == nullptr ) + pszInitName = CPLStrdup(poDS->GetDescription()); - static thread_local int nAntiRecursionCounter = 0; - // arbitrary number. 32 should be enough to handle a .ovr.ovr.ovr... - if( nAntiRecursionCounter == 64 ) + AntiRecursionStruct& antiRec = GetAntiRecursion(); + // 32 should be enough to handle a .ovr.ovr.ovr... + if( antiRec.nRecLevel == 32 ) + return; + if( antiRec.oSetFiles.find(pszInitName) != antiRec.oSetFiles.end() ) return; - ++nAntiRecursionCounter; + antiRec.oSetFiles.insert(pszInitName); + ++antiRec.nRecLevel; CPLDebug( "GDAL", "GDALDefaultOverviews::OverviewScan()" ); /* -------------------------------------------------------------------- */ /* Open overview dataset if it exists. */ /* -------------------------------------------------------------------- */ - if( pszInitName == nullptr ) - pszInitName = CPLStrdup(poDS->GetDescription()); - if( !EQUAL(pszInitName,":::VIRTUAL:::") && GDALCanFileAcceptSidecarFile(pszInitName) ) { @@ -359,7 +403,9 @@ void GDALDefaultOverviews::OverviewScan() } } - --nAntiRecursionCounter; + // Undo anti recursion protection + antiRec.oSetFiles.erase(pszInitName); + --antiRec.nRecLevel; } /************************************************************************/ diff --git a/gdal/port/cpl_multiproc.h b/gdal/port/cpl_multiproc.h index d22e73e40b7c..fd61e83ff72b 100644 --- a/gdal/port/cpl_multiproc.h +++ b/gdal/port/cpl_multiproc.h @@ -227,6 +227,7 @@ class CPL_DLL CPLLockHolder #define CTLS_VSIERRORCONTEXT 16 /* cpl_vsi_error.cpp */ #define CTLS_ERRORHANDLERACTIVEDATA 17 /* cpl_error.cpp */ #define CTLS_PROJCONTEXTHOLDER 18 /* ogr_proj_p.cpp */ +#define CTLS_GDALDEFAULTOVR_ANTIREC 19 /* gdaldefaultoverviews.cpp */ #define CTLS_MAX 32