mirror of
https://github.com/DrBeef/ioq3quest.git
synced 2024-11-22 12:01:41 +00:00
Fix fs_game '..' reading outside of home and base path
VMs could set fs_game to '..' at anytime to access files outside of home and base path. fs_game sent by server to clients could also be '..' to access files outside of home and base path. '..' was not caught by FS_CheckDirTraversal() as it expects filenames not a single directory. I've made fs_game be latched to prevent VMs from changing it with no good way to validate it before it's used. com_basegame and fs_basegame are now latched as well. Additionally, it's now possible to change com_basegame while the engine is running. game_restart or vid_restart will make it take affect. com_homepath is now CVAR_PROTECTED to prevent VMs from changing it to a directory traversal. This requires my two previous commits for preventing VMs from changing engine latch cvars and only Cvar_Get fs_game in FS_Startup (so CVAR_INIT isn't added in serveral other places). Reported by Noah Metzger (Chomenor).
This commit is contained in:
parent
78ca670d4f
commit
3638f69dff
5 changed files with 54 additions and 32 deletions
|
@ -1245,7 +1245,7 @@ void CL_ClearMemory(qboolean shutdownRef)
|
|||
CL_ShutdownAll(shutdownRef);
|
||||
|
||||
// if not running a server clear the whole hunk
|
||||
if ( !com_sv_running->integer ) {
|
||||
if ( !com_sv_running || !com_sv_running->integer ) {
|
||||
// clear the whole hunk
|
||||
Hunk_Clear();
|
||||
// clear collision map data
|
||||
|
@ -1361,7 +1361,7 @@ static void CL_OldGame(void)
|
|||
{
|
||||
// change back to previous fs_game
|
||||
cl_oldGameSet = qfalse;
|
||||
Cvar_Set2("fs_game", cl_oldGame, qtrue);
|
||||
Cvar_Set("fs_game", cl_oldGame);
|
||||
FS_ConditionalRestart(clc.checksumFeed, qfalse);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -399,7 +399,7 @@ void CL_SystemInfoChanged( void ) {
|
|||
// ehw!
|
||||
if (!Q_stricmp(key, "fs_game"))
|
||||
{
|
||||
if(FS_CheckDirTraversal(value))
|
||||
if(FS_InvalidGameDir(value))
|
||||
{
|
||||
Com_Printf(S_COLOR_YELLOW "WARNING: Server sent invalid fs_game value %s\n", value);
|
||||
continue;
|
||||
|
|
|
@ -2404,6 +2404,9 @@ void Com_GameRestart(int checksumFeed, qboolean disconnect)
|
|||
CL_Shutdown("Game directory changed", disconnect, qfalse);
|
||||
}
|
||||
|
||||
// change com_basegame to latched value
|
||||
com_basegame = Cvar_Get("com_basegame", BASEGAME, CVAR_LATCH|CVAR_NORESTART);
|
||||
|
||||
FS_Restart(checksumFeed);
|
||||
|
||||
// Clean out any user and VM created cvars
|
||||
|
@ -2439,15 +2442,6 @@ Expose possibility to change current running mod to the user
|
|||
|
||||
void Com_GameRestart_f(void)
|
||||
{
|
||||
if(!FS_FilenameCompare(Cmd_Argv(1), com_basegame->string))
|
||||
{
|
||||
// This is the standard base game. Servers and clients should
|
||||
// use "" and not the standard basegame name because this messes
|
||||
// up pak file negotiation and lots of other stuff
|
||||
|
||||
Cvar_Set("fs_game", "");
|
||||
}
|
||||
else
|
||||
Cvar_Set("fs_game", Cmd_Argv(1));
|
||||
|
||||
Com_GameRestart(0, qtrue);
|
||||
|
@ -2705,11 +2699,8 @@ void Com_Init( char *commandLine ) {
|
|||
CL_InitKeyCommands();
|
||||
|
||||
com_standalone = Cvar_Get("com_standalone", "0", CVAR_ROM);
|
||||
com_basegame = Cvar_Get("com_basegame", BASEGAME, CVAR_INIT);
|
||||
com_homepath = Cvar_Get("com_homepath", "", CVAR_INIT);
|
||||
|
||||
if(!com_basegame->string[0])
|
||||
Cvar_ForceReset("com_basegame");
|
||||
com_basegame = Cvar_Get("com_basegame", BASEGAME, CVAR_LATCH|CVAR_NORESTART);
|
||||
com_homepath = Cvar_Get("com_homepath", "", CVAR_INIT|CVAR_PROTECTED);
|
||||
|
||||
FS_InitFilesystem ();
|
||||
|
||||
|
|
|
@ -3067,6 +3067,24 @@ qboolean FS_CheckDirTraversal(const char *checkdir)
|
|||
return qfalse;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
FS_InvalidGameDir
|
||||
|
||||
return true if path is a reference to current directory or directory traversal
|
||||
================
|
||||
*/
|
||||
qboolean FS_InvalidGameDir( const char *gamedir ) {
|
||||
if ( !strcmp( gamedir, "." ) || !strcmp( gamedir, ".." )
|
||||
|| !strcmp( gamedir, "/" ) || !strcmp( gamedir, "\\" )
|
||||
|| strstr( gamedir, "/.." ) || strstr( gamedir, "\\.." )
|
||||
|| FS_CheckDirTraversal( gamedir ) ) {
|
||||
return qtrue;
|
||||
}
|
||||
|
||||
return qfalse;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
FS_ComparePaks
|
||||
|
@ -3301,13 +3319,34 @@ static void FS_Startup( const char *gameName )
|
|||
|
||||
fs_debug = Cvar_Get( "fs_debug", "0", 0 );
|
||||
fs_basepath = Cvar_Get ("fs_basepath", Sys_DefaultInstallPath(), CVAR_INIT|CVAR_PROTECTED );
|
||||
fs_basegame = Cvar_Get ("fs_basegame", "", CVAR_INIT );
|
||||
fs_basegame = Cvar_Get ("fs_basegame", "", CVAR_LATCH|CVAR_NORESTART );
|
||||
homePath = Sys_DefaultHomePath();
|
||||
if (!homePath || !homePath[0]) {
|
||||
homePath = fs_basepath->string;
|
||||
}
|
||||
fs_homepath = Cvar_Get ("fs_homepath", homePath, CVAR_INIT|CVAR_PROTECTED );
|
||||
fs_gamedirvar = Cvar_Get ("fs_game", "", CVAR_INIT|CVAR_SYSTEMINFO );
|
||||
fs_gamedirvar = Cvar_Get ("fs_game", "", CVAR_LATCH|CVAR_NORESTART|CVAR_SYSTEMINFO );
|
||||
|
||||
if (!gameName[0]) {
|
||||
Cvar_ForceReset( "com_basegame" );
|
||||
}
|
||||
|
||||
if (!FS_FilenameCompare(fs_gamedirvar->string, gameName)) {
|
||||
// This is the standard base game. Servers and clients should
|
||||
// use "" and not the standard basegame name because this messes
|
||||
// up pak file negotiation and lots of other stuff
|
||||
Cvar_ForceReset( "fs_game" );
|
||||
}
|
||||
|
||||
if (FS_InvalidGameDir(gameName)) {
|
||||
Com_Error( ERR_DROP, "Invalid com_basegame '%s'", gameName );
|
||||
}
|
||||
if (FS_InvalidGameDir(fs_basegame->string)) {
|
||||
Com_Error( ERR_DROP, "Invalid fs_basegame '%s'", fs_basegame->string );
|
||||
}
|
||||
if (FS_InvalidGameDir(fs_gamedirvar->string)) {
|
||||
Com_Error( ERR_DROP, "Invalid fs_game '%s'", fs_gamedirvar->string );
|
||||
}
|
||||
|
||||
// add search path elements in reverse priority order
|
||||
fs_gogpath = Cvar_Get ("fs_gogpath", Sys_GogPath(), CVAR_INIT|CVAR_PROTECTED );
|
||||
|
@ -3391,8 +3430,6 @@ static void FS_Startup( const char *gameName )
|
|||
// print the current search paths
|
||||
FS_Path_f();
|
||||
|
||||
fs_gamedirvar->modified = qfalse; // We just loaded, it's not modified
|
||||
|
||||
Com_Printf( "----------------------\n" );
|
||||
|
||||
#ifdef FS_MISSING
|
||||
|
@ -4040,18 +4077,11 @@ Return qtrue if restarting due to game directory changed, qfalse otherwise
|
|||
*/
|
||||
qboolean FS_ConditionalRestart(int checksumFeed, qboolean disconnect)
|
||||
{
|
||||
if(fs_gamedirvar->modified)
|
||||
{
|
||||
if(FS_FilenameCompare(lastValidGame, fs_gamedirvar->string) &&
|
||||
(*lastValidGame || FS_FilenameCompare(fs_gamedirvar->string, com_basegame->string)) &&
|
||||
(*fs_gamedirvar->string || FS_FilenameCompare(lastValidGame, com_basegame->string)))
|
||||
if (com_basegame->latchedString || fs_basegame->latchedString || fs_gamedirvar->latchedString)
|
||||
{
|
||||
Com_GameRestart(checksumFeed, disconnect);
|
||||
return qtrue;
|
||||
}
|
||||
else
|
||||
fs_gamedirvar->modified = qfalse;
|
||||
}
|
||||
|
||||
if(checksumFeed != fs_checksumFeed)
|
||||
FS_Restart(checksumFeed);
|
||||
|
|
|
@ -726,6 +726,7 @@ void FS_PureServerSetLoadedPaks( const char *pakSums, const char *pakNames );
|
|||
// sole exception of .cfg files.
|
||||
|
||||
qboolean FS_CheckDirTraversal(const char *checkdir);
|
||||
qboolean FS_InvalidGameDir(const char *gamedir);
|
||||
qboolean FS_idPak(char *pak, char *base, int numPaks);
|
||||
qboolean FS_ComparePaks( char *neededpaks, int len, qboolean dlstring );
|
||||
|
||||
|
|
Loading…
Reference in a new issue