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:
Zack Middleton 2018-01-21 04:27:55 -06:00
parent 78ca670d4f
commit 3638f69dff
5 changed files with 54 additions and 32 deletions

View file

@ -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,16 +2442,7 @@ 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));
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 ();