From 3dcbf287f07925b96f9cb6b159d097641d9d0c96 Mon Sep 17 00:00:00 2001 From: Skeletonxf Date: Sat, 24 Oct 2020 14:41:14 +0100 Subject: [PATCH] Tell the client the LevelChainId before it uses it to read a variable bit length message Fixes very serious dormant vanilla bug where any planet with a level chain that had a different max level to the level chain with an id of 0 would read the wrong number of bits from the message, and offset the rest of the message by a number of bits, breaking all later decoding (and before I started patching to get my way to here, also risk CTDing the client due to trying to create data with stupidly large sizes on the graphics code). This bug is part of vanilla, but could not be triggered without mods, as all level chains in vanilla had 5 levels, so the bug occured but didn't break the decoding due to the incorrect number and correct number coinciding to be the same --- scripts/client/nodes/PlanetNode.as | 13 +++++++++++++ scripts/server/planets/SurfaceComponent.as | 11 +++++++++++ scripts/shadow/planets/SurfaceComponent.as | 11 +++++++++++ 3 files changed, 35 insertions(+) diff --git a/scripts/client/nodes/PlanetNode.as b/scripts/client/nodes/PlanetNode.as index df364e91..14146288 100644 --- a/scripts/client/nodes/PlanetNode.as +++ b/scripts/client/nodes/PlanetNode.as @@ -262,6 +262,19 @@ class DynTex { return; } + // Try to fail more gracefully than causing a CTD if the + // grid size is wrong + // If the netcode messes up this can sometimes be way larger than any + // actual grid size. In that scenario, trying to create the Image + // can easily cause a Crash To Desktop and completely stop the game. + if (size.x > 3000 || size.y > 3000) { + print("Read grid size that is way too high, aborting texture cache to avoid CTD"); + print(string(size.x)+"x"+string(size.y)); + print("Has the netcode or PlanetSurface gone haywire?"); + @this.obj = null; + return; + } + Image img(size, 4); uint shown = obj.getSurfaceData(img); diff --git a/scripts/server/planets/SurfaceComponent.as b/scripts/server/planets/SurfaceComponent.as index 3d9482e0..ed69e5d6 100644 --- a/scripts/server/planets/SurfaceComponent.as +++ b/scripts/server/planets/SurfaceComponent.as @@ -2591,6 +2591,17 @@ tidy class SurfaceComponent : Component_SurfaceComponent, Savable { msg.write0(); } msg.writeBit(needsPopulationForLevel); + // Tell the client the LevelChainId before it tries to use it, fixes + // bug where the client was reading the max level of a planet before + // it found out the level chain of that planet. This meant that any + // planet with a level chain that had a different max level to the + // level chain with an id of 0 would be decoded incorrectly, and offset + // the rest of the message by some number of bits, completely breaking + // all decoding that followed. In the worst case, the broken decoding + // would cause a Crash To Desktop as the PlanetNode tried to create + // an Image with a ludicrous size, or the PlanetSurface tried to + // create an array for a ludicrous grid size that ran out of memory. + msg.writeLimited(LevelChainId,getLevelChainCount()); msg.writeLimited(ResourceLevel,maxLevel); msg.writeBit(isSendingColonizers); } diff --git a/scripts/shadow/planets/SurfaceComponent.as b/scripts/shadow/planets/SurfaceComponent.as index 6b79b76e..59ee8a78 100644 --- a/scripts/shadow/planets/SurfaceComponent.as +++ b/scripts/shadow/planets/SurfaceComponent.as @@ -435,6 +435,17 @@ tidy class SurfaceComponent : Component_SurfaceComponent { growthRate = 1.0; needsPopulationForLevel = msg.readBit(); + // Tell the client the LevelChainId before it tries to use it, fixes + // bug where the client was reading the max level of a planet before + // it found out the level chain of that planet. This meant that any + // planet with a level chain that had a different max level to the + // level chain with an id of 0 would be decoded incorrectly, and offset + // the rest of the message by some number of bits, completely breaking + // all decoding that followed. In the worst case, the broken decoding + // would cause a Crash To Desktop as the PlanetNode tried to create + // an Image with a ludicrous size, or the PlanetSurface tried to + // create an array for a ludicrous grid size that ran out of memory. + LevelChainId = msg.readLimited(getLevelChainCount()); int maxLevel = getLevelChain(LevelChainId).levels.length-1; ResourceLevel = msg.readLimited(maxLevel);