CVE-2017-6903: Insufficient Information (NVD-CWE-noinfo)
value: In ioquake3 before 2017-03-14, the auto-downloading feature has insufficient content restrictions. This also affects Quake III Arena, OpenArena, OpenJK, iortcw, and other id Tech 3 (aka Quake 3 engine) forks. A malicious auto-downloaded file can trigger loading of crafted auto-downloaded files as native code DLLs. A malicious auto-downloaded file can contain configuration defaults that override the user's. Executable bytecode in a malicious auto-downloaded file can set configuration variables to values that will result in unwanted native code DLLs being loaded, resulting in sandbox escape.
CWE description: There is insufficient information about the issue to classify it; details are unkown or unspecified.
CVSS v3 base score: 7.8
Published: 2017-03-14T22:59Z
Repository: https://github.com/JACoders/OpenJK
Language: C++
Files changed: code/client/cl_main.cpp, code/qcommon/files.cpp, codemp/client/cl_main.cpp, codemp/qcommon/files.cpp, shared/sys/sys_main.cpp
Commit date: 2017-03-13 22:20:58 -0500
Commit message: Shared: Merge ioquake/ioq3@376267d534476a875d8b9228149c4ee18b74a4fd

Don't load .pk3s as .dlls, and don't load user config files from .pk3s.
Diff: diff --git a/code/client/cl_main.cpp b/code/client/cl_main.cpp
index 43e36de4..bac6e4c5 100644
--- a/code/client/cl_main.cpp
+++ b/code/client/cl_main.cpp
@@ -1082,11 +1082,11 @@ void CL_InitRef( void ) {
 	static refimport_t rit;
 	char		dllName[MAX_OSPATH];
 	GetRefAPI_t	GetRefAPI;
 
 	Com_Printf( "----- Initializing Renderer ----\n" );
-    cl_renderer = Cvar_Get( "cl_renderer", DEFAULT_RENDER_LIBRARY, CVAR_ARCHIVE|CVAR_LATCH );
+    cl_renderer = Cvar_Get( "cl_renderer", DEFAULT_RENDER_LIBRARY, CVAR_ARCHIVE|CVAR_LATCH|CVAR_PROTECTED );
 
 	Com_sprintf( dllName, sizeof( dllName ), "%s_" ARCH_STRING DLL_EXT, cl_renderer->string );
 
 	if( !(rendererLib = Sys_LoadDll( dllName, qfalse )) && strcmp( cl_renderer->string, cl_renderer->resetString ) )
 	{
diff --git a/code/qcommon/files.cpp b/code/qcommon/files.cpp
index 24e92908..c35d0e00 100644
--- a/code/qcommon/files.cpp
+++ b/code/qcommon/files.cpp
@@ -1256,10 +1256,11 @@ long FS_FOpenFileRead( const char *filename, fileHandle_t *file, qboolean unique
 	fileInPack_t	*pakFile;
 	directory_t		*dir;
 	long			hash;
 	//unz_s			*zfi;
 	//void			*temp;
+	bool			isUserConfig = false;
 
 	hash = 0;
 
 	FS_AssertInitialised();
 
@@ -1289,10 +1290,12 @@ long FS_FOpenFileRead( const char *filename, fileHandle_t *file, qboolean unique
 	if( com_fullyInitialized && strstr( filename, "q3key" ) ) {
 		*file = 0;
 		return -1;
 	}
 
+	isUserConfig = !Q_stricmp( filename, "autoexec_sp.cfg" ) || !Q_stricmp( filename, Q3CONFIG_NAME );
+
 	//
 	// search through the path, one element at a time
 	//
 
 	*file = FS_HandleForFile();
@@ -1314,10 +1317,15 @@ long FS_FOpenFileRead( const char *filename, fileHandle_t *file, qboolean unique
 			if ( search->pack ) {
 				hash = FS_HashFileName(filename, search->pack->hashSize);
 			}
 			// is the element a pak file?
 			if ( search->pack && search->pack->hashTable[hash] ) {
+				// autoexec_sp.cfg and openjk_sp.cfg can only be loaded outside of pk3 files.
+				if ( isUserConfig ) {
+					continue;
+				}
+
 				// look through all the pak file elements
 				pak = search->pack;
 				pakFile = pak->hashTable[hash];
 				do {
 					// case and separator insensitive comparisons
diff --git a/codemp/client/cl_main.cpp b/codemp/client/cl_main.cpp
index 07d85dbc..3de7f1ae 100644
--- a/codemp/client/cl_main.cpp
+++ b/codemp/client/cl_main.cpp
@@ -2362,11 +2362,11 @@ void CL_InitRef( void ) {
 	GetRefAPI_t	GetRefAPI;
 	char		dllName[MAX_OSPATH];
 
 	Com_Printf( "----- Initializing Renderer ----\n" );
 
-	cl_renderer = Cvar_Get( "cl_renderer", DEFAULT_RENDER_LIBRARY, CVAR_ARCHIVE|CVAR_LATCH, "Which renderer library to use" );
+	cl_renderer = Cvar_Get( "cl_renderer", DEFAULT_RENDER_LIBRARY, CVAR_ARCHIVE|CVAR_LATCH|CVAR_PROTECTED, "Which renderer library to use" );
 
 	Com_sprintf( dllName, sizeof( dllName ), "%s_" ARCH_STRING DLL_EXT, cl_renderer->string );
 
 	if( !(rendererLib = Sys_LoadDll( dllName, qfalse )) && strcmp( cl_renderer->string, cl_renderer->resetString ) )
 	{
diff --git a/codemp/qcommon/files.cpp b/codemp/qcommon/files.cpp
index cd4b5ee6..4fb8b4a9 100644
--- a/codemp/qcommon/files.cpp
+++ b/codemp/qcommon/files.cpp
@@ -1265,10 +1265,11 @@ long FS_FOpenFileRead( const char *filename, fileHandle_t *file, qboolean unique
 	directory_t		*dir;
 	long			hash;
 	//unz_s			*zfi;
 	//void			*temp;
 	int				l;
+	bool			isUserConfig = false;
 
 	hash = 0;
 
 	FS_AssertInitialised();
 
@@ -1298,10 +1299,12 @@ long FS_FOpenFileRead( const char *filename, fileHandle_t *file, qboolean unique
 	if( com_fullyInitialized && strstr( filename, "q3key" ) ) {
 		*file = 0;
 		return -1;
 	}
 
+	isUserConfig = !Q_stricmp( filename, "autoexec.cfg" ) || !Q_stricmp( filename, Q3CONFIG_CFG );
+
 	//
 	// search through the path, one element at a time
 	//
 
 	*file = FS_HandleForFile();
@@ -1328,10 +1331,15 @@ long FS_FOpenFileRead( const char *filename, fileHandle_t *file, qboolean unique
 				// disregard if it doesn't match one of the allowed pure pak files
 				if ( !FS_PakIsPure(search->pack) ) {
 					continue;
 				}
 
+				// autoexec.cfg and openjk.cfg can only be loaded outside of pk3 files.
+				if ( isUserConfig ) {
+					continue;
+				}
+
 				// look through all the pak file elements
 				pak = search->pack;
 				pakFile = pak->hashTable[hash];
 				do {
 					// case and separator insensitive comparisons
diff --git a/shared/sys/sys_main.cpp b/shared/sys/sys_main.cpp
index dafe3195..ac50708c 100644
--- a/shared/sys/sys_main.cpp
+++ b/shared/sys/sys_main.cpp
@@ -296,10 +296,17 @@ from executable path, then fs_basepath.
 */
 void *Sys_LoadDll( const char *name, qboolean useSystemLib )
 {
 	void *dllhandle = NULL;
 
+	// Don't load any DLLs that end with the pk3 extension
+	if ( COM_CompareExtension( name, ".pk3" ) )
+	{
+		Com_Printf( S_COLOR_YELLOW "WARNING: Rejecting DLL named \"%s\"", name );
+		return NULL;
+	}
+
 	if ( useSystemLib )
 	{
 		Com_Printf( "Trying to load \"%s\"...\n", name );
 
 		dllhandle = Sys_LoadLibrary( name );

Vulnerable code:     cl_renderer = Cvar_Get( "cl_renderer", DEFAULT_RENDER_LIBRARY, CVAR_ARCHIVE|CVAR_LATCH );
	cl_renderer = Cvar_Get( "cl_renderer", DEFAULT_RENDER_LIBRARY, CVAR_ARCHIVE|CVAR_LATCH, "Which renderer library to use" );
Fixed code:     cl_renderer = Cvar_Get( "cl_renderer", DEFAULT_RENDER_LIBRARY, CVAR_ARCHIVE|CVAR_LATCH|CVAR_PROTECTED );
	bool			isUserConfig = false;
	isUserConfig = !Q_stricmp( filename, "autoexec_sp.cfg" ) || !Q_stricmp( filename, Q3CONFIG_NAME );

				// autoexec_sp.cfg and openjk_sp.cfg can only be loaded outside of pk3 files.
				if ( isUserConfig ) {
					continue;
				}

	cl_renderer = Cvar_Get( "cl_renderer", DEFAULT_RENDER_LIBRARY, CVAR_ARCHIVE|CVAR_LATCH|CVAR_PROTECTED, "Which renderer library to use" );
	bool			isUserConfig = false;
	isUserConfig = !Q_stricmp( filename, "autoexec.cfg" ) || !Q_stricmp( filename, Q3CONFIG_CFG );

				// autoexec.cfg and openjk.cfg can only be loaded outside of pk3 files.
				if ( isUserConfig ) {
					continue;
				}

	// Don't load any DLLs that end with the pk3 extension
	if ( COM_CompareExtension( name, ".pk3" ) )
	{
		Com_Printf( S_COLOR_YELLOW "WARNING: Rejecting DLL named \"%s\"", name );
		return NULL;
	}