Merge pull request #1481 from adamhathcock/adam/lzma2-invalid-props

Report invalid LZMA2 chunk properties as a data error
This commit is contained in:
Adam Hathcock
2026-10-27 15:32:27 +00:00
committed by GitHub
3 changed files with 45 additions and 9 deletions

View File

@@ -146,11 +146,8 @@ public partial class LzmaStream
await _inputStream!
.ReadExactAsync(headerBuffer, 0, 1, cancellationToken)
.ConfigureAwait(false);
Properties[0] = headerBuffer[0];
_inputPosition++;
_decoder ??= new Decoder();
_decoder.SetDecoderProperties(Properties);
SetChunkProperties(headerBuffer[0]);
}
else if (_needProps)
{

View File

@@ -547,6 +547,21 @@ public partial class LzmaStream : Stream, IStreamStack, IAsyncDisposable
return value;
}
private void SetChunkProperties(byte properties)
{
// A properties byte encodes (pb * 5 + lp) * 9 + lc with pb <= 4; a larger value is
// corrupt stream data, not an invalid caller argument.
if (properties >= 9 * 5 * 5)
{
throw new DataErrorException();
}
Properties[0] = properties;
// Properties initialization resets every probability and match-state field.
_decoder ??= new Decoder();
_decoder.SetDecoderProperties(Properties);
}
private void DecodeChunkHeader()
{
var control = ReadChunkHeaderByte();
@@ -585,11 +600,7 @@ public partial class LzmaStream : Stream, IStreamStack, IAsyncDisposable
if (control >= 0xC0)
{
_needProps = false;
Properties[0] = (byte)ReadChunkHeaderByte();
// Properties initialization resets every probability and match-state field.
_decoder ??= new Decoder();
_decoder.SetDecoderProperties(Properties);
SetChunkProperties((byte)ReadChunkHeaderByte());
}
else if (_needProps)
{

View File

@@ -78,6 +78,34 @@ public class LzmaDecoderSafetyTests
});
}
// LZMA2 chunk with dictionary and properties reset whose properties byte encodes pb > 4.
private static readonly byte[] InvalidChunkProperties = { 0xE0, 0, 0, 0, 4, 0xFF, 0, 0, 0, 0 };
[Fact]
public void Lzma2InvalidChunkPropertiesThrowsDataError()
{
using var input = new MemoryStream(InvalidChunkProperties);
using var stream = LzmaStream.Create(new byte[] { 0 }, input, leaveOpen: true);
Assert.Throws<DataErrorException>(() => stream.ReadByte());
}
[Fact]
public async Task AsyncLzma2InvalidChunkPropertiesThrowsDataError()
{
using var input = new MemoryStream(InvalidChunkProperties);
using var stream = await LzmaStream.CreateAsync(
new byte[] { 0 },
input,
-1,
-1,
leaveOpen: true
);
var buffer = new byte[16];
await Assert.ThrowsAsync<DataErrorException>(() =>
stream.ReadAsync(buffer, 0, buffer.Length, CancellationToken.None)
);
}
#if !LEGACY_DOTNET
[Theory]
[InlineData(false)]