Fix gzip FEXTRA XLEN overflow

This commit is contained in:
Vadim Syrov
2026-10-06 14:09:08 +03:00
committed by Adam Hathcock
parent bc58792b86
commit b047d6860a
2 changed files with 80 additions and 2 deletions

View File

@@ -755,7 +755,7 @@ internal class ZlibBaseStream : Stream, IStreamStack
n = _stream.Read(header.Slice(0, 2)); // 2-byte length field
totalBytesRead += n;
var extraLength = (short)(header[0] + header[1] * 256);
var extraLength = header[0] + (header[1] * 256);
var extra = new byte[extraLength];
n = _stream.Read(extra, 0, extra.Length);
if (n != extraLength)
@@ -815,7 +815,7 @@ internal class ZlibBaseStream : Stream, IStreamStack
n = await _stream.ReadAsync(header, 0, 2, cancellationToken).ConfigureAwait(false); // 2-byte length field
totalBytesRead += n;
var extraLength = (short)(header[0] + header[1] * 256);
var extraLength = header[0] + (header[1] * 256);
var extra = new byte[extraLength];
n = await _stream
.ReadAsync(extra, 0, extra.Length, cancellationToken)

View File

@@ -0,0 +1,78 @@
using System;
using System.IO;
using System.Threading.Tasks;
using AwesomeAssertions;
using SharpCompress.Test.Mocks;
using Xunit;
using SharpCompressionMode = SharpCompress.Compressors.CompressionMode;
using SystemCompressionMode = System.IO.Compression.CompressionMode;
namespace SharpCompress.Test.GZip;
public class GZipExtraFieldTests
{
private static readonly byte[] EXPECTED_PAYLOAD = [.. "gzip payload"u8];
[Theory]
[InlineData(32767)]
[InlineData(32768)]
[InlineData(65535)]
public void GZipStream_Read_WithLargeExtraField_ShouldReturnPayload(int extraLength)
{
using var input = new MemoryStream(CreateGZipWithExtraField(extraLength));
using var gzip = new SharpCompress.Compressors.Deflate.GZipStream(
input,
SharpCompressionMode.Decompress
);
using var output = new MemoryStream();
gzip.CopyTo(output);
_ = output.ToArray().Should().Equal(EXPECTED_PAYLOAD);
}
[Theory]
[InlineData(32767)]
[InlineData(32768)]
[InlineData(65535)]
public async ValueTask GZipStream_ReadAsync_WithLargeExtraField_ShouldReturnPayload(
int extraLength
)
{
using var rawInput = new MemoryStream(CreateGZipWithExtraField(extraLength));
await using var input = new AsyncOnlyStream(rawInput, disposeStream: false);
await using var gzip = new SharpCompress.Compressors.Deflate.GZipStream(
input,
SharpCompressionMode.Decompress
);
using var output = new MemoryStream();
await gzip.CopyToAsync(output);
_ = output.ToArray().Should().Equal(EXPECTED_PAYLOAD);
}
private static byte[] CreateGZipWithExtraField(int extraLength)
{
using var compressed = new MemoryStream();
using (
var gzip = new System.IO.Compression.GZipStream(
compressed,
SystemCompressionMode.Compress,
leaveOpen: true
)
)
{
gzip.Write(EXPECTED_PAYLOAD, 0, EXPECTED_PAYLOAD.Length);
}
var original = compressed.ToArray();
var result = new byte[original.Length + extraLength + 2];
Buffer.BlockCopy(original, 0, result, 0, 10);
result[3] |= 0x04;
result[10] = (byte)extraLength;
result[11] = (byte)(extraLength >> 8);
Buffer.BlockCopy(original, 10, result, 12 + extraLength, original.Length - 10);
return result;
}
}