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

Add .NET Libraries fuzzing targets and automation #101993

Merged
merged 37 commits into from
May 22, 2024

Conversation

MihaZupan
Copy link
Member

@MihaZupan MihaZupan commented May 7, 2024

This PR introduces a new DotnetFuzzing project under src/libraries/Fuzzing which contains fuzzing targets and relevant automation for fuzzing locally, and to automatically submit jobs to OneFuzz.

The goal is that it should be easy to author new fuzzing targets without having to deal with the infrastructure aspects.

I included the following targets for now:

  • HttpHeadersFuzzer
  • JsonDocumentFuzzer
  • SearchValuesByteCharFuzzer
  • SearchValuesStringFuzzer
  • UTF8Fuzzer

The new deploy-to-onefuzz.yml internal pipeline will periodically build the runtime and resubmit fuzzing jobs to OneFuzz.

See the new README.md for details about what it looks like to run locally / add new targets.

@MihaZupan MihaZupan added this to the 9.0.0 milestone May 7, 2024
@MihaZupan MihaZupan self-assigned this May 7, 2024
Copy link
Contributor

Tagging subscribers to this area: @dotnet/area-meta
See info in area-owners.md if you want to be subscribed.

eng/pipelines/libraries/fuzzing/deploy-to-onefuzz.yml Outdated Show resolved Hide resolved
env:
onefuzzDropDirectory: $(fuzzerProject)/deployment/UTF8Fuzzer
SYSTEM_ACCESSTOKEN: $(System.AccessToken)
displayName: Send UTF8Fuzzer to OneFuzz
Copy link
Member

Choose a reason for hiding this comment

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

So for right now, until the workaround is no longer needed, to add new tests one adds a new test file and then also updates this file?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes.

When you add a new target and test it locally, the prepare-onefuzz part of
dotnet publish -o publish && publish/DotnetFuzzing.exe prepare-onefuzz deployment
will also update this file for you, so you should only have to:

  • Add 1 file
  • Test changes
  • Commit the 2 changed files

Comment on lines +3 to +4
<NetCoreAppCurrentVersion>9.0</NetCoreAppCurrentVersion>
<NetCoreAppCurrent>net$(NetCoreAppCurrentVersion)</NetCoreAppCurrent>
Copy link
Member

Choose a reason for hiding this comment

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

This can't share the same settings that the rest of the repo uses?

Copy link
Member Author

Choose a reason for hiding this comment

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

I think it should be possible, I just gave up after spending a few hours bashing my head against different configurations that wouldn't compile.
We have similar isolated configurations for HttpStress / SslStress.


namespace DotnetFuzzing;

internal static class Assert
Copy link
Member

Choose a reason for hiding this comment

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

We can't use xunit's asserts directly, and/or AssertExtensions?

Copy link
Member Author

Choose a reason for hiding this comment

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

I think we'd have to figure out #101993 (comment) first.
Given it's just helpers for Equal(T, T) and Equal(Span<T>, Span<T>) at this point, I didn't think it mattered enough.


<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>$(NetCoreAppCurrent)-windows</TargetFramework>
Copy link
Member

Choose a reason for hiding this comment

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

This only works on Windows?

Copy link
Member Author

Choose a reason for hiding this comment

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

As-is, yes.

We could make it work on Linux as well if needed, it's "just work". Namely updating the pipeline, and tweaking how we consume local bits to avoid the limitation in SharpFuzz to instrument mixed-mode assemblies only on Windows.

