From b3127beb89c20447bf8044fd3bae71ae04f553e7 Mon Sep 17 00:00:00 2001 From: vis2k Date: Sat, 21 Dec 2019 15:09:33 +0100 Subject: [PATCH] fix: MultiplexTransport GetMaxMessageSize NullReferenceException when called on server. And fixes potential exploits / out of sync issues where clients with different transports might see different game states because of different max message sizes. (#1332) --- .../Runtime/Transport/MultiplexTransport.cs | 27 +++++++++++++++---- Assets/Mirror/Runtime/Transport/Transport.cs | 7 ++++- 2 files changed, 28 insertions(+), 6 deletions(-) diff --git a/Assets/Mirror/Runtime/Transport/MultiplexTransport.cs b/Assets/Mirror/Runtime/Transport/MultiplexTransport.cs index 92caa508e..028022d44 100644 --- a/Assets/Mirror/Runtime/Transport/MultiplexTransport.cs +++ b/Assets/Mirror/Runtime/Transport/MultiplexTransport.cs @@ -104,11 +104,6 @@ public override bool ClientSend(int channelId, ArraySegment segment) return available.ClientSend(channelId, segment); } - public override int GetMaxPacketSize(int channelId = 0) - { - return available.GetMaxPacketSize(channelId); - } - #endregion #region Server @@ -239,6 +234,28 @@ public override void ServerStop() } #endregion + public override int GetMaxPacketSize(int channelId = 0) + { + // finding the max packet size in a multiplex environment has to be + // done very carefully: + // * servers run multiple transports at the same time + // * different clients run different transports + // * there should only ever be ONE true max packet size for everyone, + // otherwise a spawn message might be sent to all tcp sockets, but + // be too big for some udp sockets. that would be a debugging + // nightmare and allow for possible exploits and players on + // different platforms seeing a different game state. + // => the safest solution is to use the smallest max size for all + // transports. that will never fail. + int mininumAllowedSize = int.MaxValue; + foreach (Transport transport in transports) + { + int size = transport.GetMaxPacketSize(channelId); + mininumAllowedSize = Mathf.Min(size, mininumAllowedSize); + } + return mininumAllowedSize; + } + public override void Shutdown() { foreach (Transport transport in transports) diff --git a/Assets/Mirror/Runtime/Transport/Transport.cs b/Assets/Mirror/Runtime/Transport/Transport.cs index a40ee1d50..b66c2ae63 100644 --- a/Assets/Mirror/Runtime/Transport/Transport.cs +++ b/Assets/Mirror/Runtime/Transport/Transport.cs @@ -177,8 +177,13 @@ public virtual bool GetConnectionInfo(int connectionId, out string address) /// /// The maximum packet size for a given channel. Unreliable transports - /// usually can only deliver small packets. Reliable fragmented channels + /// usually can only deliver small packets. Reliable fragmented channels /// can usually deliver large ones. + /// + /// GetMaxPacketSize needs to return a value at all times. Even if the + /// Transport isn't running, or isn't Available(). This is because + /// Fallback and Multiplex transports need to find the smallest possible + /// packet size at runtime. /// /// channel id /// the size in bytes that can be sent via the provided channel