From: Simon McVittie Date: Thu, 16 Feb 2012 20:28:58 +0000 Subject: CVE-2011-3012, CVE-2011-2764 - backport from ioquake3 to prevent DLL overwriting This is a backport of several patches: * part of ioquake3 r1405, from TsT (attempt to prevent DLL overwriting, CVE-2011-3012) * part of ioquake3 r1456, from Patrick Baggett (using __func__) * ioquake3 r1499, from Tim Angus (fix potential buffer underrun) * ioquake3 r2098, from Thilo Schulz (fix incomplete DLL overwrite prevention in previous commits, CVE-2011-2764) Origin: backport Bug-Debian: http://bugs.debian.org/660836 Bug-CVE: http://security-tracker.debian.org/tracker/CVE-2011-3012 Bug-CVE: http://security-tracker.debian.org/tracker/CVE-2011-2764 --- src/qcommon/files.c | 34 ++++++++++++++++++++++++++++++++++ src/qcommon/q_shared.c | 24 ++++++++++++++++++++++++ src/qcommon/q_shared.h | 1 + 3 files changed, 59 insertions(+), 0 deletions(-) diff --git a/src/qcommon/files.c b/src/qcommon/files.c index 49390a0..2e28cab 100644 --- src/qcommon/files.c +++ src/qcommon/files.c @@ -510,6 +510,24 @@ static qboolean FS_CreatePath (char *OSPath) { /* ================= +FS_CheckFilenameIsNotExecutable + +ERR_FATAL if trying to maniuplate a file with the platform library extension +================= + */ +static void FS_CheckFilenameIsNotExecutable( const char *filename, const char *function ) +{ + // Check if the filename ends with the library extension + if(COM_CompareExtension(filename, DLL_EXT)) + { + Com_Error( ERR_FATAL, "%s: Not allowed to manipulate '%s' due " + "to %s extension\n", function, filename, DLL_EXT ); + } +} + + +/* +================= FS_CopyFile Copy a fully specified file from one place to another @@ -522,6 +540,8 @@ static void FS_CopyFile( char *fromOSPath, char *toOSPath ) { Com_Printf( "copy %s to %s\n", fromOSPath, toOSPath ); + FS_CheckFilenameIsNotExecutable( toOSPath, __func__ ); + if (strstr(fromOSPath, "journal.dat") || strstr(fromOSPath, "journaldata.dat")) { Com_Printf( "Ignoring journal files\n"); return; @@ -563,6 +583,8 @@ FS_Remove =========== */ void FS_Remove( const char *osPath ) { + FS_CheckFilenameIsNotExecutable( osPath, __func__ ); + remove( osPath ); } @@ -573,6 +595,8 @@ FS_HomeRemove =========== */ void FS_HomeRemove( const char *homePath ) { + FS_CheckFilenameIsNotExecutable( homePath, __func__ ); + remove( FS_BuildOSPath( fs_homepath->string, fs_gamedir, homePath ) ); } @@ -650,6 +674,8 @@ fileHandle_t FS_SV_FOpenFileWrite( const char *filename ) { Com_Printf( "FS_SV_FOpenFileWrite: %s\n", ospath ); } + FS_CheckFilenameIsNotExecutable( ospath, __func__ ); + if( FS_CreatePath( ospath ) ) { return 0; } @@ -775,6 +801,8 @@ void FS_SV_Rename( const char *from, const char *to ) { Com_Printf( "FS_SV_Rename: %s --> %s\n", from_ospath, to_ospath ); } + FS_CheckFilenameIsNotExecutable( to_ospath, __func__ ); + if (rename( from_ospath, to_ospath )) { // Failed, try copying it and deleting the original FS_CopyFile ( from_ospath, to_ospath ); @@ -807,6 +835,8 @@ void FS_Rename( const char *from, const char *to ) { Com_Printf( "FS_Rename: %s --> %s\n", from_ospath, to_ospath ); } + FS_CheckFilenameIsNotExecutable( to_ospath, __func__ ); + if (rename( from_ospath, to_ospath )) { // Failed, try copying it and deleting the original FS_CopyFile ( from_ospath, to_ospath ); @@ -871,6 +901,8 @@ fileHandle_t FS_FOpenFileWrite( const char *filename ) { Com_Printf( "FS_FOpenFileWrite: %s\n", ospath ); } + FS_CheckFilenameIsNotExecutable( ospath, __func__ ); + if( FS_CreatePath( ospath ) ) { return 0; } @@ -917,6 +949,8 @@ fileHandle_t FS_FOpenFileAppend( const char *filename ) { Com_Printf( "FS_FOpenFileAppend: %s\n", ospath ); } + FS_CheckFilenameIsNotExecutable( ospath, __func__ ); + if( FS_CreatePath( ospath ) ) { return 0; } diff --git a/src/qcommon/q_shared.c b/src/qcommon/q_shared.c index 44085cc..c87b44b 100644 --- src/qcommon/q_shared.c +++ src/qcommon/q_shared.c @@ -77,6 +77,30 @@ void COM_StripExtension( const char *in, char *out, int destsize ) { out[length] = 0; } +/* +============ +COM_CompareExtension + +string compare the end of the strings and return qtrue if strings match +============ +*/ +qboolean COM_CompareExtension(const char *in, const char *ext) +{ + int inlen, extlen; + + inlen = strlen(in); + extlen = strlen(ext); + + if(extlen <= inlen) + { + in += inlen - extlen; + + if(!Q_stricmp(in, ext)) + return qtrue; + } + + return qfalse; +} /* ================== diff --git a/src/qcommon/q_shared.h b/src/qcommon/q_shared.h index d491708..83f5789 100644 --- src/qcommon/q_shared.h +++ src/qcommon/q_shared.h @@ -628,6 +628,7 @@ float Com_Clamp( float min, float max, float value ); char *COM_SkipPath( char *pathname ); void COM_StripExtension(const char *in, char *out, int destsize); +qboolean COM_CompareExtension(const char *in, const char *ext); void COM_DefaultExtension( char *path, int maxSize, const char *extension ); void COM_BeginParseSession( const char *name );