From 14b56e051483fb3ee623eb70a4b6c54408ba6629 Mon Sep 17 00:00:00 2001 From: s1lentq Date: Wed, 7 Dec 2022 19:15:08 +0700 Subject: [PATCH 01/10] Added more check for possible numleaf overflow Minor refactoring --- rehlds/HLTV/Core/src/BSPModel.cpp | 2 +- rehlds/HLTV/Core/src/BSPModel.h | 5 ++--- rehlds/engine/cmodel.cpp | 6 +++--- rehlds/engine/cmodel.h | 5 ----- rehlds/engine/server.h | 5 ----- rehlds/engine/sv_main.cpp | 13 ++++++++++--- rehlds/public/rehlds/bspfile.h | 1 + 7 files changed, 17 insertions(+), 20 deletions(-) diff --git a/rehlds/HLTV/Core/src/BSPModel.cpp b/rehlds/HLTV/Core/src/BSPModel.cpp index 15f091d0b..65892bcfd 100644 --- a/rehlds/HLTV/Core/src/BSPModel.cpp +++ b/rehlds/HLTV/Core/src/BSPModel.cpp @@ -170,7 +170,7 @@ byte *BSPModel::LeafPVS(mleaf_t *leaf) byte *BSPModel::DecompressVis(unsigned char *in) { - static unsigned char decompressed[MODEL_MAX_PVS]; + static unsigned char decompressed[MAX_MAP_LEAFS / 8]; if (in == nullptr) { return m_novis; } diff --git a/rehlds/HLTV/Core/src/BSPModel.h b/rehlds/HLTV/Core/src/BSPModel.h index 259960fcb..1ceb8dfdc 100644 --- a/rehlds/HLTV/Core/src/BSPModel.h +++ b/rehlds/HLTV/Core/src/BSPModel.h @@ -32,6 +32,7 @@ #include "l_studio.h" #include "edict.h" +#include "bspfile.h" // values for model_t's needload #define NL_PRESENT 0 @@ -87,9 +88,7 @@ class BSPModel: public IBSPModel { protected: model_t m_model; - - enum { MODEL_MAX_PVS = 1024 }; - byte m_novis[MODEL_MAX_PVS]; + byte m_novis[MAX_MAP_LEAFS / 8]; byte *m_base; int m_visframecount; diff --git a/rehlds/engine/cmodel.cpp b/rehlds/engine/cmodel.cpp index 1e4851230..3236e1bb4 100644 --- a/rehlds/engine/cmodel.cpp +++ b/rehlds/engine/cmodel.cpp @@ -31,17 +31,17 @@ unsigned char *gPAS; unsigned char *gPVS; int gPVSRowBytes; -unsigned char mod_novis[MODEL_MAX_PVS]; +unsigned char mod_novis[MAX_MAP_LEAFS / 8]; void Mod_Init(void) { SW_Mod_Init(); - Q_memset(mod_novis, 255, MODEL_MAX_PVS); + Q_memset(mod_novis, 0xFF, MAX_MAP_LEAFS / 8); } unsigned char *Mod_DecompressVis(unsigned char *in, model_t *model) { - static unsigned char decompressed[MODEL_MAX_PVS]; + static unsigned char decompressed[MAX_MAP_LEAFS / 8]; if (in == NULL) { diff --git a/rehlds/engine/cmodel.h b/rehlds/engine/cmodel.h index 5b8d5eb1f..dd99cec07 100644 --- a/rehlds/engine/cmodel.h +++ b/rehlds/engine/cmodel.h @@ -29,15 +29,10 @@ #pragma once #include "maintypes.h" -#include "model.h" - -// Looks like no more than 8096 visibility leafs per world model -const int MODEL_MAX_PVS = 1024; extern unsigned char *gPAS; extern unsigned char *gPVS; extern int gPVSRowBytes; -extern unsigned char mod_novis[MODEL_MAX_PVS]; void Mod_Init(void); unsigned char *Mod_DecompressVis(unsigned char *in, model_t *model); diff --git a/rehlds/engine/server.h b/rehlds/engine/server.h index 2b10515a8..4bdd7efb6 100644 --- a/rehlds/engine/server.h +++ b/rehlds/engine/server.h @@ -405,7 +405,6 @@ enum GameType_e extern GameType_e g_eGameType; -extern int fatbytes; extern int giNextUserMsg; extern int hashstrings_collisions; @@ -418,10 +417,6 @@ extern delta_t *g_pweapondelta; extern delta_t *g_pusercmddelta; #endif -extern unsigned char fatpvs[1024]; -extern int fatpasbytes; -extern unsigned char fatpas[1024]; - extern int gPacketSuppressed; extern char localinfo[MAX_LOCALINFO]; diff --git a/rehlds/engine/sv_main.cpp b/rehlds/engine/sv_main.cpp index cb67538e0..83a3e3cf7 100644 --- a/rehlds/engine/sv_main.cpp +++ b/rehlds/engine/sv_main.cpp @@ -4030,9 +4030,10 @@ void SV_EmitEvents_internal(client_t *cl, packet_entities_t *pack, sizebuf_t *ms } int fatbytes; -unsigned char fatpvs[1024]; +unsigned char fatpvs[MAX_MAP_LEAFS / 8]; + int fatpasbytes; -unsigned char fatpas[1024]; +unsigned char fatpas[MAX_MAP_LEAFS / 8]; void SV_AddToFatPVS(vec_t *org, mnode_t *node) { @@ -4074,6 +4075,9 @@ unsigned char* EXT_FUNC SV_FatPVS(float *org) #endif // REHLDS_FIXES fatbytes = (g_psv.worldmodel->numleafs + 31) >> 3; + if (fatbytes >= (MAX_MAP_LEAFS / 8)) + Sys_Error("%s: MAX_MAP_LEAFS limit exceeded\n", __func__); + Q_memset(fatpvs, 0, fatbytes); SV_AddToFatPVS(org, g_psv.worldmodel->nodes); return fatpvs; @@ -4131,6 +4135,9 @@ unsigned char* EXT_FUNC SV_FatPAS(float *org) #endif // REHLDS_FIXES fatpasbytes = (g_psv.worldmodel->numleafs + 31) >> 3; + if (fatpasbytes >= (MAX_MAP_LEAFS / 8)) + Sys_Error("%s: MAX_MAP_LEAFS limit exceeded\n", __func__); + Q_memset(fatpas, 0, fatpasbytes); SV_AddToFatPAS(org, g_psv.worldmodel->nodes); return fatpas; @@ -6155,7 +6162,7 @@ int SV_SpawnServer(qboolean bIsDemo, char *server, char *startspot) if (g_psvs.maxclients <= 1) { int row = (g_psv.worldmodel->numleafs + 7) / 8; - if (row < 0 || row > MODEL_MAX_PVS) + if (row < 0 || row > (MAX_MAP_LEAFS / 8)) { Sys_Error("%s: oversized g_psv.worldmodel->numleafs: %i", __func__, g_psv.worldmodel->numleafs); } diff --git a/rehlds/public/rehlds/bspfile.h b/rehlds/public/rehlds/bspfile.h index 3c4dfee7b..c3a94bb05 100644 --- a/rehlds/public/rehlds/bspfile.h +++ b/rehlds/public/rehlds/bspfile.h @@ -32,6 +32,7 @@ #define HLBSP_VERSION 30 // half-life regular version #define MAX_MAP_HULLS 4 +#define MAX_MAP_LEAFS 8192 // signed short limit #define CONTENTS_ORIGIN -7 // removed at csg time #define CONTENTS_CLIP -8 // changed to contents_solid From 5e8b0ba616c571646c4fc67b188d1a630650d928 Mon Sep 17 00:00:00 2001 From: s1lentq Date: Wed, 7 Dec 2022 19:17:09 +0700 Subject: [PATCH 02/10] Increased limit leafs MAX_MAP_LEAFS up to 32767 --- rehlds/public/rehlds/bspfile.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rehlds/public/rehlds/bspfile.h b/rehlds/public/rehlds/bspfile.h index c3a94bb05..4998fcf81 100644 --- a/rehlds/public/rehlds/bspfile.h +++ b/rehlds/public/rehlds/bspfile.h @@ -32,7 +32,7 @@ #define HLBSP_VERSION 30 // half-life regular version #define MAX_MAP_HULLS 4 -#define MAX_MAP_LEAFS 8192 // signed short limit +#define MAX_MAP_LEAFS 32767 // signed short limit #define CONTENTS_ORIGIN -7 // removed at csg time #define CONTENTS_CLIP -8 // changed to contents_solid From 17964599538cab2edbf5bbbdac52171b9917670a Mon Sep 17 00:00:00 2001 From: Hamdi Date: Sat, 11 Feb 2023 00:03:53 +0000 Subject: [PATCH 03/10] Add SV_AllowPhysent hook (#951) * Add SV_AllowPhysent hook --- rehlds/engine/sv_user.cpp | 13 +++++++++++++ rehlds/public/rehlds/rehlds_api.h | 7 ++++++- rehlds/rehlds/rehlds_api_impl.cpp | 4 ++++ rehlds/rehlds/rehlds_api_impl.h | 6 ++++++ rehlds/version/version.h | 2 +- 5 files changed, 30 insertions(+), 2 deletions(-) diff --git a/rehlds/engine/sv_user.cpp b/rehlds/engine/sv_user.cpp index 5e2c0018b..0912cc089 100644 --- a/rehlds/engine/sv_user.cpp +++ b/rehlds/engine/sv_user.cpp @@ -511,6 +511,14 @@ void SV_CopyEdictToPhysent(physent_t *pe, int e, edict_t *check) pe->vuser4[2] = check->v.vuser4[2]; } +bool EXT_FUNC SV_AllowPhysent_mod(edict_t* check, edict_t* sv_player) { + return true; +} + +bool SV_AllowPhysent(edict_t* check, edict_t* sv_player) { + return g_RehldsHookchains.m_SV_AllowPhysent.callChain(SV_AllowPhysent_mod, check, sv_player); +} + void SV_AddLinksToPM_(areanode_t *node, float *pmove_mins, float *pmove_maxs) { struct link_s *l; @@ -547,6 +555,11 @@ void SV_AddLinksToPM_(areanode_t *node, float *pmove_mins, float *pmove_maxs) if (check->v.solid != SOLID_BSP && check->v.solid != SOLID_BBOX && check->v.solid != SOLID_SLIDEBOX && check->v.solid != SOLID_NOT) continue; + // Apply our own custom checks + if (!SV_AllowPhysent(check, sv_player)) { + continue; + } + e = NUM_FOR_EDICT(check); ve = &pmove->visents[pmove->numvisent]; pmove->numvisent = pmove->numvisent + 1; diff --git a/rehlds/public/rehlds/rehlds_api.h b/rehlds/public/rehlds/rehlds_api.h index debea3317..bc8358194 100644 --- a/rehlds/public/rehlds/rehlds_api.h +++ b/rehlds/public/rehlds/rehlds_api.h @@ -37,7 +37,7 @@ #include "pr_dlls.h" #define REHLDS_API_VERSION_MAJOR 3 -#define REHLDS_API_VERSION_MINOR 12 +#define REHLDS_API_VERSION_MINOR 13 //Steam_NotifyClientConnect hook typedef IHookChain IRehldsHook_Steam_NotifyClientConnect; @@ -255,6 +255,10 @@ typedef IVoidHookChainRegistry IRehldsHook_SV_ClientPrintf; typedef IVoidHookChainRegistry IRehldsHookRegistry_SV_ClientPrintf; +//SV_AllowPhysent hook +typedef IHookChain IRehldsHook_SV_AllowPhysent; +typedef IHookChainRegistry IRehldsHookRegistry_SV_AllowPhysent; + class IRehldsHookchains { public: virtual ~IRehldsHookchains() { } @@ -313,6 +317,7 @@ class IRehldsHookchains { virtual IRehldsHookRegistry_EV_Precache* EV_Precache() = 0; virtual IRehldsHookRegistry_SV_AddResource* SV_AddResource() = 0; virtual IRehldsHookRegistry_SV_ClientPrintf* SV_ClientPrintf() = 0; + virtual IRehldsHookRegistry_SV_AllowPhysent* SV_AllowPhysent() = 0; }; struct RehldsFuncs_t { diff --git a/rehlds/rehlds/rehlds_api_impl.cpp b/rehlds/rehlds/rehlds_api_impl.cpp index 5a41c1e96..d18622036 100644 --- a/rehlds/rehlds/rehlds_api_impl.cpp +++ b/rehlds/rehlds/rehlds_api_impl.cpp @@ -879,6 +879,10 @@ IRehldsHookRegistry_SV_ClientPrintf* CRehldsHookchains::SV_ClientPrintf(){ return &m_SV_ClientPrintf; } +IRehldsHookRegistry_SV_AllowPhysent* CRehldsHookchains::SV_AllowPhysent() { + return &m_SV_AllowPhysent; +} + int EXT_FUNC CRehldsApi::GetMajorVersion() { return REHLDS_API_VERSION_MAJOR; diff --git a/rehlds/rehlds/rehlds_api_impl.h b/rehlds/rehlds/rehlds_api_impl.h index 28b1c3e74..699bd1649 100644 --- a/rehlds/rehlds/rehlds_api_impl.h +++ b/rehlds/rehlds/rehlds_api_impl.h @@ -250,6 +250,10 @@ typedef IVoidHookChainRegistryImpl CRehldsHook_SV_ClientPrintf; typedef IVoidHookChainRegistryImpl CRehldsHookRegistry_SV_ClientPrintf; +//SV_AllowPhysent hook +typedef IHookChainImpl CRehldsHook_SV_AllowPhysent; +typedef IHookChainRegistryImpl CRehldsHookRegistry_SV_AllowPhysent; + class CRehldsHookchains : public IRehldsHookchains { public: CRehldsHookRegistry_Steam_NotifyClientConnect m_Steam_NotifyClientConnect; @@ -306,6 +310,7 @@ class CRehldsHookchains : public IRehldsHookchains { CRehldsHookRegistry_EV_Precache m_EV_Precache; CRehldsHookRegistry_SV_AddResource m_SV_AddResource; CRehldsHookRegistry_SV_ClientPrintf m_SV_ClientPrintf; + CRehldsHookRegistry_SV_AllowPhysent m_SV_AllowPhysent; public: EXT_FUNC virtual IRehldsHookRegistry_Steam_NotifyClientConnect* Steam_NotifyClientConnect(); @@ -362,6 +367,7 @@ class CRehldsHookchains : public IRehldsHookchains { EXT_FUNC virtual IRehldsHookRegistry_EV_Precache* EV_Precache(); EXT_FUNC virtual IRehldsHookRegistry_SV_AddResource* SV_AddResource(); EXT_FUNC virtual IRehldsHookRegistry_SV_ClientPrintf* SV_ClientPrintf(); + EXT_FUNC virtual IRehldsHookRegistry_SV_AllowPhysent* SV_AllowPhysent(); }; extern CRehldsHookchains g_RehldsHookchains; diff --git a/rehlds/version/version.h b/rehlds/version/version.h index 9c1ad7184..55a454b1e 100644 --- a/rehlds/version/version.h +++ b/rehlds/version/version.h @@ -6,5 +6,5 @@ #pragma once #define VERSION_MAJOR 3 -#define VERSION_MINOR 12 +#define VERSION_MINOR 13 #define VERSION_MAINTENANCE 0 From a680f18ee1e7eb8c39fbdc45682163ca9477d783 Mon Sep 17 00:00:00 2001 From: Sergey Shorokhov Date: Mon, 8 May 2023 12:24:16 +0300 Subject: [PATCH 04/10] SV_BuildSoundMsg: fix '\n' in args check - fix #965 --- rehlds/engine/sv_main.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/rehlds/engine/sv_main.cpp b/rehlds/engine/sv_main.cpp index 83a3e3cf7..9a34fa783 100644 --- a/rehlds/engine/sv_main.cpp +++ b/rehlds/engine/sv_main.cpp @@ -680,22 +680,22 @@ qboolean SV_BuildSoundMsg(edict_t *entity, int channel, const char *sample, int if (volume < 0 || volume > 255) { - Con_Printf("%s: volume = %i", __func__, volume); + Con_Printf("%s: volume = %i\n", __func__, volume); volume = (volume < 0) ? 0 : 255; } if (attenuation < 0.0f || attenuation > 4.0f) { - Con_Printf("%s: attenuation = %f", __func__, attenuation); + Con_Printf("%s: attenuation = %f\n", __func__, attenuation); attenuation = (attenuation < 0.0f) ? 0.0f : 4.0f; } if (channel < 0 || channel > 7) { - Con_Printf("%s: channel = %i", __func__, channel); + Con_Printf("%s: channel = %i\n", __func__, channel); channel = (channel < 0) ? CHAN_AUTO : CHAN_NETWORKVOICE_BASE; } if (pitch < 0 || pitch > 255) { - Con_Printf("%s: pitch = %i", __func__, pitch); + Con_Printf("%s: pitch = %i\n", __func__, pitch); pitch = (pitch < 0) ? 0 : 255; } @@ -707,7 +707,7 @@ qboolean SV_BuildSoundMsg(edict_t *entity, int channel, const char *sample, int sound_num = Q_atoi(sample + 1); if (sound_num >= CVOXFILESENTENCEMAX) { - Con_Printf("%s: invalid sentence number: %s", __func__, sample + 1); + Con_Printf("%s: invalid sentence number: %s\n", __func__, sample + 1); return FALSE; } } From 0c5ce53666811c4243ed5aa0c755dab26d2283d4 Mon Sep 17 00:00:00 2001 From: s1lentq Date: Sun, 2 Jul 2023 03:45:49 +0700 Subject: [PATCH 05/10] Allow the clients to connect on the server of different game Fixed #975 Client should be use "setinfo _gd " --- rehlds/engine/sv_main.cpp | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/rehlds/engine/sv_main.cpp b/rehlds/engine/sv_main.cpp index 9a34fa783..fa79fe9c5 100644 --- a/rehlds/engine/sv_main.cpp +++ b/rehlds/engine/sv_main.cpp @@ -1112,8 +1112,18 @@ void SV_SendServerinfo_internal(sizebuf_t *msg, client_t *client) else MSG_WriteByte(msg, 0); - COM_FileBase(com_gamedir, message); - MSG_WriteString(msg, message); + const char *pszGameDir = message; + +#ifdef REHLDS_FIXES + // Give the client a chance to connect in to the server with different game + const char *gd = Info_ValueForKey(client->userinfo, "_gd"); + if (gd[0]) + pszGameDir = gd; + else +#endif + COM_FileBase(com_gamedir, message); + + MSG_WriteString(msg, pszGameDir); MSG_WriteString(msg, Cvar_VariableString("hostname")); MSG_WriteString(msg, g_psv.modelname); From 8841ba4aecb8f428fbca9e91844b9ab5ef39e95b Mon Sep 17 00:00:00 2001 From: s1lentq Date: Tue, 4 Jul 2023 01:33:41 +0700 Subject: [PATCH 06/10] GetAttachment: Added attachment index bounds check --- rehlds/engine/r_studio.cpp | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/rehlds/engine/r_studio.cpp b/rehlds/engine/r_studio.cpp index 5b12b835e..906c205a4 100644 --- a/rehlds/engine/r_studio.cpp +++ b/rehlds/engine/r_studio.cpp @@ -906,14 +906,23 @@ void EXT_FUNC GetAttachment(const edict_t *pEdict, int iAttachment, float *rgflO mstudioattachment_t *pattachment; vec3_t angles; - angles[0] = -pEdict->v.angles[0]; - angles[1] = pEdict->v.angles[1]; - angles[2] = pEdict->v.angles[2]; - pstudiohdr = (studiohdr_t *)Mod_Extradata(g_psv.models[pEdict->v.modelindex]); + +#ifdef REHLDS_FIXES + if (!pstudiohdr) + return; + + if (iAttachment < 0 || iAttachment >= pstudiohdr->numattachments) + return; // invalid attachment +#endif + pattachment = (mstudioattachment_t *)((char *)pstudiohdr + pstudiohdr->attachmentindex); pattachment += iAttachment; + angles[0] = -pEdict->v.angles[0]; + angles[1] = pEdict->v.angles[1]; + angles[2] = pEdict->v.angles[2]; + g_pSvBlendingAPI->SV_StudioSetupBones( g_psv.models[pEdict->v.modelindex], pEdict->v.frame, From 918612fa238355d01bfdef15e970de2f67695b81 Mon Sep 17 00:00:00 2001 From: s1lentq Date: Tue, 4 Jul 2023 01:39:26 +0700 Subject: [PATCH 07/10] GetBonePosition: Added bone index bounds check --- rehlds/engine/r_studio.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/rehlds/engine/r_studio.cpp b/rehlds/engine/r_studio.cpp index 906c205a4..4124bf67f 100644 --- a/rehlds/engine/r_studio.cpp +++ b/rehlds/engine/r_studio.cpp @@ -881,6 +881,15 @@ void EXT_FUNC AnimationAutomove(const edict_t *pEdict, float flTime) void EXT_FUNC GetBonePosition(const edict_t *pEdict, int iBone, float *rgflOrigin, float *rgflAngles) { pstudiohdr = (studiohdr_t *)Mod_Extradata(g_psv.models[pEdict->v.modelindex]); + +#ifdef REHLDS_FIXES + if (!pstudiohdr) + return; + + if (iBone < 0 || iBone >= pstudiohdr->numbones) + return; // invalid bone +#endif + g_pSvBlendingAPI->SV_StudioSetupBones( g_psv.models[pEdict->v.modelindex], pEdict->v.frame, From f955b07b69a10db72290b2b35e3579151e9dc810 Mon Sep 17 00:00:00 2001 From: Sergey Shorokhov Date: Mon, 3 Jul 2023 22:02:28 +0300 Subject: [PATCH 08/10] Revert "change destinition folder for linux build (#842)" (#977) This reverts commit 9508c8376bd14fbcd92beaa93b191ee4fb1c90a3. --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index ddedaf4a3..29a64b6d7 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -277,7 +277,7 @@ jobs: github.event.action == 'published' && startsWith(github.ref, 'refs/tags/') run: | - 7z a -tzip rehlds-bin-${{ env.APP_VERSION }}.zip bin/linux32/ hlsdk/ + 7z a -tzip rehlds-bin-${{ env.APP_VERSION }}.zip bin/ hlsdk/ 7z a -t7z -m0=lzma2 -mx=9 -mfb=64 -aoa rehlds-dbg-${{ env.APP_VERSION }}.7z debug/ - name: Publish artifacts From 2ba27d409c364d12c01b6b72813ac4b991a6e224 Mon Sep 17 00:00:00 2001 From: s1lentq Date: Sun, 3 Sep 2023 15:08:30 +0700 Subject: [PATCH 09/10] Fixed reversing mistake, missing checking string for null --- rehlds/engine/pr_cmds.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/rehlds/engine/pr_cmds.cpp b/rehlds/engine/pr_cmds.cpp index e1d956a7e..e83cbb429 100644 --- a/rehlds/engine/pr_cmds.cpp +++ b/rehlds/engine/pr_cmds.cpp @@ -1447,6 +1447,9 @@ int EXT_FUNC PF_precache_model_I_internal(const char *s) { for (int i = 0; i < MAX_MODELS; i++) { + if (!g_psv.model_precache[i]) + continue; + // use case-sensitive names to increase performance #ifdef REHLDS_FIXES if (!Q_strcmp(g_psv.model_precache[i], s)) @@ -1545,7 +1548,7 @@ int EXT_FUNC PF_precache_generic_I_internal(const char *s) { for (int i = 0; i < MAX_GENERIC; i++) { - if (!Q_stricmp(g_psv.generic_precache[i], s)) + if (g_psv.generic_precache[i] && !Q_stricmp(g_psv.generic_precache[i], s)) return i; } Host_Error("%s: '%s' Precache can only be done in spawn functions", __func__, s); From de3679f0391f1452532c820f07a8c4042b1c4281 Mon Sep 17 00:00:00 2001 From: s1lentq Date: Wed, 20 Sep 2023 20:20:14 +0700 Subject: [PATCH 10/10] Host_Motd_f: Fixed viewing motd when motdfile is not specified --- rehlds/engine/common.cpp | 28 ++++++++++++++++++++++++++++ rehlds/engine/common.h | 2 ++ rehlds/engine/host_cmd.cpp | 10 +++++++++- 3 files changed, 39 insertions(+), 1 deletion(-) diff --git a/rehlds/engine/common.cpp b/rehlds/engine/common.cpp index badf9931b..e70d03ca1 100644 --- a/rehlds/engine/common.cpp +++ b/rehlds/engine/common.cpp @@ -1978,6 +1978,34 @@ NOXREF int COM_ExpandFilename(char *filename) return *filename != 0; } +// small helper function shared by lots of modules +qboolean COM_IsAbsolutePath(const char *pStr) +{ + if (strchr(pStr, ':') || pStr[0] == '/' || pStr[0] == '\\') + return FALSE; + + return TRUE; +} + +qboolean COM_IsValidPath(const char *pszFilename) +{ + if (!pszFilename) + return FALSE; + + if (Q_strlen(pszFilename) <= 0 || + Q_strstr(pszFilename, "\\\\") || // to protect network paths + Q_strstr(pszFilename, ":") || // to protect absolute paths + Q_strstr(pszFilename, "..") || // to protect relative paths + Q_strstr(pszFilename, "~") || + Q_strstr(pszFilename, "\n") || // CFileSystem_Stdio::FS_fopen doesn't allow this + Q_strstr(pszFilename, "\r")) // CFileSystem_Stdio::FS_fopen doesn't allow this + { + return FALSE; + } + + return TRUE; +} + int EXT_FUNC COM_FileSize(const char *filename) { FileHandle_t fp; diff --git a/rehlds/engine/common.h b/rehlds/engine/common.h index 1a7fc081a..94d940480 100644 --- a/rehlds/engine/common.h +++ b/rehlds/engine/common.h @@ -187,6 +187,8 @@ void COM_CreatePath(char *path); NOXREF void COM_CopyFile(char *netpath, char *cachepath); NOXREF int COM_ExpandFilename(char *filename); int COM_FileSize(const char *filename); +qboolean COM_IsAbsolutePath(const char *pStr); +qboolean COM_IsValidPath(const char *pszFilename); unsigned char *COM_LoadFile(const char *path, int usehunk, int *pLength); void COM_FreeFile(void *buffer); void COM_CopyFileChunk(FileHandle_t dst, FileHandle_t src, int nSize); diff --git a/rehlds/engine/host_cmd.cpp b/rehlds/engine/host_cmd.cpp index d76815cb8..3d6558c2b 100644 --- a/rehlds/engine/host_cmd.cpp +++ b/rehlds/engine/host_cmd.cpp @@ -205,11 +205,19 @@ void Host_Motd_f(void) char *next; pFileList = motdfile.string; - if (*pFileList == '/' || Q_strstr(pFileList, ":") || Q_strstr(pFileList, "..") || Q_strstr(pFileList, "\\")) + if (!COM_IsValidPath(pFileList) || COM_IsAbsolutePath(pFileList)) { Con_Printf("Unable to open %s (contains illegal characters)\n", pFileList); return; } + + const char *pchExtension = COM_FileExtension(pFileList); + if (Q_stricmp(pchExtension, "txt") != 0) + { + Con_Printf("Invalid motdfile name %s (wrong file extension, must be .txt)\n", pFileList); + return; + } + pFile = FS_Open(pFileList, "rb"); if (!pFile) {