Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update fuzzing infra to build and use the shared framework #108555

Merged
merged 4 commits into from
Oct 5, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ namespace System.Buffers
{
public static unsafe partial class BoundedMemory
{
private static DefaultImplementation<T> AllocateWithoutDataPopulationDefault<T>(int elementCount, PoisonPagePlacement placement) where T : unmanaged
private static DefaultImplementation<T> AllocateWithoutDataPopulationDefault<T>(int elementCount, PoisonPagePlacement _) where T : unmanaged
{
// On non-Windows platforms, we don't yet have support for changing the permissions of individual pages.
// We'll instead use AllocHGlobal / FreeHGlobal to carve out a r+w section of unmanaged memory.
Expand Down Expand Up @@ -143,4 +143,4 @@ protected override bool ReleaseHandle()
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,15 @@ private static WindowsImplementation<T> AllocateWithoutDataPopulationWindows<T>(
}

// Reserve and commit the entire range as NOACCESS.

VirtualAllocHandle handle = VirtualAllocHandle.Allocate(
lpAddress: IntPtr.Zero,
dwSize: (IntPtr)totalBytesToAllocate /* cast throws OverflowException if out of range */,
flAllocationType: VirtualAllocAllocationType.MEM_RESERVE | VirtualAllocAllocationType.MEM_COMMIT,
flProtect: VirtualAllocProtection.PAGE_NOACCESS);
VirtualAllocHandle handle;
checked
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Was this checked added due to a bug? It seems like it would only throw on 32-bit platforms.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not due to a bug, after changing the project build with current runtime settings many analyzer diagnostics found that are fixed or suppressed with the PR.

CA2020 Starting with .NET 7 the explicit conversion '(IntPtr)Int64' will not throw when overflowing in an unchecked context. Wrap the expression with a 'checked' statement to restore the .NET 6 behavior.

Flagged at row 38: dwSize: (IntPtr)totalBytesToAllocate /* cast throws OverflowException if out of range */,

Given that this type is for testing, and also base on the comment I assumed it is important to restore the overflowing behavior

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suppressed have all other warnings for this BoundedMemory type, now after moving <IsTestSupportProject>true</IsTestSupportProject> property above importing parent Directory.Build.props this type is not being analyzed anymore, same as all other test types. I can revert this and other suppressions with my other PR

{
handle = VirtualAllocHandle.Allocate(
lpAddress: IntPtr.Zero,
dwSize: (IntPtr)totalBytesToAllocate /* cast throws OverflowException if out of range */,
flAllocationType: VirtualAllocAllocationType.MEM_RESERVE | VirtualAllocAllocationType.MEM_COMMIT,
flProtect: VirtualAllocProtection.PAGE_NOACCESS);
}

if (handle == null || handle.IsInvalid)
{
Expand Down
9 changes: 4 additions & 5 deletions src/libraries/Fuzzing/Directory.Build.props
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
<Project>
<PropertyGroup>
<NetCoreAppCurrentVersion>10.0</NetCoreAppCurrentVersion>
<NetCoreAppCurrent>net$(NetCoreAppCurrentVersion)</NetCoreAppCurrent>
<ProductVersion>$(NetCoreAppCurrentVersion).0</ProductVersion>
<TestUtilities>..\..\Common\tests\TestUtilities</TestUtilities>
<IsTestSupportProject>true</IsTestSupportProject>
<TestUtilities>..\..\Common\tests\TestUtilities</TestUtilities>
</PropertyGroup>
</Project>
<Import Project="..\Directory.Build.props" />
</Project>
2 changes: 0 additions & 2 deletions src/libraries/Fuzzing/Directory.Build.targets

This file was deleted.

12 changes: 8 additions & 4 deletions src/libraries/Fuzzing/DotnetFuzzing.sln
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
.gitignore = .gitignore
..\..\..\eng\pipelines\libraries\fuzzing\deploy-to-onefuzz.yml = ..\..\..\eng\pipelines\libraries\fuzzing\deploy-to-onefuzz.yml
Directory.Build.props = Directory.Build.props
Directory.Build.targets = Directory.Build.targets
nuget.config = nuget.config
README.md = README.md
OneFuzz.md = OneFuzz.md
README.md = README.md
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.Formats.Nrbf", "..\System.Formats.Nrbf\src\System.Formats.Nrbf.csproj", "{034899ED-D501-46A3-A8AB-710C28C5CAB9}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand All @@ -25,11 +25,15 @@ Global
{002673BF-11AE-4072-9CBE-FC312BF68613}.Debug|Any CPU.Build.0 = Debug|Any CPU
{002673BF-11AE-4072-9CBE-FC312BF68613}.Release|Any CPU.ActiveCfg = Release|Any CPU
{002673BF-11AE-4072-9CBE-FC312BF68613}.Release|Any CPU.Build.0 = Release|Any CPU
{034899ED-D501-46A3-A8AB-710C28C5CAB9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{034899ED-D501-46A3-A8AB-710C28C5CAB9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{034899ED-D501-46A3-A8AB-710C28C5CAB9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{034899ED-D501-46A3-A8AB-710C28C5CAB9}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {0BAD3B6E-67D4-418D-A45F-49B3F79168DF}
EndGlobalSection
EndGlobal
EndGlobal
32 changes: 23 additions & 9 deletions src/libraries/Fuzzing/DotnetFuzzing/DotnetFuzzing.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,44 @@

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net9.0-windows</TargetFramework>
<PublishSelfContained>true</PublishSelfContained>
<TargetFramework>$(NetCoreAppCurrent)</TargetFramework>
<SelfContained>true</SelfContained>
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
<UseAppHost>true</UseAppHost>
<AppHostSourcePath>$(ArtifactsDir)\bin\win-x64.Debug\corehost\apphost.exe</AppHostSourcePath>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<EnablePreviewFeatures>True</EnablePreviewFeatures>
<NoWarn>$(NoWarn);CA2252</NoWarn>
<NoWarn>$(NoWarn);CS1591;IL3000;SYSLIB1054;CA1512;SYSLIB5005;</NoWarn>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<EnableTrimAnalyzer>false</EnableTrimAnalyzer>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="SharpFuzz" Version="2.1.1" />
</ItemGroup>

<ItemGroup>
<FrameworkReference Update="Microsoft.NETCore.App" RuntimeFrameworkVersion="$(ProductVersion)-dev" />
</ItemGroup>

<ItemGroup>
<Compile Include="Assert.cs" />
<Compile Include="Fuzzers\AssemblyNameInfoFuzzer.cs" />
<Compile Include="Fuzzers\Base64Fuzzer.cs" />
<Compile Include="Fuzzers\Base64UrlFuzzer.cs" />
<Compile Include="Fuzzers\HttpHeadersFuzzer.cs" />
<Compile Include="Fuzzers\JsonDocumentFuzzer.cs" />
<Compile Include="Fuzzers\NrbfDecoderFuzzer.cs" />
<Compile Include="Fuzzers\SearchValuesByteCharFuzzer.cs" />
<Compile Include="Fuzzers\SearchValuesStringFuzzer.cs" />
<Compile Include="Fuzzers\TextEncodingFuzzer.cs" />
<Compile Include="Fuzzers\TypeNameFuzzer.cs" />
<Compile Include="Fuzzers\UTF8Fuzzer.cs" />
<Compile Include="IFuzzer.cs" />
<Compile Include="PooledBoundedMemory.cs" />
<Compile Include="Program.cs" />
<Compile Include="$(TestUtilities)\System\Buffers\BoundedMemory.*" Link="TestUtilities\%(Filename)%(Extension)" />
<Compile Include="$(TestUtilities)\System\Buffers\PoisonPagePlacement.cs" Link="TestUtilities\PoisonPagePlacement.cs" />
</ItemGroup>

<ItemGroup>
<None Update="Dictionaries\*">
<None Include="Dictionaries\*">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
Expand Down
6 changes: 3 additions & 3 deletions src/libraries/Fuzzing/DotnetFuzzing/Fuzzers/Base64Fuzzer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

namespace DotnetFuzzing.Fuzzers
{
internal class Base64Fuzzer : IFuzzer
internal sealed class Base64Fuzzer : IFuzzer
{
public string[] TargetAssemblies => [];

Expand All @@ -27,8 +27,8 @@ public void FuzzTarget(ReadOnlySpan<byte> bytes)

Assert.Equal(OperationStatus.Done, status);
Assert.Equal(bytes.Length, bytesConsumed);
Assert.Equal(true, maxEncodedLength >= bytesEncoded && maxEncodedLength - 2 <= bytesEncoded);
Assert.Equal(true, maxEncodedLength >= bytesEncoded && maxEncodedLength - 2 <= bytesEncoded);

status = Base64.DecodeFromUtf8(encoderDest.Slice(0, bytesEncoded), decoderDest, out int bytesRead, out int bytesDecoded);

Assert.Equal(OperationStatus.Done, status);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public void FuzzTarget(ReadOnlySpan<byte> bytes)
Span<byte> decoderDest = decoderDestPoisoned.Span;

{ // IsFinalBlock = true
OperationStatus status = Base64Url.EncodeToChars(input, encoderDest, out int bytesConsumed, out int bytesEncoded);
OperationStatus status = Base64Url.EncodeToChars(input, encoderDest, out int bytesConsumed, out int bytesEncoded);

Assert.Equal(OperationStatus.Done, status);
Assert.Equal(bytes.Length, bytesConsumed);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ private static void Test(Span<byte> testSpan, Stream stream)
}
}

private class NonSeekableStream : MemoryStream
private sealed class NonSeekableStream : MemoryStream
{
public NonSeekableStream(byte[] buffer) : base(buffer) { }
public override bool CanSeek => false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ private static void TestWithSubstitution(ReadOnlySpan<byte> input, Encoding enco

using PooledBoundedMemory<char> chars = PooledBoundedMemory<char>.Rent(charCount, PoisonPagePlacement.After);
using PooledBoundedMemory<char> chars2 = PooledBoundedMemory<char>.Rent(charCount, PoisonPagePlacement.After);

// *4 for worst case scenario (*2 for char->byte + *2 for encoding)
// +2 is for possible Base64 padding with UTF7Encoding.
using PooledBoundedMemory<byte> bytes = PooledBoundedMemory<byte>.Rent(charCount * 4 + 2, PoisonPagePlacement.After);
Expand Down Expand Up @@ -153,14 +153,13 @@ private static void TestWithConvert(ReadOnlySpan<byte> input, Encoding encoding)
private static void TestWithConvert(ReadOnlySpan<byte> input, Encoding encoding, int blockSize)
{
Decoder decoder = encoding.GetDecoder();
Encoder encoder = encoding.GetEncoder();

int charCount = decoder.GetCharCount(input, flush: true);

using PooledBoundedMemory<char> chars = PooledBoundedMemory<char>.Rent(charCount, PoisonPagePlacement.After);
using PooledBoundedMemory<char> chars2 = PooledBoundedMemory<char>.Rent(charCount, PoisonPagePlacement.After);

decoder.Reset();
decoder.Reset();
int charsUsedTotal = 0;
int i = 0;

Expand Down
6 changes: 3 additions & 3 deletions src/libraries/Fuzzing/DotnetFuzzing/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ DotnetFuzzing prepare-onefuzz <output directory>

string publishDirectory = Path.GetDirectoryName(typeof(Program).Assembly.Location) ?? Environment.CurrentDirectory;

await PrepareOneFuzzDeploymentAsync(fuzzers, publishDirectory, args[1]);
await PrepareOneFuzzDeploymentAsync(fuzzers, publishDirectory, args[1]).ConfigureAwait(false);
return;
}

Expand Down Expand Up @@ -108,7 +108,7 @@ private static async Task PrepareOneFuzzDeploymentAsync(IFuzzer[] fuzzers, strin
await DownloadArtifactAsync(
Path.Combine(publishDirectory, "libfuzzer-dotnet.exe"),
"https://github.com/Metalnem/libfuzzer-dotnet/releases/download/v2023.06.26.1359/libfuzzer-dotnet-windows.exe",
"cbc1f510caaec01b17b5e89fc780f426710acee7429151634bbf4d0c57583458");
"cbc1f510caaec01b17b5e89fc780f426710acee7429151634bbf4d0c57583458").ConfigureAwait(false);

foreach (IFuzzer fuzzer in fuzzers)
{
Expand Down Expand Up @@ -263,7 +263,7 @@ private static async Task DownloadArtifactAsync(string path, string url, string
Console.WriteLine($"Downloading {Path.GetFileName(path)}");

using var client = new HttpClient();
byte[] bytes = await client.GetByteArrayAsync(url);
byte[] bytes = await client.GetByteArrayAsync(url).ConfigureAwait(false);

if (!Convert.ToHexString(SHA256.HashData(bytes)).Equals(hash, StringComparison.OrdinalIgnoreCase))
{
Expand Down
1 change: 1 addition & 0 deletions src/libraries/Fuzzing/DotnetFuzzing/run.bat
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
%~dp0..\..\..\..\artifacts\bin\DotnetFuzzing\Debug\net10.0\win-x64\DotnetFuzzing.exe prepare-onefuzz deployment
20 changes: 13 additions & 7 deletions src/libraries/Fuzzing/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,28 +18,34 @@ Useful links:

### Prerequisites

Build the runtime with the following arguments:
Build the runtime if haven't already:
buyaa-n marked this conversation as resolved.
Show resolved Hide resolved
```cmd
./build.cmd clr+libs+packs+host -rc Checked -c Debug
./build.cmd clr+libs -rc release
MihaZupan marked this conversation as resolved.
Show resolved Hide resolved
```

and install the SharpFuzz command line tool:
```cmd
dotnet tool install --global SharpFuzz.CommandLine
```

> [!TIP]
> The project uses a checked runtime + debug libraries configuration by default.
> If you want to use a different configuration, make sure to also adjust the artifact paths in `nuget.config`.
> The project uses a release runtime + debug libraries configuration by default.
> If you want to use a different configuration, make sure to also adjust the paths in `run.bat`.
buyaa-n marked this conversation as resolved.
Show resolved Hide resolved

### Fuzzing locally

The `prepare-onefuzz` command will create separate directories for each fuzzing target, instrument the relevant assemblies, and generate a helper script for running them locally.
Note that this command must be ran on the published artifacts (won't work with `dotnet run`).
Build the `DotnetFuzzing` fuzzing project, the project is self contained so it will produce `DotnetFuzzing.exe` and all libraries needed for run into the output.
buyaa-n marked this conversation as resolved.
Show resolved Hide resolved

```cmd
cd src/libraries/Fuzzing/DotnetFuzzing

dotnet publish -o publish; publish/DotnetFuzzing.exe prepare-onefuzz deployment
dotnet build
```

Now can `run run.bat` that will finds the path to the `DotnetFuzzing.exe` and run it with required arguments `\path\DotnetFuzzing.exe prepare-onefuzz deployment`. The `prepare-onefuzz` command will create separate directories for each fuzzing target, instrument the relevant assemblies, and generate a helper script for running them locally.
buyaa-n marked this conversation as resolved.
Show resolved Hide resolved

```cmd
run.bat
```

You can now start fuzzing by running the `local-run.bat` script in the folder of the fuzzer you are interested in.
Expand Down
19 changes: 0 additions & 19 deletions src/libraries/Fuzzing/nuget.config

This file was deleted.

Loading