Fix bug that allows a malicious server to write and overwrite any files in the main folder

Fix bug that allows a malicious server to write and overwrite any files in the main folder

diff --git a/src/engine/cm/cm_load_tech3.cpp b/src/engine/cm/cm_load_tech3.cpp
index d1fde1f..51e26b0 100644
--- a/src/engine/cm/cm_load_tech3.cpp
+++ b/src/engine/cm/cm_load_tech3.cpp
@@ -1217,7 +1217,7 @@ void idCollisionModelManagerLocal::LoadMap( pointer name, bool clientload, sint*
     {
         Com_Error( ERR_DROP, "idCollisionModelManagerLocal::LoadMap: %s has wrong version number (%i should be %i)", name, header.version, BSP_VERSION );
     }
-
+    
     cmod_base = ( uchar8* ) buf;
     
     // load into heap
diff --git a/src/engine/framework/FileSystem.cpp b/src/engine/framework/FileSystem.cpp
index 023a255..a046553 100644
--- a/src/engine/framework/FileSystem.cpp
+++ b/src/engine/framework/FileSystem.cpp
@@ -3786,6 +3786,7 @@ bool idFileSystemLocal::ComparePaks( valueType* neededpaks, sint len, bool dlstr
 {
     searchpath_t* sp;
     bool havepak, badchecksum;
+    valueType* origpos = neededpaks;
     sint i;
     
     if( !fs_numServerReferencedPaks )
@@ -3807,6 +3808,13 @@ bool idFileSystemLocal::ComparePaks( valueType* neededpaks, sint len, bool dlstr
             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] )
@@ -3822,6 +3830,8 @@ bool idFileSystemLocal::ComparePaks( valueType* neededpaks, sint len, bool dlstr
             
             if( dlstring )
             {
+                origpos += ::strlen( origpos );
+                
                 // Remote name
                 Q_strcat( neededpaks, len, "@" );
                 Q_strcat( neededpaks, len, fs_serverReferencedPakNames[i] );
@@ -3843,6 +3853,12 @@ bool idFileSystemLocal::ComparePaks( valueType* neededpaks, sint len, bool dlstr
                     Q_strcat( neededpaks, len, fs_serverReferencedPakNames[i] );
                     Q_strcat( neededpaks, len, ".pk3" );
                 }
+                
+                if( ::strlen( origpos ) + ( origpos - neededpaks ) >= len - 1 )
+                {
+                    *origpos = '\0';
+                    break;
+                }
             }
             else
             {
@@ -4461,7 +4477,7 @@ checksums to see if any pk3 files need to be auto-downloaded.
 */
 void idFileSystemLocal::PureServerSetReferencedPaks( pointer pakSums, pointer pakNames )
 {
-    sint i, c, d;
+    sint i, c, d = 0;
     
     cmdSystem->TokenizeString( pakSums );
     
@@ -4471,14 +4487,7 @@ void idFileSystemLocal::PureServerSetReferencedPaks( pointer pakSums, pointer pa
         c = MAX_SEARCH_PATHS;
     }
     
-    fs_numServerReferencedPaks = c;
-    
-    for( i = 0 ; i < c ; i++ )
-    {
-        fs_serverReferencedPaks[i] = atoi( cmdSystem->Argv( i ) );
-    }
-    
-    for( i = 0 ; i < c ; i++ )
+    for( i = 0 ; i < sizeof( fs_serverReferencedPakNames ) / sizeof( *fs_serverReferencedPakNames ); i++ )
     {
         if( fs_serverReferencedPakNames[i] )
         {
@@ -4498,12 +4507,23 @@ void idFileSystemLocal::PureServerSetReferencedPaks( pointer pakSums, pointer pa
         {
             d = MAX_SEARCH_PATHS;
         }
+        else if( d > c )
+        {
+            d = c;
+        }
         
         for( i = 0 ; i < d ; i++ )
         {
             fs_serverReferencedPakNames[i] = CopyString( cmdSystem->Argv( i ) );
         }
     }
+    
+    if( d < c )
+    {
+        c = d;
+    }
+    
+    fs_numServerReferencedPaks = c;
 }
 
 /*

GitHub
sha: ee5f4ff5