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.

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

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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

7 participants