Files
RobustToolbox/Robust.Shared/Serialization/NetUnsafeFloatSerializer.cs
PJB3005 65b8d0cce2 Add network serialization float NaN sanitization
Apparently cheat clients have figured out that none of SS14's code does validation against NaN inputs. Uh oh.

IRobustSerializer can now be configured to remove NaN values when reading. This is intended to be set on the server to completely block the issue.

Added "Unsafe" float types that can be used to bypass the new configurable behavior, in case somebody *really* needs NaNs.

An alternative option was to make a "SafeFloat" type, and only apply the sanitization to that. The problem is that would require updating hundreds if not thousands of messages in SS14, and probably significantly confuse contributors on "when use what." Blocking NaNs by default is likely to cause little issues while ensuring the entire exploit is guaranteed impossible.
2026-01-25 03:45:50 +01:00

79 lines
2.1 KiB
C#

using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using JetBrains.Annotations;
using NetSerializer;
using Robust.Shared.Maths;
namespace Robust.Shared.Serialization;
/// <summary>
/// NetSerializer type serializer for <see cref="UnsafeFloat"/>, <see cref="UnsafeHalf"/>, and <see cref="UnsafeFloat"/>.
/// </summary>
internal sealed class NetUnsafeFloatSerializer : IStaticTypeSerializer
{
public bool Handles(Type type)
{
return type == typeof(UnsafeFloat) || type == typeof(UnsafeDouble) || type == typeof(UnsafeHalf);
}
public IEnumerable<Type> GetSubtypes(Type type)
{
return [];
}
public MethodInfo GetStaticWriter(Type type)
{
return typeof(NetUnsafeFloatSerializer).GetMethod(nameof(Write),
BindingFlags.NonPublic | BindingFlags.Static,
[typeof(Stream), type])!;
}
public MethodInfo GetStaticReader(Type type)
{
return typeof(NetUnsafeFloatSerializer).GetMethod(nameof(Read),
BindingFlags.NonPublic | BindingFlags.Static,
[typeof(Stream), type.MakeByRefType()])!;
}
[UsedImplicitly]
private static void Write(Stream stream, UnsafeFloat value)
{
Primitives.WritePrimitive(stream, value);
}
[UsedImplicitly]
private static void Read(Stream stream, out UnsafeFloat value)
{
Primitives.ReadPrimitive(stream, out float readValue);
value = readValue;
}
[UsedImplicitly]
private static void Write(Stream stream, UnsafeDouble value)
{
Primitives.WritePrimitive(stream, value);
}
[UsedImplicitly]
private static void Read(Stream stream, out UnsafeDouble value)
{
Primitives.ReadPrimitive(stream, out double readValue);
value = readValue;
}
[UsedImplicitly]
private static void Write(Stream stream, UnsafeHalf value)
{
Primitives.WritePrimitive(stream, value);
}
[UsedImplicitly]
private static void Read(Stream stream, out UnsafeHalf value)
{
Primitives.ReadPrimitive(stream, out Half readValue);
value = readValue;
}
}