From 05f4a279f9f30cac4d361edebab31dc4a6c1f65f Mon Sep 17 00:00:00 2001 From: anzz1 Date: Sat, 2 Mar 2024 17:24:04 +0200 Subject: [PATCH 01/11] Add steamcmd instructions to readme (#1021) --- README.md | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 7ee72b71..15439cde 100644 --- a/README.md +++ b/README.md @@ -15,8 +15,16 @@ You can try playing on one of many servers that are using ReHLDS: [Game Tracker] ## How can use it? -ReHLDS is fully compatible with latest official HLDS downloaded by steamcmd. All you have to do is to download rehlds binaries and replace original swds.dll/engine_i486.so. For windows you can also copy a swds.pdb file with a debug information. -
Warning! ReHLDS is not compatible with an old 5xxx or below platforms downloaded by hldsupdatetool. +ReHLDS is fully compatible with the official pre-anniversary edition of HLDS (engine version <= 8684) downloaded by steamcmd. All you have to do is to download rehlds binaries and replace original swds.dll/engine_i486.so. For windows you can also copy a swds.pdb file with a debug information. + +Warning! ReHLDS is not compatible with an old 5xxx or below platforms downloaded by hldsupdatetool. + +#### Downloading HLDS via steamcmd + +``` +app_set_config 90 mod cstrike +app_update 90 -beta steam_legacy validate +``` ## Downloads * [Release builds](https://github.com/dreamstalker/rehlds/releases) From 174414db81116b3647e7bb1b906417d6a38ed3a3 Mon Sep 17 00:00:00 2001 From: s1lentq Date: Mon, 18 Mar 2024 21:57:57 +0700 Subject: [PATCH 02/11] Draw_ValidateCustomLogo: Minor refactoring & cleanup --- rehlds/engine/decals.cpp | 69 +++++++++++++++++----------------------- 1 file changed, 30 insertions(+), 39 deletions(-) diff --git a/rehlds/engine/decals.cpp b/rehlds/engine/decals.cpp index 975d7f97..1705b7f6 100644 --- a/rehlds/engine/decals.cpp +++ b/rehlds/engine/decals.cpp @@ -717,14 +717,9 @@ NOXREF qboolean Draw_CacheReload(cachewad_t *wad, int i, lumpinfo_t *pLump, cach qboolean Draw_ValidateCustomLogo(cachewad_t *wad, unsigned char *data, lumpinfo_t *lump) { texture_t tex; - miptex_t *mip; - miptex_t tmp; - int pix; - int pixoffset; - int paloffset; - int palettesize; - int nPalleteCount; - int nSize; + miptex_t *mip, tmp; + int i, pix, paloffset, palettesize; + int size; if (wad->cacheExtra != DECAL_EXTRASIZE) { @@ -734,58 +729,54 @@ qboolean Draw_ValidateCustomLogo(cachewad_t *wad, unsigned char *data, lumpinfo_ tex = *(texture_t *)data; mip = (miptex_t *)(data + wad->cacheExtra); - tmp = *mip; + // Copy mip texture data + tmp = *mip; tex.width = LittleLong(tmp.width); tex.height = LittleLong(tmp.height); - tex.anim_max = 0; - tex.anim_min = 0; - tex.anim_total = 0; - tex.alternate_anims = NULL; - tex.anim_next = NULL; + tex.anim_total = tex.anim_min = tex.anim_max = 0; + tex.alternate_anims = tex.anim_next = NULL; - if (!tex.width || tex.width > 256 || tex.height > 256) + for (i = 0; i < MIPLEVELS; i++) + tex.offsets[i] = wad->cacheExtra + LittleLong(tmp.offsets[i]); + + if (tex.width <= 0 || tex.height <= 0 || + // Check if texture dimensions exceed limits + tex.width > 256 || tex.height > 256) { - Con_Printf("%s: Bad wad dimensions %s\n", __func__, wad->name); + Con_Printf("%s: Bad cached wad tex size %ux%u on %s\n", __func__, tex.width, tex.height, wad->name); return FALSE; } - for (int i = 0; i < MIPLEVELS; i++) - tex.offsets[i] = wad->cacheExtra + LittleLong(tmp.offsets[i]); - pix = tex.width * tex.height; - pixoffset = pix + (pix >> 2) + (pix >> 4) + (pix >> 6); + size = pix + (pix >> 2) + (pix >> 4) + (pix >> 6); -#ifdef REHLDS_FIXES - // Ensure that pixoffset won't be exceed the pre allocated buffer - // This can happen when there are no color palettes in payload - if ((pixoffset + sizeof(texture_t)) >= (unsigned)(wad->cacheExtra + lump->size)) + if ((unsigned)(size + sizeof(miptex_t)) >= (unsigned)(lump->size + wad->cacheExtra)) { - Con_Printf("%s: Bad wad payload size %s\n", __func__, wad->name); - return FALSE; + Con_Printf("%s: Bad cached wad size %i/%i on %s\n", __func__, size + sizeof(miptex_t), lump->size + wad->cacheExtra, wad->name); } -#endif - paloffset = (pix >> 2) + tmp.offsets[0] + pix; - palettesize = (pix >> 4) + paloffset; + paloffset = size + sizeof(lumpinfo_t) + sizeof(miptex_t); + palettesize = *(u_short *)(data + paloffset); // Get palette size - if ((tmp.offsets[0] + pix != tmp.offsets[1]) - || paloffset != tmp.offsets[2] - || palettesize != tmp.offsets[3]) + for (i = 0; i < 3; i++) { - Con_Printf("%s: Bad cached wad %s\n", __func__, wad->name); - return FALSE; + // Check if offsets are valid for mip levels + if (pix + tmp.offsets[i] != tmp.offsets[i + 1]) + { + Con_Printf("%s: Bad cached wad %s\n", __func__, wad->name); + return FALSE; + } + pix >>= 2; } - nPalleteCount = *(u_short *)(data + pixoffset + sizeof(texture_t)); - if (nPalleteCount > 256) + if (palettesize > 256) { - Con_Printf("%s: Bad cached wad palette size %i on %s\n", __func__, nPalleteCount, wad->name); + Con_Printf("%s: Bad cached wad palette size %i on %s\n", __func__, palettesize, wad->name); return FALSE; } - nSize = pixoffset + LittleLong(tmp.offsets[0]) + 3 * nPalleteCount + 2; - if (nSize > lump->disksize) + if ((palettesize + 2 * (palettesize + 1) + size + LittleLong(tmp.offsets[0])) > lump->disksize) { Con_Printf("%s: Bad cached wad %s\n", __func__, wad->name); return FALSE; From 516bb936271b1cf8523d6f97a421370128a7c964 Mon Sep 17 00:00:00 2001 From: s1lentq Date: Mon, 18 Mar 2024 21:59:18 +0700 Subject: [PATCH 03/11] HPAK_ResourceForHash: Remove message with missing custom.hpk --- rehlds/engine/hashpak.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/rehlds/engine/hashpak.cpp b/rehlds/engine/hashpak.cpp index 3e760121..2befee64 100644 --- a/rehlds/engine/hashpak.cpp +++ b/rehlds/engine/hashpak.cpp @@ -620,7 +620,9 @@ qboolean HPAK_ResourceForHash(char *pakname, unsigned char *hash, struct resourc fp = FS_Open(name, "rb"); if (!fp) { +#ifndef REHLDS_FIXES Con_Printf("ERROR: couldn't open %s.\n", name); +#endif return FALSE; } FS_Read(&header, sizeof(hash_pack_header_t), 1, fp); From 59ed3f6867b1b3cba69cd7650887841da8e76d42 Mon Sep 17 00:00:00 2001 From: s1lentq Date: Mon, 18 Mar 2024 22:04:02 +0700 Subject: [PATCH 04/11] SV_ParseResourceList: Do not uploading according to sv_allowupload cvar --- rehlds/engine/sv_upld.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/rehlds/engine/sv_upld.cpp b/rehlds/engine/sv_upld.cpp index e28a0e3d..82b83150 100644 --- a/rehlds/engine/sv_upld.cpp +++ b/rehlds/engine/sv_upld.cpp @@ -509,8 +509,13 @@ void SV_ParseResourceList(client_t *pSenderClient) } } - host_client->uploading = TRUE; - host_client->uploaddoneregistering = FALSE; +#ifdef REHLDS_FIXES + if (sv_allow_upload.value != 0.0f) +#endif //REHLDS_FIXES + { + host_client->uploading = TRUE; + host_client->uploaddoneregistering = FALSE; - SV_BatchUploadRequest(host_client); + SV_BatchUploadRequest(host_client); + } } From f26ad71aba6a596602245c64af71cd196196859f Mon Sep 17 00:00:00 2001 From: s1lentq Date: Mon, 18 Mar 2024 22:09:18 +0700 Subject: [PATCH 05/11] Do not send customizations list on duplicate or missing resource --- rehlds/engine/sv_upld.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/rehlds/engine/sv_upld.cpp b/rehlds/engine/sv_upld.cpp index 82b83150..1cd93f6e 100644 --- a/rehlds/engine/sv_upld.cpp +++ b/rehlds/engine/sv_upld.cpp @@ -138,6 +138,9 @@ void SV_CreateCustomizationList(client_t *pHost) { pCust->nUserData2 = nLumps; gEntityInterface.pfnPlayerCustomization(pHost->edict, pCust); +#ifdef REHLDS_FIXES + SV_Customization(pHost, pResource, TRUE); +#endif } else { @@ -205,10 +208,6 @@ void SV_RegisterResources(void) pHost->uploading = FALSE; #ifdef REHLDS_FIXES SV_CreateCustomizationList(pHost); // FIXED: Call this function only once. It was crazy to call it for each resource available. - for (pResource = pHost->resourcesonhand.pNext; pResource != &pHost->resourcesonhand; pResource = pResource->pNext) - { - SV_Customization(pHost, pResource, TRUE); - } #else // REHLDS_FIXES for (pResource = pHost->resourcesonhand.pNext; pResource != &pHost->resourcesonhand; pResource = pResource->pNext) { From 462fe55fb832209270118b6def6034f8eec6efbf Mon Sep 17 00:00:00 2001 From: s1lentq Date: Mon, 18 Mar 2024 22:12:01 +0700 Subject: [PATCH 06/11] SV_CreateCustomizationList: spew logs in only dev mode --- rehlds/engine/sv_upld.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rehlds/engine/sv_upld.cpp b/rehlds/engine/sv_upld.cpp index 1cd93f6e..aced9ed0 100644 --- a/rehlds/engine/sv_upld.cpp +++ b/rehlds/engine/sv_upld.cpp @@ -145,9 +145,9 @@ void SV_CreateCustomizationList(client_t *pHost) else { if (sv_allow_upload.value == 0.0f) - Con_Printf("Ignoring custom decal from %s\n", pHost->name); + Con_DPrintf("Ignoring custom decal from %s\n", pHost->name); else - Con_Printf("Ignoring invalid custom decal from %s\n", pHost->name); + Con_DPrintf("Ignoring invalid custom decal from %s\n", pHost->name); } } } From ec47e4d97834c35f8667684f15a372c85505ce55 Mon Sep 17 00:00:00 2001 From: s1lentq Date: Mon, 18 Mar 2024 22:17:23 +0700 Subject: [PATCH 07/11] Do not propagate custom logos according to sv_send_logos cvar --- rehlds/engine/sv_main.cpp | 6 ++++++ rehlds/engine/sv_upld.cpp | 5 +++++ 2 files changed, 11 insertions(+) diff --git a/rehlds/engine/sv_main.cpp b/rehlds/engine/sv_main.cpp index 870a5fab..8f99c0fa 100644 --- a/rehlds/engine/sv_main.cpp +++ b/rehlds/engine/sv_main.cpp @@ -5748,6 +5748,12 @@ void SV_PropagateCustomizations(void) if (pCust->bInUse) { pResource = &pCust->resource; + +#ifdef REHLDS_FIXES + if ((pResource->ucFlags & RES_CUSTOM) && !sv_send_logos.value) + continue; +#endif + MSG_WriteByte(&host_client->netchan.message, svc_customization); MSG_WriteByte(&host_client->netchan.message, i); MSG_WriteByte(&host_client->netchan.message, pResource->type); diff --git a/rehlds/engine/sv_upld.cpp b/rehlds/engine/sv_upld.cpp index aced9ed0..425e439e 100644 --- a/rehlds/engine/sv_upld.cpp +++ b/rehlds/engine/sv_upld.cpp @@ -160,6 +160,11 @@ void SV_Customization(client_t *pPlayer, resource_t *pResource, qboolean bSkipPl int nPlayerNumber; client_t *pHost; +#ifdef REHLDS_FIXES + if ((pResource->ucFlags & RES_CUSTOM) && !sv_send_logos.value) + return; +#endif + // Get originating player id for (i = 0, pHost = g_psvs.clients; i < g_psvs.maxclients; i++, pHost++) { From 3c282b435c7d0508d72104d26a0c9171f7feea71 Mon Sep 17 00:00:00 2001 From: s1lentq Date: Tue, 26 Mar 2024 20:41:53 +0700 Subject: [PATCH 08/11] Draw_ValidateCustomLogo: Fixed incorrect offset to palette size --- rehlds/engine/decals.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rehlds/engine/decals.cpp b/rehlds/engine/decals.cpp index 1705b7f6..19959d3b 100644 --- a/rehlds/engine/decals.cpp +++ b/rehlds/engine/decals.cpp @@ -756,8 +756,8 @@ qboolean Draw_ValidateCustomLogo(cachewad_t *wad, unsigned char *data, lumpinfo_ Con_Printf("%s: Bad cached wad size %i/%i on %s\n", __func__, size + sizeof(miptex_t), lump->size + wad->cacheExtra, wad->name); } - paloffset = size + sizeof(lumpinfo_t) + sizeof(miptex_t); - palettesize = *(u_short *)(data + paloffset); // Get palette size + paloffset = size + sizeof(miptex_t); + palettesize = *(u_short *)(data + wad->cacheExtra + paloffset); // Get palette size for (i = 0; i < 3; i++) { From b870de768b3260b4c4b500c0a143caff1b697a9c Mon Sep 17 00:00:00 2001 From: Sergey Shorokhov Date: Sat, 6 Apr 2024 22:09:47 +0300 Subject: [PATCH 09/11] fix: README badges [skip ci] --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 15439cde..d6a0b385 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# ReHLDS [![C/C++ CI](https://github.com/dreamstalker/rehlds/actions/workflows/build.yml/badge.svg)](https://github.com/dreamstalker/rehlds/actions/workflows/build.yml) [![Download](https://camo.githubusercontent.com/7ab483250adb4037b26e9575331218ee51108190d0938b7836d32f1209ccf907/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f72656c656173652f647265616d7374616c6b65722f7265686c64732e737667)](https://github.com/dreamstalker/rehlds/releases/latest) [![Downloads](https://camo.githubusercontent.com/d37654956d99bb9fb7a348fdac39b214d6ae14a7cfb9f96bf873c6b46cdf9ef6/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f646f776e6c6f6164732f647265616d7374616c6b65722f7265686c64732f746f74616c3f636f6c6f723d696d706f7274616e74)]() [![Percentage of issues still open](http://isitmaintained.com/badge/open/dreamstalker/rehlds.svg)](http://isitmaintained.com/project/dreamstalker/rehlds "Percentage of issues still open") [![License: GPL v3](https://img.shields.io/badge/License-GPL%20v3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0) ReHLDS +# ReHLDS [![C/C++ CI](https://github.com/dreamstalker/rehlds/actions/workflows/build.yml/badge.svg)](https://github.com/dreamstalker/rehlds/actions/workflows/build.yml) [![GitHub release (by tag)](https://img.shields.io/github/downloads/dreamstalker/rehlds/latest/total)](https://github.com/dreamstalker/rehlds/releases/latest) ![GitHub all releases](https://img.shields.io/github/downloads/dreamstalker/rehlds/total) [![Percentage of issues still open](http://isitmaintained.com/badge/open/dreamstalker/rehlds.svg)](http://isitmaintained.com/project/dreamstalker/rehlds "Percentage of issues still open") [![License: GPL v3](https://img.shields.io/badge/License-GPL%20v3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0) ReHLDS Reverse-engineered (and bugfixed) HLDS ## What is this? From 61ee4f926938b1894bedfd9f139d45db48d89903 Mon Sep 17 00:00:00 2001 From: s1lentq Date: Wed, 10 Apr 2024 12:30:59 +0700 Subject: [PATCH 10/11] Netchan_CreateFileFragments: Fixed a hang connection on verifying resource stage, when precached file exists but is absolutely empty --- rehlds/engine/net_chan.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/rehlds/engine/net_chan.cpp b/rehlds/engine/net_chan.cpp index 94149bc2..5e51a8cc 100644 --- a/rehlds/engine/net_chan.cpp +++ b/rehlds/engine/net_chan.cpp @@ -1203,7 +1203,9 @@ int Netchan_CreateFileFragments(qboolean server, netchan_t *chan, const char *fi if (!FS_FileExists(filename)) return FALSE; - if (FS_FileSize(filename) > sv_filetransfermaxsize.value) + + unsigned int nSize = FS_FileSize(filename); + if (nSize == 0 || nSize > sv_filetransfermaxsize.value) return FALSE; auto wait = (fragbufwaiting_t *)Mem_ZeroMalloc(sizeof(fragbufwaiting_t)); From 0d1bdbab671752aa579d7b4e10f4cf04d69a49a4 Mon Sep 17 00:00:00 2001 From: Dmitry Novikov Date: Sun, 14 Apr 2024 01:04:03 +0700 Subject: [PATCH 11/11] Implemented reduction of impact caused by zip-bomb exploit (#994) * Implemented reduction of impact caused by zip-bomb exploit Added network security CVars: - sv_net_incoming_decompression (0-1) Enables or disables incoming data decompression - sv_net_incoming_decompression_max_ratio (0.0 - 100.0) Sets max allowed ratio between compressed and decompressed data. (A ratio close to 90 indicates large uncompressed data with low entropy) - sv_net_incoming_decompression_max_size (16-65536) Adjusts max size of output data after decompression. Added CVar sv_net_incoming_decompression_punish for ban * Fix missing reg CVar sv_net_incoming_decompression_punish --- README.md | 4 ++ rehlds/engine/net_chan.cpp | 99 +++++++++++++++++++++++++++++++++----- 2 files changed, 91 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index d6a0b385..b824c153 100644 --- a/README.md +++ b/README.md @@ -63,6 +63,10 @@ This means that plugins that do binary code analysis (Orpheu for example) probab
  • sv_rehlds_local_gametime <1|0> // A feature of local gametime which decrease "lags" if you run same map for a long time. Default: 0
  • sv_use_entity_file // Use custom entity file for a map. Path to an entity file will be "maps/[map name].ent". 0 - use original entities. 1 - use .ent files from maps directory. 2 - use .ent files from maps directory and create new .ent file if not exist.
  • sv_usercmd_custom_random_seed // When enabled server will populate an additional random seed independent of the client. Default: 0 +
  • sv_net_incoming_decompression <1|0> // When enabled server will decompress of incoming compressed file transfer payloads. Default: 1 +
  • sv_net_incoming_decompression_max_ratio <0|100> // Sets the max allowed ratio between compressed and uncompressed data for file transfer. (A ratio close to 90 indicates large uncompressed data with low entropy) Default: 80.0 +
  • sv_net_incoming_decompression_max_size <16|65536> // Sets the max allowed size for decompressed file transfer data. Default: 65536 bytes +
  • sv_net_incoming_decompression_punish // Time in minutes for which the player will be banned for malformed/abnormal bzip2 fragments (0 - Permanent, use a negative number for a kick). Default: -1
  • sv_tags <comma-delimited string list of tags> // Sets a string defining the "gametags" for this server, this is optional, but if it is set it allows users/scripts to filter in the matchmaking/server-browser interfaces based on the value. Default: "" diff --git a/rehlds/engine/net_chan.cpp b/rehlds/engine/net_chan.cpp index 5e51a8cc..71fc0f6d 100644 --- a/rehlds/engine/net_chan.cpp +++ b/rehlds/engine/net_chan.cpp @@ -36,6 +36,12 @@ cvar_t net_showpackets = { "net_showpackets", "0", 0, 0.0f, nullptr}; cvar_t net_showdrop = { "net_showdrop", "0", 0, 0.0f, nullptr}; cvar_t net_drawslider = { "net_drawslider", "0", 0, 0.0f, nullptr}; cvar_t net_chokeloopback = { "net_chokeloop", "0", 0, 0.0f, nullptr}; + +cvar_t sv_net_incoming_decompression = { "sv_net_incoming_decompression", "1", 0, 1.0f, nullptr }; +cvar_t sv_net_incoming_decompression_max_ratio = { "sv_net_incoming_decompression_max_ratio", "75.0", 0, 75.0f, nullptr }; +cvar_t sv_net_incoming_decompression_max_size = { "sv_net_incoming_decompression_max_size", "65536", 0, 65536.0f, nullptr }; +cvar_t sv_net_incoming_decompression_punish = { "sv_net_incoming_decompression_punish", "-1", 0, -1.0f, NULL }; + cvar_t sv_filetransfercompression = { "sv_filetransfercompression", "1", 0, 0.0f, nullptr}; cvar_t sv_filetransfermaxsize = { "sv_filetransfermaxsize", "10485760", 0, 0.0f, nullptr}; @@ -1433,6 +1439,9 @@ qboolean Netchan_CopyNormalFragments(netchan_t *chan) p = chan->incomingbufs[FRAG_NORMAL_STREAM]; + chan->incomingbufs[FRAG_NORMAL_STREAM] = nullptr; + chan->incomingready[FRAG_NORMAL_STREAM] = FALSE; + SZ_Clear(&net_message); MSG_BeginReading(); @@ -1470,27 +1479,87 @@ qboolean Netchan_CopyNormalFragments(netchan_t *chan) } SZ_Clear(&net_message); - - chan->incomingbufs[FRAG_NORMAL_STREAM] = nullptr; - chan->incomingready[FRAG_NORMAL_STREAM] = FALSE; - return FALSE; } #endif // REHLDS_FIXES + qboolean success = TRUE; + if (*(uint32 *)net_message.data == MAKEID('B', 'Z', '2', '\0')) { + // Determine whether decompression of compressed data is allowed +#ifdef REHLDS_FIXES + if (!sv_net_incoming_decompression.value) + { + if (chan->player_slot == 0) + { + Con_DPrintf("Incoming compressed data disallowed from\n"); + return FALSE; + } + // compressed data is expected only after requesting resource list + else if (host_client->m_sendrescount == 0) + { + Con_DPrintf("%s:Incoming compressed data disallowed from %s\n", NET_AdrToString(chan->remote_address), host_client->name); + return FALSE; + } + } +#endif + char uncompressed[65536]; - unsigned int uncompressedSize = 65536; - BZ2_bzBuffToBuffDecompress(uncompressed, &uncompressedSize, (char*)net_message.data + 4, net_message.cursize - 4, 1, 0); - Q_memcpy(net_message.data, uncompressed, uncompressedSize); - net_message.cursize = uncompressedSize; - } + unsigned int uncompressedSize = clamp((int)sv_net_incoming_decompression_max_size.value, 16, 65536); // valid range (16 - 65536) bytes + unsigned int compressedSize = net_message.cursize - 4; - chan->incomingbufs[FRAG_NORMAL_STREAM] = nullptr; - chan->incomingready[FRAG_NORMAL_STREAM] = FALSE; + // Decompress net buffer data + if (success && (BZ2_bzBuffToBuffDecompress(uncompressed, &uncompressedSize, (char *)net_message.data + 4, compressedSize, 1, 0) == BZ_OK)) + { +#ifdef REHLDS_FIXES + // Check for an abnormal size ratio between compressed and uncompressed data + if (sv_net_incoming_decompression_max_ratio.value > 0 && compressedSize < uncompressedSize) + { + float ratio = ((float)(uncompressedSize - compressedSize) / uncompressedSize) * 100.0f; + if (ratio >= sv_net_incoming_decompression_max_ratio.value) + { + if (chan->player_slot == 0) + Con_DPrintf("Incoming abnormal uncompressed size with ratio %.2f\n", ratio); + else + Con_DPrintf("%s:Incoming abnormal uncompressed size with ratio %.2f from %s\n", NET_AdrToString(chan->remote_address), ratio, host_client->name); - return TRUE; + success = FALSE; + } + } +#endif + + // Copy uncompressed data back to the net buffer + Q_memcpy(net_message.data, uncompressed, uncompressedSize); + net_message.cursize = uncompressedSize; + } + else + { + // malformed data or compressed data exceeding sv_net_incoming_decompression_max_size + success = FALSE; + } + + // Drop client if decompression was unsuccessful + if (!success) + { + if ((chan->player_slot - 1) == host_client - g_psvs.clients) + { +#ifdef REHLDS_FIXES + if (sv_net_incoming_decompression_punish.value >= 0) + { + Con_DPrintf("%s:Banned for malformed/abnormal bzip2 fragments from %s\n", NET_AdrToString(chan->remote_address), host_client->name); + Cbuf_AddText(va("addip %.1f %s\n", sv_net_incoming_decompression_punish.value, NET_BaseAdrToString(chan->remote_address))); + } +#endif + + SV_DropClient(host_client, FALSE, "Malformed/abnormal compressed data"); + } + + SZ_Clear(&net_message); + } + } + + return success; } qboolean Netchan_CopyFileFragments(netchan_t *chan) @@ -1826,6 +1895,12 @@ void Netchan_Init(void) Cvar_RegisterVariable(&net_chokeloopback); Cvar_RegisterVariable(&net_drawslider); Cvar_RegisterVariable(&sv_filetransfercompression); +#ifdef REHLDS_FIXES + Cvar_RegisterVariable(&sv_net_incoming_decompression); + Cvar_RegisterVariable(&sv_net_incoming_decompression_max_ratio); + Cvar_RegisterVariable(&sv_net_incoming_decompression_max_size); + Cvar_RegisterVariable(&sv_net_incoming_decompression_punish); +#endif Cvar_RegisterVariable(&sv_filetransfermaxsize); }