Skip to content

Commit

Permalink
Avoid misaligned-span UB
Browse files Browse the repository at this point in the history
  • Loading branch information
MihaZupan committed May 20, 2024
1 parent fc79990 commit fe24c98
Show file tree
Hide file tree
Showing 4 changed files with 26 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,16 @@ internal sealed class HttpHeadersFuzzer : IFuzzer

public void FuzzTarget(ReadOnlySpan<byte> bytes)
{
if (bytes.IsEmpty)
if (bytes.Length < 2)
{
return;
}

// We use the first byte to select a known header name.
// The rest of the input is used as the UTF-16 header value.
// The second byte is skipped to keep the value chars 2-byte aligned.
string name = s_knownHeaderNames[bytes[0] % s_knownHeaderNames.Length];
string value = MemoryMarshal.Cast<byte, char>(bytes.Slice(1)).ToString();
string value = MemoryMarshal.Cast<byte, char>(bytes.Slice(2)).ToString();

Test(s_requestHeaders, name, value);
Test(s_contentHeaders, name, value);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ public void FuzzTarget(ReadOnlySpan<byte> bytes)
return;
}

// The first byte is used to select various options.
// The rest of the input is used as the UTF-8 JSON payload.
byte optionsByte = bytes[0];
bytes = bytes.Slice(1);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

using System.Buffers;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

namespace DotnetFuzzing.Fuzzers;
Expand All @@ -12,7 +13,7 @@ internal sealed class SearchValuesByteCharFuzzer : IFuzzer
public string[] TargetAssemblies => [];
public string[] TargetCoreLibPrefixes { get; } = ["System.Buffers", "System.SpanHelpers", "System.PackedSpanHelpers"];

public void FuzzTarget(ReadOnlySpan<byte> bytes)
public unsafe void FuzzTarget(ReadOnlySpan<byte> bytes)
{
int newLine = bytes.IndexOf((byte)'\n');
if (newLine < 0)
Expand All @@ -28,10 +29,17 @@ public void FuzzTarget(ReadOnlySpan<byte> bytes)

Test(byteHaystack0.Span, byteHaystack1.Span, values, SearchValues.Create(values));

if ((nuint)Unsafe.AsPointer(ref MemoryMarshal.GetReference(haystack)) % 2 != 0 && !haystack.IsEmpty)
{
// Ensure that the haystack is 2-byte aligned now that we're about to cast it to chars.
haystack = haystack.Slice(1);
}

using var charHaystack0 = PooledBoundedMemory<char>.Rent(MemoryMarshal.Cast<byte, char>(haystack), PoisonPagePlacement.Before);
using var charHaystack1 = PooledBoundedMemory<char>.Rent(MemoryMarshal.Cast<byte, char>(haystack), PoisonPagePlacement.After);

Test(charHaystack0.Span, charHaystack1.Span, MemoryMarshal.Cast<byte, char>(values), SearchValues.Create(MemoryMarshal.Cast<byte, char>(values)));
ReadOnlySpan<char> charValues = MemoryMarshal.Cast<byte, char>(values);
Test(charHaystack0.Span, charHaystack1.Span, charValues, SearchValues.Create(charValues));
}

private static void Test<T>(ReadOnlySpan<T> haystack, ReadOnlySpan<T> haystackCopy, ReadOnlySpan<T> values, SearchValues<T> searchValues)
Expand Down
11 changes: 9 additions & 2 deletions src/libraries/Fuzzing/DotnetFuzzing/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using SharpFuzz;
using System.Buffers;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Security.Cryptography;
using System.Text;
Expand Down Expand Up @@ -66,7 +67,7 @@ DotnetFuzzing prepare-onefuzz <output directory>
RunFuzzer(fuzzer, inputFiles: args.Length > 1 ? args[1] : null);
}

private static void RunFuzzer(IFuzzer fuzzer, string? inputFiles)
private static unsafe void RunFuzzer(IFuzzer fuzzer, string? inputFiles)
{
if (!string.IsNullOrEmpty(inputFiles))
{
Expand All @@ -82,7 +83,13 @@ private static void RunFuzzer(IFuzzer fuzzer, string? inputFiles)
return;
}

Fuzzer.LibFuzzer.Run(fuzzer.FuzzTarget);
Fuzzer.LibFuzzer.Run(bytes =>
{
// Some fuzzers assume that the input is at least 2-byte aligned.
ArgumentOutOfRangeException.ThrowIfNotEqual((nuint)Unsafe.AsPointer(ref MemoryMarshal.GetReference(bytes)) % 8, 0U);

fuzzer.FuzzTarget(bytes);
});
}

private static async Task PrepareOneFuzzDeploymentAsync(IFuzzer[] fuzzers, string publishDirectory, string outputDirectory)
Expand Down

0 comments on commit fe24c98

Please sign in to comment.