From e4d8dfe7b679d6fe6854e869f7ba0920cccdf69d Mon Sep 17 00:00:00 2001 From: Adam Sitnik Date: Tue, 3 Sep 2024 15:03:04 +0200 Subject: [PATCH] Improve AssemblyNameInfo Fuzzer (#107257) --- .../Dictionaries/assemblynameinfo.dict | 16 ++++++ .../Fuzzers/AssemblyNameInfoFuzzer.cs | 56 +++++++++++++++---- 2 files changed, 62 insertions(+), 10 deletions(-) create mode 100644 src/libraries/Fuzzing/DotnetFuzzing/Dictionaries/assemblynameinfo.dict diff --git a/src/libraries/Fuzzing/DotnetFuzzing/Dictionaries/assemblynameinfo.dict b/src/libraries/Fuzzing/DotnetFuzzing/Dictionaries/assemblynameinfo.dict new file mode 100644 index 0000000000000..f15a4c6c72173 --- /dev/null +++ b/src/libraries/Fuzzing/DotnetFuzzing/Dictionaries/assemblynameinfo.dict @@ -0,0 +1,16 @@ +"MyAssemblyName, Version=1.0.0.0, PublicKeyToken=b77a5c561934e089" +"System.IO.Pipelines.Tests, PublicKey=00240000048000009400000006020000002400005253413100040000010001004b86c4cb78549b34bab61a3b1800e23bfeb5b3ec390074041536a7e3cbd97f5f04cf0f857155a8928eaa29ebfd11cfbbad3ba70efea7bda3226c6a8d370a4cd303f714486b6ebc225985a638471e6ef571cc92a4613c00b8fa65d61ccee0cbe5f36330c9a01f4183559f1bef24cc2917c6d913e3a541333a1d05d9bed22b38cb" +"System.IO.Pipelines.Tests, PublicKey=null" +"Abc, ProcessorArchitecture=X86" +"Abc, ProcessorArchitecture=Amd64" +"Abc, ProcessorArchitecture=Arm" +"Abc, ProcessorArchitecture=MSIL" +"Abc, ContentType=WindowsRuntime" +"Abc, Retargetable=Yes" +"Esc\\[aped" +"MyAssemblyName, Version=1.0.0.0, PublicKeyToken=b77a5c561934e089", "MyAssemblyName, Version=1.0.0.0, PublicKeyToken=b77a5c561934e089" +"MyAssemblyName, Version=1.0.0.0, PublicKey=00000000000000000400000000000000", "MyAssemblyName, Version=1.0.0.0, PublicKeyToken=b77a5c561934e089" +"TerraFX.Interop.Windows, PublicKey=002400000c800000940000000602000000240000525341310004000001000100897039f5ff762b25b9ba982c3f5836c34e299279c33df505bf806a07bccdf0e1216e661943f557b954cb18422ed522a5b3174b85385052677f39c4ce19f30a1ddbaa507054bc5943461651f396afc612cd80419c5ee2b5277571ff65f51d14ba99e4e4196de0f393e89850a465f019dbdc365ed5e81bbafe1370f54efd254ba8, TerraFX.Interop.Windows, PublicKeyToken=35b01b53313a6f7e" +"aaaa, language=en-en" +"aaaa, foo=bar, foo=baz" +"aa/name " \ No newline at end of file diff --git a/src/libraries/Fuzzing/DotnetFuzzing/Fuzzers/AssemblyNameInfoFuzzer.cs b/src/libraries/Fuzzing/DotnetFuzzing/Fuzzers/AssemblyNameInfoFuzzer.cs index e4ce320c40f67..9ce1bd255c7b6 100644 --- a/src/libraries/Fuzzing/DotnetFuzzing/Fuzzers/AssemblyNameInfoFuzzer.cs +++ b/src/libraries/Fuzzing/DotnetFuzzing/Fuzzers/AssemblyNameInfoFuzzer.cs @@ -4,6 +4,7 @@ using System.Buffers; using System.Reflection.Metadata; using System.Runtime.InteropServices; +using System.Text; namespace DotnetFuzzing.Fuzzers { @@ -13,9 +14,12 @@ internal sealed class AssemblyNameInfoFuzzer : IFuzzer public string[] TargetCoreLibPrefixes => []; + public string Dictionary => "assemblynameinfo.dict"; + public void FuzzTarget(ReadOnlySpan bytes) { - ReadOnlySpan chars = MemoryMarshal.Cast(bytes); + Span chars = new char[Encoding.UTF8.GetCharCount(bytes)]; + Encoding.UTF8.GetChars(bytes, chars); using PooledBoundedMemory inputPoisonedBefore = PooledBoundedMemory.Rent(chars, PoisonPagePlacement.Before); using PooledBoundedMemory inputPoisonedAfter = PooledBoundedMemory.Rent(chars, PoisonPagePlacement.After); @@ -26,19 +30,51 @@ public void FuzzTarget(ReadOnlySpan bytes) private static void Test(PooledBoundedMemory inputPoisoned) { - bool shouldSucceed = AssemblyNameInfo.TryParse(inputPoisoned.Span, out _); - - try + if (AssemblyNameInfo.TryParse(inputPoisoned.Span, out AssemblyNameInfo? fromTryParse)) { - AssemblyNameInfo.Parse(inputPoisoned.Span); + AssemblyNameInfo fromParse = AssemblyNameInfo.Parse(inputPoisoned.Span); + + Assert.Equal(fromTryParse.Name, fromParse.Name); + Assert.Equal(fromTryParse.FullName, fromParse.FullName); + Assert.Equal(fromTryParse.CultureName, fromParse.CultureName); + Assert.Equal(fromTryParse.Flags, fromParse.Flags); + Assert.Equal(fromTryParse.Version, fromParse.Version); + Assert.SequenceEqual(fromTryParse.PublicKeyOrToken.AsSpan(), fromParse.PublicKeyOrToken.AsSpan()); + + Assert.Equal(fromTryParse.ToAssemblyName().Name, fromParse.ToAssemblyName().Name); + Assert.Equal(fromTryParse.ToAssemblyName().Version, fromParse.ToAssemblyName().Version); + Assert.Equal(fromTryParse.ToAssemblyName().ContentType, fromParse.ToAssemblyName().ContentType); + Assert.Equal(fromTryParse.ToAssemblyName().CultureName, fromParse.ToAssemblyName().CultureName); + + Assert.Equal(fromTryParse.Name, fromParse.ToAssemblyName().Name); + Assert.Equal(fromTryParse.CultureName, fromParse.ToAssemblyName().CultureName); + Assert.Equal(fromTryParse.Version, fromParse.ToAssemblyName().Version); + + // AssemblyNameInfo.FullName can be different than AssemblyName.FullName: + // AssemblyNameInfo includes public key, AssemblyName only its Token. + + try + { + Assert.Equal(fromTryParse.ToAssemblyName().FullName, fromParse.ToAssemblyName().FullName); + } + catch (System.Security.SecurityException) + { + // AssemblyName.FullName performs public key validation, AssemblyNameInfo does not (on purpose). + } } - catch (ArgumentException) + else { - Assert.Equal(false, shouldSucceed); - return; - } + try + { + _ = AssemblyNameInfo.Parse(inputPoisoned.Span); + } + catch (ArgumentException) + { + return; + } - Assert.Equal(true, shouldSucceed); + throw new Exception("Parsing was supposed to fail!"); + } } } }