diff --git a/.gitignore b/.gitignore index 7e74065d1..7209c6cbc 100644 --- a/.gitignore +++ b/.gitignore @@ -37,6 +37,9 @@ bld/ # Uncomment if you have tasks that create the project's static files in wwwroot #wwwroot/ +# Jetbrains Rider cache directory +.idea/ + # Visual Studio 2017 auto generated files Generated\ Files/ @@ -65,7 +68,6 @@ StyleCopReport.xml *_p.c *_h.h *.ilk -*.meta *.obj *.iobj *.pch @@ -353,12 +355,21 @@ MigrationBackup/ # mac-created file to track user view preferences for a directory .DS_Store +# Analysis results +*.sarif + # Unity src/MessagePack.UnityClient/bin/* src/MessagePack.UnityClient/Library/* src/MessagePack.UnityClient/obj/* src/MessagePack.UnityClient/Temp/* +src/MessagePack.UnityClient/UserSettings/* +src/MessagePack.UnityClient/Assets/Packages/ # BenchmarkDotNet results BenchmarkDotNet.Artifacts/ + +src/MessagePack.UnityClient/.vsconfig + +*.lscache diff --git a/azure-pipelines/build.yml b/azure-pipelines/build.yml index 4021879d8..c9f5fc170 100644 --- a/azure-pipelines/build.yml +++ b/azure-pipelines/build.yml @@ -26,7 +26,7 @@ jobs: - job: Linux pool: - vmImage: Ubuntu 20.04 + vmImage: ubuntu-22.04 steps: - checkout: self fetchDepth: 0 # avoid shallow clone so nbgv can do its work. diff --git a/sandbox/DynamicCodeDumper/DynamicCodeDumper.csproj b/sandbox/DynamicCodeDumper/DynamicCodeDumper.csproj index 8d1a7c7e2..676074044 100644 --- a/sandbox/DynamicCodeDumper/DynamicCodeDumper.csproj +++ b/sandbox/DynamicCodeDumper/DynamicCodeDumper.csproj @@ -46,6 +46,9 @@ Code\DynamicAssembly.cs + + Code\DynamicAssemblyFactory.cs + Code\ExpressionUtility.cs diff --git a/sandbox/Sandbox/Generated.cs b/sandbox/Sandbox/Generated.cs index 696478189..16b349886 100644 --- a/sandbox/Sandbox/Generated.cs +++ b/sandbox/Sandbox/Generated.cs @@ -3093,6 +3093,53 @@ public void Serialize(ref global::MessagePack.MessagePackWriter writer, global:: } } + public sealed class SimpleGenericDataFormatter : global::MessagePack.Formatters.IMessagePackFormatter> + { + + public void Serialize(ref global::MessagePack.MessagePackWriter writer, global::SharedData.SimpleGenericData value, global::MessagePack.MessagePackSerializerOptions options) + { + if (value == null) + { + writer.WriteNil(); + return; + } + + global::MessagePack.IFormatterResolver formatterResolver = options.Resolver; + writer.WriteArrayHeader(1); + global::MessagePack.FormatterResolverExtensions.GetFormatterWithVerify(formatterResolver).Serialize(ref writer, value.Value, options); + } + + public global::SharedData.SimpleGenericData Deserialize(ref global::MessagePack.MessagePackReader reader, global::MessagePack.MessagePackSerializerOptions options) + { + if (reader.TryReadNil()) + { + return null; + } + + options.Security.DepthStep(ref reader); + global::MessagePack.IFormatterResolver formatterResolver = options.Resolver; + var length = reader.ReadArrayHeader(); + var __Value__ = default(T); + + for (int i = 0; i < length; i++) + { + switch (i) + { + case 0: + __Value__ = global::MessagePack.FormatterResolverExtensions.GetFormatterWithVerify(formatterResolver).Deserialize(ref reader, options); + break; + default: + reader.Skip(); + break; + } + } + + var ____result = new global::SharedData.SimpleGenericData(__Value__); + reader.Depth--; + return ____result; + } + } + public sealed class SimpleIntKeyDataFormatter : global::MessagePack.Formatters.IMessagePackFormatter { diff --git a/src/MessagePack.AspNetCoreMvcFormatter/MessagePackInputFormatter.cs b/src/MessagePack.AspNetCoreMvcFormatter/MessagePackInputFormatter.cs index c2038f5a0..f84b4bf7a 100644 --- a/src/MessagePack.AspNetCoreMvcFormatter/MessagePackInputFormatter.cs +++ b/src/MessagePack.AspNetCoreMvcFormatter/MessagePackInputFormatter.cs @@ -9,16 +9,17 @@ namespace MessagePack.AspNetCoreMvcFormatter public class MessagePackInputFormatter : InputFormatter { private const string ContentType = "application/x-msgpack"; - private readonly MessagePackSerializerOptions? options; + private static readonly MessagePackSerializerOptions DefaultOptions = MessagePackSerializerOptions.Standard.WithSecurity(MessagePackSecurity.UntrustedData); + private readonly MessagePackSerializerOptions options; public MessagePackInputFormatter() - : this(null) + : this(DefaultOptions) { } public MessagePackInputFormatter(MessagePackSerializerOptions? options) { - this.options = options; + this.options = options ?? DefaultOptions; SupportedMediaTypes.Add(ContentType); } diff --git a/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Formatters/CollectionFormatter.cs b/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Formatters/CollectionFormatter.cs index 29d8ca7d7..02da01f9e 100644 --- a/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Formatters/CollectionFormatter.cs +++ b/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Formatters/CollectionFormatter.cs @@ -765,7 +765,7 @@ protected override ILookup Complete(Dictionary> Create(int count, MessagePackSerializerOptions options) { - return new Dictionary>(count); + return new Dictionary>(count, options.Security.GetEqualityComparer()); } } diff --git a/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Formatters/ExpandoObjectFormatter.cs b/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Formatters/ExpandoObjectFormatter.cs index 2d9328880..98932401f 100644 --- a/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Formatters/ExpandoObjectFormatter.cs +++ b/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Formatters/ExpandoObjectFormatter.cs @@ -8,6 +8,8 @@ namespace MessagePack.Formatters { public class ExpandoObjectFormatter : IMessagePackFormatter { + internal const int MaximumUntrustedDataMemberCount = 1024; + public static readonly IMessagePackFormatter Instance = new ExpandoObjectFormatter(); private ExpandoObjectFormatter() @@ -23,6 +25,7 @@ private ExpandoObjectFormatter() var result = new ExpandoObject(); int count = reader.ReadMapHeader(); + ThrowIfMapTooLargeForUntrustedData(count, options); if (count > 0) { IFormatterResolver resolver = options.Resolver; @@ -49,6 +52,14 @@ private ExpandoObjectFormatter() return result; } + internal static void ThrowIfMapTooLargeForUntrustedData(int count, MessagePackSerializerOptions options) + { + if (options.Security.HashCollisionResistant && count > MaximumUntrustedDataMemberCount) + { + throw new MessagePackSerializationException($"ExpandoObject map size exceeds the limit of {MaximumUntrustedDataMemberCount} entries allowed under untrusted data security mode."); + } + } + public void Serialize(ref MessagePackWriter writer, ExpandoObject? value, MessagePackSerializerOptions options) { if (value is null) diff --git a/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Formatters/MultiDimensionalArrayFormatter.cs b/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Formatters/MultiDimensionalArrayFormatter.cs index 44812d1a0..128e52e42 100644 --- a/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Formatters/MultiDimensionalArrayFormatter.cs +++ b/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Formatters/MultiDimensionalArrayFormatter.cs @@ -2,9 +2,7 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System; -using System.Buffers; -using System.Collections.Generic; -using System.Text; +using System.Diagnostics.CodeAnalysis; #pragma warning disable SA1402 // File may only contain a single type #pragma warning disable SA1649 // File name should match first type name @@ -62,6 +60,7 @@ public void Serialize(ref MessagePackWriter writer, T[,]? value, MessagePackSeri var iLength = reader.ReadInt32(); var jLength = reader.ReadInt32(); var maxLen = reader.ReadArrayHeader(); + MultiDimensionalArrayFormatterHelper.ThrowIfLengthsDontMatch("T[,]", maxLen, iLength, jLength); var array = new T[iLength, jLength]; @@ -148,6 +147,7 @@ public void Serialize(ref MessagePackWriter writer, T[,,]? value, MessagePackSer var jLength = reader.ReadInt32(); var kLength = reader.ReadInt32(); var maxLen = reader.ReadArrayHeader(); + MultiDimensionalArrayFormatterHelper.ThrowIfLengthsDontMatch("T[,,]", maxLen, iLength, jLength, kLength); var array = new T[iLength, jLength, kLength]; @@ -244,6 +244,8 @@ public void Serialize(ref MessagePackWriter writer, T[,,,]? value, MessagePackSe var kLength = reader.ReadInt32(); var lLength = reader.ReadInt32(); var maxLen = reader.ReadArrayHeader(); + MultiDimensionalArrayFormatterHelper.ThrowIfLengthsDontMatch("T[,,,]", maxLen, iLength, jLength, kLength, lLength); + var array = new T[iLength, jLength, kLength, lLength]; var i = 0; @@ -291,4 +293,34 @@ public void Serialize(ref MessagePackWriter writer, T[,,,]? value, MessagePackSe } } } + + internal static class MultiDimensionalArrayFormatterHelper + { + internal static void ThrowIfLengthsDontMatch(string format, int actualLength, int firstLength, int secondLength, int thirdLength = 1, int fourthLength = 1) + { + if (firstLength < 0 || secondLength < 0 || thirdLength < 0 || fourthLength < 0) + { + ThrowInvalidFormat(format); + } + + int expectedLength; + try + { + expectedLength = checked(firstLength * secondLength * thirdLength * fourthLength); + } + catch (OverflowException) + { + ThrowInvalidFormat(format); + return; + } + + if (expectedLength != actualLength) + { + ThrowInvalidFormat(format); + } + } + + [DoesNotReturn] + private static void ThrowInvalidFormat(string format) => throw new MessagePackSerializationException($"Invalid {format} format"); + } } diff --git a/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Formatters/StandardClassLibraryFormatter.cs b/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Formatters/StandardClassLibraryFormatter.cs index da2444b41..1cc840e5b 100644 --- a/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Formatters/StandardClassLibraryFormatter.cs +++ b/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Formatters/StandardClassLibraryFormatter.cs @@ -649,9 +649,14 @@ public void Serialize(ref MessagePackWriter writer, T? value, MessagePackSeriali public T? Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options) { - return reader.ReadString() is string value - ? (T?)Type.GetType(value, throwOnError: true) - : null; + if (reader.ReadString() is not string value) + { + return null; + } + + Type type = options.LoadType(value) ?? throw new TypeLoadException(value); + options.ThrowIfDeserializingTypeIsDisallowed(type); + return (T?)type; } } diff --git a/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Internal/DynamicAssembly.cs b/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Internal/DynamicAssembly.cs index 7e410e446..90ee1698f 100644 --- a/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Internal/DynamicAssembly.cs +++ b/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Internal/DynamicAssembly.cs @@ -20,6 +20,11 @@ internal class DynamicAssembly // don't expose ModuleBuilder //// public ModuleBuilder ModuleBuilder { get { return moduleBuilder; } } + /// + /// Initializes a new instance of the class. + /// Please use instead in order to work across different AssemblyLoadContext that may have duplicate modules. + /// + /// Name of the module to be generated. public DynamicAssembly(string moduleName) { #if NETFRAMEWORK // We don't ship a net472 target, but we might add one for debugging purposes diff --git a/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Internal/DynamicAssemblyFactory.cs b/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Internal/DynamicAssemblyFactory.cs new file mode 100644 index 000000000..1529e07bf --- /dev/null +++ b/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Internal/DynamicAssemblyFactory.cs @@ -0,0 +1,63 @@ +// Copyright (c) All contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Collections.Generic; +using System.Reflection; + +#if NET +using System.Runtime.Loader; +#endif + +namespace MessagePack.Internal +{ + /// + /// This class is responsible for managing DynamicAssembly instance creation taking into account + /// AssemblyLoadContext when running under .NET. + /// + internal class DynamicAssemblyFactory + { + private readonly string moduleName; + + private readonly Lazy singletonAssembly; + +#if NET + private readonly Dictionary alcCache = new(); +#endif + + public DynamicAssemblyFactory(string moduleName) + { + this.moduleName = moduleName; + this.singletonAssembly = new Lazy(() => new DynamicAssembly(this.moduleName)); + } + +#if NET + public DynamicAssembly GetDynamicAssembly(Type? type) + { + if (type is null || AssemblyLoadContext.GetLoadContext(type.Assembly) is not AssemblyLoadContext loadContext) + { + return this.singletonAssembly.Value; + } + else + { + DynamicAssembly? assembly = null; + lock (this.alcCache) + { + if (!this.alcCache.TryGetValue(loadContext, out assembly)) + { + assembly = new DynamicAssembly(this.moduleName); + this.alcCache[loadContext] = assembly; + } + + return assembly; + } + } + } +#else + public DynamicAssembly GetDynamicAssembly(Type? type) + { + return this.singletonAssembly.Value; + } +#endif + } +} diff --git a/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Internal/TinyJsonReader.cs b/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Internal/TinyJsonReader.cs index 2d082f9f7..89036c12e 100644 --- a/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Internal/TinyJsonReader.cs +++ b/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Internal/TinyJsonReader.cs @@ -134,62 +134,64 @@ private static bool IsWordBreak(char c) private void ReadNextToken() { - this.SkipWhiteSpace(); - - var intChar = this.reader.Peek(); - if (intChar == -1) + while (true) { - this.TokenType = TinyJsonToken.None; - return; - } + this.SkipWhiteSpace(); - var c = (char)intChar; - switch (c) - { - case '{': - this.TokenType = TinyJsonToken.StartObject; - return; - case '}': - this.TokenType = TinyJsonToken.EndObject; - return; - case '[': - this.TokenType = TinyJsonToken.StartArray; - return; - case ']': - this.TokenType = TinyJsonToken.EndArray; - return; - case '"': - this.TokenType = TinyJsonToken.String; - return; - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - case '-': - this.TokenType = TinyJsonToken.Number; - return; - case 't': - this.TokenType = TinyJsonToken.True; - return; - case 'f': - this.TokenType = TinyJsonToken.False; - return; - case 'n': - this.TokenType = TinyJsonToken.Null; - return; - case ',': - case ':': - this.reader.Read(); - this.ReadNextToken(); + var intChar = this.reader.Peek(); + if (intChar == -1) + { + this.TokenType = TinyJsonToken.None; return; - default: - throw new TinyJsonException("Invalid String:" + c); + } + + var c = (char)intChar; + switch (c) + { + case '{': + this.TokenType = TinyJsonToken.StartObject; + return; + case '}': + this.TokenType = TinyJsonToken.EndObject; + return; + case '[': + this.TokenType = TinyJsonToken.StartArray; + return; + case ']': + this.TokenType = TinyJsonToken.EndArray; + return; + case '"': + this.TokenType = TinyJsonToken.String; + return; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + case '-': + this.TokenType = TinyJsonToken.Number; + return; + case 't': + this.TokenType = TinyJsonToken.True; + return; + case 'f': + this.TokenType = TinyJsonToken.False; + return; + case 'n': + this.TokenType = TinyJsonToken.Null; + return; + case ',': + case ':': + this.reader.Read(); + continue; + default: + throw new TinyJsonException("Invalid String:" + c); + } } } diff --git a/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Internal/UnsafeMemory.Low.cs b/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Internal/UnsafeMemory.Low.cs index 1e6627029..07690fd8e 100644 --- a/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Internal/UnsafeMemory.Low.cs +++ b/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Internal/UnsafeMemory.Low.cs @@ -17,12 +17,20 @@ public static class UnsafeMemory public static readonly bool Is32Bit = IntPtr.Size == 4; } + /// + /// Highly tuned method for writing raw bytes to a . + /// + /// + /// The methods on this class are not safe, in that they use pointer arithmetic + /// and assume that the caller has provided a with a length + /// of at least the number of bytes being written. The caller must ensure that this is the case. + /// public static partial class UnsafeMemory32 { [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe void WriteRaw1(ref MessagePackWriter writer, ReadOnlySpan src) { - Span dst = writer.GetSpan(src.Length); + Span dst = writer.GetSpan(1); fixed (byte* pSrc = &src[0]) fixed (byte* pDst = &dst[0]) @@ -30,13 +38,13 @@ public static unsafe void WriteRaw1(ref MessagePackWriter writer, ReadOnlySpan src) { - Span dst = writer.GetSpan(src.Length); + Span dst = writer.GetSpan(2); fixed (byte* pSrc = &src[0]) fixed (byte* pDst = &dst[0]) @@ -44,13 +52,13 @@ public static unsafe void WriteRaw2(ref MessagePackWriter writer, ReadOnlySpan src) { - Span dst = writer.GetSpan(src.Length); + Span dst = writer.GetSpan(3); fixed (byte* pSrc = &src[0]) fixed (byte* pDst = &dst[0]) @@ -59,16 +67,24 @@ public static unsafe void WriteRaw3(ref MessagePackWriter writer, ReadOnlySpan + /// Highly tuned method for writing raw bytes to a . + /// + /// + /// The methods on this class are not safe, in that they use pointer arithmetic + /// and assume that the caller has provided a with a length + /// of at least the number of bytes being written. The caller must ensure that this is the case. + /// public static partial class UnsafeMemory64 { [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe void WriteRaw1(ref MessagePackWriter writer, ReadOnlySpan src) { - Span dst = writer.GetSpan(src.Length); + Span dst = writer.GetSpan(1); fixed (byte* pSrc = &src[0]) fixed (byte* pDst = &dst[0]) @@ -76,13 +92,13 @@ public static unsafe void WriteRaw1(ref MessagePackWriter writer, ReadOnlySpan src) { - Span dst = writer.GetSpan(src.Length); + Span dst = writer.GetSpan(2); fixed (byte* pSrc = &src[0]) fixed (byte* pDst = &dst[0]) @@ -90,13 +106,13 @@ public static unsafe void WriteRaw2(ref MessagePackWriter writer, ReadOnlySpan src) { - Span dst = writer.GetSpan(src.Length); + Span dst = writer.GetSpan(3); fixed (byte* pSrc = &src[0]) fixed (byte* pDst = &dst[0]) @@ -105,13 +121,13 @@ public static unsafe void WriteRaw3(ref MessagePackWriter writer, ReadOnlySpan src) { - Span dst = writer.GetSpan(src.Length); + Span dst = writer.GetSpan(4); fixed (byte* pSrc = &src[0]) fixed (byte* pDst = &dst[0]) @@ -119,13 +135,13 @@ public static unsafe void WriteRaw4(ref MessagePackWriter writer, ReadOnlySpan src) { - Span dst = writer.GetSpan(src.Length); + Span dst = writer.GetSpan(5); fixed (byte* pSrc = &src[0]) fixed (byte* pDst = &dst[0]) @@ -134,13 +150,13 @@ public static unsafe void WriteRaw5(ref MessagePackWriter writer, ReadOnlySpan src) { - Span dst = writer.GetSpan(src.Length); + Span dst = writer.GetSpan(6); fixed (byte* pSrc = &src[0]) fixed (byte* pDst = &dst[0]) @@ -149,13 +165,13 @@ public static unsafe void WriteRaw6(ref MessagePackWriter writer, ReadOnlySpan src) { - Span dst = writer.GetSpan(src.Length); + Span dst = writer.GetSpan(7); fixed (byte* pSrc = &src[0]) fixed (byte* pDst = &dst[0]) @@ -164,7 +180,7 @@ public static unsafe void WriteRaw7(ref MessagePackWriter writer, ReadOnlySpan input, Span output) int length; if (IntPtr.Size == 4) { - length = LZ4_uncompress_32(inputPtr, outputPtr, output.Length); + length = LZ4_uncompress_32(inputPtr, input.Length, outputPtr, output.Length); } else { - length = LZ4_uncompress_64(inputPtr, outputPtr, output.Length); + length = LZ4_uncompress_64(inputPtr, input.Length, outputPtr, output.Length); } if (length != input.Length) diff --git a/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/LZ4/LZ4Codec.Unsafe32.Dirty.cs b/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/LZ4/LZ4Codec.Unsafe32.Dirty.cs index 22d39b25d..23a40ddca 100644 --- a/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/LZ4/LZ4Codec.Unsafe32.Dirty.cs +++ b/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/LZ4/LZ4Codec.Unsafe32.Dirty.cs @@ -600,6 +600,7 @@ private static unsafe int LZ4_compress64kCtx_32( private static unsafe int LZ4_uncompress_32( byte* src, + int src_len, byte* dst, int dst_len) { @@ -609,6 +610,7 @@ private static unsafe int LZ4_uncompress_32( { // r93 var src_p = src; + var src_end = src + src_len; byte* xxx_ref; var dst_p = dst; @@ -627,16 +629,26 @@ private static unsafe int LZ4_uncompress_32( int length; // get runlength + if (src_p >= src_end) + { + goto _output_error; + } + xxx_token = *src_p++; if ((length = (int)(xxx_token >> ML_BITS)) == RUN_MASK) { int len; - for (; (len = *src_p++) == 255; length += 255) + do { - /* do nothing */ - } + if (src_p >= src_end) + { + goto _output_error; + } - length += len; + len = *src_p++; + length += len; + } + while (len == 255); } // copy literals @@ -649,11 +661,21 @@ private static unsafe int LZ4_uncompress_32( goto _output_error; // Error : not enough place for another match (min 4) + 5 literals } + if (length > src_end - src_p) + { + goto _output_error; + } + BlockCopy32(src_p, dst_p, length); src_p += length; break; // EOF } + if (length > src_end - src_p) + { + goto _output_error; + } + do { *(uint*)dst_p = *(uint*)src_p; @@ -668,6 +690,11 @@ private static unsafe int LZ4_uncompress_32( dst_p = dst_cpy; // get offset + if (src_end - src_p < 2) + { + goto _output_error; + } + xxx_ref = dst_cpy - (*(ushort*)src_p); src_p += 2; if (xxx_ref < dst) @@ -678,12 +705,18 @@ private static unsafe int LZ4_uncompress_32( // get matchlength if ((length = (int)(xxx_token & ML_MASK)) == ML_MASK) { - for (; *src_p == 255; length += 255) + int len; + do { - src_p++; - } + if (src_p >= src_end) + { + goto _output_error; + } - length += *src_p++; + len = *src_p++; + length += len; + } + while (len == 255); } // copy repeated sequence diff --git a/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/LZ4/LZ4Codec.Unsafe64.Dirty.cs b/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/LZ4/LZ4Codec.Unsafe64.Dirty.cs index ba10e68d2..f807ef17e 100644 --- a/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/LZ4/LZ4Codec.Unsafe64.Dirty.cs +++ b/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/LZ4/LZ4Codec.Unsafe64.Dirty.cs @@ -612,6 +612,7 @@ private static unsafe int LZ4_compress64kCtx_64( private static unsafe int LZ4_uncompress_64( byte* src, + int src_len, byte* dst, int dst_len) { @@ -622,6 +623,7 @@ private static unsafe int LZ4_uncompress_64( { // r93 var src_p = src; + var src_end = src + src_len; byte* dst_ref; var dst_p = dst; @@ -640,16 +642,26 @@ private static unsafe int LZ4_uncompress_64( int length; // get runlength + if (src_p >= src_end) + { + goto _output_error; + } + token = *src_p++; if ((length = token >> ML_BITS) == RUN_MASK) { int len; - for (; (len = *src_p++) == 255; length += 255) + do { - /* do nothing */ - } + if (src_p >= src_end) + { + goto _output_error; + } - length += len; + len = *src_p++; + length += len; + } + while (len == 255); } // copy literals @@ -662,11 +674,21 @@ private static unsafe int LZ4_uncompress_64( goto _output_error; // Error : not enough place for another match (min 4) + 5 literals } + if (length > src_end - src_p) + { + goto _output_error; + } + BlockCopy64(src_p, dst_p, length); src_p += length; break; // EOF } + if (length > src_end - src_p) + { + goto _output_error; + } + do { *(ulong*)dst_p = *(ulong*)src_p; @@ -678,6 +700,11 @@ private static unsafe int LZ4_uncompress_64( dst_p = dst_cpy; // get offset + if (src_end - src_p < 2) + { + goto _output_error; + } + dst_ref = dst_cpy - (*(ushort*)src_p); src_p += 2; if (dst_ref < dst) @@ -688,12 +715,18 @@ private static unsafe int LZ4_uncompress_64( // get matchlength if ((length = token & ML_MASK) == ML_MASK) { - for (; *src_p == 255; length += 255) + int len; + do { - src_p++; - } + if (src_p >= src_end) + { + goto _output_error; + } - length += *src_p++; + len = *src_p++; + length += len; + } + while (len == 255); } // copy repeated sequence diff --git a/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/MessagePackReader.cs b/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/MessagePackReader.cs index d2c630d73..5a38fccd6 100644 --- a/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/MessagePackReader.cs +++ b/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/MessagePackReader.cs @@ -154,81 +154,123 @@ public byte NextCode /// internal bool TrySkip() { - if (this.reader.Remaining == 0) + long remainingStructures = 1; + while (remainingStructures > 0) { - return false; - } + if (this.reader.Remaining == 0) + { + return false; + } - byte code = this.NextCode; - switch (code) - { - case MessagePackCode.Nil: - case MessagePackCode.True: - case MessagePackCode.False: - return this.reader.TryAdvance(1); - case MessagePackCode.Int8: - case MessagePackCode.UInt8: - return this.reader.TryAdvance(2); - case MessagePackCode.Int16: - case MessagePackCode.UInt16: - return this.reader.TryAdvance(3); - case MessagePackCode.Int32: - case MessagePackCode.UInt32: - case MessagePackCode.Float32: - return this.reader.TryAdvance(5); - case MessagePackCode.Int64: - case MessagePackCode.UInt64: - case MessagePackCode.Float64: - return this.reader.TryAdvance(9); - case MessagePackCode.Map16: - case MessagePackCode.Map32: - return this.TrySkipNextMap(); - case MessagePackCode.Array16: - case MessagePackCode.Array32: - return this.TrySkipNextArray(); - case MessagePackCode.Str8: - case MessagePackCode.Str16: - case MessagePackCode.Str32: - return this.TryGetStringLengthInBytes(out int length) && this.reader.TryAdvance(length); - case MessagePackCode.Bin8: - case MessagePackCode.Bin16: - case MessagePackCode.Bin32: - return this.TryGetBytesLength(out length) && this.reader.TryAdvance(length); - case MessagePackCode.FixExt1: - case MessagePackCode.FixExt2: - case MessagePackCode.FixExt4: - case MessagePackCode.FixExt8: - case MessagePackCode.FixExt16: - case MessagePackCode.Ext8: - case MessagePackCode.Ext16: - case MessagePackCode.Ext32: - return this.TryReadExtensionFormatHeader(out ExtensionHeader header) && this.reader.TryAdvance(header.Length); - default: - if ((code >= MessagePackCode.MinNegativeFixInt && code <= MessagePackCode.MaxNegativeFixInt) || - (code >= MessagePackCode.MinFixInt && code <= MessagePackCode.MaxFixInt)) - { - return this.reader.TryAdvance(1); - } + remainingStructures--; + byte code = this.NextCode; + switch (code) + { + case byte x when (x >= MessagePackCode.MinNegativeFixInt && x <= MessagePackCode.MaxNegativeFixInt) || (x >= MessagePackCode.MinFixInt && x <= MessagePackCode.MaxFixInt): + case MessagePackCode.Nil: + case MessagePackCode.True: + case MessagePackCode.False: + if (!this.reader.TryAdvance(1)) + { + return false; + } - if (code >= MessagePackCode.MinFixMap && code <= MessagePackCode.MaxFixMap) - { - return this.TrySkipNextMap(); - } + break; + case MessagePackCode.Int8: + case MessagePackCode.UInt8: + if (!this.reader.TryAdvance(2)) + { + return false; + } - if (code >= MessagePackCode.MinFixArray && code <= MessagePackCode.MaxFixArray) - { - return this.TrySkipNextArray(); - } + break; + case MessagePackCode.Int16: + case MessagePackCode.UInt16: + if (!this.reader.TryAdvance(3)) + { + return false; + } - if (code >= MessagePackCode.MinFixStr && code <= MessagePackCode.MaxFixStr) - { - return this.TryGetStringLengthInBytes(out length) && this.reader.TryAdvance(length); - } + break; + case MessagePackCode.Int32: + case MessagePackCode.UInt32: + case MessagePackCode.Float32: + if (!this.reader.TryAdvance(5)) + { + return false; + } - // We don't actually expect to ever hit this point, since every code is supported. - Debug.Fail("Missing handler for code: " + code); - throw ThrowInvalidCode(code); + break; + case MessagePackCode.Int64: + case MessagePackCode.UInt64: + case MessagePackCode.Float64: + if (!this.reader.TryAdvance(9)) + { + return false; + } + + break; + case byte x when x >= MessagePackCode.MinFixMap && x <= MessagePackCode.MaxFixMap: + case MessagePackCode.Map16: + case MessagePackCode.Map32: + if (!this.TryReadMapHeader(out int count)) + { + return false; + } + + remainingStructures = checked(remainingStructures + ((long)count * 2)); + break; + case byte x when x >= MessagePackCode.MinFixArray && x <= MessagePackCode.MaxFixArray: + case MessagePackCode.Array16: + case MessagePackCode.Array32: + if (!this.TryReadArrayHeader(out count)) + { + return false; + } + + remainingStructures = checked(remainingStructures + count); + break; + case byte x when x >= MessagePackCode.MinFixStr && x <= MessagePackCode.MaxFixStr: + case MessagePackCode.Str8: + case MessagePackCode.Str16: + case MessagePackCode.Str32: + if (!this.TryGetStringLengthInBytes(out int length) || !this.reader.TryAdvance(length)) + { + return false; + } + + break; + case MessagePackCode.Bin8: + case MessagePackCode.Bin16: + case MessagePackCode.Bin32: + if (!this.TryGetBytesLength(out length) || !this.reader.TryAdvance(length)) + { + return false; + } + + break; + case MessagePackCode.FixExt1: + case MessagePackCode.FixExt2: + case MessagePackCode.FixExt4: + case MessagePackCode.FixExt8: + case MessagePackCode.FixExt16: + case MessagePackCode.Ext8: + case MessagePackCode.Ext16: + case MessagePackCode.Ext32: + if (!this.TryReadExtensionFormatHeader(out ExtensionHeader header) || !this.reader.TryAdvance(header.Length)) + { + return false; + } + + break; + default: + // We don't actually expect to ever hit this point, since every code is supported. + Debug.Fail("Missing handler for code: " + code); + throw ThrowInvalidCode(code); + } } + + return true; } /// @@ -390,7 +432,7 @@ public int ReadMapHeader() // Protect against corrupted or mischievious data that may lead to allocating way too much memory. // We allow for each primitive to be the minimal 1 byte in size, and we have a key=value map, so that's 2 bytes. // Formatters that know each element is larger can optionally add a stronger check. - ThrowInsufficientBufferUnless(this.reader.Remaining >= count * 2); + ThrowInsufficientBufferUnless(this.reader.Remaining >= (long)count * 2); return count; } @@ -1130,22 +1172,5 @@ private string ReadStringSlow(int byteLength) ArrayPool.Shared.Return(charArray); return value; } - - private bool TrySkipNextArray() => this.TryReadArrayHeader(out int count) && this.TrySkip(count); - - private bool TrySkipNextMap() => this.TryReadMapHeader(out int count) && this.TrySkip(count * 2); - - private bool TrySkip(int count) - { - for (int i = 0; i < count; i++) - { - if (!this.TrySkip()) - { - return false; - } - } - - return true; - } } } diff --git a/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/MessagePackSecurity.cs b/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/MessagePackSecurity.cs index 3a6715299..9d8a71d5c 100644 --- a/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/MessagePackSecurity.cs +++ b/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/MessagePackSecurity.cs @@ -19,6 +19,8 @@ namespace MessagePack /// public class MessagePackSecurity { + private const int DefaultUntrustedDataMaximumDecompressedSize = 64 * 1024 * 1024; + /// /// Gets an instance preconfigured with settings that omit all protections. Useful for deserializing fully-trusted and valid msgpack sequences. /// @@ -31,6 +33,7 @@ public class MessagePackSecurity { HashCollisionResistant = true, MaximumObjectGraphDepth = 500, + MaximumDecompressedSize = DefaultUntrustedDataMaximumDecompressedSize, }; private static readonly SipHash Hash = new(); @@ -57,6 +60,7 @@ protected MessagePackSecurity(MessagePackSecurity copyFrom) this.HashCollisionResistant = copyFrom.HashCollisionResistant; this.MaximumObjectGraphDepth = copyFrom.MaximumObjectGraphDepth; + this.MaximumDecompressedSize = copyFrom.MaximumDecompressedSize; } /// @@ -81,6 +85,12 @@ protected MessagePackSecurity(MessagePackSecurity copyFrom) /// public int MaximumObjectGraphDepth { get; private set; } = int.MaxValue; + /// + /// Gets the maximum decompressed size in bytes allowed when deserializing compressed payloads. + /// + /// The default value is for and 64MB for . + public int MaximumDecompressedSize { get; private set; } = int.MaxValue; + /// /// Gets a copy of these options with the property set to a new value. /// @@ -98,6 +108,28 @@ public MessagePackSecurity WithMaximumObjectGraphDepth(int maximumObjectGraphDep return clone; } + /// + /// Gets a copy of these options with the property set to a new value. + /// + /// The new value for the property. Must not be negative. + /// The new instance; or the original if the value is unchanged. + public MessagePackSecurity WithMaximumDecompressedSize(int maximumDecompressedSize) + { + if (this.MaximumDecompressedSize == maximumDecompressedSize) + { + return this; + } + + if (maximumDecompressedSize < 0) + { + throw new ArgumentOutOfRangeException(nameof(maximumDecompressedSize)); + } + + var clone = this.Clone(); + clone.MaximumDecompressedSize = maximumDecompressedSize; + return clone; + } + /// /// Gets a copy of these options with the property set to a new value. /// diff --git a/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/MessagePackSerializer.Json.cs b/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/MessagePackSerializer.Json.cs index b9d02ac62..baf8a4e92 100644 --- a/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/MessagePackSerializer.Json.cs +++ b/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/MessagePackSerializer.Json.cs @@ -89,7 +89,7 @@ public static void ConvertToJson(ref MessagePackReader reader, TextWriter jsonWr { using (var scratchRental = options.SequencePool.Rent()) { - if (TryDecompress(ref reader, scratchRental.Value)) + if (TryDecompress(ref reader, scratchRental.Value, options)) { var scratchReader = new MessagePackReader(scratchRental.Value) { @@ -184,6 +184,11 @@ public static void ConvertFromJson(TextReader reader, ref MessagePackWriter writ } private static uint FromJsonCore(TinyJsonReader jr, ref MessagePackWriter writer, MessagePackSerializerOptions options) + { + return FromJsonCore(jr, ref writer, options, 0); + } + + private static uint FromJsonCore(TinyJsonReader jr, ref MessagePackWriter writer, MessagePackSerializerOptions options, int depth) { uint count = 0; while (jr.Read()) @@ -193,11 +198,13 @@ private static uint FromJsonCore(TinyJsonReader jr, ref MessagePackWriter writer case TinyJsonToken.None: break; case TinyJsonToken.StartObject: + VerifyJsonObjectGraphDepth(options, depth); + // Set up a scratch area to serialize the collection since we don't know its length yet, which must be written first. using (var scratchRental = options.SequencePool.Rent()) { MessagePackWriter scratchWriter = writer.Clone(scratchRental.Value); - var mapCount = FromJsonCore(jr, ref scratchWriter, options); + var mapCount = FromJsonCore(jr, ref scratchWriter, options, depth + 1); scratchWriter.Flush(); mapCount = mapCount / 2; // remove propertyname string count. @@ -210,11 +217,13 @@ private static uint FromJsonCore(TinyJsonReader jr, ref MessagePackWriter writer case TinyJsonToken.EndObject: return count; // break case TinyJsonToken.StartArray: + VerifyJsonObjectGraphDepth(options, depth); + // Set up a scratch area to serialize the collection since we don't know its length yet, which must be written first. using (var scratchRental = options.SequencePool.Rent()) { MessagePackWriter scratchWriter = writer.Clone(scratchRental.Value); - var arrayCount = FromJsonCore(jr, ref scratchWriter, options); + var arrayCount = FromJsonCore(jr, ref scratchWriter, options, depth + 1); scratchWriter.Flush(); writer.WriteArrayHeader(arrayCount); @@ -270,6 +279,14 @@ private static uint FromJsonCore(TinyJsonReader jr, ref MessagePackWriter writer return count; } + private static void VerifyJsonObjectGraphDepth(MessagePackSerializerOptions options, int depth) + { + if (depth >= options.Security.MaximumObjectGraphDepth) + { + throw new InsufficientExecutionStackException($"This JSON sequence has an object graph that exceeds the maximum depth allowed of {options.Security.MaximumObjectGraphDepth}."); + } + } + private static void ToJsonCore(ref MessagePackReader reader, TextWriter writer, MessagePackSerializerOptions options) { MessagePackType type = reader.NextMessagePackType; @@ -393,46 +410,54 @@ private static void ToJsonCore(ref MessagePackReader reader, TextWriter writer, #if !UNITY_2018_3_OR_NEWER else if (extHeader.TypeCode == ThisLibraryExtensionTypeCodes.TypelessFormatter) { - // prepare type name token - var privateBuilder = new StringBuilder(); - var typeNameTokenBuilder = new StringBuilder(); - SequencePosition positionBeforeTypeNameRead = reader.Position; - ToJsonCore(ref reader, new StringWriter(typeNameTokenBuilder), options); - int typeNameReadSize = (int)reader.Sequence.Slice(positionBeforeTypeNameRead, reader.Position).Length; - if (extHeader.Length > typeNameReadSize) + options.Security.DepthStep(ref reader); + try { - // object map or array - MessagePackType typeInside = reader.NextMessagePackType; - if (typeInside != MessagePackType.Array && typeInside != MessagePackType.Map) + // prepare type name token + var privateBuilder = new StringBuilder(); + var typeNameTokenBuilder = new StringBuilder(); + SequencePosition positionBeforeTypeNameRead = reader.Position; + ToJsonCore(ref reader, new StringWriter(typeNameTokenBuilder), options); + int typeNameReadSize = (int)reader.Sequence.Slice(positionBeforeTypeNameRead, reader.Position).Length; + if (extHeader.Length > typeNameReadSize) { - privateBuilder.Append("{"); - } + // object map or array + MessagePackType typeInside = reader.NextMessagePackType; + if (typeInside != MessagePackType.Array && typeInside != MessagePackType.Map) + { + privateBuilder.Append("{"); + } - ToJsonCore(ref reader, new StringWriter(privateBuilder), options); + ToJsonCore(ref reader, new StringWriter(privateBuilder), options); - // insert type name token to start of object map or array - if (typeInside != MessagePackType.Array) - { - typeNameTokenBuilder.Insert(0, "\"$type\":"); - } + // insert type name token to start of object map or array + if (typeInside != MessagePackType.Array) + { + typeNameTokenBuilder.Insert(0, "\"$type\":"); + } - if (typeInside != MessagePackType.Array && typeInside != MessagePackType.Map) - { - privateBuilder.Append("}"); - } + if (typeInside != MessagePackType.Array && typeInside != MessagePackType.Map) + { + privateBuilder.Append("}"); + } - if (privateBuilder.Length > 2) - { - typeNameTokenBuilder.Append(","); - } + if (privateBuilder.Length > 2) + { + typeNameTokenBuilder.Append(","); + } - privateBuilder.Insert(1, typeNameTokenBuilder.ToString()); + privateBuilder.Insert(1, typeNameTokenBuilder.ToString()); - writer.Write(privateBuilder.ToString()); + writer.Write(privateBuilder.ToString()); + } + else + { + writer.Write("{\"$type\":" + typeNameTokenBuilder.ToString() + "}"); + } } - else + finally { - writer.Write("{\"$type\":" + typeNameTokenBuilder.ToString() + "}"); + reader.Depth--; } } #endif diff --git a/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/MessagePackSerializer.cs b/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/MessagePackSerializer.cs index a75917b0b..8d11b3122 100644 --- a/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/MessagePackSerializer.cs +++ b/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/MessagePackSerializer.cs @@ -234,7 +234,7 @@ public static T Deserialize(ref MessagePackReader reader, MessagePackSerializ using (var msgPackUncompressedRental = options.SequencePool.Rent()) { var msgPackUncompressed = msgPackUncompressedRental.Value; - if (TryDecompress(ref reader, msgPackUncompressed)) + if (TryDecompress(ref reader, msgPackUncompressed, options)) { MessagePackReader uncompressedReader = reader.Clone(msgPackUncompressed.AsReadOnlySequence); return options.Resolver.GetFormatterWithVerify().Deserialize(ref uncompressedReader, options); @@ -482,7 +482,7 @@ private static int LZ4Operation(in ReadOnlySequence input, Span outp } } - private static bool TryDecompress(ref MessagePackReader reader, IBufferWriter writer) + private static bool TryDecompress(ref MessagePackReader reader, IBufferWriter writer, MessagePackSerializerOptions options) { if (!reader.End) { @@ -504,6 +504,7 @@ private static bool TryDecompress(ref MessagePackReader reader, IBufferWriter compressedData = extReader.Sequence.Slice(extReader.Position); + ThrowIfInvalidLz4BlockLength(uncompressedLength, options.Security.MaximumDecompressedSize); Span uncompressedSpan = writer.GetSpan(uncompressedLength).Slice(0, uncompressedLength); int actualUncompressedLength = LZ4Operation(compressedData, uncompressedSpan, LZ4CodecDecode); Debug.Assert(actualUncompressedLength == uncompressedLength, "Unexpected length of uncompressed data."); @@ -530,6 +531,7 @@ private static bool TryDecompress(ref MessagePackReader reader, IBufferWriter.Shared.Rent(sequenceCount); try { + long remainingMaxDecompressedSize = options.Security.MaximumDecompressedSize; for (int i = 0; i < sequenceCount; i++) { uncompressedLengths[i] = reader.ReadInt32(); @@ -539,6 +541,8 @@ private static bool TryDecompress(ref MessagePackReader reader, IBufferWriter lz4Block = reader.ReadBytes() ?? throw MessagePackSerializationException.ThrowUnexpectedNilWhileDeserializing>(); + ThrowIfInvalidLz4BlockLength(uncompressedLength, remainingMaxDecompressedSize); + remainingMaxDecompressedSize -= uncompressedLength; Span uncompressedSpan = writer.GetSpan(uncompressedLength).Slice(0, uncompressedLength); var actualUncompressedLength = LZ4Operation(lz4Block, uncompressedSpan, LZ4CodecDecode); Debug.Assert(actualUncompressedLength == uncompressedLength, "Unexpected length of uncompressed data."); @@ -559,6 +563,14 @@ private static bool TryDecompress(ref MessagePackReader reader, IBufferWriter remainingMaxDecompressedSize) + { + throw new MessagePackSerializationException("LZ4 block declares a decompressed length that exceeds the configured maximum."); + } + } + private static void ToLZ4BinaryCore(in ReadOnlySequence msgpackUncompressedData, ref MessagePackWriter writer, MessagePackCompression compression, int minCompressionSize) { if (msgpackUncompressedData.Length < minCompressionSize) diff --git a/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/MessagePackSerializerOptions.cs b/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/MessagePackSerializerOptions.cs index f750f93df..8c660f464 100644 --- a/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/MessagePackSerializerOptions.cs +++ b/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/MessagePackSerializerOptions.cs @@ -24,8 +24,25 @@ public class MessagePackSerializerOptions /// private static readonly HashSet DisallowedTypes = new HashSet { + "Microsoft.VisualStudio.Text.Formatting.TextFormattingRunProperties", + "System.CodeDom.Compiler.CompilerResults", "System.CodeDom.Compiler.TempFileCollection", + "System.Configuration.SettingsPropertyValue", + "System.Data.DataSet", + "System.Data.DataTable", + "System.Diagnostics.Process", + "System.Diagnostics.ProcessStartInfo", + "System.Drawing.Design.ToolboxItemContainer", + "System.IdentityModel.Tokens.SessionSecurityToken", "System.Management.IWbemClassObjectFreeThreaded", + "System.Security.Claims.ClaimsIdentity", + "System.Security.Claims.ClaimsPrincipal", + "System.Security.Principal.WindowsIdentity", + "System.Security.Principal.WindowsPrincipal", + "System.Web.Security.RolePrincipal", + "System.Windows.Data.ObjectDataProvider", + "System.Windows.ResourceDictionary", + "System.Workflow.ComponentModel.Serialization.ActivitySurrogateSelector", }; #if !DYNAMICCODEDUMPER @@ -169,16 +186,32 @@ protected MessagePackSerializerOptions(MessagePackSerializerOptions copyFrom) /// The type to be instantiated. /// Thrown if the is not allowed to be deserialized. /// + /// /// This method provides a means for an important security mitigation when using the Typeless formatter to prevent untrusted messagepack from /// deserializing objects that may be harmful if instantiated, disposed or finalized. - /// The default implementation throws for only a few known dangerous types. + /// The default implementation throws for only a few known dangerous types, or types that nest those dangerous types as generic type arguments or array element types. /// Applications that deserialize from untrusted sources should override this method and throw if the type is not among the expected set. + /// + /// + /// This method is for backward compatibility reasons. + /// For better security, the preferred method to override is . + /// /// public virtual void ThrowIfDeserializingTypeIsDisallowed(Type type) { - if (type.FullName is string fullName && DisallowedTypes.Contains(fullName)) + this.ThrowIfDeserializingTypeIsDisallowedCore(type); + + if (type.HasElementType && type.GetElementType() is Type elementType) { - throw new MessagePackSerializationException($"Deserialization attempted to create the type {fullName} which is not allowed."); + this.ThrowIfDeserializingTypeIsDisallowed(elementType); + } + + if (type.IsConstructedGenericType) + { + foreach (Type genericTypeArgument in type.GenericTypeArguments) + { + this.ThrowIfDeserializingTypeIsDisallowed(genericTypeArgument); + } } } @@ -355,6 +388,31 @@ public MessagePackSerializerOptions WithPool(SequencePool pool) return result; } + /// + /// Checks whether a specific given type may be deserialized, disregarding generic type arguments or array element types. + /// + /// The type to be instantiated. + /// Thrown if the is not allowed to be deserialized. + /// + /// + /// This method provides a means for an important security mitigation when using the Typeless formatter to prevent untrusted messagepack from + /// deserializing objects that may be harmful if instantiated, disposed or finalized. + /// The default implementation throws for only a few known dangerous types. + /// Applications that deserialize from untrusted sources should override this method and throw if the type is not among the expected set. + /// + /// + /// This method is called from the default implementation of + /// for the top-level type and again for each generic type argument or array element type. + /// + /// + protected virtual void ThrowIfDeserializingTypeIsDisallowedCore(Type type) + { + if (type.FullName is string fullName && DisallowedTypes.Contains(fullName)) + { + throw new MessagePackSerializationException($"Deserialization attempted to create the type {fullName} which is not allowed."); + } + } + /// /// Creates a clone of this instance with the same properties set. /// diff --git a/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Resolvers/DynamicEnumResolver.cs b/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Resolvers/DynamicEnumResolver.cs index f11be19e2..c9ce48e0c 100644 --- a/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Resolvers/DynamicEnumResolver.cs +++ b/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Resolvers/DynamicEnumResolver.cs @@ -25,7 +25,7 @@ public sealed class DynamicEnumResolver : IFormatterResolver private const string ModuleName = "MessagePack.Resolvers.DynamicEnumResolver"; - private static readonly Lazy DynamicAssembly; + private static readonly DynamicAssemblyFactory DynamicAssemblyFactory; private static int nameSequence = 0; @@ -35,13 +35,13 @@ private DynamicEnumResolver() static DynamicEnumResolver() { - DynamicAssembly = new Lazy(() => new DynamicAssembly(ModuleName)); + DynamicAssemblyFactory = new DynamicAssemblyFactory(ModuleName); } #if NETFRAMEWORK internal AssemblyBuilder Save() { - return DynamicAssembly.Value.Save(); + return DynamicAssemblyFactory.GetDynamicAssembly(type: null).Save(); } #endif @@ -95,7 +95,7 @@ private static TypeInfo BuildType(Type enumType) { using (MonoProtection.EnterRefEmitLock()) { - TypeBuilder typeBuilder = DynamicAssembly.Value.DefineType("MessagePack.Formatters." + enumType.FullName!.Replace(".", "_") + "Formatter" + Interlocked.Increment(ref nameSequence), TypeAttributes.Public | TypeAttributes.Sealed, null, new[] { formatterType }); + TypeBuilder typeBuilder = DynamicAssemblyFactory.GetDynamicAssembly(enumType).DefineType("MessagePack.Formatters." + enumType.FullName!.Replace(".", "_") + "Formatter" + Interlocked.Increment(ref nameSequence), TypeAttributes.Public | TypeAttributes.Sealed, null, new[] { formatterType }); // void Serialize(ref MessagePackWriter writer, T value, MessagePackSerializerOptions options); { diff --git a/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Resolvers/DynamicObjectResolver.cs b/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Resolvers/DynamicObjectResolver.cs index 6769e0ac6..e05283e88 100644 --- a/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Resolvers/DynamicObjectResolver.cs +++ b/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Resolvers/DynamicObjectResolver.cs @@ -38,13 +38,13 @@ public sealed class DynamicObjectResolver : IFormatterResolver /// public static readonly MessagePackSerializerOptions Options; - internal static readonly Lazy DynamicAssembly; + internal static readonly DynamicAssemblyFactory DynamicAssemblyFactory; static DynamicObjectResolver() { Instance = new DynamicObjectResolver(); Options = new MessagePackSerializerOptions(Instance); - DynamicAssembly = new Lazy(() => new DynamicAssembly(ModuleName)); + DynamicAssemblyFactory = new DynamicAssemblyFactory(ModuleName); } private DynamicObjectResolver() @@ -54,7 +54,7 @@ private DynamicObjectResolver() #if NETFRAMEWORK internal AssemblyBuilder Save() { - return DynamicAssembly.Value.Save(); + return DynamicAssemblyFactory.GetDynamicAssembly(type: null).Save(); } #endif @@ -99,7 +99,7 @@ static FormatterCache() TypeInfo? formatterTypeInfo; try { - formatterTypeInfo = DynamicObjectTypeBuilder.BuildType(DynamicAssembly.Value, typeof(T), false, false); + formatterTypeInfo = DynamicObjectTypeBuilder.BuildType(DynamicAssemblyFactory.GetDynamicAssembly(typeof(T)), typeof(T), false, false); } catch (InitAccessorInGenericClassNotSupportedException) { @@ -181,7 +181,7 @@ public sealed class DynamicContractlessObjectResolver : IFormatterResolver private const string ModuleName = "MessagePack.Resolvers.DynamicContractlessObjectResolver"; - private static readonly Lazy DynamicAssembly; + private static readonly DynamicAssemblyFactory DynamicAssemblyFactory; private DynamicContractlessObjectResolver() { @@ -189,13 +189,13 @@ private DynamicContractlessObjectResolver() static DynamicContractlessObjectResolver() { - DynamicAssembly = new Lazy(() => new DynamicAssembly(ModuleName)); + DynamicAssemblyFactory = new DynamicAssemblyFactory(ModuleName); } #if NETFRAMEWORK internal AssemblyBuilder Save() { - return DynamicAssembly.Value.Save(); + return DynamicAssemblyFactory.GetDynamicAssembly(type: null).Save(); } #endif @@ -242,7 +242,7 @@ static FormatterCache() return; } - TypeInfo? formatterTypeInfo = DynamicObjectTypeBuilder.BuildType(DynamicAssembly.Value, typeof(T), true, true); + TypeInfo? formatterTypeInfo = DynamicObjectTypeBuilder.BuildType(DynamicAssemblyFactory.GetDynamicAssembly(typeof(T)), typeof(T), true, true); if (formatterTypeInfo == null) { return; diff --git a/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Resolvers/DynamicUnionResolver.cs b/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Resolvers/DynamicUnionResolver.cs index 90e26a755..3f321b787 100644 --- a/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Resolvers/DynamicUnionResolver.cs +++ b/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Resolvers/DynamicUnionResolver.cs @@ -37,7 +37,8 @@ public sealed class DynamicUnionResolver : IFormatterResolver /// public static readonly MessagePackSerializerOptions Options; - private static readonly Lazy DynamicAssembly; + private static readonly DynamicAssemblyFactory DynamicAssemblyFactory; + #if !UNITY_2018_3_OR_NEWER private static readonly Regex SubtractFullNameRegex = new Regex(@", Version=\d+.\d+.\d+.\d+, Culture=\w+, PublicKeyToken=\w+", RegexOptions.Compiled); #else @@ -50,7 +51,7 @@ static DynamicUnionResolver() { Instance = new DynamicUnionResolver(); Options = new MessagePackSerializerOptions(Instance); - DynamicAssembly = new Lazy(() => new DynamicAssembly(ModuleName)); + DynamicAssemblyFactory = new DynamicAssemblyFactory(ModuleName); } private DynamicUnionResolver() @@ -60,7 +61,7 @@ private DynamicUnionResolver() #if NETFRAMEWORK internal AssemblyBuilder Save() { - return DynamicAssembly.Value.Save(); + return DynamicAssemblyFactory.GetDynamicAssembly(type: null).Save(); } #endif @@ -138,7 +139,7 @@ static FormatterCache() Type formatterType = typeof(IMessagePackFormatter<>).MakeGenericType(type); using (MonoProtection.EnterRefEmitLock()) { - TypeBuilder typeBuilder = DynamicAssembly.Value.DefineType("MessagePack.Formatters." + SubtractFullNameRegex.Replace(type.FullName!, string.Empty).Replace(".", "_") + "Formatter" + +Interlocked.Increment(ref nameSequence), TypeAttributes.Public | TypeAttributes.Sealed, null, new[] { formatterType }); + TypeBuilder typeBuilder = DynamicAssemblyFactory.GetDynamicAssembly(type).DefineType("MessagePack.Formatters." + SubtractFullNameRegex.Replace(type.FullName!, string.Empty).Replace(".", "_") + "Formatter" + +Interlocked.Increment(ref nameSequence), TypeAttributes.Public | TypeAttributes.Sealed, null, new[] { formatterType }); FieldBuilder? typeToKeyAndJumpMap = null; // Dictionary> FieldBuilder? keyToJumpMap = null; // Dictionary @@ -330,6 +331,14 @@ private static void BuildDeserialize(Type type, UnionAttribute[] infos, MethodBu il.MarkLabel(falseLabel); + var reader = new ArgumentField(il, 1); + + // options.Security.DepthStep(ref reader); + il.EmitLdarg(2); + il.EmitCall(getSecurityFromOptions); + reader.EmitLdarg(); + il.EmitCall(securityDepthStep); + // IFormatterResolver resolver = options.Resolver; LocalBuilder localResolver = il.DeclareLocal(typeof(IFormatterResolver)); il.EmitLdarg(2); @@ -338,7 +347,6 @@ private static void BuildDeserialize(Type type, UnionAttribute[] infos, MethodBu // read-array header and validate, reader.ReadArrayHeader() != 2) throw; Label rightLabel = il.DefineLabel(); - var reader = new ArgumentField(il, 1); reader.EmitLdarg(); il.EmitCall(MessagePackReaderTypeInfo.ReadArrayHeader); il.EmitLdc_I4(2); @@ -405,6 +413,14 @@ private static void BuildDeserialize(Type type, UnionAttribute[] infos, MethodBu il.MarkLabel(loopEnd); + // reader.Depth--; + reader.EmitLdarg(); + il.Emit(OpCodes.Dup); + il.EmitCall(readerDepthGet); + il.Emit(OpCodes.Ldc_I4_1); + il.Emit(OpCodes.Sub_Ovf); + il.EmitCall(readerDepthSet); + il.Emit(OpCodes.Ldloc, result); il.Emit(OpCodes.Ret); } @@ -429,6 +445,10 @@ private static bool IsZeroStartSequential(UnionAttribute[] infos) private static readonly Type refKvp = typeof(KeyValuePair).MakeByRefType(); private static readonly MethodInfo getFormatterWithVerify = typeof(FormatterResolverExtensions).GetRuntimeMethods().First(x => x.Name == "GetFormatterWithVerify"); private static readonly MethodInfo getResolverFromOptions = typeof(MessagePackSerializerOptions).GetRuntimeProperty(nameof(MessagePackSerializerOptions.Resolver))!.GetMethod!; + private static readonly MethodInfo getSecurityFromOptions = typeof(MessagePackSerializerOptions).GetRuntimeProperty(nameof(MessagePackSerializerOptions.Security))!.GetMethod!; + private static readonly MethodInfo securityDepthStep = typeof(MessagePackSecurity).GetRuntimeMethod(nameof(MessagePackSecurity.DepthStep), new[] { typeof(MessagePackReader).MakeByRefType() })!; + private static readonly MethodInfo readerDepthGet = typeof(MessagePackReader).GetRuntimeProperty(nameof(MessagePackReader.Depth))!.GetMethod!; + private static readonly MethodInfo readerDepthSet = typeof(MessagePackReader).GetRuntimeProperty(nameof(MessagePackReader.Depth))!.SetMethod!; private static readonly Func getSerialize = t => typeof(IMessagePackFormatter<>).MakeGenericType(t).GetRuntimeMethod("Serialize", new[] { typeof(MessagePackWriter).MakeByRefType(), t, typeof(MessagePackSerializerOptions) })!; private static readonly Func getDeserialize = t => typeof(IMessagePackFormatter<>).MakeGenericType(t).GetRuntimeMethod("Deserialize", new[] { typeof(MessagePackReader).MakeByRefType(), typeof(MessagePackSerializerOptions) })!; diff --git a/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Resolvers/ExpandoObjectResolver.cs b/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Resolvers/ExpandoObjectResolver.cs index ffc7b149c..11107efac 100644 --- a/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Resolvers/ExpandoObjectResolver.cs +++ b/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Resolvers/ExpandoObjectResolver.cs @@ -40,6 +40,7 @@ private class PrimitiveObjectWithExpandoMaps : PrimitiveObjectFormatter { protected override object DeserializeMap(ref MessagePackReader reader, int length, MessagePackSerializerOptions options) { + ExpandoObjectFormatter.ThrowIfMapTooLargeForUntrustedData(length, options); IMessagePackFormatter keyFormatter = options.Resolver.GetFormatterWithVerify(); IMessagePackFormatter? objectFormatter = options.Resolver.GetFormatterWithVerify(); IDictionary dictionary = new ExpandoObject(); diff --git a/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/T4/UnsafeMemory.cs b/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/T4/UnsafeMemory.cs index 7956db01f..9ebcd6e79 100644 --- a/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/T4/UnsafeMemory.cs +++ b/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/T4/UnsafeMemory.cs @@ -20,7 +20,7 @@ public static partial class UnsafeMemory32 [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe void WriteRaw4(ref MessagePackWriter writer, ReadOnlySpan src) { - Span dst = writer.GetSpan(src.Length); + Span dst = writer.GetSpan(4); fixed (byte* pSrc = &src[0]) fixed (byte* pDst = &dst[0]) @@ -28,13 +28,13 @@ public static unsafe void WriteRaw4(ref MessagePackWriter writer, ReadOnlySpan src) { - Span dst = writer.GetSpan(src.Length); + Span dst = writer.GetSpan(5); fixed (byte* pSrc = &src[0]) fixed (byte* pDst = &dst[0]) @@ -43,13 +43,13 @@ public static unsafe void WriteRaw5(ref MessagePackWriter writer, ReadOnlySpan src) { - Span dst = writer.GetSpan(src.Length); + Span dst = writer.GetSpan(6); fixed (byte* pSrc = &src[0]) fixed (byte* pDst = &dst[0]) @@ -58,13 +58,13 @@ public static unsafe void WriteRaw6(ref MessagePackWriter writer, ReadOnlySpan src) { - Span dst = writer.GetSpan(src.Length); + Span dst = writer.GetSpan(7); fixed (byte* pSrc = &src[0]) fixed (byte* pDst = &dst[0]) @@ -73,13 +73,13 @@ public static unsafe void WriteRaw7(ref MessagePackWriter writer, ReadOnlySpan src) { - Span dst = writer.GetSpan(src.Length); + Span dst = writer.GetSpan(8); fixed (byte* pSrc = &src[0]) fixed (byte* pDst = &dst[0]) @@ -88,13 +88,13 @@ public static unsafe void WriteRaw8(ref MessagePackWriter writer, ReadOnlySpan src) { - Span dst = writer.GetSpan(src.Length); + Span dst = writer.GetSpan(9); fixed (byte* pSrc = &src[0]) fixed (byte* pDst = &dst[0]) @@ -104,13 +104,13 @@ public static unsafe void WriteRaw9(ref MessagePackWriter writer, ReadOnlySpan src) { - Span dst = writer.GetSpan(src.Length); + Span dst = writer.GetSpan(10); fixed (byte* pSrc = &src[0]) fixed (byte* pDst = &dst[0]) @@ -120,13 +120,13 @@ public static unsafe void WriteRaw10(ref MessagePackWriter writer, ReadOnlySpan< *(int*)(pDst + 6) = *(int*)(pSrc + 6); } - writer.Advance(src.Length); + writer.Advance(10); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe void WriteRaw11(ref MessagePackWriter writer, ReadOnlySpan src) { - Span dst = writer.GetSpan(src.Length); + Span dst = writer.GetSpan(11); fixed (byte* pSrc = &src[0]) fixed (byte* pDst = &dst[0]) @@ -136,13 +136,13 @@ public static unsafe void WriteRaw11(ref MessagePackWriter writer, ReadOnlySpan< *(int*)(pDst + 7) = *(int*)(pSrc + 7); } - writer.Advance(src.Length); + writer.Advance(11); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe void WriteRaw12(ref MessagePackWriter writer, ReadOnlySpan src) { - Span dst = writer.GetSpan(src.Length); + Span dst = writer.GetSpan(12); fixed (byte* pSrc = &src[0]) fixed (byte* pDst = &dst[0]) @@ -152,13 +152,13 @@ public static unsafe void WriteRaw12(ref MessagePackWriter writer, ReadOnlySpan< *(int*)(pDst + 8) = *(int*)(pSrc + 8); } - writer.Advance(src.Length); + writer.Advance(12); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe void WriteRaw13(ref MessagePackWriter writer, ReadOnlySpan src) { - Span dst = writer.GetSpan(src.Length); + Span dst = writer.GetSpan(13); fixed (byte* pSrc = &src[0]) fixed (byte* pDst = &dst[0]) @@ -169,13 +169,13 @@ public static unsafe void WriteRaw13(ref MessagePackWriter writer, ReadOnlySpan< *(int*)(pDst + 9) = *(int*)(pSrc + 9); } - writer.Advance(src.Length); + writer.Advance(13); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe void WriteRaw14(ref MessagePackWriter writer, ReadOnlySpan src) { - Span dst = writer.GetSpan(src.Length); + Span dst = writer.GetSpan(14); fixed (byte* pSrc = &src[0]) fixed (byte* pDst = &dst[0]) @@ -186,13 +186,13 @@ public static unsafe void WriteRaw14(ref MessagePackWriter writer, ReadOnlySpan< *(int*)(pDst + 10) = *(int*)(pSrc + 10); } - writer.Advance(src.Length); + writer.Advance(14); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe void WriteRaw15(ref MessagePackWriter writer, ReadOnlySpan src) { - Span dst = writer.GetSpan(src.Length); + Span dst = writer.GetSpan(15); fixed (byte* pSrc = &src[0]) fixed (byte* pDst = &dst[0]) @@ -203,13 +203,13 @@ public static unsafe void WriteRaw15(ref MessagePackWriter writer, ReadOnlySpan< *(int*)(pDst + 11) = *(int*)(pSrc + 11); } - writer.Advance(src.Length); + writer.Advance(15); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe void WriteRaw16(ref MessagePackWriter writer, ReadOnlySpan src) { - Span dst = writer.GetSpan(src.Length); + Span dst = writer.GetSpan(16); fixed (byte* pSrc = &src[0]) fixed (byte* pDst = &dst[0]) @@ -220,13 +220,13 @@ public static unsafe void WriteRaw16(ref MessagePackWriter writer, ReadOnlySpan< *(int*)(pDst + 12) = *(int*)(pSrc + 12); } - writer.Advance(src.Length); + writer.Advance(16); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe void WriteRaw17(ref MessagePackWriter writer, ReadOnlySpan src) { - Span dst = writer.GetSpan(src.Length); + Span dst = writer.GetSpan(17); fixed (byte* pSrc = &src[0]) fixed (byte* pDst = &dst[0]) @@ -238,13 +238,13 @@ public static unsafe void WriteRaw17(ref MessagePackWriter writer, ReadOnlySpan< *(int*)(pDst + 13) = *(int*)(pSrc + 13); } - writer.Advance(src.Length); + writer.Advance(17); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe void WriteRaw18(ref MessagePackWriter writer, ReadOnlySpan src) { - Span dst = writer.GetSpan(src.Length); + Span dst = writer.GetSpan(18); fixed (byte* pSrc = &src[0]) fixed (byte* pDst = &dst[0]) @@ -256,13 +256,13 @@ public static unsafe void WriteRaw18(ref MessagePackWriter writer, ReadOnlySpan< *(int*)(pDst + 14) = *(int*)(pSrc + 14); } - writer.Advance(src.Length); + writer.Advance(18); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe void WriteRaw19(ref MessagePackWriter writer, ReadOnlySpan src) { - Span dst = writer.GetSpan(src.Length); + Span dst = writer.GetSpan(19); fixed (byte* pSrc = &src[0]) fixed (byte* pDst = &dst[0]) @@ -274,13 +274,13 @@ public static unsafe void WriteRaw19(ref MessagePackWriter writer, ReadOnlySpan< *(int*)(pDst + 15) = *(int*)(pSrc + 15); } - writer.Advance(src.Length); + writer.Advance(19); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe void WriteRaw20(ref MessagePackWriter writer, ReadOnlySpan src) { - Span dst = writer.GetSpan(src.Length); + Span dst = writer.GetSpan(20); fixed (byte* pSrc = &src[0]) fixed (byte* pDst = &dst[0]) @@ -292,13 +292,13 @@ public static unsafe void WriteRaw20(ref MessagePackWriter writer, ReadOnlySpan< *(int*)(pDst + 16) = *(int*)(pSrc + 16); } - writer.Advance(src.Length); + writer.Advance(20); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe void WriteRaw21(ref MessagePackWriter writer, ReadOnlySpan src) { - Span dst = writer.GetSpan(src.Length); + Span dst = writer.GetSpan(21); fixed (byte* pSrc = &src[0]) fixed (byte* pDst = &dst[0]) @@ -311,13 +311,13 @@ public static unsafe void WriteRaw21(ref MessagePackWriter writer, ReadOnlySpan< *(int*)(pDst + 17) = *(int*)(pSrc + 17); } - writer.Advance(src.Length); + writer.Advance(21); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe void WriteRaw22(ref MessagePackWriter writer, ReadOnlySpan src) { - Span dst = writer.GetSpan(src.Length); + Span dst = writer.GetSpan(22); fixed (byte* pSrc = &src[0]) fixed (byte* pDst = &dst[0]) @@ -330,13 +330,13 @@ public static unsafe void WriteRaw22(ref MessagePackWriter writer, ReadOnlySpan< *(int*)(pDst + 18) = *(int*)(pSrc + 18); } - writer.Advance(src.Length); + writer.Advance(22); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe void WriteRaw23(ref MessagePackWriter writer, ReadOnlySpan src) { - Span dst = writer.GetSpan(src.Length); + Span dst = writer.GetSpan(23); fixed (byte* pSrc = &src[0]) fixed (byte* pDst = &dst[0]) @@ -349,13 +349,13 @@ public static unsafe void WriteRaw23(ref MessagePackWriter writer, ReadOnlySpan< *(int*)(pDst + 19) = *(int*)(pSrc + 19); } - writer.Advance(src.Length); + writer.Advance(23); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe void WriteRaw24(ref MessagePackWriter writer, ReadOnlySpan src) { - Span dst = writer.GetSpan(src.Length); + Span dst = writer.GetSpan(24); fixed (byte* pSrc = &src[0]) fixed (byte* pDst = &dst[0]) @@ -368,13 +368,13 @@ public static unsafe void WriteRaw24(ref MessagePackWriter writer, ReadOnlySpan< *(int*)(pDst + 20) = *(int*)(pSrc + 20); } - writer.Advance(src.Length); + writer.Advance(24); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe void WriteRaw25(ref MessagePackWriter writer, ReadOnlySpan src) { - Span dst = writer.GetSpan(src.Length); + Span dst = writer.GetSpan(25); fixed (byte* pSrc = &src[0]) fixed (byte* pDst = &dst[0]) @@ -388,13 +388,13 @@ public static unsafe void WriteRaw25(ref MessagePackWriter writer, ReadOnlySpan< *(int*)(pDst + 21) = *(int*)(pSrc + 21); } - writer.Advance(src.Length); + writer.Advance(25); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe void WriteRaw26(ref MessagePackWriter writer, ReadOnlySpan src) { - Span dst = writer.GetSpan(src.Length); + Span dst = writer.GetSpan(26); fixed (byte* pSrc = &src[0]) fixed (byte* pDst = &dst[0]) @@ -408,13 +408,13 @@ public static unsafe void WriteRaw26(ref MessagePackWriter writer, ReadOnlySpan< *(int*)(pDst + 22) = *(int*)(pSrc + 22); } - writer.Advance(src.Length); + writer.Advance(26); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe void WriteRaw27(ref MessagePackWriter writer, ReadOnlySpan src) { - Span dst = writer.GetSpan(src.Length); + Span dst = writer.GetSpan(27); fixed (byte* pSrc = &src[0]) fixed (byte* pDst = &dst[0]) @@ -428,13 +428,13 @@ public static unsafe void WriteRaw27(ref MessagePackWriter writer, ReadOnlySpan< *(int*)(pDst + 23) = *(int*)(pSrc + 23); } - writer.Advance(src.Length); + writer.Advance(27); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe void WriteRaw28(ref MessagePackWriter writer, ReadOnlySpan src) { - Span dst = writer.GetSpan(src.Length); + Span dst = writer.GetSpan(28); fixed (byte* pSrc = &src[0]) fixed (byte* pDst = &dst[0]) @@ -448,13 +448,13 @@ public static unsafe void WriteRaw28(ref MessagePackWriter writer, ReadOnlySpan< *(int*)(pDst + 24) = *(int*)(pSrc + 24); } - writer.Advance(src.Length); + writer.Advance(28); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe void WriteRaw29(ref MessagePackWriter writer, ReadOnlySpan src) { - Span dst = writer.GetSpan(src.Length); + Span dst = writer.GetSpan(29); fixed (byte* pSrc = &src[0]) fixed (byte* pDst = &dst[0]) @@ -469,13 +469,13 @@ public static unsafe void WriteRaw29(ref MessagePackWriter writer, ReadOnlySpan< *(int*)(pDst + 25) = *(int*)(pSrc + 25); } - writer.Advance(src.Length); + writer.Advance(29); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe void WriteRaw30(ref MessagePackWriter writer, ReadOnlySpan src) { - Span dst = writer.GetSpan(src.Length); + Span dst = writer.GetSpan(30); fixed (byte* pSrc = &src[0]) fixed (byte* pDst = &dst[0]) @@ -490,13 +490,13 @@ public static unsafe void WriteRaw30(ref MessagePackWriter writer, ReadOnlySpan< *(int*)(pDst + 26) = *(int*)(pSrc + 26); } - writer.Advance(src.Length); + writer.Advance(30); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe void WriteRaw31(ref MessagePackWriter writer, ReadOnlySpan src) { - Span dst = writer.GetSpan(src.Length); + Span dst = writer.GetSpan(31); fixed (byte* pSrc = &src[0]) fixed (byte* pDst = &dst[0]) @@ -511,7 +511,7 @@ public static unsafe void WriteRaw31(ref MessagePackWriter writer, ReadOnlySpan< *(int*)(pDst + 27) = *(int*)(pSrc + 27); } - writer.Advance(src.Length); + writer.Advance(31); } } @@ -520,7 +520,7 @@ public static partial class UnsafeMemory64 [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe void WriteRaw8(ref MessagePackWriter writer, ReadOnlySpan src) { - Span dst = writer.GetSpan(src.Length); + Span dst = writer.GetSpan(8); fixed (byte* pSrc = &src[0]) fixed (byte* pDst = &dst[0]) @@ -528,13 +528,13 @@ public static unsafe void WriteRaw8(ref MessagePackWriter writer, ReadOnlySpan src) { - Span dst = writer.GetSpan(src.Length); + Span dst = writer.GetSpan(9); fixed (byte* pSrc = &src[0]) fixed (byte* pDst = &dst[0]) @@ -543,13 +543,13 @@ public static unsafe void WriteRaw9(ref MessagePackWriter writer, ReadOnlySpan src) { - Span dst = writer.GetSpan(src.Length); + Span dst = writer.GetSpan(10); fixed (byte* pSrc = &src[0]) fixed (byte* pDst = &dst[0]) @@ -558,13 +558,13 @@ public static unsafe void WriteRaw10(ref MessagePackWriter writer, ReadOnlySpan< *(long*)(pDst + 2) = *(long*)(pSrc + 2); } - writer.Advance(src.Length); + writer.Advance(10); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe void WriteRaw11(ref MessagePackWriter writer, ReadOnlySpan src) { - Span dst = writer.GetSpan(src.Length); + Span dst = writer.GetSpan(11); fixed (byte* pSrc = &src[0]) fixed (byte* pDst = &dst[0]) @@ -573,13 +573,13 @@ public static unsafe void WriteRaw11(ref MessagePackWriter writer, ReadOnlySpan< *(long*)(pDst + 3) = *(long*)(pSrc + 3); } - writer.Advance(src.Length); + writer.Advance(11); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe void WriteRaw12(ref MessagePackWriter writer, ReadOnlySpan src) { - Span dst = writer.GetSpan(src.Length); + Span dst = writer.GetSpan(12); fixed (byte* pSrc = &src[0]) fixed (byte* pDst = &dst[0]) @@ -588,13 +588,13 @@ public static unsafe void WriteRaw12(ref MessagePackWriter writer, ReadOnlySpan< *(long*)(pDst + 4) = *(long*)(pSrc + 4); } - writer.Advance(src.Length); + writer.Advance(12); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe void WriteRaw13(ref MessagePackWriter writer, ReadOnlySpan src) { - Span dst = writer.GetSpan(src.Length); + Span dst = writer.GetSpan(13); fixed (byte* pSrc = &src[0]) fixed (byte* pDst = &dst[0]) @@ -603,13 +603,13 @@ public static unsafe void WriteRaw13(ref MessagePackWriter writer, ReadOnlySpan< *(long*)(pDst + 5) = *(long*)(pSrc + 5); } - writer.Advance(src.Length); + writer.Advance(13); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe void WriteRaw14(ref MessagePackWriter writer, ReadOnlySpan src) { - Span dst = writer.GetSpan(src.Length); + Span dst = writer.GetSpan(14); fixed (byte* pSrc = &src[0]) fixed (byte* pDst = &dst[0]) @@ -618,13 +618,13 @@ public static unsafe void WriteRaw14(ref MessagePackWriter writer, ReadOnlySpan< *(long*)(pDst + 6) = *(long*)(pSrc + 6); } - writer.Advance(src.Length); + writer.Advance(14); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe void WriteRaw15(ref MessagePackWriter writer, ReadOnlySpan src) { - Span dst = writer.GetSpan(src.Length); + Span dst = writer.GetSpan(15); fixed (byte* pSrc = &src[0]) fixed (byte* pDst = &dst[0]) @@ -633,13 +633,13 @@ public static unsafe void WriteRaw15(ref MessagePackWriter writer, ReadOnlySpan< *(long*)(pDst + 7) = *(long*)(pSrc + 7); } - writer.Advance(src.Length); + writer.Advance(15); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe void WriteRaw16(ref MessagePackWriter writer, ReadOnlySpan src) { - Span dst = writer.GetSpan(src.Length); + Span dst = writer.GetSpan(16); fixed (byte* pSrc = &src[0]) fixed (byte* pDst = &dst[0]) @@ -648,13 +648,13 @@ public static unsafe void WriteRaw16(ref MessagePackWriter writer, ReadOnlySpan< *(long*)(pDst + 8) = *(long*)(pSrc + 8); } - writer.Advance(src.Length); + writer.Advance(16); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe void WriteRaw17(ref MessagePackWriter writer, ReadOnlySpan src) { - Span dst = writer.GetSpan(src.Length); + Span dst = writer.GetSpan(17); fixed (byte* pSrc = &src[0]) fixed (byte* pDst = &dst[0]) @@ -664,13 +664,13 @@ public static unsafe void WriteRaw17(ref MessagePackWriter writer, ReadOnlySpan< *(long*)(pDst + 9) = *(long*)(pSrc + 9); } - writer.Advance(src.Length); + writer.Advance(17); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe void WriteRaw18(ref MessagePackWriter writer, ReadOnlySpan src) { - Span dst = writer.GetSpan(src.Length); + Span dst = writer.GetSpan(18); fixed (byte* pSrc = &src[0]) fixed (byte* pDst = &dst[0]) @@ -680,13 +680,13 @@ public static unsafe void WriteRaw18(ref MessagePackWriter writer, ReadOnlySpan< *(long*)(pDst + 10) = *(long*)(pSrc + 10); } - writer.Advance(src.Length); + writer.Advance(18); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe void WriteRaw19(ref MessagePackWriter writer, ReadOnlySpan src) { - Span dst = writer.GetSpan(src.Length); + Span dst = writer.GetSpan(19); fixed (byte* pSrc = &src[0]) fixed (byte* pDst = &dst[0]) @@ -696,13 +696,13 @@ public static unsafe void WriteRaw19(ref MessagePackWriter writer, ReadOnlySpan< *(long*)(pDst + 11) = *(long*)(pSrc + 11); } - writer.Advance(src.Length); + writer.Advance(19); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe void WriteRaw20(ref MessagePackWriter writer, ReadOnlySpan src) { - Span dst = writer.GetSpan(src.Length); + Span dst = writer.GetSpan(20); fixed (byte* pSrc = &src[0]) fixed (byte* pDst = &dst[0]) @@ -712,13 +712,13 @@ public static unsafe void WriteRaw20(ref MessagePackWriter writer, ReadOnlySpan< *(long*)(pDst + 12) = *(long*)(pSrc + 12); } - writer.Advance(src.Length); + writer.Advance(20); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe void WriteRaw21(ref MessagePackWriter writer, ReadOnlySpan src) { - Span dst = writer.GetSpan(src.Length); + Span dst = writer.GetSpan(21); fixed (byte* pSrc = &src[0]) fixed (byte* pDst = &dst[0]) @@ -728,13 +728,13 @@ public static unsafe void WriteRaw21(ref MessagePackWriter writer, ReadOnlySpan< *(long*)(pDst + 13) = *(long*)(pSrc + 13); } - writer.Advance(src.Length); + writer.Advance(21); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe void WriteRaw22(ref MessagePackWriter writer, ReadOnlySpan src) { - Span dst = writer.GetSpan(src.Length); + Span dst = writer.GetSpan(22); fixed (byte* pSrc = &src[0]) fixed (byte* pDst = &dst[0]) @@ -744,13 +744,13 @@ public static unsafe void WriteRaw22(ref MessagePackWriter writer, ReadOnlySpan< *(long*)(pDst + 14) = *(long*)(pSrc + 14); } - writer.Advance(src.Length); + writer.Advance(22); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe void WriteRaw23(ref MessagePackWriter writer, ReadOnlySpan src) { - Span dst = writer.GetSpan(src.Length); + Span dst = writer.GetSpan(23); fixed (byte* pSrc = &src[0]) fixed (byte* pDst = &dst[0]) @@ -760,13 +760,13 @@ public static unsafe void WriteRaw23(ref MessagePackWriter writer, ReadOnlySpan< *(long*)(pDst + 15) = *(long*)(pSrc + 15); } - writer.Advance(src.Length); + writer.Advance(23); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe void WriteRaw24(ref MessagePackWriter writer, ReadOnlySpan src) { - Span dst = writer.GetSpan(src.Length); + Span dst = writer.GetSpan(24); fixed (byte* pSrc = &src[0]) fixed (byte* pDst = &dst[0]) @@ -776,13 +776,13 @@ public static unsafe void WriteRaw24(ref MessagePackWriter writer, ReadOnlySpan< *(long*)(pDst + 16) = *(long*)(pSrc + 16); } - writer.Advance(src.Length); + writer.Advance(24); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe void WriteRaw25(ref MessagePackWriter writer, ReadOnlySpan src) { - Span dst = writer.GetSpan(src.Length); + Span dst = writer.GetSpan(25); fixed (byte* pSrc = &src[0]) fixed (byte* pDst = &dst[0]) @@ -793,13 +793,13 @@ public static unsafe void WriteRaw25(ref MessagePackWriter writer, ReadOnlySpan< *(long*)(pDst + 17) = *(long*)(pSrc + 17); } - writer.Advance(src.Length); + writer.Advance(25); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe void WriteRaw26(ref MessagePackWriter writer, ReadOnlySpan src) { - Span dst = writer.GetSpan(src.Length); + Span dst = writer.GetSpan(26); fixed (byte* pSrc = &src[0]) fixed (byte* pDst = &dst[0]) @@ -810,13 +810,13 @@ public static unsafe void WriteRaw26(ref MessagePackWriter writer, ReadOnlySpan< *(long*)(pDst + 18) = *(long*)(pSrc + 18); } - writer.Advance(src.Length); + writer.Advance(26); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe void WriteRaw27(ref MessagePackWriter writer, ReadOnlySpan src) { - Span dst = writer.GetSpan(src.Length); + Span dst = writer.GetSpan(27); fixed (byte* pSrc = &src[0]) fixed (byte* pDst = &dst[0]) @@ -827,13 +827,13 @@ public static unsafe void WriteRaw27(ref MessagePackWriter writer, ReadOnlySpan< *(long*)(pDst + 19) = *(long*)(pSrc + 19); } - writer.Advance(src.Length); + writer.Advance(27); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe void WriteRaw28(ref MessagePackWriter writer, ReadOnlySpan src) { - Span dst = writer.GetSpan(src.Length); + Span dst = writer.GetSpan(28); fixed (byte* pSrc = &src[0]) fixed (byte* pDst = &dst[0]) @@ -844,13 +844,13 @@ public static unsafe void WriteRaw28(ref MessagePackWriter writer, ReadOnlySpan< *(long*)(pDst + 20) = *(long*)(pSrc + 20); } - writer.Advance(src.Length); + writer.Advance(28); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe void WriteRaw29(ref MessagePackWriter writer, ReadOnlySpan src) { - Span dst = writer.GetSpan(src.Length); + Span dst = writer.GetSpan(29); fixed (byte* pSrc = &src[0]) fixed (byte* pDst = &dst[0]) @@ -861,13 +861,13 @@ public static unsafe void WriteRaw29(ref MessagePackWriter writer, ReadOnlySpan< *(long*)(pDst + 21) = *(long*)(pSrc + 21); } - writer.Advance(src.Length); + writer.Advance(29); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe void WriteRaw30(ref MessagePackWriter writer, ReadOnlySpan src) { - Span dst = writer.GetSpan(src.Length); + Span dst = writer.GetSpan(30); fixed (byte* pSrc = &src[0]) fixed (byte* pDst = &dst[0]) @@ -878,13 +878,13 @@ public static unsafe void WriteRaw30(ref MessagePackWriter writer, ReadOnlySpan< *(long*)(pDst + 22) = *(long*)(pSrc + 22); } - writer.Advance(src.Length); + writer.Advance(30); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe void WriteRaw31(ref MessagePackWriter writer, ReadOnlySpan src) { - Span dst = writer.GetSpan(src.Length); + Span dst = writer.GetSpan(31); fixed (byte* pSrc = &src[0]) fixed (byte* pDst = &dst[0]) @@ -895,7 +895,7 @@ public static unsafe void WriteRaw31(ref MessagePackWriter writer, ReadOnlySpan< *(long*)(pDst + 23) = *(long*)(pSrc + 23); } - writer.Advance(src.Length); + writer.Advance(31); } } } diff --git a/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Unity/Extension/UnsafeBlitFormatter.cs b/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Unity/Extension/UnsafeBlitFormatter.cs index 14efd4fa0..011b91997 100644 --- a/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Unity/Extension/UnsafeBlitFormatter.cs +++ b/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Unity/Extension/UnsafeBlitFormatter.cs @@ -48,19 +48,26 @@ public void Serialize(ref MessagePackWriter writer, T[]? value, MessagePackSeria return null; } - ExtensionHeader header = reader.ReadExtensionFormatHeader(); - if (header.TypeCode != this.TypeCode) + ExtensionResult extension = reader.ReadExtensionFormat(); + if (extension.TypeCode != this.TypeCode) { throw new InvalidOperationException("Invalid typeCode."); } - var byteLength = reader.ReadInt32(); - var isLittleEndian = reader.ReadBoolean(); + MessagePackReader extensionReader = reader.Clone(extension.Data); + var byteLength = extensionReader.ReadInt32(); + var isLittleEndian = extensionReader.ReadBoolean(); + int elementSize = Marshal.SizeOf(); + long remainingBytes = extensionReader.Sequence.Length - extensionReader.Consumed; + if (byteLength < 0 || byteLength % elementSize != 0 || byteLength != remainingBytes) + { + throw new MessagePackSerializationException("Invalid Unity blit extension length."); + } // Allocate a T[] that we will return. We'll then cast the T[] as byte[] so we can copy the byte sequence directly into it. - var result = new T[byteLength / Marshal.SizeOf()]; + var result = new T[byteLength / elementSize]; Span resultAsBytes = MemoryMarshal.Cast(result); - reader.ReadRaw(byteLength).CopyTo(resultAsBytes); + extensionReader.ReadRaw(byteLength).CopyTo(resultAsBytes); // Reverse the byte order if necessary. if (isLittleEndian != BitConverter.IsLittleEndian) diff --git a/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/package.json b/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/package.json index b9c7de1bc..7df5b04d2 100644 --- a/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/package.json +++ b/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/package.json @@ -1,7 +1,7 @@ { "name": "com.neuecc.messagepack", "displayName": "MessagePack", - "version": "2.5.140", + "version": "2.5.302", "unity": "2018.4", "description": "Extremely Fast MessagePack Serializer for C#.", "keywords": [ diff --git a/src/MessagePack.UnityClient/Assets/Scripts/Tests/Class1.cs b/src/MessagePack.UnityClient/Assets/Scripts/Tests/Class1.cs index 1af2f9e0e..20676dbfc 100644 --- a/src/MessagePack.UnityClient/Assets/Scripts/Tests/Class1.cs +++ b/src/MessagePack.UnityClient/Assets/Scripts/Tests/Class1.cs @@ -87,6 +87,18 @@ public class SimpleIntKeyData ////public int Prop7 { get; set; } } + [MessagePackObject] + public class SimpleGenericData + { + [Key(0)] + public T Value { get; set; } + + public SimpleGenericData(T value) + { + this.Value = value; + } + } + public class OreOreFormatter : IMessagePackFormatter { public int Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options) diff --git a/src/MessagePack.UnityClient/Assets/Scripts/Tests/ShareTests/ExpandoObjectTests.cs b/src/MessagePack.UnityClient/Assets/Scripts/Tests/ShareTests/ExpandoObjectTests.cs index 99f3b808a..9cbf63bb8 100644 --- a/src/MessagePack.UnityClient/Assets/Scripts/Tests/ShareTests/ExpandoObjectTests.cs +++ b/src/MessagePack.UnityClient/Assets/Scripts/Tests/ShareTests/ExpandoObjectTests.cs @@ -3,6 +3,7 @@ #if !UNITY_2018_3_OR_NEWER +using System.Collections.Generic; using System.Dynamic; using System.Runtime.Serialization; using MessagePack.Resolvers; @@ -85,6 +86,24 @@ public void ExpandoObject_DeepGraphContainsCustomTypes() Assert.Equal(expando.Other.OtherProperty, expando2.Other.OtherProperty); } + [Fact] + [Trait("CWE", "407")] + public void ExpandoObject_UntrustedDataRejectsLargeMaps() + { + byte[] msgpack = CreateMapWithNilValues(1025); + + Assert.Throws(() => MessagePackSerializer.Deserialize(msgpack, ExpandoObjectResolver.Options)); + } + + [Fact] + [Trait("CWE", "407")] + public void ExpandoObjectNestedMap_UntrustedDataRejectsLargeMaps() + { + byte[] msgpack = CreateMapWithNilValues(1025); + + Assert.Throws(() => MessagePackSerializer.Deserialize(msgpack, ExpandoObjectResolver.Options)); + } + #if !UNITY_2018_3_OR_NEWER [Fact] @@ -115,6 +134,17 @@ public class CustomObject [DataMember] public string OtherProperty { get; set; } } + + private static byte[] CreateMapWithNilValues(int count) + { + var dictionary = new Dictionary(); + for (int index = 0; index < count; index++) + { + dictionary.Add("k" + index.ToString(System.Globalization.CultureInfo.InvariantCulture), null); + } + + return MessagePackSerializer.Serialize(dictionary, MessagePackSerializerOptions.Standard); + } } } diff --git a/src/MessagePack.UnityClient/Assets/Scripts/Tests/ShareTests/LZ4Test.cs b/src/MessagePack.UnityClient/Assets/Scripts/Tests/ShareTests/LZ4Test.cs index f314b572a..3a75c5ac2 100644 --- a/src/MessagePack.UnityClient/Assets/Scripts/Tests/ShareTests/LZ4Test.cs +++ b/src/MessagePack.UnityClient/Assets/Scripts/Tests/ShareTests/LZ4Test.cs @@ -1,6 +1,7 @@ // Copyright (c) All contributors. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. +using System.Buffers; using System.Linq; using Xunit; using Xunit.Abstractions; @@ -22,6 +23,64 @@ public LZ4Test(ITestOutputHelper logger) #endif + [Theory] + [InlineData(MessagePackCompression.Lz4Block)] + [InlineData(MessagePackCompression.Lz4BlockArray)] + [Trait("CWE", "409")] + public void Lz4RejectsDeclaredOutputOverMaximumBeforeAllocating(MessagePackCompression compression) + { + byte[] payload = compression == MessagePackCompression.Lz4Block + ? new byte[] { 0xC7, 0x06, 0x63, 0xD2, 0x7F, 0xFF, 0xFF, 0xFF, 0x00 } + : new byte[] { 0x92, 0xC7, 0x05, 0x62, 0xD2, 0x7F, 0xFF, 0xFF, 0xFF, 0xC4, 0x01, 0x00 }; + var arrayPool = new ThrowingArrayPool(1024); + var options = MessagePackSerializerOptions.Standard + .WithCompression(compression) + .WithSecurity(MessagePackSecurity.UntrustedData) + .WithPool(new SequencePool(1, arrayPool)); + + MessagePackSerializationException ex = Assert.Throws(() => MessagePackSerializer.Deserialize(payload, options)); + + Assert.Contains("exceeds the configured maximum", FlattenMessages(ex)); + Assert.Null(arrayPool.LargestRequestedLength); + } + + [Fact] + [Trait("CWE", "409")] + public void Lz4BlockArrayRejectsTotalDeclaredOutputOverMaximum() + { + byte[] payload = + { + 0x93, + 0xC7, 0x02, 0x62, 0x04, 0x04, + 0xC4, 0x05, 0x40, 0x20, 0x20, 0x20, 0x20, + 0xC4, 0x05, 0x40, 0x20, 0x20, 0x20, 0x20, + }; + var options = MessagePackSerializerOptions.Standard + .WithCompression(MessagePackCompression.Lz4BlockArray) + .WithSecurity(MessagePackSecurity.UntrustedData.WithMaximumDecompressedSize(7)); + + MessagePackSerializationException ex = Assert.Throws(() => MessagePackSerializer.Deserialize(payload, options)); + + Assert.Contains("exceeds the configured maximum", FlattenMessages(ex)); + } + + [Theory] + [InlineData(MessagePackCompression.Lz4Block)] + [InlineData(MessagePackCompression.Lz4BlockArray)] + [Trait("CWE", "409")] + public void Lz4AllowsHighlyCompressiblePayloadWithinMaximum(MessagePackCompression compression) + { + string data = new string(' ', 100_000); + var options = MessagePackSerializerOptions.Standard + .WithCompression(compression) + .WithSecurity(MessagePackSecurity.UntrustedData.WithMaximumDecompressedSize(200_000)); + + byte[] payload = MessagePackSerializer.Serialize(data, options); + string actual = MessagePackSerializer.Deserialize(payload, options); + + Assert.Equal(data, actual); + } + [Fact] public void Lz4Compress() { @@ -32,6 +91,47 @@ public void Lz4Compress() Execute(10000); } + [Fact] + [Trait("CWE", "125")] + public void Lz4BlockRejectsTruncatedLiteralRun() + { + const int extensionByteCount = 1024; + int uncompressedLength = 15 + (255 * extensionByteCount) + 16; + + byte[] sizeHeader = + { + 0xCE, + (byte)(uncompressedLength >> 24), + (byte)(uncompressedLength >> 16), + (byte)(uncompressedLength >> 8), + (byte)uncompressedLength, + }; + + byte[] lz4 = new byte[1 + extensionByteCount]; + lz4[0] = 0xF0; + for (int i = 1; i < lz4.Length; i++) + { + lz4[i] = 0xFF; + } + + int bodyLength = sizeHeader.Length + lz4.Length; + byte[] payload = new byte[6 + bodyLength]; + int offset = 0; + payload[offset++] = 0xC9; + payload[offset++] = (byte)(bodyLength >> 24); + payload[offset++] = (byte)(bodyLength >> 16); + payload[offset++] = (byte)(bodyLength >> 8); + payload[offset++] = (byte)bodyLength; + payload[offset++] = 99; + System.Array.Copy(sizeHeader, 0, payload, offset, sizeHeader.Length); + offset += sizeHeader.Length; + System.Array.Copy(lz4, 0, payload, offset, lz4.Length); + + var options = MessagePackSerializerOptions.Standard.WithCompression(MessagePackCompression.Lz4Block); + + Assert.Throws(() => MessagePackSerializer.Deserialize(payload, options)); + } + private void Execute(int count) { // Large @@ -82,5 +182,37 @@ private static void SequenceStructuralEqual(SharedData.SimpleStringKeyData[] act actual[i].Prop3.Is(expected[i].Prop3); } } + + private static string FlattenMessages(System.Exception ex) + { + return ex.InnerException is null ? ex.Message : ex.Message + " " + FlattenMessages(ex.InnerException); + } + + private class ThrowingArrayPool : ArrayPool + { + private readonly int maximumLength; + + internal ThrowingArrayPool(int maximumLength) + { + this.maximumLength = maximumLength; + } + + internal int? LargestRequestedLength { get; private set; } + + public override byte[] Rent(int minimumLength) + { + this.LargestRequestedLength = this.LargestRequestedLength.HasValue ? System.Math.Max(this.LargestRequestedLength.Value, minimumLength) : minimumLength; + if (minimumLength > this.maximumLength) + { + throw new System.InvalidOperationException("Unexpected decompression allocation request: " + minimumLength); + } + + return new byte[minimumLength]; + } + + public override void Return(byte[] array, bool clearArray = false) + { + } + } } } diff --git a/src/MessagePack.UnityClient/Assets/Scripts/Tests/ShareTests/MessagePackReaderTests.cs b/src/MessagePack.UnityClient/Assets/Scripts/Tests/ShareTests/MessagePackReaderTests.cs index 774927d13..33c363436 100644 --- a/src/MessagePack.UnityClient/Assets/Scripts/Tests/ShareTests/MessagePackReaderTests.cs +++ b/src/MessagePack.UnityClient/Assets/Scripts/Tests/ShareTests/MessagePackReaderTests.cs @@ -101,6 +101,33 @@ public void ReadMapHeader_MitigatesLargeAllocations() }); } + [Fact] + [Trait("CWE", "190")] + public void ReadMapHeader_MitigatesLargeAllocations_WhenMinimumPayloadLengthOverflowsInt32() + { + byte[] msgpack = { MessagePackCode.Map32, 0x40, 0, 0, 0 }; + + Assert.Throws(() => + { + var reader = new MessagePackReader(msgpack); + reader.ReadMapHeader(); + }); + } + + [Fact] + [Trait("CWE", "190")] + public void SkipMap_MitigatesLargeAllocations_WhenMinimumPayloadLengthOverflowsInt32() + { + byte[] msgpack = { MessagePackCode.Map32, 0x40, 0, 0, 0 }; + + var ex = Assert.ThrowsAny(() => + { + var reader = new MessagePackReader(msgpack); + reader.Skip(); + }); + Assert.True(ex is EndOfStreamException or MessagePackSerializationException or OverflowException); + } + [Fact] public void TryReadMapHeader() { @@ -252,6 +279,49 @@ public void ReadRaw() Assert.True(reader.End); } + [Fact] + [Trait("CWE", "674")] + public void Skip_DeeplyNestedArrays_DoesNotOverflowStack() + { + const int depth = 100_000; + byte[] msgpack = new byte[depth + 1]; + + for (int i = 0; i < depth; i++) + { + msgpack[i] = MessagePackCode.MinFixArray + 1; + } + + msgpack[msgpack.Length - 1] = MessagePackCode.Nil; + + MessagePackReader reader = new(msgpack); + + reader.Skip(); + + Assert.True(reader.End); + } + + [Fact] + [Trait("CWE", "674")] + public void Skip_DeeplyNestedMaps_DoesNotOverflowStack() + { + const int depth = 100_000; + byte[] msgpack = new byte[(depth * 2) + 1]; + + for (int i = 0; i < depth; i++) + { + msgpack[i * 2] = MessagePackCode.MinFixMap + 1; + msgpack[(i * 2) + 1] = MessagePackCode.Nil; + } + + msgpack[msgpack.Length - 1] = MessagePackCode.Nil; + + MessagePackReader reader = new(msgpack); + + reader.Skip(); + + Assert.True(reader.End); + } + [Fact] public void Depth() { @@ -322,6 +392,15 @@ void AssertIncomplete(WriterEncoder encoder, ReadOperation decoder, bool v AssertIncomplete((ref MessagePackWriter writer) => writer.Write(0xff), (ref MessagePackReader reader) => reader.ReadUInt64()); } + [Fact] + [Trait("CWE", "789")] + public void ReadDateTime_RejectsInvalidExtensionLengths() + { + byte[] payload = new byte[] { MessagePackCode.Ext32, 0x00, 0x10, 0x00, 0x00, 0xff }; + + Assert.Throws(() => new MessagePackReader(new ReadOnlySequence(payload)).ReadDateTime()); + } + [Fact] public void CreatePeekReader() { diff --git a/src/MessagePack.UnityClient/Assets/Scripts/Tests/ShareTests/MessagePackSecurityTests.cs b/src/MessagePack.UnityClient/Assets/Scripts/Tests/ShareTests/MessagePackSecurityTests.cs index 74121e5d7..ef1cd3f4d 100644 --- a/src/MessagePack.UnityClient/Assets/Scripts/Tests/ShareTests/MessagePackSecurityTests.cs +++ b/src/MessagePack.UnityClient/Assets/Scripts/Tests/ShareTests/MessagePackSecurityTests.cs @@ -31,12 +31,14 @@ public MessagePackSecurityTests(ITestOutputHelper logger) public void Untrusted() { Assert.True(MessagePackSecurity.UntrustedData.HashCollisionResistant); + Assert.Equal(64 * 1024 * 1024, MessagePackSecurity.UntrustedData.MaximumDecompressedSize); } [Fact] public void Trusted() { Assert.False(MessagePackSecurity.TrustedData.HashCollisionResistant); + Assert.Equal(int.MaxValue, MessagePackSecurity.TrustedData.MaximumDecompressedSize); } [Fact] @@ -46,6 +48,15 @@ public void WithHashCollisionResistant() Assert.True(MessagePackSecurity.TrustedData.WithHashCollisionResistant(true).HashCollisionResistant); } + [Fact] + [Trait("CWE", "409")] + public void WithMaximumDecompressedSize() + { + Assert.Same(MessagePackSecurity.UntrustedData, MessagePackSecurity.UntrustedData.WithMaximumDecompressedSize(64 * 1024 * 1024)); + Assert.Throws(() => MessagePackSecurity.UntrustedData.WithMaximumDecompressedSize(-1)); + Assert.Equal(1024, MessagePackSecurity.UntrustedData.WithMaximumDecompressedSize(1024).MaximumDecompressedSize); + } + [Fact] public void EqualityComparer_CollisionResistance_Int64() { diff --git a/src/MessagePack.UnityClient/Assets/Scripts/Tests/ShareTests/MessagePackSerializerTest.cs b/src/MessagePack.UnityClient/Assets/Scripts/Tests/ShareTests/MessagePackSerializerTest.cs index 211a35143..5157b4fa8 100644 --- a/src/MessagePack.UnityClient/Assets/Scripts/Tests/ShareTests/MessagePackSerializerTest.cs +++ b/src/MessagePack.UnityClient/Assets/Scripts/Tests/ShareTests/MessagePackSerializerTest.cs @@ -209,6 +209,18 @@ public async Task SerializeAndDeserializeAsync_MultipleValues_SeekableStream(boo Assert.Equal(3, await MessagePackSerializer.DeserializeAsync(stream)); } + [Fact] + [Trait("CWE", "674")] + public void StackDepthCheck_ConvertToJsonTypelessExtension() + { + const int maxDepth = 3; + byte[] msgpack = BuildNestedTypelessExtension(maxDepth + 1); + var options = MessagePackSerializerOptions.Standard + .WithSecurity(MessagePackSecurity.UntrustedData.WithMaximumObjectGraphDepth(maxDepth)); + + AssertConvertToJsonRecursionCheckThrows(new ReadOnlySequence(msgpack), options); + } + [Theory] [InlineData(true)] [InlineData(false)] @@ -275,6 +287,18 @@ public void StackDepthCheck_DynamicObjectResolver() Assert.IsType(ex.InnerException); } + [Fact] + [Trait("CWE", "674")] + public void StackDepthCheck_DynamicUnionResolver() + { + byte[] msgpack = MessagePackSerializer.Serialize(new DepthCheckedUnionBranch()); + var options = MessagePackSerializerOptions.Standard + .WithSecurity(MessagePackSecurity.UntrustedData.WithMaximumObjectGraphDepth(1)); + + var ex = Assert.Throws(() => MessagePackSerializer.Deserialize(msgpack, options)); + Assert.IsType(ex.InnerException); + } + #endif private delegate void WriterHelper(ref MessagePackWriter writer); @@ -318,6 +342,28 @@ private static void AssertConvertToJsonRecursionCheckThrows(ReadOnlySequence(ex.InnerException); } + private static byte[] BuildNestedTypelessExtension(int levels) + { + byte[] msgpack = new byte[(levels * 6) + 2]; + int offset = msgpack.Length; + msgpack[--offset] = (byte)'x'; + msgpack[--offset] = 0xa1; + int innerLength = 2; + + for (int level = 0; level < levels; level++) + { + msgpack[--offset] = unchecked((byte)ThisLibraryExtensionTypeCodes.TypelessFormatter); + msgpack[--offset] = (byte)innerLength; + msgpack[--offset] = (byte)(innerLength >> 8); + msgpack[--offset] = (byte)(innerLength >> 16); + msgpack[--offset] = (byte)(innerLength >> 24); + msgpack[--offset] = 0xc9; + innerLength += 6; + } + + return msgpack; + } + [DataContract] public class RecursiveObjectGraph { @@ -414,4 +460,30 @@ protected override void Dispose(bool disposing) base.Dispose(disposing); } } + + [MessagePackObject(keyAsPropertyName: true)] + public class SkipUnknownMemberTarget + { + public int Known { get; set; } + } + + [Union(0, typeof(DepthCheckedUnionLeaf))] + [Union(999, typeof(DepthCheckedUnionBranch))] + public interface IDepthCheckedUnionNode + { + } + + [MessagePackObject] + public class DepthCheckedUnionLeaf : IDepthCheckedUnionNode + { + [Key(0)] + public int Value { get; set; } + } + + [MessagePackObject] + public class DepthCheckedUnionBranch : IDepthCheckedUnionNode + { + [Key(0)] + public IDepthCheckedUnionNode Child { get; set; } + } } diff --git a/src/MessagePack.UnityClient/Assets/Scripts/Tests/ShareTests/MessagePackSerializerTypelessTests.cs b/src/MessagePack.UnityClient/Assets/Scripts/Tests/ShareTests/MessagePackSerializerTypelessTests.cs index 995aaa6c2..9243854f6 100644 --- a/src/MessagePack.UnityClient/Assets/Scripts/Tests/ShareTests/MessagePackSerializerTypelessTests.cs +++ b/src/MessagePack.UnityClient/Assets/Scripts/Tests/ShareTests/MessagePackSerializerTypelessTests.cs @@ -4,6 +4,7 @@ #if !UNITY_2018_3_OR_NEWER using System; +using System.Collections.Generic; using System.Runtime.Serialization; using MessagePack; using MessagePack.Formatters; @@ -47,6 +48,24 @@ public void SerializationOfDisallowedType() Assert.IsType(ex.InnerException); } + [Theory] + [MemberData(nameof(DisallowedNestedTypeData))] + [Trait("CWE", "502")] + public void SerializationOfDisallowedNestedType(object value) + { + var myOptions = new MyTypelessOptions(); + byte[] msgpack = MessagePackSerializer.Typeless.Serialize(value, myOptions); + this.logger.WriteLine(MessagePackSerializer.ConvertToJson(msgpack, myOptions)); + var ex = Assert.Throws(() => MessagePackSerializer.Typeless.Deserialize(msgpack, myOptions)); + Assert.IsType(ex.InnerException); + } + + public static IEnumerable DisallowedNestedTypeData() + { + yield return new object[] { new MyObject[] { new() { SomeValue = 5 } } }; + yield return new object[] { new List { new() { SomeValue = 5 } } }; + } + [Fact(Skip = "Known bug https://github.com/neuecc/MessagePack-CSharp/issues/651")] public void DecimalShouldBeDeserializedAsDecimal() { @@ -137,7 +156,7 @@ internal MyTypelessOptions(MyTypelessOptions copyFrom) { } - public override void ThrowIfDeserializingTypeIsDisallowed(Type type) + protected override void ThrowIfDeserializingTypeIsDisallowedCore(Type type) { if (type == typeof(MyObject)) { diff --git a/src/MessagePack.UnityClient/Assets/Scripts/Tests/ShareTests/MultiDimensionalArrayTest.cs b/src/MessagePack.UnityClient/Assets/Scripts/Tests/ShareTests/MultiDimensionalArrayTest.cs index f4a0a2619..59daa7fab 100644 --- a/src/MessagePack.UnityClient/Assets/Scripts/Tests/ShareTests/MultiDimensionalArrayTest.cs +++ b/src/MessagePack.UnityClient/Assets/Scripts/Tests/ShareTests/MultiDimensionalArrayTest.cs @@ -67,5 +67,60 @@ public void MultiDimensional(int dataI, int dataJ, int dataK, int dataL) } } } + + [Fact] + [Trait("CWE", "789")] + public void RejectsTwoDimensionalArrayWithMismatchedElementCount() + { + byte[] payload = + { + 0x93, + 0xCE, 0x00, 0x00, 0x07, 0xD0, + 0xCE, 0x00, 0x00, 0x07, 0xD0, + 0x90, + }; + + AssertRejects(payload); + } + + [Fact] + [Trait("CWE", "789")] + public void RejectsThreeDimensionalArrayWithMismatchedElementCount() + { + byte[] payload = + { + 0x94, + 0xCC, 0x80, + 0xCC, 0x80, + 0xCC, 0x80, + 0x90, + }; + + AssertRejects(payload); + } + + [Fact] + [Trait("CWE", "789")] + public void RejectsFourDimensionalArrayWithMismatchedElementCount() + { + byte[] payload = + { + 0x95, + 0x20, + 0x20, + 0x20, + 0x20, + 0x90, + }; + + AssertRejects(payload); + } + + private void AssertRejects(byte[] payload) + { + var options = MessagePackSerializerOptions.Standard.WithSecurity(MessagePackSecurity.UntrustedData); + + Assert.Throws(() => MessagePackSerializer.Deserialize(payload, options)); + } } } diff --git a/src/MessagePack.UnityClient/Assets/Scripts/Tests/ShareTests/StandardClassLibraryFormatterTests.cs b/src/MessagePack.UnityClient/Assets/Scripts/Tests/ShareTests/StandardClassLibraryFormatterTests.cs index 351234765..c3c60cef1 100644 --- a/src/MessagePack.UnityClient/Assets/Scripts/Tests/ShareTests/StandardClassLibraryFormatterTests.cs +++ b/src/MessagePack.UnityClient/Assets/Scripts/Tests/ShareTests/StandardClassLibraryFormatterTests.cs @@ -35,6 +35,27 @@ public void SystemType_Serializable_Null() Assert.Equal(type, type2); } + [Fact] + public void SystemType_DeserializeUsesLoadType() + { + byte[] msgpack = MessagePackSerializer.Serialize(new TypeHolder { Type = typeof(Uri) }, MessagePackSerializerOptions.Standard); + var options = new RejectingTypeLoadOptions(typeof(Uri)); + + var ex = Assert.Throws(() => MessagePackSerializer.Deserialize(msgpack, options)); + Assert.IsType(ex.InnerException); + Assert.Equal(1, options.LoadTypeCalls); + } + + [Fact] + public void SystemType_DeserializeRejectsDisallowedType() + { + byte[] msgpack = MessagePackSerializer.Serialize(new TypeHolder { Type = typeof(Uri) }, MessagePackSerializerOptions.Standard); + var options = new DisallowingTypeOptions(typeof(Uri)); + + var ex = Assert.Throws(() => MessagePackSerializer.Deserialize(msgpack, options)); + Assert.IsType(ex.InnerException); + } + [Fact] public void DeserializeByteArrayFromFixArray() { @@ -132,5 +153,68 @@ private T Roundtrip(T value, bool breakupBuffer = false) return MessagePackSerializer.Deserialize(msgpack, MessagePackSerializerOptions.Standard); } } + + [MessagePackObject] + public class TypeHolder + { + [Key(0)] + public Type Type { get; set; } + } + + private class RejectingTypeLoadOptions : MessagePackSerializerOptions + { + private readonly Type rejectedType; + + internal RejectingTypeLoadOptions(Type rejectedType) + : base(MessagePackSerializerOptions.Standard) + { + this.rejectedType = rejectedType; + } + + private RejectingTypeLoadOptions(RejectingTypeLoadOptions copyFrom) + : base(copyFrom) + { + this.rejectedType = copyFrom.rejectedType; + this.LoadTypeCalls = copyFrom.LoadTypeCalls; + } + + public int LoadTypeCalls { get; private set; } + + public override Type LoadType(string typeName) + { + Type type = base.LoadType(typeName); + this.LoadTypeCalls++; + return type == this.rejectedType ? null : type; + } + + protected override MessagePackSerializerOptions Clone() => new RejectingTypeLoadOptions(this); + } + + private class DisallowingTypeOptions : MessagePackSerializerOptions + { + private readonly Type rejectedType; + + internal DisallowingTypeOptions(Type rejectedType) + : base(MessagePackSerializerOptions.Standard) + { + this.rejectedType = rejectedType; + } + + private DisallowingTypeOptions(DisallowingTypeOptions copyFrom) + : base(copyFrom) + { + this.rejectedType = copyFrom.rejectedType; + } + + public override void ThrowIfDeserializingTypeIsDisallowed(Type type) + { + if (type == this.rejectedType) + { + throw new TypeAccessException(); + } + } + + protected override MessagePackSerializerOptions Clone() => new DisallowingTypeOptions(this); + } } } diff --git a/src/MessagePack.UnityClient/Assets/Scripts/Tests/ShareTests/ToJsonTest.cs b/src/MessagePack.UnityClient/Assets/Scripts/Tests/ShareTests/ToJsonTest.cs index 8069ea266..99fceee42 100644 --- a/src/MessagePack.UnityClient/Assets/Scripts/Tests/ShareTests/ToJsonTest.cs +++ b/src/MessagePack.UnityClient/Assets/Scripts/Tests/ShareTests/ToJsonTest.cs @@ -47,6 +47,29 @@ public void ComplexToJson() this.JsonConvert(json, LZ4Standard).Is(json); } + [Theory] + [InlineData(false)] + [InlineData(true)] + [Trait("CWE", "674")] + public void ConvertFromJsonRejectsExcessiveNesting(bool compression) + { + var options = MessagePackSerializerOptions.Standard + .WithCompression(compression ? MessagePackCompression.Lz4Block : MessagePackCompression.None) + .WithSecurity(MessagePackSecurity.UntrustedData.WithMaximumObjectGraphDepth(3)); + + Assert.Throws(() => MessagePackSerializer.ConvertFromJson("[[[[1]]]]", options)); + } + + [Fact] + [Trait("CWE", "674")] + public void ConvertFromJsonSkipsLongSeparatorRunIteratively() + { + var json = new string(',', 200_000) + "null"; + var msgpack = MessagePackSerializer.ConvertFromJson(json); + + MessagePackSerializer.ConvertToJson(msgpack).Is("null"); + } + [Fact] public void FloatJson() { diff --git a/src/MessagePack.UnityClient/Assets/Scripts/Tests/ShareTests/UnsafeMemoryTest.cs b/src/MessagePack.UnityClient/Assets/Scripts/Tests/ShareTests/UnsafeMemoryTest.cs index c9b5f023e..14002930b 100644 --- a/src/MessagePack.UnityClient/Assets/Scripts/Tests/ShareTests/UnsafeMemoryTest.cs +++ b/src/MessagePack.UnityClient/Assets/Scripts/Tests/ShareTests/UnsafeMemoryTest.cs @@ -3,12 +3,7 @@ using System; using System.Buffers; -using System.Collections.Generic; using System.Linq; -using System.Reflection; -using System.Text; -using System.Threading.Tasks; -using MessagePack.Formatters; using MessagePack.Internal; using Nerdbank.Streams; using Xunit; @@ -70,6 +65,35 @@ public void WriteRaw() } } + [Fact] + public void WriteRaw_LargerSpan() + { + ReadOnlySpan src = new byte[MessagePackRange.MaxFixStringLength + 15]; + Sequence dst = new(); + + // x86 + for (int i = 1; i <= MessagePackRange.MaxFixStringLength; i++) + { + dst.Reset(); + MessagePackWriter dstWriter = new(dst); + (typeof(UnsafeMemory32).GetMethod("WriteRaw" + i).CreateDelegate(typeof(WriteDelegate)) as WriteDelegate).Invoke(ref dstWriter, src); + dstWriter.Flush(); + dst.Length.Is(i); + src.Slice(0, i).SequenceEqual(CodeGenHelpers.GetSpanFromSequence(dst.AsReadOnlySequence)).IsTrue(); + } + + // x64 + for (int i = 1; i <= MessagePackRange.MaxFixStringLength; i++) + { + dst.Reset(); + var dstWriter = new MessagePackWriter(dst); + (typeof(UnsafeMemory64).GetMethod("WriteRaw" + i).CreateDelegate(typeof(WriteDelegate)) as WriteDelegate).Invoke(ref dstWriter, src); + dstWriter.Flush(); + dst.Length.Is(i); + src.Slice(0, i).SequenceEqual(CodeGenHelpers.GetSpanFromSequence(dst.AsReadOnlySequence)).IsTrue(); + } + } + #endif } } diff --git a/src/MessagePack/Internal/UnsafeMemory.cs b/src/MessagePack/Internal/UnsafeMemory.cs index 7956db01f..9ebcd6e79 100644 --- a/src/MessagePack/Internal/UnsafeMemory.cs +++ b/src/MessagePack/Internal/UnsafeMemory.cs @@ -20,7 +20,7 @@ public static partial class UnsafeMemory32 [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe void WriteRaw4(ref MessagePackWriter writer, ReadOnlySpan src) { - Span dst = writer.GetSpan(src.Length); + Span dst = writer.GetSpan(4); fixed (byte* pSrc = &src[0]) fixed (byte* pDst = &dst[0]) @@ -28,13 +28,13 @@ public static unsafe void WriteRaw4(ref MessagePackWriter writer, ReadOnlySpan src) { - Span dst = writer.GetSpan(src.Length); + Span dst = writer.GetSpan(5); fixed (byte* pSrc = &src[0]) fixed (byte* pDst = &dst[0]) @@ -43,13 +43,13 @@ public static unsafe void WriteRaw5(ref MessagePackWriter writer, ReadOnlySpan src) { - Span dst = writer.GetSpan(src.Length); + Span dst = writer.GetSpan(6); fixed (byte* pSrc = &src[0]) fixed (byte* pDst = &dst[0]) @@ -58,13 +58,13 @@ public static unsafe void WriteRaw6(ref MessagePackWriter writer, ReadOnlySpan src) { - Span dst = writer.GetSpan(src.Length); + Span dst = writer.GetSpan(7); fixed (byte* pSrc = &src[0]) fixed (byte* pDst = &dst[0]) @@ -73,13 +73,13 @@ public static unsafe void WriteRaw7(ref MessagePackWriter writer, ReadOnlySpan src) { - Span dst = writer.GetSpan(src.Length); + Span dst = writer.GetSpan(8); fixed (byte* pSrc = &src[0]) fixed (byte* pDst = &dst[0]) @@ -88,13 +88,13 @@ public static unsafe void WriteRaw8(ref MessagePackWriter writer, ReadOnlySpan src) { - Span dst = writer.GetSpan(src.Length); + Span dst = writer.GetSpan(9); fixed (byte* pSrc = &src[0]) fixed (byte* pDst = &dst[0]) @@ -104,13 +104,13 @@ public static unsafe void WriteRaw9(ref MessagePackWriter writer, ReadOnlySpan src) { - Span dst = writer.GetSpan(src.Length); + Span dst = writer.GetSpan(10); fixed (byte* pSrc = &src[0]) fixed (byte* pDst = &dst[0]) @@ -120,13 +120,13 @@ public static unsafe void WriteRaw10(ref MessagePackWriter writer, ReadOnlySpan< *(int*)(pDst + 6) = *(int*)(pSrc + 6); } - writer.Advance(src.Length); + writer.Advance(10); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe void WriteRaw11(ref MessagePackWriter writer, ReadOnlySpan src) { - Span dst = writer.GetSpan(src.Length); + Span dst = writer.GetSpan(11); fixed (byte* pSrc = &src[0]) fixed (byte* pDst = &dst[0]) @@ -136,13 +136,13 @@ public static unsafe void WriteRaw11(ref MessagePackWriter writer, ReadOnlySpan< *(int*)(pDst + 7) = *(int*)(pSrc + 7); } - writer.Advance(src.Length); + writer.Advance(11); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe void WriteRaw12(ref MessagePackWriter writer, ReadOnlySpan src) { - Span dst = writer.GetSpan(src.Length); + Span dst = writer.GetSpan(12); fixed (byte* pSrc = &src[0]) fixed (byte* pDst = &dst[0]) @@ -152,13 +152,13 @@ public static unsafe void WriteRaw12(ref MessagePackWriter writer, ReadOnlySpan< *(int*)(pDst + 8) = *(int*)(pSrc + 8); } - writer.Advance(src.Length); + writer.Advance(12); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe void WriteRaw13(ref MessagePackWriter writer, ReadOnlySpan src) { - Span dst = writer.GetSpan(src.Length); + Span dst = writer.GetSpan(13); fixed (byte* pSrc = &src[0]) fixed (byte* pDst = &dst[0]) @@ -169,13 +169,13 @@ public static unsafe void WriteRaw13(ref MessagePackWriter writer, ReadOnlySpan< *(int*)(pDst + 9) = *(int*)(pSrc + 9); } - writer.Advance(src.Length); + writer.Advance(13); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe void WriteRaw14(ref MessagePackWriter writer, ReadOnlySpan src) { - Span dst = writer.GetSpan(src.Length); + Span dst = writer.GetSpan(14); fixed (byte* pSrc = &src[0]) fixed (byte* pDst = &dst[0]) @@ -186,13 +186,13 @@ public static unsafe void WriteRaw14(ref MessagePackWriter writer, ReadOnlySpan< *(int*)(pDst + 10) = *(int*)(pSrc + 10); } - writer.Advance(src.Length); + writer.Advance(14); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe void WriteRaw15(ref MessagePackWriter writer, ReadOnlySpan src) { - Span dst = writer.GetSpan(src.Length); + Span dst = writer.GetSpan(15); fixed (byte* pSrc = &src[0]) fixed (byte* pDst = &dst[0]) @@ -203,13 +203,13 @@ public static unsafe void WriteRaw15(ref MessagePackWriter writer, ReadOnlySpan< *(int*)(pDst + 11) = *(int*)(pSrc + 11); } - writer.Advance(src.Length); + writer.Advance(15); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe void WriteRaw16(ref MessagePackWriter writer, ReadOnlySpan src) { - Span dst = writer.GetSpan(src.Length); + Span dst = writer.GetSpan(16); fixed (byte* pSrc = &src[0]) fixed (byte* pDst = &dst[0]) @@ -220,13 +220,13 @@ public static unsafe void WriteRaw16(ref MessagePackWriter writer, ReadOnlySpan< *(int*)(pDst + 12) = *(int*)(pSrc + 12); } - writer.Advance(src.Length); + writer.Advance(16); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe void WriteRaw17(ref MessagePackWriter writer, ReadOnlySpan src) { - Span dst = writer.GetSpan(src.Length); + Span dst = writer.GetSpan(17); fixed (byte* pSrc = &src[0]) fixed (byte* pDst = &dst[0]) @@ -238,13 +238,13 @@ public static unsafe void WriteRaw17(ref MessagePackWriter writer, ReadOnlySpan< *(int*)(pDst + 13) = *(int*)(pSrc + 13); } - writer.Advance(src.Length); + writer.Advance(17); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe void WriteRaw18(ref MessagePackWriter writer, ReadOnlySpan src) { - Span dst = writer.GetSpan(src.Length); + Span dst = writer.GetSpan(18); fixed (byte* pSrc = &src[0]) fixed (byte* pDst = &dst[0]) @@ -256,13 +256,13 @@ public static unsafe void WriteRaw18(ref MessagePackWriter writer, ReadOnlySpan< *(int*)(pDst + 14) = *(int*)(pSrc + 14); } - writer.Advance(src.Length); + writer.Advance(18); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe void WriteRaw19(ref MessagePackWriter writer, ReadOnlySpan src) { - Span dst = writer.GetSpan(src.Length); + Span dst = writer.GetSpan(19); fixed (byte* pSrc = &src[0]) fixed (byte* pDst = &dst[0]) @@ -274,13 +274,13 @@ public static unsafe void WriteRaw19(ref MessagePackWriter writer, ReadOnlySpan< *(int*)(pDst + 15) = *(int*)(pSrc + 15); } - writer.Advance(src.Length); + writer.Advance(19); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe void WriteRaw20(ref MessagePackWriter writer, ReadOnlySpan src) { - Span dst = writer.GetSpan(src.Length); + Span dst = writer.GetSpan(20); fixed (byte* pSrc = &src[0]) fixed (byte* pDst = &dst[0]) @@ -292,13 +292,13 @@ public static unsafe void WriteRaw20(ref MessagePackWriter writer, ReadOnlySpan< *(int*)(pDst + 16) = *(int*)(pSrc + 16); } - writer.Advance(src.Length); + writer.Advance(20); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe void WriteRaw21(ref MessagePackWriter writer, ReadOnlySpan src) { - Span dst = writer.GetSpan(src.Length); + Span dst = writer.GetSpan(21); fixed (byte* pSrc = &src[0]) fixed (byte* pDst = &dst[0]) @@ -311,13 +311,13 @@ public static unsafe void WriteRaw21(ref MessagePackWriter writer, ReadOnlySpan< *(int*)(pDst + 17) = *(int*)(pSrc + 17); } - writer.Advance(src.Length); + writer.Advance(21); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe void WriteRaw22(ref MessagePackWriter writer, ReadOnlySpan src) { - Span dst = writer.GetSpan(src.Length); + Span dst = writer.GetSpan(22); fixed (byte* pSrc = &src[0]) fixed (byte* pDst = &dst[0]) @@ -330,13 +330,13 @@ public static unsafe void WriteRaw22(ref MessagePackWriter writer, ReadOnlySpan< *(int*)(pDst + 18) = *(int*)(pSrc + 18); } - writer.Advance(src.Length); + writer.Advance(22); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe void WriteRaw23(ref MessagePackWriter writer, ReadOnlySpan src) { - Span dst = writer.GetSpan(src.Length); + Span dst = writer.GetSpan(23); fixed (byte* pSrc = &src[0]) fixed (byte* pDst = &dst[0]) @@ -349,13 +349,13 @@ public static unsafe void WriteRaw23(ref MessagePackWriter writer, ReadOnlySpan< *(int*)(pDst + 19) = *(int*)(pSrc + 19); } - writer.Advance(src.Length); + writer.Advance(23); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe void WriteRaw24(ref MessagePackWriter writer, ReadOnlySpan src) { - Span dst = writer.GetSpan(src.Length); + Span dst = writer.GetSpan(24); fixed (byte* pSrc = &src[0]) fixed (byte* pDst = &dst[0]) @@ -368,13 +368,13 @@ public static unsafe void WriteRaw24(ref MessagePackWriter writer, ReadOnlySpan< *(int*)(pDst + 20) = *(int*)(pSrc + 20); } - writer.Advance(src.Length); + writer.Advance(24); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe void WriteRaw25(ref MessagePackWriter writer, ReadOnlySpan src) { - Span dst = writer.GetSpan(src.Length); + Span dst = writer.GetSpan(25); fixed (byte* pSrc = &src[0]) fixed (byte* pDst = &dst[0]) @@ -388,13 +388,13 @@ public static unsafe void WriteRaw25(ref MessagePackWriter writer, ReadOnlySpan< *(int*)(pDst + 21) = *(int*)(pSrc + 21); } - writer.Advance(src.Length); + writer.Advance(25); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe void WriteRaw26(ref MessagePackWriter writer, ReadOnlySpan src) { - Span dst = writer.GetSpan(src.Length); + Span dst = writer.GetSpan(26); fixed (byte* pSrc = &src[0]) fixed (byte* pDst = &dst[0]) @@ -408,13 +408,13 @@ public static unsafe void WriteRaw26(ref MessagePackWriter writer, ReadOnlySpan< *(int*)(pDst + 22) = *(int*)(pSrc + 22); } - writer.Advance(src.Length); + writer.Advance(26); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe void WriteRaw27(ref MessagePackWriter writer, ReadOnlySpan src) { - Span dst = writer.GetSpan(src.Length); + Span dst = writer.GetSpan(27); fixed (byte* pSrc = &src[0]) fixed (byte* pDst = &dst[0]) @@ -428,13 +428,13 @@ public static unsafe void WriteRaw27(ref MessagePackWriter writer, ReadOnlySpan< *(int*)(pDst + 23) = *(int*)(pSrc + 23); } - writer.Advance(src.Length); + writer.Advance(27); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe void WriteRaw28(ref MessagePackWriter writer, ReadOnlySpan src) { - Span dst = writer.GetSpan(src.Length); + Span dst = writer.GetSpan(28); fixed (byte* pSrc = &src[0]) fixed (byte* pDst = &dst[0]) @@ -448,13 +448,13 @@ public static unsafe void WriteRaw28(ref MessagePackWriter writer, ReadOnlySpan< *(int*)(pDst + 24) = *(int*)(pSrc + 24); } - writer.Advance(src.Length); + writer.Advance(28); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe void WriteRaw29(ref MessagePackWriter writer, ReadOnlySpan src) { - Span dst = writer.GetSpan(src.Length); + Span dst = writer.GetSpan(29); fixed (byte* pSrc = &src[0]) fixed (byte* pDst = &dst[0]) @@ -469,13 +469,13 @@ public static unsafe void WriteRaw29(ref MessagePackWriter writer, ReadOnlySpan< *(int*)(pDst + 25) = *(int*)(pSrc + 25); } - writer.Advance(src.Length); + writer.Advance(29); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe void WriteRaw30(ref MessagePackWriter writer, ReadOnlySpan src) { - Span dst = writer.GetSpan(src.Length); + Span dst = writer.GetSpan(30); fixed (byte* pSrc = &src[0]) fixed (byte* pDst = &dst[0]) @@ -490,13 +490,13 @@ public static unsafe void WriteRaw30(ref MessagePackWriter writer, ReadOnlySpan< *(int*)(pDst + 26) = *(int*)(pSrc + 26); } - writer.Advance(src.Length); + writer.Advance(30); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe void WriteRaw31(ref MessagePackWriter writer, ReadOnlySpan src) { - Span dst = writer.GetSpan(src.Length); + Span dst = writer.GetSpan(31); fixed (byte* pSrc = &src[0]) fixed (byte* pDst = &dst[0]) @@ -511,7 +511,7 @@ public static unsafe void WriteRaw31(ref MessagePackWriter writer, ReadOnlySpan< *(int*)(pDst + 27) = *(int*)(pSrc + 27); } - writer.Advance(src.Length); + writer.Advance(31); } } @@ -520,7 +520,7 @@ public static partial class UnsafeMemory64 [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe void WriteRaw8(ref MessagePackWriter writer, ReadOnlySpan src) { - Span dst = writer.GetSpan(src.Length); + Span dst = writer.GetSpan(8); fixed (byte* pSrc = &src[0]) fixed (byte* pDst = &dst[0]) @@ -528,13 +528,13 @@ public static unsafe void WriteRaw8(ref MessagePackWriter writer, ReadOnlySpan src) { - Span dst = writer.GetSpan(src.Length); + Span dst = writer.GetSpan(9); fixed (byte* pSrc = &src[0]) fixed (byte* pDst = &dst[0]) @@ -543,13 +543,13 @@ public static unsafe void WriteRaw9(ref MessagePackWriter writer, ReadOnlySpan src) { - Span dst = writer.GetSpan(src.Length); + Span dst = writer.GetSpan(10); fixed (byte* pSrc = &src[0]) fixed (byte* pDst = &dst[0]) @@ -558,13 +558,13 @@ public static unsafe void WriteRaw10(ref MessagePackWriter writer, ReadOnlySpan< *(long*)(pDst + 2) = *(long*)(pSrc + 2); } - writer.Advance(src.Length); + writer.Advance(10); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe void WriteRaw11(ref MessagePackWriter writer, ReadOnlySpan src) { - Span dst = writer.GetSpan(src.Length); + Span dst = writer.GetSpan(11); fixed (byte* pSrc = &src[0]) fixed (byte* pDst = &dst[0]) @@ -573,13 +573,13 @@ public static unsafe void WriteRaw11(ref MessagePackWriter writer, ReadOnlySpan< *(long*)(pDst + 3) = *(long*)(pSrc + 3); } - writer.Advance(src.Length); + writer.Advance(11); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe void WriteRaw12(ref MessagePackWriter writer, ReadOnlySpan src) { - Span dst = writer.GetSpan(src.Length); + Span dst = writer.GetSpan(12); fixed (byte* pSrc = &src[0]) fixed (byte* pDst = &dst[0]) @@ -588,13 +588,13 @@ public static unsafe void WriteRaw12(ref MessagePackWriter writer, ReadOnlySpan< *(long*)(pDst + 4) = *(long*)(pSrc + 4); } - writer.Advance(src.Length); + writer.Advance(12); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe void WriteRaw13(ref MessagePackWriter writer, ReadOnlySpan src) { - Span dst = writer.GetSpan(src.Length); + Span dst = writer.GetSpan(13); fixed (byte* pSrc = &src[0]) fixed (byte* pDst = &dst[0]) @@ -603,13 +603,13 @@ public static unsafe void WriteRaw13(ref MessagePackWriter writer, ReadOnlySpan< *(long*)(pDst + 5) = *(long*)(pSrc + 5); } - writer.Advance(src.Length); + writer.Advance(13); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe void WriteRaw14(ref MessagePackWriter writer, ReadOnlySpan src) { - Span dst = writer.GetSpan(src.Length); + Span dst = writer.GetSpan(14); fixed (byte* pSrc = &src[0]) fixed (byte* pDst = &dst[0]) @@ -618,13 +618,13 @@ public static unsafe void WriteRaw14(ref MessagePackWriter writer, ReadOnlySpan< *(long*)(pDst + 6) = *(long*)(pSrc + 6); } - writer.Advance(src.Length); + writer.Advance(14); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe void WriteRaw15(ref MessagePackWriter writer, ReadOnlySpan src) { - Span dst = writer.GetSpan(src.Length); + Span dst = writer.GetSpan(15); fixed (byte* pSrc = &src[0]) fixed (byte* pDst = &dst[0]) @@ -633,13 +633,13 @@ public static unsafe void WriteRaw15(ref MessagePackWriter writer, ReadOnlySpan< *(long*)(pDst + 7) = *(long*)(pSrc + 7); } - writer.Advance(src.Length); + writer.Advance(15); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe void WriteRaw16(ref MessagePackWriter writer, ReadOnlySpan src) { - Span dst = writer.GetSpan(src.Length); + Span dst = writer.GetSpan(16); fixed (byte* pSrc = &src[0]) fixed (byte* pDst = &dst[0]) @@ -648,13 +648,13 @@ public static unsafe void WriteRaw16(ref MessagePackWriter writer, ReadOnlySpan< *(long*)(pDst + 8) = *(long*)(pSrc + 8); } - writer.Advance(src.Length); + writer.Advance(16); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe void WriteRaw17(ref MessagePackWriter writer, ReadOnlySpan src) { - Span dst = writer.GetSpan(src.Length); + Span dst = writer.GetSpan(17); fixed (byte* pSrc = &src[0]) fixed (byte* pDst = &dst[0]) @@ -664,13 +664,13 @@ public static unsafe void WriteRaw17(ref MessagePackWriter writer, ReadOnlySpan< *(long*)(pDst + 9) = *(long*)(pSrc + 9); } - writer.Advance(src.Length); + writer.Advance(17); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe void WriteRaw18(ref MessagePackWriter writer, ReadOnlySpan src) { - Span dst = writer.GetSpan(src.Length); + Span dst = writer.GetSpan(18); fixed (byte* pSrc = &src[0]) fixed (byte* pDst = &dst[0]) @@ -680,13 +680,13 @@ public static unsafe void WriteRaw18(ref MessagePackWriter writer, ReadOnlySpan< *(long*)(pDst + 10) = *(long*)(pSrc + 10); } - writer.Advance(src.Length); + writer.Advance(18); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe void WriteRaw19(ref MessagePackWriter writer, ReadOnlySpan src) { - Span dst = writer.GetSpan(src.Length); + Span dst = writer.GetSpan(19); fixed (byte* pSrc = &src[0]) fixed (byte* pDst = &dst[0]) @@ -696,13 +696,13 @@ public static unsafe void WriteRaw19(ref MessagePackWriter writer, ReadOnlySpan< *(long*)(pDst + 11) = *(long*)(pSrc + 11); } - writer.Advance(src.Length); + writer.Advance(19); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe void WriteRaw20(ref MessagePackWriter writer, ReadOnlySpan src) { - Span dst = writer.GetSpan(src.Length); + Span dst = writer.GetSpan(20); fixed (byte* pSrc = &src[0]) fixed (byte* pDst = &dst[0]) @@ -712,13 +712,13 @@ public static unsafe void WriteRaw20(ref MessagePackWriter writer, ReadOnlySpan< *(long*)(pDst + 12) = *(long*)(pSrc + 12); } - writer.Advance(src.Length); + writer.Advance(20); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe void WriteRaw21(ref MessagePackWriter writer, ReadOnlySpan src) { - Span dst = writer.GetSpan(src.Length); + Span dst = writer.GetSpan(21); fixed (byte* pSrc = &src[0]) fixed (byte* pDst = &dst[0]) @@ -728,13 +728,13 @@ public static unsafe void WriteRaw21(ref MessagePackWriter writer, ReadOnlySpan< *(long*)(pDst + 13) = *(long*)(pSrc + 13); } - writer.Advance(src.Length); + writer.Advance(21); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe void WriteRaw22(ref MessagePackWriter writer, ReadOnlySpan src) { - Span dst = writer.GetSpan(src.Length); + Span dst = writer.GetSpan(22); fixed (byte* pSrc = &src[0]) fixed (byte* pDst = &dst[0]) @@ -744,13 +744,13 @@ public static unsafe void WriteRaw22(ref MessagePackWriter writer, ReadOnlySpan< *(long*)(pDst + 14) = *(long*)(pSrc + 14); } - writer.Advance(src.Length); + writer.Advance(22); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe void WriteRaw23(ref MessagePackWriter writer, ReadOnlySpan src) { - Span dst = writer.GetSpan(src.Length); + Span dst = writer.GetSpan(23); fixed (byte* pSrc = &src[0]) fixed (byte* pDst = &dst[0]) @@ -760,13 +760,13 @@ public static unsafe void WriteRaw23(ref MessagePackWriter writer, ReadOnlySpan< *(long*)(pDst + 15) = *(long*)(pSrc + 15); } - writer.Advance(src.Length); + writer.Advance(23); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe void WriteRaw24(ref MessagePackWriter writer, ReadOnlySpan src) { - Span dst = writer.GetSpan(src.Length); + Span dst = writer.GetSpan(24); fixed (byte* pSrc = &src[0]) fixed (byte* pDst = &dst[0]) @@ -776,13 +776,13 @@ public static unsafe void WriteRaw24(ref MessagePackWriter writer, ReadOnlySpan< *(long*)(pDst + 16) = *(long*)(pSrc + 16); } - writer.Advance(src.Length); + writer.Advance(24); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe void WriteRaw25(ref MessagePackWriter writer, ReadOnlySpan src) { - Span dst = writer.GetSpan(src.Length); + Span dst = writer.GetSpan(25); fixed (byte* pSrc = &src[0]) fixed (byte* pDst = &dst[0]) @@ -793,13 +793,13 @@ public static unsafe void WriteRaw25(ref MessagePackWriter writer, ReadOnlySpan< *(long*)(pDst + 17) = *(long*)(pSrc + 17); } - writer.Advance(src.Length); + writer.Advance(25); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe void WriteRaw26(ref MessagePackWriter writer, ReadOnlySpan src) { - Span dst = writer.GetSpan(src.Length); + Span dst = writer.GetSpan(26); fixed (byte* pSrc = &src[0]) fixed (byte* pDst = &dst[0]) @@ -810,13 +810,13 @@ public static unsafe void WriteRaw26(ref MessagePackWriter writer, ReadOnlySpan< *(long*)(pDst + 18) = *(long*)(pSrc + 18); } - writer.Advance(src.Length); + writer.Advance(26); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe void WriteRaw27(ref MessagePackWriter writer, ReadOnlySpan src) { - Span dst = writer.GetSpan(src.Length); + Span dst = writer.GetSpan(27); fixed (byte* pSrc = &src[0]) fixed (byte* pDst = &dst[0]) @@ -827,13 +827,13 @@ public static unsafe void WriteRaw27(ref MessagePackWriter writer, ReadOnlySpan< *(long*)(pDst + 19) = *(long*)(pSrc + 19); } - writer.Advance(src.Length); + writer.Advance(27); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe void WriteRaw28(ref MessagePackWriter writer, ReadOnlySpan src) { - Span dst = writer.GetSpan(src.Length); + Span dst = writer.GetSpan(28); fixed (byte* pSrc = &src[0]) fixed (byte* pDst = &dst[0]) @@ -844,13 +844,13 @@ public static unsafe void WriteRaw28(ref MessagePackWriter writer, ReadOnlySpan< *(long*)(pDst + 20) = *(long*)(pSrc + 20); } - writer.Advance(src.Length); + writer.Advance(28); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe void WriteRaw29(ref MessagePackWriter writer, ReadOnlySpan src) { - Span dst = writer.GetSpan(src.Length); + Span dst = writer.GetSpan(29); fixed (byte* pSrc = &src[0]) fixed (byte* pDst = &dst[0]) @@ -861,13 +861,13 @@ public static unsafe void WriteRaw29(ref MessagePackWriter writer, ReadOnlySpan< *(long*)(pDst + 21) = *(long*)(pSrc + 21); } - writer.Advance(src.Length); + writer.Advance(29); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe void WriteRaw30(ref MessagePackWriter writer, ReadOnlySpan src) { - Span dst = writer.GetSpan(src.Length); + Span dst = writer.GetSpan(30); fixed (byte* pSrc = &src[0]) fixed (byte* pDst = &dst[0]) @@ -878,13 +878,13 @@ public static unsafe void WriteRaw30(ref MessagePackWriter writer, ReadOnlySpan< *(long*)(pDst + 22) = *(long*)(pSrc + 22); } - writer.Advance(src.Length); + writer.Advance(30); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe void WriteRaw31(ref MessagePackWriter writer, ReadOnlySpan src) { - Span dst = writer.GetSpan(src.Length); + Span dst = writer.GetSpan(31); fixed (byte* pSrc = &src[0]) fixed (byte* pDst = &dst[0]) @@ -895,7 +895,7 @@ public static unsafe void WriteRaw31(ref MessagePackWriter writer, ReadOnlySpan< *(long*)(pDst + 23) = *(long*)(pSrc + 23); } - writer.Advance(src.Length); + writer.Advance(31); } } } diff --git a/src/MessagePack/Internal/UnsafeMemory.tt b/src/MessagePack/Internal/UnsafeMemory.tt index cace009d7..6d1891701 100644 --- a/src/MessagePack/Internal/UnsafeMemory.tt +++ b/src/MessagePack/Internal/UnsafeMemory.tt @@ -28,7 +28,7 @@ namespace MessagePack.Internal [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe void WriteRaw<#= i #>(ref MessagePackWriter writer, ReadOnlySpan src) { - Span dst = writer.GetSpan(src.Length); + Span dst = writer.GetSpan(<#= i #>); fixed (byte* pSrc = &src[0]) fixed (byte* pDst = &dst[0]) @@ -41,7 +41,7 @@ namespace MessagePack.Internal <# } #> } - writer.Advance(src.Length); + writer.Advance(<#= i #>); } <# } #> } @@ -52,7 +52,7 @@ namespace MessagePack.Internal [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe void WriteRaw<#= i #>(ref MessagePackWriter writer, ReadOnlySpan src) { - Span dst = writer.GetSpan(src.Length); + Span dst = writer.GetSpan(<#= i #>); fixed (byte* pSrc = &src[0]) fixed (byte* pDst = &dst[0]) @@ -65,7 +65,7 @@ namespace MessagePack.Internal <# } #> } - writer.Advance(src.Length); + writer.Advance(<#= i #>); } <# } #> } diff --git a/src/MessagePack/net472/PublicAPI.Shipped.txt b/src/MessagePack/net472/PublicAPI.Shipped.txt index 2893efd85..ad5a0623a 100644 --- a/src/MessagePack/net472/PublicAPI.Shipped.txt +++ b/src/MessagePack/net472/PublicAPI.Shipped.txt @@ -1177,9 +1177,12 @@ MessagePack.Formatters.StringInterningFormatter MessagePack.Formatters.StringInterningFormatter.Deserialize(ref MessagePack.MessagePackReader reader, MessagePack.MessagePackSerializerOptions! options) -> string? MessagePack.Formatters.StringInterningFormatter.Serialize(ref MessagePack.MessagePackWriter writer, string? value, MessagePack.MessagePackSerializerOptions! options) -> void MessagePack.Formatters.StringInterningFormatter.StringInterningFormatter() -> void +MessagePack.MessagePackSecurity.MaximumDecompressedSize.get -> int +MessagePack.MessagePackSecurity.WithMaximumDecompressedSize(int maximumDecompressedSize) -> MessagePack.MessagePackSecurity! MessagePack.MessagePackSerializerOptions.CompressionMinLength.get -> int MessagePack.MessagePackSerializerOptions.SuggestedContiguousMemorySize.get -> int MessagePack.MessagePackSerializerOptions.WithCompressionMinLength(int compressionMinLength) -> MessagePack.MessagePackSerializerOptions! MessagePack.MessagePackSerializerOptions.WithSuggestedContiguousMemorySize(int suggestedContiguousMemorySize) -> MessagePack.MessagePackSerializerOptions! static MessagePack.MessagePackWriter.GetEncodedLength(long value) -> int static MessagePack.MessagePackWriter.GetEncodedLength(ulong value) -> int +virtual MessagePack.MessagePackSerializerOptions.ThrowIfDeserializingTypeIsDisallowedCore(System.Type! type) -> void diff --git a/src/MessagePack/net6.0/PublicAPI.Shipped.txt b/src/MessagePack/net6.0/PublicAPI.Shipped.txt index 2c67e9468..cc4cfc419 100644 --- a/src/MessagePack/net6.0/PublicAPI.Shipped.txt +++ b/src/MessagePack/net6.0/PublicAPI.Shipped.txt @@ -1189,6 +1189,8 @@ MessagePack.Formatters.StringInterningFormatter.StringInterningFormatter() -> vo MessagePack.Formatters.TimeOnlyFormatter MessagePack.Formatters.TimeOnlyFormatter.Deserialize(ref MessagePack.MessagePackReader reader, MessagePack.MessagePackSerializerOptions! options) -> System.TimeOnly MessagePack.Formatters.TimeOnlyFormatter.Serialize(ref MessagePack.MessagePackWriter writer, System.TimeOnly value, MessagePack.MessagePackSerializerOptions! options) -> void +MessagePack.MessagePackSecurity.MaximumDecompressedSize.get -> int +MessagePack.MessagePackSecurity.WithMaximumDecompressedSize(int maximumDecompressedSize) -> MessagePack.MessagePackSecurity! MessagePack.MessagePackSerializerOptions.CompressionMinLength.get -> int MessagePack.MessagePackSerializerOptions.SuggestedContiguousMemorySize.get -> int MessagePack.MessagePackSerializerOptions.WithCompressionMinLength(int compressionMinLength) -> MessagePack.MessagePackSerializerOptions! @@ -1197,3 +1199,4 @@ static MessagePack.MessagePackWriter.GetEncodedLength(long value) -> int static MessagePack.MessagePackWriter.GetEncodedLength(ulong value) -> int static readonly MessagePack.Formatters.DateOnlyFormatter.Instance -> MessagePack.Formatters.DateOnlyFormatter! static readonly MessagePack.Formatters.TimeOnlyFormatter.Instance -> MessagePack.Formatters.TimeOnlyFormatter! +virtual MessagePack.MessagePackSerializerOptions.ThrowIfDeserializingTypeIsDisallowedCore(System.Type! type) -> void diff --git a/src/MessagePack/netstandard2.0/PublicAPI.Shipped.txt b/src/MessagePack/netstandard2.0/PublicAPI.Shipped.txt index 2893efd85..ad5a0623a 100644 --- a/src/MessagePack/netstandard2.0/PublicAPI.Shipped.txt +++ b/src/MessagePack/netstandard2.0/PublicAPI.Shipped.txt @@ -1177,9 +1177,12 @@ MessagePack.Formatters.StringInterningFormatter MessagePack.Formatters.StringInterningFormatter.Deserialize(ref MessagePack.MessagePackReader reader, MessagePack.MessagePackSerializerOptions! options) -> string? MessagePack.Formatters.StringInterningFormatter.Serialize(ref MessagePack.MessagePackWriter writer, string? value, MessagePack.MessagePackSerializerOptions! options) -> void MessagePack.Formatters.StringInterningFormatter.StringInterningFormatter() -> void +MessagePack.MessagePackSecurity.MaximumDecompressedSize.get -> int +MessagePack.MessagePackSecurity.WithMaximumDecompressedSize(int maximumDecompressedSize) -> MessagePack.MessagePackSecurity! MessagePack.MessagePackSerializerOptions.CompressionMinLength.get -> int MessagePack.MessagePackSerializerOptions.SuggestedContiguousMemorySize.get -> int MessagePack.MessagePackSerializerOptions.WithCompressionMinLength(int compressionMinLength) -> MessagePack.MessagePackSerializerOptions! MessagePack.MessagePackSerializerOptions.WithSuggestedContiguousMemorySize(int suggestedContiguousMemorySize) -> MessagePack.MessagePackSerializerOptions! static MessagePack.MessagePackWriter.GetEncodedLength(long value) -> int static MessagePack.MessagePackWriter.GetEncodedLength(ulong value) -> int +virtual MessagePack.MessagePackSerializerOptions.ThrowIfDeserializingTypeIsDisallowedCore(System.Type! type) -> void diff --git a/tests/MessagePack.AspNetCoreMvcFormatter.Tests/AspNetCoreMvcFormatterTest.cs b/tests/MessagePack.AspNetCoreMvcFormatter.Tests/AspNetCoreMvcFormatterTest.cs index 96b54b315..ed2219b1e 100644 --- a/tests/MessagePack.AspNetCoreMvcFormatter.Tests/AspNetCoreMvcFormatterTest.cs +++ b/tests/MessagePack.AspNetCoreMvcFormatter.Tests/AspNetCoreMvcFormatterTest.cs @@ -2,6 +2,7 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System; +using System.Collections.Generic; using System.IO; using System.Text; using System.Threading; @@ -195,6 +196,34 @@ public void MessagePackInputFormatterSupportsXMsgPack() inputFormatter.SupportedMediaTypes.Is(MsgPackContentType); } + [Fact] + public async Task MessagePackInputFormatterDefaultsToUntrustedData() + { + const long value1 = 0x100000001; + const long value2 = 0x200000002; + + var messagePackBinary = MessagePackSerializer.Serialize(new Dictionary + { + [value1] = 1, + [value2] = 2, + }); + + var httpContext = new DefaultHttpContext(); + httpContext.Features.Set(new TestResponseFeature()); + httpContext.Request.Body = new NonSeekableReadStream(messagePackBinary); + httpContext.Request.ContentType = MsgPackContentType; + + InputFormatterContext inputFormatterContext = this.CreateInputFormatterContext(typeof(Dictionary), httpContext); + var inputFormatter = new MessagePackInputFormatter(); + + InputFormatterResult result = await inputFormatter.ReadAsync(inputFormatterContext); + + Assert.False(result.HasError); + var dictionary = Assert.IsType>(result.Model); + Assert.Equal(EqualityComparer.Default.GetHashCode(value1), EqualityComparer.Default.GetHashCode(value2)); + Assert.NotEqual(dictionary.Comparer.GetHashCode(value1), dictionary.Comparer.GetHashCode(value2)); + } + /// /// JsonOutputFormatterTests.cs#L453. /// diff --git a/tests/MessagePack.Tests/AssemblyLoadContextTests.cs b/tests/MessagePack.Tests/AssemblyLoadContextTests.cs new file mode 100644 index 000000000..d2ed970a7 --- /dev/null +++ b/tests/MessagePack.Tests/AssemblyLoadContextTests.cs @@ -0,0 +1,198 @@ +// Copyright (c) All contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#if NET + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Runtime.Loader; +using System.Text; +using System.Threading.Tasks; +using ComplexdUnion; +using MessagePack; +using MessagePack.Formatters; +using MessagePack.Resolvers; +using SharedData; +using Xunit; + +#pragma warning disable SA1302 // Interface names should begin with I +#pragma warning disable SA1403 // File may only contain a single namespace + +public class AssemblyLoadContextTests : IDisposable +{ + private static readonly string SharedDataAssemblyName = typeof(RootUnionType).Assembly.Location; + private readonly AssemblyLoadContext loadContext = new AssemblyLoadContext("TestContext", isCollectible: true); + + public void Dispose() + { + this.loadContext.Unload(); + } + + [Fact] + public void DynamicUnionResolverWorksAcrossAssemblyLoadContexts() + { + RootUnionType unionTypeInMainLoadContext = new SubUnionType1(); + var options = this.CreateSerializerOptions(); + + var buffer1 = MessagePackSerializer.Serialize(unionTypeInMainLoadContext, options: options); + var o1 = MessagePackSerializer.Deserialize(buffer1, options: options); + + Assert.True(o1 is SubUnionType1); + + var assembly = this.loadContext.LoadFromAssemblyPath(SharedDataAssemblyName); + object unionTypeInOtherContext = assembly.CreateInstance(typeof(SubUnionType1).FullName); + Type rootUnionType = assembly.GetType(typeof(RootUnionType).FullName); + + var buffer2 = MessagePackSerializer.Serialize(rootUnionType, unionTypeInOtherContext, options: options); + var o2 = MessagePackSerializer.Deserialize(rootUnionType, buffer2, options: options); + + Assert.True(o2.GetType().IsAssignableTo(rootUnionType)); + } + + [Fact] + public void DynamicEnumResolverWorksAcrossAssemblyLoadContexts() + { + ByteEnum e1 = ByteEnum.A; + var options = this.CreateSerializerOptions(); + + var b1 = MessagePackSerializer.Serialize(e1, options: options); + var o1 = MessagePackSerializer.Deserialize(b1, options: options); + + Assert.Equal(typeof(ByteEnum), o1.GetType()); + + var assembly = this.loadContext.LoadFromAssemblyPath(SharedDataAssemblyName); + Type enumType = assembly.GetType(typeof(ByteEnum).FullName); + object e2 = Enum.GetValues(enumType).GetValue(1); + + var b2 = MessagePackSerializer.Serialize(enumType, e2, options: options); + var o2 = MessagePackSerializer.Deserialize(enumType, b2, options: options); + + Assert.Equal(o2.GetType(), e2.GetType()); + } + + [Fact] + public void DynamicObjectResolverWorksAcrossAssemblyLoadContexts() + { + FirstSimpleData e1 = new FirstSimpleData(); + var options = this.CreateSerializerOptions(); + + var b1 = MessagePackSerializer.Serialize(e1, options: options); + var o1 = MessagePackSerializer.Deserialize(b1, options: options); + + Assert.Equal(typeof(FirstSimpleData), o1.GetType()); + + var assembly = this.loadContext.LoadFromAssemblyPath(SharedDataAssemblyName); + Type objectType = assembly.GetType(typeof(FirstSimpleData).FullName); + object e2 = assembly.CreateInstance(typeof(FirstSimpleData).FullName); + + var b2 = MessagePackSerializer.Serialize(objectType, e2, options: options); + var o2 = MessagePackSerializer.Deserialize(objectType, b2, options: options); + + Assert.Equal(o2.GetType(), e2.GetType()); + } + + [Fact] + public void DynamiObjectResolverWorksWithGenericCollectionsAcrossAssemblyLoadContexts() + { + IList e1 = new List { new FirstSimpleData(), new FirstSimpleData() }; + var options = this.CreateSerializerOptions(); + + var b1 = MessagePackSerializer.Serialize(e1, options: options); + var o1 = MessagePackSerializer.Deserialize>(b1, options: options); + + Assert.Equal(typeof(List), o1.GetType()); + + var assembly = this.loadContext.LoadFromAssemblyPath(SharedDataAssemblyName); + Type objectType = assembly.GetType(typeof(FirstSimpleData).FullName); + Type listType = typeof(List<>).MakeGenericType(objectType); + object list = Activator.CreateInstance(listType); + + // Add two instances to the list + var addMethod = listType.GetMethod("Add"); + addMethod.Invoke(list, new[] { assembly.CreateInstance(typeof(FirstSimpleData).FullName) }); + addMethod.Invoke(list, new[] { assembly.CreateInstance(typeof(FirstSimpleData).FullName) }); + + Assert.Equal(objectType, (list as System.Collections.IList)[0].GetType()); + + var b2 = MessagePackSerializer.Serialize(listType, list, options: options); + var o2 = MessagePackSerializer.Deserialize(listType, b2, options: options); + + // Verify the element type directly from the generic type arguments + Type elementType = o2.GetType().GetGenericArguments()[0]; + Assert.Equal(objectType, elementType); + + // Get the first item to verify its actual runtime type + var enumerable = o2 as System.Collections.IList; + Assert.Equal(objectType, enumerable[0].GetType()); + } + + [Fact] + public void DynamiObjectResolverWorksWithGenericsAcrossAssemblyLoadContexts() + { + SimpleGenericData e1 = new SimpleGenericData(new FirstSimpleData()); + var options = this.CreateSerializerOptions(); + + var b1 = MessagePackSerializer.Serialize(e1, options: options); + var o1 = MessagePackSerializer.Deserialize>(b1, options: options); + + Assert.Equal(typeof(SimpleGenericData), o1.GetType()); + + var assembly = this.loadContext.LoadFromAssemblyPath(SharedDataAssemblyName); + Type dataType = assembly.GetType(typeof(FirstSimpleData).FullName); + Type simpleGenericType = assembly.GetType(typeof(SimpleGenericData<>).FullName); + Type genericType = simpleGenericType.MakeGenericType(dataType); + object data = Activator.CreateInstance(dataType); + object genericData = Activator.CreateInstance(genericType, data); + + var b2 = MessagePackSerializer.Serialize(genericType, genericData, options: options); + var o2 = MessagePackSerializer.Deserialize(genericType, b2, options: options); + + // Verify the element type directly from the generic type arguments + Type elementType = o2.GetType().GetGenericArguments()[0]; + Assert.Equal(dataType, elementType); + } + + [Fact] + public void DynamicContractlessObjectResolverWorksAcrossAssemblyLoadContexts() + { + FirstSimpleData e1 = new FirstSimpleData(); + var options = new MessagePackSerializerOptions( + CompositeResolver.Create( + BuiltinResolver.Instance, + PrimitiveObjectResolver.Instance, + DynamicContractlessObjectResolver.Instance)); + + var b1 = MessagePackSerializer.Serialize(e1, options: options); + var o1 = MessagePackSerializer.Deserialize(b1, options: options); + + Assert.Equal(typeof(FirstSimpleData), o1.GetType()); + + var assembly = this.loadContext.LoadFromAssemblyPath(SharedDataAssemblyName); + Type objectType = assembly.GetType(typeof(FirstSimpleData).FullName); + object e2 = assembly.CreateInstance(typeof(FirstSimpleData).FullName); + + var b2 = MessagePackSerializer.Serialize(objectType, e2, options: options); + var o2 = MessagePackSerializer.Deserialize(objectType, b2, options: options); + + Assert.Equal(o2.GetType(), e2.GetType()); + } + + private MessagePackSerializerOptions CreateSerializerOptions() + { + // Avoid default options as it will use source generated formatter which works in this scenario. + return new MessagePackSerializerOptions( + CompositeResolver.Create( + BuiltinResolver.Instance, + AttributeFormatterResolver.Instance, + DynamicEnumResolver.Instance, + DynamicGenericResolver.Instance, + DynamicUnionResolver.Instance, + DynamicObjectResolver.Instance, + PrimitiveObjectResolver.Instance)); + } +} + +#endif diff --git a/tests/MessagePack.Tests/ExtensionTests/UnityShimTest.cs b/tests/MessagePack.Tests/ExtensionTests/UnityShimTest.cs index 7e35b2448..df5b1abce 100644 --- a/tests/MessagePack.Tests/ExtensionTests/UnityShimTest.cs +++ b/tests/MessagePack.Tests/ExtensionTests/UnityShimTest.cs @@ -94,6 +94,18 @@ public void EnsureSpecCompatibilityTest(BlitContainer data) EnsureSpecCompatibility(data.Array); } + [Fact] + [Trait("CWE", "789")] + public void BlitRejectsByteLengthThatExceedsExtensionBody() + { + MessagePackSerializerOptions options = MessagePackSerializerOptions.Standard.WithResolver(new WithUnityBlitResolver()); + byte[] payload = { 0xC7, 0x06, unchecked((byte)ThisLibraryExtensionTypeCodes.UnityInt), 0xCE, 0x00, 0x00, 0x00, 0x08, 0xC3 }; + + var ex = Assert.Throws(() => MessagePackSerializer.Deserialize(payload, options)); + var inner = Assert.IsType(ex.InnerException); + Assert.Contains("Invalid Unity blit extension length", inner.Message); + } + public class WithUnityBlitResolver : IFormatterResolver { public IMessagePackFormatter GetFormatter() diff --git a/version.json b/version.json index f24af0f90..40602d3e9 100644 --- a/version.json +++ b/version.json @@ -1,9 +1,11 @@ { "$schema": "https://raw.githubusercontent.com/dotnet/Nerdbank.GitVersioning/master/src/NerdBank.GitVersioning/version.schema.json", "version": "2.5", + "versionHeightOffset": "95", "publicReleaseRefSpec": [ "^refs/heads/master$", "^refs/heads/v1\\.x$", + "^refs/heads/v2\\.x$", "^refs/heads/v\\d+(?:.\\d+)?$", "^refs/heads/develop$" ],