From 9d727af1acdda1cf1506493184d6c99c293c795a Mon Sep 17 00:00:00 2001 From: Adam Sitnik Date: Wed, 11 Sep 2024 02:05:19 +0200 Subject: [PATCH] [NRBF] Fuzzing non-seekable stream input (#107605) --- .../Fuzzers/NrbfDecoderFuzzer.cs | 27 ++++++++++++++----- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/src/libraries/Fuzzing/DotnetFuzzing/Fuzzers/NrbfDecoderFuzzer.cs b/src/libraries/Fuzzing/DotnetFuzzing/Fuzzers/NrbfDecoderFuzzer.cs index 46da18e4b0fc85..5c6397187ff643 100644 --- a/src/libraries/Fuzzing/DotnetFuzzing/Fuzzers/NrbfDecoderFuzzer.cs +++ b/src/libraries/Fuzzing/DotnetFuzzing/Fuzzers/NrbfDecoderFuzzer.cs @@ -18,16 +18,23 @@ internal sealed class NrbfDecoderFuzzer : IFuzzer public void FuzzTarget(ReadOnlySpan bytes) { - using PooledBoundedMemory inputPoisonedAfter = PooledBoundedMemory.Rent(bytes, PoisonPagePlacement.After); - using PooledBoundedMemory inputPoisonedBefore = PooledBoundedMemory.Rent(bytes, PoisonPagePlacement.Before); - using MemoryStream streamAfter = new MemoryStream(inputPoisonedAfter.Memory.ToArray()); - using MemoryStream streamBefore = new MemoryStream(inputPoisonedBefore.Memory.ToArray()); + Test(bytes, PoisonPagePlacement.Before); + Test(bytes, PoisonPagePlacement.After); + } + + private static void Test(ReadOnlySpan bytes, PoisonPagePlacement poisonPagePlacement) + { + using PooledBoundedMemory inputPoisoned = PooledBoundedMemory.Rent(bytes, poisonPagePlacement); + + using MemoryStream seekableStream = new(inputPoisoned.Memory.ToArray()); + Test(inputPoisoned.Span, seekableStream); - Test(inputPoisonedAfter.Span, streamAfter); - Test(inputPoisonedBefore.Span, streamBefore); + // NrbfDecoder has few code paths dedicated to non-seekable streams, let's test them as well. + using NonSeekableStream nonSeekableStream = new(inputPoisoned.Memory.ToArray()); + Test(inputPoisoned.Span, nonSeekableStream); } - private static void Test(Span testSpan, MemoryStream stream) + private static void Test(Span testSpan, Stream stream) { if (NrbfDecoder.StartsWithPayloadHeader(testSpan)) { @@ -109,5 +116,11 @@ private static void Test(Span testSpan, MemoryStream stream) catch (EndOfStreamException) { /* The end of the stream was reached before reading SerializationRecordType.MessageEnd record. */ } } } + + private class NonSeekableStream : MemoryStream + { + public NonSeekableStream(byte[] buffer) : base(buffer) { } + public override bool CanSeek => false; + } } }