Skip to content

Commit

Permalink
Add .NET Libraries fuzzing targets and automation (dotnet#101993)
Browse files Browse the repository at this point in the history
* Initial fuzzing setup

* Initial pipeline

* Install sharpfuzz to the working directory

* Initial instructions

* Add a few helpful links

* Enable OneFuzz deployment task

* Remove BlameAlias default

* Speed up headers fuzzer

* Add BoundedMemory reference

* Use BoundedMemory in SearchValues targets

* Swap property order

* Add a UTF8 fuzzing target

* Reuse instrumented assemblies when unchanged

* Add support for using dictionaries

* Add simple json fuzzing target

* Mention SharpFuzz in THIRD-PARTY-NOTICES.TXT

* Tweak readme

* Don't reuse assembly if prefixes changed

* Temporarily disable dictionary files

* Avoid name conflicts between CI jobs and test submissions

* Add some basic OneFuzz docs

* Add PooledBoundedMemory to fuzzer sample

* Typo

* More docs

* Avoid transcoding overhead in Json fuzzer

* Enable cron schedule

* Tweak docs

* Fix OneFuzz dictionary file paths

* Workaround OneFuzz issue with multiple jobs in deployment

* Clarify what alias to use

* Test JsonDocument instead of JsonSerializer

* Get rid of BlameAlias

* Tweak getters

* Remove a few unused helpers

* Tweak OneFuzz workaround comment

* Remove StringBuilder use

* Avoid misaligned-span UB
  • Loading branch information
MihaZupan authored and Ruihan-Yin committed May 30, 2024
1 parent 6daa215 commit 96b62ab
Show file tree
Hide file tree
Showing 20 changed files with 1,438 additions and 0 deletions.
29 changes: 29 additions & 0 deletions THIRD-PARTY-NOTICES.TXT
Original file line number Diff line number Diff line change
Expand Up @@ -1345,3 +1345,32 @@ Permission is hereby granted, free of charge, to any person obtaining a copy of
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

License for SharpFuzz and related samples
--------------------------------------

https://github.com/Metalnem/sharpfuzz
https://github.com/Metalnem/dotnet-fuzzers
https://github.com/Metalnem/libfuzzer-dotnet

MIT License

Copyright (c) 2018 Nemanja Mijailovic

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
107 changes: 107 additions & 0 deletions eng/pipelines/libraries/fuzzing/deploy-to-onefuzz.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
trigger: none

schedules:
- cron: "0 10 * * *" # 10 AM UTC
displayName: OneFuzz deployment nightly run
branches:
include:
- main

variables:
- template: ../variables.yml
- name: fuzzerProject
value: $(Build.SourcesDirectory)/src/libraries/Fuzzing/DotnetFuzzing
- name: dotnetPath
value: $(Build.SourcesDirectory)/.dotnet/dotnet

extends:
template: /eng/pipelines/common/templates/pipeline-with-resources.yml
parameters:
stages:
- stage: Build
jobs:
- job: windows
displayName: Build & Deploy to OneFuzz
timeoutInMinutes: 120
pool:
name: $(DncEngInternalBuildPool)
demands: ImageOverride -equals windows.vs2022.amd64

steps:
- checkout: self
clean: true
fetchDepth: 1
lfs: false

- powershell: |
cd $(Build.SourcesDirectory)
./build.cmd clr+libs+packs+host -rc Checked -c Debug
displayName: Build runtime (checked + debug)
- powershell: |
cd $(fuzzerProject)
$(dotnetPath) publish -o publish
displayName: Build Fuzzing targets
- powershell: |
cd $(fuzzerProject)
$(dotnetPath) tool install --tool-path . SharpFuzz.CommandLine
displayName: Install SharpFuzz.CommandLine
- powershell: |
cd $(fuzzerProject)
publish/DotnetFuzzing.exe prepare-onefuzz deployment
displayName: Prepare OneFuzz deployment
# OneFuzz can't currently handle a single deployment where multiple jobs share similar assemblies/pdbs.
# As a workaround, we emit a task for every fuzzing target individually.
# https://fuzzfest.visualstudio.com/Onefuzz/_workitems/edit/191504/ is tracking this issue.
# - task: onefuzz-task@0
# inputs:
# onefuzzOSes: 'Windows'
# env:
# onefuzzDropDirectory: $(fuzzerProject)/deployment
# SYSTEM_ACCESSTOKEN: $(System.AccessToken)
# displayName: Send to OneFuzz

# ONEFUZZ_TASK_WORKAROUND_START
- task: onefuzz-task@0
inputs:
onefuzzOSes: 'Windows'
env:
onefuzzDropDirectory: $(fuzzerProject)/deployment/HttpHeadersFuzzer
SYSTEM_ACCESSTOKEN: $(System.AccessToken)
displayName: Send HttpHeadersFuzzer to OneFuzz

- task: onefuzz-task@0
inputs:
onefuzzOSes: 'Windows'
env:
onefuzzDropDirectory: $(fuzzerProject)/deployment/JsonDocumentFuzzer
SYSTEM_ACCESSTOKEN: $(System.AccessToken)
displayName: Send JsonDocumentFuzzer to OneFuzz

- task: onefuzz-task@0
inputs:
onefuzzOSes: 'Windows'
env:
onefuzzDropDirectory: $(fuzzerProject)/deployment/SearchValuesByteCharFuzzer
SYSTEM_ACCESSTOKEN: $(System.AccessToken)
displayName: Send SearchValuesByteCharFuzzer to OneFuzz

- task: onefuzz-task@0
inputs:
onefuzzOSes: 'Windows'
env:
onefuzzDropDirectory: $(fuzzerProject)/deployment/SearchValuesStringFuzzer
SYSTEM_ACCESSTOKEN: $(System.AccessToken)
displayName: Send SearchValuesStringFuzzer to OneFuzz

- task: onefuzz-task@0
inputs:
onefuzzOSes: 'Windows'
env:
onefuzzDropDirectory: $(fuzzerProject)/deployment/UTF8Fuzzer
SYSTEM_ACCESSTOKEN: $(System.AccessToken)
displayName: Send UTF8Fuzzer to OneFuzz
# ONEFUZZ_TASK_WORKAROUND_END
5 changes: 5 additions & 0 deletions src/libraries/Fuzzing/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
TempNugetCache
publish
deployment
inputs
crash-*
8 changes: 8 additions & 0 deletions src/libraries/Fuzzing/Directory.Build.props
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<Project>
<PropertyGroup>
<NetCoreAppCurrentVersion>9.0</NetCoreAppCurrentVersion>
<NetCoreAppCurrent>net$(NetCoreAppCurrentVersion)</NetCoreAppCurrent>
<ProductVersion>$(NetCoreAppCurrentVersion).0</ProductVersion>
<TestUtilities>..\..\Common\tests\TestUtilities</TestUtilities>
</PropertyGroup>
</Project>
2 changes: 2 additions & 0 deletions src/libraries/Fuzzing/Directory.Build.targets
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
<Project>
</Project>
36 changes: 36 additions & 0 deletions src/libraries/Fuzzing/DotnetFuzzing.sln
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.11.34807.36
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DotnetFuzzing", "DotnetFuzzing\DotnetFuzzing.csproj", "{002673BF-11AE-4072-9CBE-FC312BF68613}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{6DDAE3F1-325F-468C-92DB-5947A3AD757E}"
ProjectSection(SolutionItems) = preProject
.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
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{002673BF-11AE-4072-9CBE-FC312BF68613}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{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
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {0BAD3B6E-67D4-418D-A45F-49B3F79168DF}
EndGlobalSection
EndGlobal
37 changes: 37 additions & 0 deletions src/libraries/Fuzzing/DotnetFuzzing/Assert.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

namespace DotnetFuzzing;

internal static class Assert
{
// Feel free to add any other helpers as needed.

public static void Equal<T>(T expected, T actual)
{
if (!EqualityComparer<T>.Default.Equals(expected, actual))
{
Throw(expected, actual);
}

static void Throw(T expected, T actual) =>
throw new Exception($"Expected={expected} Actual={actual}");
}

public static void SequenceEqual<T>(ReadOnlySpan<T> expected, ReadOnlySpan<T> actual)
{
if (!expected.SequenceEqual(actual))
{
Throw(expected, actual);
}

static void Throw(ReadOnlySpan<T> expected, ReadOnlySpan<T> actual)
{
Equal(expected.Length, actual.Length);

int diffIndex = expected.CommonPrefixLength(actual);

throw new Exception($"Expected={expected[diffIndex]} Actual={actual[diffIndex]} at index {diffIndex}");
}
}
}
73 changes: 73 additions & 0 deletions src/libraries/Fuzzing/DotnetFuzzing/Dictionaries/json.dict
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
"0"
"7"
","
":"
"2.1e24"

"true"
"false"
"null"

"\"\""
"\"\":"

"{}"
",{}"
":{}"
"{\"\":0}"
"{{}}"

"[]"
",[]"
":[]"
"[0]"
"[[]]"

"''"
"\\"
"\\b"
"\\f"
"\\n"
"\\r"
"\\t"
"\\u0000"
"\\x00"
"\\0"
"\\uD800\\uDC00"
"\\uDBFF\\uDFFF"

"\"\":0"
"//"
"/**/"


# Things like geojson, json-ld, ...
"$ref"
"type"
"coordinates"
"@context"
"@id"
"@type"

# Strings with truncated special values
"{\"foo\":fa"
"{\"foo\":t"
"{\"foo\":nul"

"{"
"}"
"\"qty\": 1, \"qty\": -1"
"\"qty\": 1, \"qty\\ud800\": -1"
"\"qty\": 1, \"qt\\y\": -1"
"/*"
"*/"
"\""
"1.7976931348623157e+308"
"5e-324"
"9007199254740991"
"-9007199254740991"

"}="

",,"
"{\"\":"
33 changes: 33 additions & 0 deletions src/libraries/Fuzzing/DotnetFuzzing/DotnetFuzzing.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>$(NetCoreAppCurrent)-windows</TargetFramework>
<PublishSelfContained>true</PublishSelfContained>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<EnablePreviewFeatures>True</EnablePreviewFeatures>
<NoWarn>CA2252</NoWarn>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>

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

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

<ItemGroup>
<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\*">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>

</Project>
Loading

0 comments on commit 96b62ab

Please sign in to comment.