From: Simon McVittie <smcv@debian.org>
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 );