src/libraries/Fuzzing/DotnetFuzzing/Fuzzers/UTF8Fuzzer.cs Outdated Show resolved Hide resolved
// Adapted from https://github.com/GrabYourPitchforks/utf8fuzz
internal sealed class UTF8Fuzzer : IFuzzer
{
public string BlameAlias => "mizupan";
Copy link
Member

Choose a reason for hiding this comment

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

Feels unsustainable to be assigning these to a specific alias. Can we create some kind of team alias that these are assigned to instead?

Copy link
Member Author

Choose a reason for hiding this comment

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

Sadly can't assign work items to groups / multiple people in AzDo.
I've changed it to always assign me for now, and I'll re-assign as needed (we shouldn't be getting these reports all that often anyway).

string[] TargetCoreLibPrefixes { get; }

/// <summary>Optional name of the dictionary to use to better guide the fuzzer.</summary>
string? Dictionary => null;
Copy link
Member

Choose a reason for hiding this comment

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

Is this overridden anywhere?

Copy link
Member Author

Choose a reason for hiding this comment

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

The JsonDocumentFuzzer sets json.dict


await DownloadArtifactAsync(
Path.Combine(publishDirectory, "libfuzzer-dotnet.exe"),
"https://github.com/Metalnem/libfuzzer-dotnet/releases/download/v2023.06.26.1359/libfuzzer-dotnet-windows.exe",
Copy link
Member

Choose a reason for hiding this comment

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

We're ok downloading such executables from an arbitrary repo?

Copy link
Member Author

Choose a reason for hiding this comment

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

I don't know of a great alternative.

I figured that since the version is pinned (checksum), it's pretty much the same thing as us using the SharpFuzz 2.1.1 NuGet package from the internal mirror / asking anyone working on fuzzers to install dotnet tool install --global SharpFuzz.CommandLine.

@MihaZupan MihaZupan force-pushed the libraries-fuzzing branch from abf031a to 70857b2 Compare May 17, 2024 14:15
internal sealed class PooledBoundedMemory<T> : IDisposable where T : unmanaged
{
// Default libFuzzer max_len for inputs is 4096.
private const int MaxLength = 4096 * 2;
Copy link
Member

@GrabYourPitchforks GrabYourPitchforks May 20, 2024

Choose a reason for hiding this comment

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

Isn't pooling in this fashion potentially going to allocate dozens of GB of memory? Especially in the SearchValues and UTF-8 tests, the elementCount parameter could potentially be any arbitrary integer 0 .. 4096, depending on where the fuzzer places certain delimiter characters we're searching for.

Copy link
Member Author

@MihaZupan MihaZupan May 20, 2024

Choose a reason for hiding this comment

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

Should be around 400 MB I believe (8k sizes, 2 variants of poison placement each, 2-3 memory pages each, one for chars + one for bytes).

Note that we're only pooling 1 buffer for each (type, size, placement) as that's enough for practically all uses by fuzzers.

@MihaZupan
Copy link
Member Author

@MihuBot fuzz HttpHeaders

@MihuBot
Copy link

MihuBot commented May 21, 2024

System.ArgumentException: The value cannot be an empty string or composed entirely of whitespace. (Parameter 'receivedBy')
   at System.ArgumentException.ThrowNullOrWhiteSpaceException(String argument, String paramName)
   at System.ArgumentException.ThrowIfNullOrWhiteSpace(String argument, String paramName)
   at System.Net.Http.Headers.ViaHeaderValue.CheckReceivedBy(String receivedBy)
   at System.Net.Http.Headers.ViaHeaderValue..ctor(String protocolVersion, String receivedBy, String protocolName, String comment)
   at System.Net.Http.Headers.ViaHeaderValue.GetViaLength(String input, Int32 startIndex, Object& parsedValue)
   at System.Net.Http.Headers.GenericHeaderParser.GetParsedValueLength(String value, Int32 startIndex, Object storeValue, Object& parsedValue)
   at System.Net.Http.Headers.BaseHeaderParser.TryParseValue(String value, Object storeValue, Int32& index, Object& parsedValue)
   at System.Net.Http.Headers.HttpHeaders.TryParseAndAddRawHeaderValue(HeaderDescriptor descriptor, HeaderStoreItemInfo info, String value, Boolean addWhenInvalid)
   at System.Net.Http.Headers.HttpHeaders.ParseSingleRawHeaderValue(HeaderStoreItemInfo info, HeaderDescriptor descriptor, String rawValue)
   at System.Net.Http.Headers.HttpHeaders.ParseRawHeaderValues(HeaderDescriptor descriptor, HeaderStoreItemInfo info)
   at System.Net.Http.Headers.HttpHeaders.GetEnumeratorCore()+MoveNext()
   at DotnetFuzzing.Fuzzers.HttpHeadersFuzzer.<FuzzTarget>g__Test|9_0(HttpHeaders headers, String name, String value) in D:\a\runtime-utils\runtime-utils\Runner\runtime\src\libraries\Fuzzing\DotnetFuzzing\Fuzzers\HttpHeadersFuzzer.cs:line 64
   at SharpFuzz.Fuzzer.LibFuzzer.Run(ReadOnlySpanAction action, Boolean ignoreExceptions)
==7560== ERROR: libFuzzer: deadly signal
NOTE: libFuzzer has rudimentary signal handlers.
      Combine libFuzzer with AddressSanitizer or similar for better crash reports.
SUMMARY: libFuzzer: deadly signal
MS: 1 ChangeBit-; base unit: 4a6630db769ab42662c2b49ccea16d1c3754aede
0x52,0x7,0x74,0x0,0x9,0x0,0x0,0x20,
R\007t\000\011\000\000 
artifact_prefix='./'; Test unit written to fuzz-artifact-2
Base64: Ugd0AAkAACA=

HttpHeadersFuzzer-input.bin (8 B)

@MihaZupan MihaZupan merged commit 5c06e5d into dotnet:main May 22, 2024
84 checks passed
steveharter pushed a commit to steveharter/runtime that referenced this pull request May 28, 2024
* 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
Ruihan-Yin pushed a commit to Ruihan-Yin/runtime that referenced this pull request May 30, 2024
* 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
@github-actions github-actions bot locked and limited conversation to collaborators Jun 22, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants