[SCM] team based FPS game - packaging branch, debian, updated. debian/1.1.0-5-4-gdb361a5
Simon McVittie
smcv at debian.org
Wed Feb 22 09:40:36 UTC 2012
The following commit has been merged in the debian branch:
commit c3398ced4dd60c63538b28fa8981f094482047f1
Author: Simon McVittie <smcv at debian.org>
Date: Sun Feb 19 14:19:18 2012 +0000
Backport patches from ioquake3 to fix long-standing security bugs
- CVE-2006-2082: arbitrary file download from server by a malicious client
- CVE-2006-2236 ("the remapShader exploit"): missing bounds-checking on
COM_StripExtension, exploitable in clients of a malicious server
- CVE-2006-2875 ("q3cbof"): buffer overflow in CL_ParseDownload by a
malicious server
- CVE-2006-3324: arbitrary file overwriting in clients of a malicious
server
- CVE-2006-3325: arbitrary cvar overwriting (could lead to arbitrary
code execution) in clients of a malicious server
- CVE-2011-3012, CVE-2011-2764: DLL overwriting (leading to arbitrary
code execution) in clients of a malicious server if auto-downloading
is enabled
diff --git a/debian/changelog b/debian/changelog
index e2f2c24..8413f29 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,21 @@
+tremulous (1.1.0-6) UNRELEASED; urgency=medium
+
+ * Backport patches from ioquake3 to fix long-standing security bugs:
+ - CVE-2006-2082: arbitrary file download from server by a malicious client
+ - CVE-2006-2236 ("the remapShader exploit"): missing bounds-checking on
+ COM_StripExtension, exploitable in clients of a malicious server
+ - CVE-2006-2875 ("q3cbof"): buffer overflow in CL_ParseDownload by a
+ malicious server
+ - CVE-2006-3324: arbitrary file overwriting in clients of a malicious
+ server
+ - CVE-2006-3325: arbitrary cvar overwriting (could lead to arbitrary
+ code execution) in clients of a malicious server
+ - CVE-2011-3012, CVE-2011-2764: DLL overwriting (leading to arbitrary
+ code execution) in clients of a malicious server if auto-downloading
+ is enabled
+
+ -- Simon McVittie <smcv at debian.org> Sun, 11 Dec 2011 17:35:38 +0000
+
tremulous (1.1.0-5) unstable; urgency=low
* New maintainer - Debian Games Team
diff --git a/debian/patches/0010-CVE-2006-2082-do-not-allow-download-of-arbitrary-fil.patch b/debian/patches/0010-CVE-2006-2082-do-not-allow-download-of-arbitrary-fil.patch
new file mode 100644
index 0000000..a41f689
--- /dev/null
+++ b/debian/patches/0010-CVE-2006-2082-do-not-allow-download-of-arbitrary-fil.patch
@@ -0,0 +1,97 @@
+From: Simon McVittie <smcv at debian.org>
+Date: Sat, 18 Feb 2012 20:33:51 +0000
+Subject: CVE-2006-2082 - do not allow download of arbitrary files from a
+ server
+
+Any file readable by the server user could be read, via ../ sequences.
+
+Original patches by Thilo Schulz, ioquake3 r777 (which fixed the
+vulnerability) and r781 (which fixed a regression in r777 where
+uninitialized variables led to some allowed downloads being rejected too).
+
+Origin: backport
+Bug-CVE: http://security-tracker.debian.org/tracker/CVE-2006-2082
+---
+ src/server/sv_client.c | 51 ++++++++++++++++++++++++++++++++++++++++-------
+ 1 files changed, 43 insertions(+), 8 deletions(-)
+
+diff --git a/src/server/sv_client.c b/src/server/sv_client.c
+index 0272fab..53f5998 100644
+--- a/src/server/sv_client.c
++++ b/src/server/sv_client.c
+@@ -618,24 +618,57 @@ void SV_WriteDownloadToClient( client_t *cl , msg_t *msg )
+ int curindex;
+ int rate;
+ int blockspersnap;
+- int idPack, missionPack;
++ int idPack = 0, missionPack = 0, unreferenced = 1;
+ char errorMessage[1024];
++ char pakbuf[MAX_QPATH], *pakptr;
++ int numRefPaks;
+
+ if (!*cl->downloadName)
+ return; // Nothing being downloaded
+
+ if (!cl->download) {
+- // We open the file here
++ // Chop off filename extension.
++ Com_sprintf(pakbuf, sizeof(pakbuf), "%s", cl->downloadName);
++ pakptr = Q_strrchr(pakbuf, '.');
+
+- Com_Printf( "clientDownload: %d : begining \"%s\"\n", cl - svs.clients, cl->downloadName );
++ if (pakptr)
++ {
++ *pakptr = '\0';
+
+- missionPack = FS_idPak(cl->downloadName, "missionpack");
+- idPack = missionPack || FS_idPak(cl->downloadName, "baseq3");
++ // Check for pk3 filename extension
++ if(!Q_stricmp(pakptr + 1, "pk3"))
++ {
++ const char *referencedPaks = FS_ReferencedPakNames();
++
++ // Check whether the file appears in the list of referenced
++ // paks to prevent downloading of arbitrary files
++ Cmd_TokenizeStringIgnoreQuotes(referencedPaks);
++ numRefPaks = Cmd_Argc();
++
++ for(curindex = 0; curindex < numRefPaks; curindex++)
++ {
++ if(!FS_FilenameCompare(Cmd_Argv(curindex), pakbuf))
++ {
++ unreferenced = 0;
++ // now that we know the file is referenced, check whether it's legal to download it.
++ missionPack = FS_idPak(pakbuf, "missionpack");
++ idPack = missionPack || FS_idPak(pakbuf, BASEGAME);
++ break;
++ }
++ }
++ }
++ }
+
+- if ( !sv_allowDownload->integer || idPack ||
++ // We open the file here
++ if ( !sv_allowDownload->integer || idPack || unreferenced ||
+ ( cl->downloadSize = FS_SV_FOpenFileRead( cl->downloadName, &cl->download ) ) <= 0 ) {
+ // cannot auto-download file
+- if (idPack) {
++ if(unreferenced)
++ {
++ Com_Printf("clientDownload: %d : \"%s\" is not referenced and cannot be downloaded.\n", cl - svs.clients, cl->downloadName);
++ Com_sprintf(errorMessage, sizeof(errorMessage), "File \"%s\" is not referenced and cannot be downloaded.", cl->downloadName);
++ }
++ else if (idPack) {
+ Com_Printf("clientDownload: %d : \"%s\" cannot download id pk3 files\n", cl - svs.clients, cl->downloadName);
+ if (missionPack) {
+ Com_sprintf(errorMessage, sizeof(errorMessage), "Cannot autodownload Team Arena file \"%s\"\n"
+@@ -670,7 +703,9 @@ void SV_WriteDownloadToClient( client_t *cl , msg_t *msg )
+ *cl->downloadName = 0;
+ return;
+ }
+-
++
++ Com_Printf( "clientDownload: %d : beginning \"%s\"\n", cl - svs.clients, cl->downloadName );
++
+ // Init
+ cl->downloadCurrentBlock = cl->downloadClientBlock = cl->downloadXmitBlock = 0;
+ cl->downloadCount = 0;
diff --git a/debian/patches/0011-CVE-2006-2236-add-bounds-checking-to-COM_StripExtens.patch b/debian/patches/0011-CVE-2006-2236-add-bounds-checking-to-COM_StripExtens.patch
new file mode 100644
index 0000000..0819d5f
--- /dev/null
+++ b/debian/patches/0011-CVE-2006-2236-add-bounds-checking-to-COM_StripExtens.patch
@@ -0,0 +1,197 @@
+From: Simon McVittie <smcv at debian.org>
+Date: Fri, 18 Nov 2011 18:44:44 +0000
+Subject: CVE-2006-2236 - add bounds-checking to COM_StripExtension
+
+This fixes the "remapShader" exploit by backporting ioquake3 r765, with
+a further change to avoid strncpy'ing a string into itself.
+Original patch by Thilo Schulz.
+
+Origin: backport
+Bug-CVE: http://security-tracker.debian.org/tracker/CVE-2006-2236
+Bug-Fedora: https://bugzilla.redhat.com/show_bug.cgi?id=455458
+---
+ src/cgame/cg_weapons.c | 6 +++---
+ src/client/cl_main.c | 2 +-
+ src/qcommon/files.c | 2 +-
+ src/qcommon/q_shared.c | 6 ++++--
+ src/qcommon/q_shared.h | 2 +-
+ src/qcommon/vm.c | 2 +-
+ src/renderer/tr_bsp.c | 2 +-
+ src/renderer/tr_shader.c | 6 +++---
+ src/ui/ui_main.c | 2 +-
+ src/ui/ui_players.c | 4 ++--
+ 10 files changed, 18 insertions(+), 16 deletions(-)
+
+diff --git a/src/cgame/cg_weapons.c b/src/cgame/cg_weapons.c
+index ecb2499..87a9b4c 100644
+--- a/src/cgame/cg_weapons.c
++++ b/src/cgame/cg_weapons.c
+@@ -503,17 +503,17 @@ static qboolean CG_ParseWeaponFile( const char *filename, weaponInfo_t *wi )
+ CG_Printf( S_COLOR_RED "ERROR: weapon model not found %s\n", token );
+
+ strcpy( path, token );
+- COM_StripExtension( path, path );
++ COM_StripExtension( path, path, sizeof(path) );
+ strcat( path, "_flash.md3" );
+ wi->flashModel = trap_R_RegisterModel( path );
+
+ strcpy( path, token );
+- COM_StripExtension( path, path );
++ COM_StripExtension( path, path, sizeof(path) );
+ strcat( path, "_barrel.md3" );
+ wi->barrelModel = trap_R_RegisterModel( path );
+
+ strcpy( path, token );
+- COM_StripExtension( path, path );
++ COM_StripExtension( path, path, sizeof(path) );
+ strcat( path, "_hand.md3" );
+ wi->handsModel = trap_R_RegisterModel( path );
+
+diff --git a/src/client/cl_main.c b/src/client/cl_main.c
+index 3db1d6d..7b562bd 100644
+--- a/src/client/cl_main.c
++++ b/src/client/cl_main.c
+@@ -2014,7 +2014,7 @@ void CL_Frame ( int msec ) {
+ }
+
+ Q_strncpyz( mapName, COM_SkipPath( cl.mapname ), sizeof( cl.mapname ) );
+- COM_StripExtension( mapName, mapName );
++ COM_StripExtension(mapName, mapName, sizeof(mapName));
+
+ Cbuf_ExecuteText( EXEC_NOW,
+ va( "record %s-%s-%s", nowString, serverName, mapName ) );
+diff --git a/src/qcommon/files.c b/src/qcommon/files.c
+index 84db5b1..67f375c 100644
+--- a/src/qcommon/files.c
++++ b/src/qcommon/files.c
+@@ -3377,7 +3377,7 @@ void FS_FilenameCompletion( const char *dir, const char *ext,
+ Q_strncpyz( filename, filenames[ i ], MAX_STRING_CHARS );
+
+ if( stripExt ) {
+- COM_StripExtension( filename, filename );
++ COM_StripExtension(filename, filename, sizeof(filename));
+ }
+
+ callback( filename );
+diff --git a/src/qcommon/q_shared.c b/src/qcommon/q_shared.c
+index 9f152d6..44085cc 100644
+--- a/src/qcommon/q_shared.c
++++ b/src/qcommon/q_shared.c
+@@ -59,10 +59,12 @@ char *COM_SkipPath (char *pathname)
+ COM_StripExtension
+ ============
+ */
+-void COM_StripExtension( const char *in, char *out ) {
++void COM_StripExtension( const char *in, char *out, int destsize ) {
+ int length;
+
+- strcpy( out, in );
++ if (in != out) {
++ Q_strncpyz(out, in, destsize);
++ }
+
+ length = strlen(out)-1;
+ while (length > 0 && out[length] != '.')
+diff --git a/src/qcommon/q_shared.h b/src/qcommon/q_shared.h
+index 0059cdf..03b2e03 100644
+--- a/src/qcommon/q_shared.h
++++ b/src/qcommon/q_shared.h
+@@ -627,7 +627,7 @@ vec_t DistanceBetweenLineSegments(
+ float Com_Clamp( float min, float max, float value );
+
+ char *COM_SkipPath( char *pathname );
+-void COM_StripExtension( const char *in, char *out );
++void COM_StripExtension(const char *in, char *out, int destsize);
+ void COM_DefaultExtension( char *path, int maxSize, const char *extension );
+
+ void COM_BeginParseSession( const char *name );
+diff --git a/src/qcommon/vm.c b/src/qcommon/vm.c
+index 0235ffe..8fb588d 100644
+--- a/src/qcommon/vm.c
++++ b/src/qcommon/vm.c
+@@ -231,7 +231,7 @@ void VM_LoadSymbols( vm_t *vm ) {
+ return;
+ }
+
+- COM_StripExtension( vm->name, name );
++ COM_StripExtension(vm->name, name, sizeof(name));
+ Com_sprintf( symbols, sizeof( symbols ), "vm/%s.map", name );
+ len = FS_ReadFile( symbols, (void **)&mapfile );
+ if ( !mapfile ) {
+diff --git a/src/renderer/tr_bsp.c b/src/renderer/tr_bsp.c
+index eb57da8..2eff834 100644
+--- a/src/renderer/tr_bsp.c
++++ b/src/renderer/tr_bsp.c
+@@ -1824,7 +1824,7 @@ void RE_LoadWorldMap( const char *name ) {
+ Q_strncpyz( s_worldData.name, name, sizeof( s_worldData.name ) );
+
+ Q_strncpyz( s_worldData.baseName, COM_SkipPath( s_worldData.name ), sizeof( s_worldData.name ) );
+- COM_StripExtension( s_worldData.baseName, s_worldData.baseName );
++ COM_StripExtension(s_worldData.baseName, s_worldData.baseName, sizeof(s_worldData.baseName));
+
+ startMarker = ri.Hunk_Alloc(0, h_low);
+ c_gridVerts = 0;
+diff --git a/src/renderer/tr_shader.c b/src/renderer/tr_shader.c
+index 380f9bf..c349b15 100644
+--- a/src/renderer/tr_shader.c
++++ b/src/renderer/tr_shader.c
+@@ -96,7 +96,7 @@ void R_RemapShader(const char *shaderName, const char *newShaderName, const char
+
+ // remap all the shaders with the given name
+ // even tho they might have different lightmaps
+- COM_StripExtension( shaderName, strippedName );
++ COM_StripExtension(shaderName, strippedName, sizeof(strippedName));
+ hash = generateHashValue(strippedName, FILE_HASH_SIZE);
+ for (sh = hashTable[hash]; sh; sh = sh->next) {
+ if (Q_stricmp(sh->name, strippedName) == 0) {
+@@ -2366,7 +2366,7 @@ shader_t *R_FindShaderByName( const char *name ) {
+ return tr.defaultShader;
+ }
+
+- COM_StripExtension( name, strippedName );
++ COM_StripExtension(name, strippedName, sizeof(strippedName));
+
+ hash = generateHashValue(strippedName, FILE_HASH_SIZE);
+
+@@ -2434,7 +2434,7 @@ shader_t *R_FindShader( const char *name, int lightmapIndex, qboolean mipRawImag
+ lightmapIndex = LIGHTMAP_BY_VERTEX;
+ }
+
+- COM_StripExtension( name, strippedName );
++ COM_StripExtension(name, strippedName, sizeof(strippedName));
+
+ hash = generateHashValue(strippedName, FILE_HASH_SIZE);
+
+diff --git a/src/ui/ui_main.c b/src/ui/ui_main.c
+index 7509d9b..604e709 100644
+--- a/src/ui/ui_main.c
++++ b/src/ui/ui_main.c
+@@ -5376,7 +5376,7 @@ static void UI_BuildQ3Model_List( void )
+ {
+ filelen = strlen(fileptr);
+
+- COM_StripExtension(fileptr,skinname);
++ COM_StripExtension(fileptr, skinname, sizeof(skinname));
+
+ // look for icon_????
+ if (Q_stricmpn(skinname, "icon_", 5) == 0 && !(Q_stricmp(skinname,"icon_blue") == 0 || Q_stricmp(skinname,"icon_red") == 0))
+diff --git a/src/ui/ui_players.c b/src/ui/ui_players.c
+index 5dbfdd3..f7baf31 100644
+--- a/src/ui/ui_players.c
++++ b/src/ui/ui_players.c
+@@ -84,13 +84,13 @@ tryagain:
+
+ if ( weaponNum == WP_MACHINEGUN ) {
+ strcpy( path, item->world_model[0] );
+- COM_StripExtension( path, path );
++ COM_StripExtension( path, path, sizeof(path) );
+ strcat( path, "_barrel.md3" );
+ pi->barrelModel = trap_R_RegisterModel( path );
+ }
+
+ strcpy( path, item->world_model[0] );
+- COM_StripExtension( path, path );
++ COM_StripExtension( path, path, sizeof(path) );
+ strcat( path, "_flash.md3" );
+ pi->flashModel = trap_R_RegisterModel( path );
+
diff --git a/debian/patches/0012-CVE-2006-2875-fix-stack-buffer-overflow-in-CL_ParseD.patch b/debian/patches/0012-CVE-2006-2875-fix-stack-buffer-overflow-in-CL_ParseD.patch
new file mode 100644
index 0000000..12f9c78
--- /dev/null
+++ b/debian/patches/0012-CVE-2006-2875-fix-stack-buffer-overflow-in-CL_ParseD.patch
@@ -0,0 +1,73 @@
+From: Simon McVittie <smcv at debian.org>
+Date: Fri, 18 Nov 2011 20:56:32 +0000
+Subject: CVE-2006-2875 - fix stack buffer overflow in CL_ParseDownload
+
+This is exploitable by a modified server. Original patch by Thilo
+Schulz, ioquake3 r796.
+
+Origin: backport
+Bug-CVE: http://security-tracker.debian.org/tracker/CVE-2006-2875
+---
+ src/client/cl_parse.c | 28 ++++++++++++++++++++--------
+ 1 files changed, 20 insertions(+), 8 deletions(-)
+
+diff --git a/src/client/cl_parse.c b/src/client/cl_parse.c
+index 7f219b3..dc14cd6 100644
+--- a/src/client/cl_parse.c
++++ b/src/client/cl_parse.c
+@@ -256,6 +256,13 @@ void CL_ParseSnapshot( msg_t *msg ) {
+
+ // read areamask
+ len = MSG_ReadByte( msg );
++
++ if(len > sizeof(newSnap.areamask))
++ {
++ Com_Error (ERR_DROP,"CL_ParseSnapshot: Invalid size %d for areamask.", len);
++ return;
++ }
++
+ MSG_ReadData( msg, &newSnap.areamask, len);
+
+ // read playerinfo
+@@ -476,6 +483,12 @@ void CL_ParseDownload ( msg_t *msg ) {
+ unsigned char data[MAX_MSGLEN];
+ int block;
+
++ if (!*clc.downloadTempName) {
++ Com_Printf("Server sending download, but no download was requested\n");
++ CL_AddReliableCommand( "stopdl" );
++ return;
++ }
++
+ // read the data
+ block = MSG_ReadShort ( msg );
+
+@@ -494,8 +507,13 @@ void CL_ParseDownload ( msg_t *msg ) {
+ }
+
+ size = MSG_ReadShort ( msg );
+- if (size > 0)
+- MSG_ReadData( msg, data, size );
++ if (size < 0 || size > sizeof(data))
++ {
++ Com_Error(ERR_DROP, "CL_ParseDownload: Invalid size %d for download chunk.", size);
++ return;
++ }
++
++ MSG_ReadData(msg, data, size);
+
+ if (clc.downloadBlock != block) {
+ Com_DPrintf( "CL_ParseDownload: Expected block %d, got %d\n", clc.downloadBlock, block);
+@@ -505,12 +523,6 @@ void CL_ParseDownload ( msg_t *msg ) {
+ // open the file if not opened yet
+ if (!clc.download)
+ {
+- if (!*clc.downloadTempName) {
+- Com_Printf("Server sending download, but no download was requested\n");
+- CL_AddReliableCommand( "stopdl" );
+- return;
+- }
+-
+ clc.download = FS_SV_FOpenFileWrite( clc.downloadTempName );
+
+ if (!clc.download) {
diff --git a/debian/patches/0013-CVE-2006-3324-fix-arbitrary-file-overwrite-on-client.patch b/debian/patches/0013-CVE-2006-3324-fix-arbitrary-file-overwrite-on-client.patch
new file mode 100644
index 0000000..1fd00bc
--- /dev/null
+++ b/debian/patches/0013-CVE-2006-3324-fix-arbitrary-file-overwrite-on-client.patch
@@ -0,0 +1,135 @@
+From: Simon McVittie <smcv at debian.org>
+Date: Mon, 20 Feb 2012 21:57:46 +0000
+Subject: CVE-2006-3324 - fix arbitrary file overwrite on client by malicious
+ server
+
+Original patches by Thilo Schulz, ioquake3 r790, r794, r804.
+This commit also includes "a few sanity checks for checksum/pakname storage
+to fix a crash that can occur under certain circumstances", from r804
+and r805.
+
+Bug-CVE: http://security-tracker.debian.org/tracker/CVE-2006-3324
+Origin: backport
+---
+ src/qcommon/files.c | 51 +++++++++++++++++++++++++++++++++++++++------------
+ 1 files changed, 39 insertions(+), 12 deletions(-)
+
+diff --git a/src/qcommon/files.c b/src/qcommon/files.c
+index 67f375c..34afb4b 100644
+--- a/src/qcommon/files.c
++++ b/src/qcommon/files.c
+@@ -2591,15 +2591,16 @@ we are not interested in a download string format, we want something human-reada
+ qboolean FS_ComparePaks( char *neededpaks, int len, qboolean dlstring ) {
+ searchpath_t *sp;
+ qboolean havepak, badchecksum;
++ char *origpos = neededpaks;
+ int i;
+
+- if ( !fs_numServerReferencedPaks ) {
++ if (!fs_numServerReferencedPaks)
+ return qfalse; // Server didn't send any pack information along
+- }
+
+ *neededpaks = 0;
+
+- for ( i = 0 ; i < fs_numServerReferencedPaks ; i++ ) {
++ for ( i = 0 ; i < fs_numServerReferencedPaks ; i++ )
++ {
+ // Ok, see if we have this pak file
+ badchecksum = qfalse;
+ havepak = qfalse;
+@@ -2609,6 +2610,13 @@ qboolean FS_ComparePaks( char *neededpaks, int len, qboolean dlstring ) {
+ continue;
+ }
+
++ // Make sure the server cannot make us write to non-quake3 directories.
++ if(strstr(fs_serverReferencedPakNames[i], "../") || strstr(fs_serverReferencedPakNames[i], "..\\"))
++ {
++ Com_Printf("WARNING: Invalid download name %s\n", fs_serverReferencedPakNames[i]);
++ continue;
++ }
++
+ for ( sp = fs_searchpaths ; sp ; sp = sp->next ) {
+ if ( sp->pack && sp->pack->checksum == fs_serverReferencedPaks[i] ) {
+ havepak = qtrue; // This is it!
+@@ -2621,6 +2629,12 @@ qboolean FS_ComparePaks( char *neededpaks, int len, qboolean dlstring ) {
+
+ if (dlstring)
+ {
++ // We need this to make sure we won't hit the end of the buffer or the server could
++ // overwrite non-pk3 files on clients by writing so much crap into neededpaks that
++ // Q_strcat cuts off the .pk3 extension.
++
++ origpos += strlen(origpos);
++
+ // Remote name
+ Q_strcat( neededpaks, len, "@");
+ Q_strcat( neededpaks, len, fs_serverReferencedPakNames[i] );
+@@ -2641,6 +2655,14 @@ qboolean FS_ComparePaks( char *neededpaks, int len, qboolean dlstring ) {
+ Q_strcat( neededpaks, len, fs_serverReferencedPakNames[i] );
+ Q_strcat( neededpaks, len, ".pk3" );
+ }
++
++ // Find out whether it might have overflowed the buffer and don't add this file to the
++ // list if that is the case.
++ if(strlen(origpos) + (origpos - neededpaks) >= len - 1)
++ {
++ *origpos = '\0';
++ break;
++ }
+ }
+ else
+ {
+@@ -3146,7 +3168,7 @@ checksums to see if any pk3 files need to be auto-downloaded.
+ =====================
+ */
+ void FS_PureServerSetReferencedPaks( const char *pakSums, const char *pakNames ) {
+- int i, c, d;
++ int i, c, d = 0;
+
+ Cmd_TokenizeString( pakSums );
+
+@@ -3155,30 +3177,35 @@ void FS_PureServerSetReferencedPaks( const char *pakSums, const char *pakNames )
+ c = MAX_SEARCH_PATHS;
+ }
+
+- fs_numServerReferencedPaks = c;
+-
+ for ( i = 0 ; i < c ; i++ ) {
+ fs_serverReferencedPaks[i] = atoi( Cmd_Argv( i ) );
+ }
+
+- for ( i = 0 ; i < c ; i++ ) {
+- if (fs_serverReferencedPakNames[i]) {
++ for (i = 0 ; i < sizeof(fs_serverReferencedPakNames) / sizeof(*fs_serverReferencedPakNames); i++)
++ {
++ if(fs_serverReferencedPakNames[i])
+ Z_Free(fs_serverReferencedPakNames[i]);
+- }
++
+ fs_serverReferencedPakNames[i] = NULL;
+ }
++
+ if ( pakNames && *pakNames ) {
+ Cmd_TokenizeString( pakNames );
+
+ d = Cmd_Argc();
+- if ( d > MAX_SEARCH_PATHS ) {
+- d = MAX_SEARCH_PATHS;
+- }
++ if(d > c)
++ d = c;
+
+ for ( i = 0 ; i < d ; i++ ) {
+ fs_serverReferencedPakNames[i] = CopyString( Cmd_Argv( i ) );
+ }
+ }
++
++ // ensure that there are as many checksums as there are pak names.
++ if(d < c)
++ c = d;
++
++ fs_numServerReferencedPaks = c;
+ }
+
+ /*
diff --git a/debian/patches/0014-CVE-2006-3325-fix-arbitrary-cvar-overwriting.patch b/debian/patches/0014-CVE-2006-3325-fix-arbitrary-cvar-overwriting.patch
new file mode 100644
index 0000000..8a5f432
--- /dev/null
+++ b/debian/patches/0014-CVE-2006-3325-fix-arbitrary-cvar-overwriting.patch
@@ -0,0 +1,156 @@
+From: Simon McVittie <smcv at debian.org>
+Date: Fri, 18 Nov 2011 21:03:07 +0000
+Subject: CVE-2006-3325: fix arbitrary cvar overwriting
+
+Original patch by Thilo Schulz, ioquake3 r811.
+
+Bug-CVE: http://security-tracker.debian.org/tracker/CVE-2006-3325
+Origin: backport
+---
+ src/client/cl_parse.c | 23 +++++++++++++++++++++--
+ src/qcommon/cvar.c | 14 ++++++++++++++
+ src/qcommon/files.c | 19 ++++++++++++++++++-
+ src/qcommon/q_shared.h | 3 +++
+ src/qcommon/qcommon.h | 4 ++++
+ 5 files changed, 60 insertions(+), 3 deletions(-)
+
+diff --git a/src/client/cl_parse.c b/src/client/cl_parse.c
+index dc14cd6..2d36aa1 100644
+--- a/src/client/cl_parse.c
++++ b/src/client/cl_parse.c
+@@ -369,16 +369,35 @@ void CL_SystemInfoChanged( void ) {
+ // scan through all the variables in the systeminfo and locally set cvars to match
+ s = systemInfo;
+ while ( s ) {
++ int cvar_flags;
++
+ Info_NextPair( &s, key, value );
+ if ( !key[0] ) {
+ break;
+ }
++
+ // ehw!
+- if ( !Q_stricmp( key, "fs_game" ) ) {
++ if (!Q_stricmp(key, "fs_game"))
++ {
++ if(FS_CheckDirTraversal(value))
++ {
++ Com_Printf("WARNING: Server sent invalid fs_game value %s\n", value);
++ continue;
++ }
++
+ gameSet = qtrue;
+ }
+
+- Cvar_Set( key, value );
++ if((cvar_flags = Cvar_Flags(key)) == CVAR_NONEXISTENT)
++ Cvar_Get(key, value, CVAR_SERVER_CREATED | CVAR_ROM);
++ else
++ {
++ // If this cvar may not be modified by a server discard the value.
++ if(!(cvar_flags & (CVAR_SYSTEMINFO | CVAR_SERVER_CREATED)))
++ continue;
++
++ Cvar_Set(key, value);
++ }
+ }
+ // if game folder should not be set and it is set at the client side
+ if ( !gameSet && *Cvar_VariableString("fs_game") ) {
+diff --git a/src/qcommon/cvar.c b/src/qcommon/cvar.c
+index a306d88..f6caea8 100644
+--- a/src/qcommon/cvar.c
++++ b/src/qcommon/cvar.c
+@@ -162,6 +162,20 @@ void Cvar_VariableStringBuffer( const char *var_name, char *buffer, int bufsize
+ }
+ }
+
++/*
++============
++Cvar_Flags
++============
++*/
++int Cvar_Flags(const char *var_name)
++{
++ cvar_t *var;
++
++ if(! (var = Cvar_FindVar(var_name)) )
++ return CVAR_NONEXISTENT;
++ else
++ return var->flags;
++}
+
+ /*
+ ============
+diff --git a/src/qcommon/files.c b/src/qcommon/files.c
+index 34afb4b..49390a0 100644
+--- a/src/qcommon/files.c
++++ b/src/qcommon/files.c
+@@ -2564,6 +2564,23 @@ qboolean FS_idPak( char *pak, char *base ) {
+
+ /*
+ ================
++FS_idPak
++
++Check whether the string contains stuff like "../" to prevent directory traversal bugs
++and return qtrue if it does.
++================
++*/
++
++qboolean FS_CheckDirTraversal(const char *checkdir)
++{
++ if(strstr(checkdir, "../") || strstr(checkdir, "..\\"))
++ return qtrue;
++
++ return qfalse;
++}
++
++/*
++================
+ FS_ComparePaks
+
+ ----------------
+@@ -2611,7 +2628,7 @@ qboolean FS_ComparePaks( char *neededpaks, int len, qboolean dlstring ) {
+ }
+
+ // Make sure the server cannot make us write to non-quake3 directories.
+- if(strstr(fs_serverReferencedPakNames[i], "../") || strstr(fs_serverReferencedPakNames[i], "..\\"))
++ if(FS_CheckDirTraversal(fs_serverReferencedPakNames[i]))
+ {
+ Com_Printf("WARNING: Invalid download name %s\n", fs_serverReferencedPakNames[i]);
+ continue;
+diff --git a/src/qcommon/q_shared.h b/src/qcommon/q_shared.h
+index 03b2e03..d491708 100644
+--- a/src/qcommon/q_shared.h
++++ b/src/qcommon/q_shared.h
+@@ -795,6 +795,9 @@ default values.
+ #define CVAR_CHEAT 512 // can not be changed if cheats are disabled
+ #define CVAR_NORESTART 1024 // do not clear when a cvar_restart is issued
+
++#define CVAR_SERVER_CREATED 2048 // cvar was created by a server the client connected to.
++#define CVAR_NONEXISTENT 0xFFFFFFFF // Cvar doesn't exist.
++
+ // nothing outside the Cvar_*() functions should modify these fields!
+ typedef struct cvar_s {
+ char *name;
+diff --git a/src/qcommon/qcommon.h b/src/qcommon/qcommon.h
+index e6ae058..7b2fb8a 100644
+--- a/src/qcommon/qcommon.h
++++ b/src/qcommon/qcommon.h
+@@ -477,6 +477,9 @@ char *Cvar_VariableString( const char *var_name );
+ void Cvar_VariableStringBuffer( const char *var_name, char *buffer, int bufsize );
+ // returns an empty string if not defined
+
++int Cvar_Flags(const char *var_name);
++// returns CVAR_NONEXISTENT if cvar doesn't exist or the flags of that particular CVAR.
++
+ void Cvar_CommandCompletion( void(*callback)(const char *s) );
+ // callback with each valid string
+
+@@ -647,6 +650,7 @@ void FS_PureServerSetLoadedPaks( const char *pakSums, const char *pakNames );
+ // separated checksums will be checked for files, with the
+ // sole exception of .cfg files.
+
++qboolean FS_CheckDirTraversal(const char *checkdir);
+ qboolean FS_idPak( char *pak, char *base );
+ qboolean FS_ComparePaks( char *neededpaks, int len, qboolean dlstring );
+
diff --git a/debian/patches/0015-CVE-2011-3012-CVE-2011-2764-backport-from-ioquake3-t.patch b/debian/patches/0015-CVE-2011-3012-CVE-2011-2764-backport-from-ioquake3-t.patch
new file mode 100644
index 0000000..12adb99
--- /dev/null
+++ b/debian/patches/0015-CVE-2011-3012-CVE-2011-2764-backport-from-ioquake3-t.patch
@@ -0,0 +1,171 @@
+From: Simon McVittie <smcv at 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-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
+--- a/src/qcommon/files.c
++++ b/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
+--- a/src/qcommon/q_shared.c
++++ b/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
+--- a/src/qcommon/q_shared.h
++++ b/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 );
diff --git a/debian/patches/series b/debian/patches/series
index 14204cd..012065f 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -7,3 +7,9 @@
0007-Fix-to-disappearing-cursor-on-map-load-Com_Error-bug.patch
0008-Fixed-sort-by-ping.patch
0009-Disable-JIT-QVM-interpreter-on-x86-64.patch
+0010-CVE-2006-2082-do-not-allow-download-of-arbitrary-fil.patch
+0011-CVE-2006-2236-add-bounds-checking-to-COM_StripExtens.patch
+0012-CVE-2006-2875-fix-stack-buffer-overflow-in-CL_ParseD.patch
+0013-CVE-2006-3324-fix-arbitrary-file-overwrite-on-client.patch
+0014-CVE-2006-3325-fix-arbitrary-cvar-overwriting.patch
+0015-CVE-2011-3012-CVE-2011-2764-backport-from-ioquake3-t.patch
--
team based FPS game - packaging
More information about the Pkg-games-commits
mailing list