Browse Source

Merge pull request #3069 from SixLabors/js/v4-fix-3067

Throw explicit InvalidImageContentException when BMP BPP is invalid.
pull/3070/head
James Jackson-South 2 months ago
committed by GitHub
parent
commit
ec79a2f2e0
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 22
      src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs
  2. 23
      tests/ImageSharp.Tests/Formats/Bmp/BmpDecoderTests.cs
  3. 11
      tests/ImageSharp.Tests/Formats/Icon/Ico/IcoDecoderTests.cs

22
src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs

@ -131,6 +131,7 @@ internal sealed class BmpDecoderCore : ImageDecoderCore
try
{
int bytesPerColorMapEntry = this.ReadImageHeaders(stream, out bool inverted, out byte[] palette);
ushort bitsPerPixel = this.infoHeader.BitsPerPixel;
image = new Image<TPixel>(this.configuration, this.infoHeader.Width, this.infoHeader.Height, this.metadata);
@ -138,23 +139,27 @@ internal sealed class BmpDecoderCore : ImageDecoderCore
switch (this.infoHeader.Compression)
{
case BmpCompression.RGB when this.infoHeader.BitsPerPixel is 32 && this.bmpMetadata.InfoHeaderType is BmpInfoHeaderType.WinVersion3:
case BmpCompression.RGB when bitsPerPixel is 32 && this.bmpMetadata.InfoHeaderType is BmpInfoHeaderType.WinVersion3:
this.ReadRgb32Slow(stream, pixels, this.infoHeader.Width, this.infoHeader.Height, inverted);
break;
case BmpCompression.RGB when this.infoHeader.BitsPerPixel is 32:
case BmpCompression.RGB when bitsPerPixel is 32:
this.ReadRgb32Fast(stream, pixels, this.infoHeader.Width, this.infoHeader.Height, inverted);
break;
case BmpCompression.RGB when this.infoHeader.BitsPerPixel is 24:
case BmpCompression.RGB when bitsPerPixel is 24:
this.ReadRgb24(stream, pixels, this.infoHeader.Width, this.infoHeader.Height, inverted);
break;
case BmpCompression.RGB when this.infoHeader.BitsPerPixel is 16:
case BmpCompression.RGB when bitsPerPixel is 16:
this.ReadRgb16(stream, pixels, this.infoHeader.Width, this.infoHeader.Height, inverted);
break;
case BmpCompression.RGB when this.infoHeader.BitsPerPixel is <= 8 && this.processedAlphaMask:
case BmpCompression.RGB when bitsPerPixel is > 0 and <= 8 && this.processedAlphaMask:
this.ReadRgbPaletteWithAlphaMask(
stream,
pixels,
@ -166,7 +171,8 @@ internal sealed class BmpDecoderCore : ImageDecoderCore
inverted);
break;
case BmpCompression.RGB when this.infoHeader.BitsPerPixel is <= 8:
case BmpCompression.RGB when bitsPerPixel is > 0 and <= 8:
this.ReadRgbPalette(
stream,
pixels,
@ -179,6 +185,10 @@ internal sealed class BmpDecoderCore : ImageDecoderCore
break;
case BmpCompression.RGB when bitsPerPixel is <= 0 or > 32:
BmpThrowHelper.ThrowInvalidImageContentException($"Invalid bits per pixel: {bitsPerPixel}");
break;
case BmpCompression.RLE24:
this.ReadRle24(stream, pixels, this.infoHeader.Width, this.infoHeader.Height, inverted);

23
tests/ImageSharp.Tests/Formats/Bmp/BmpDecoderTests.cs

@ -571,4 +571,27 @@ public class BmpDecoderTests
});
Assert.IsType<InvalidMemoryOperationException>(ex.InnerException);
}
[Fact]
public void BmpDecoder_ThrowsException_Issue3067()
{
// Construct minimal BMP with bitsPerPixel = 0
byte[] bmp = new byte[54];
bmp[0] = (byte)'B';
bmp[1] = (byte)'M';
BitConverter.GetBytes(54).CopyTo(bmp, 2);
BitConverter.GetBytes(54).CopyTo(bmp, 10);
BitConverter.GetBytes(40).CopyTo(bmp, 14);
BitConverter.GetBytes(1).CopyTo(bmp, 18);
BitConverter.GetBytes(1).CopyTo(bmp, 22);
BitConverter.GetBytes((short)1).CopyTo(bmp, 26);
BitConverter.GetBytes((short)0).CopyTo(bmp, 28); // bitsPerPixel = 0
using MemoryStream stream = new(bmp);
Assert.Throws<InvalidImageContentException>(() =>
{
using Image image = BmpDecoder.Instance.Decode(DecoderOptions.Default, stream);
});
}
}

11
tests/ImageSharp.Tests/Formats/Icon/Ico/IcoDecoderTests.cs

@ -204,12 +204,19 @@ public class IcoDecoderTests
}
[Theory]
[WithFile(InvalidAll, PixelTypes.Rgba32)]
[WithFile(InvalidBpp, PixelTypes.Rgba32)]
public void InvalidThrows_InvalidImageContentException(TestImageProvider<Rgba32> provider)
=> Assert.Throws<InvalidImageContentException>(() =>
{
using Image<Rgba32> image = provider.GetImage(IcoDecoder.Instance);
});
[Theory]
[WithFile(InvalidAll, PixelTypes.Rgba32)]
[WithFile(InvalidCompression, PixelTypes.Rgba32)]
[WithFile(InvalidRLE4, PixelTypes.Rgba32)]
[WithFile(InvalidRLE8, PixelTypes.Rgba32)]
public void InvalidTest(TestImageProvider<Rgba32> provider)
public void InvalidThows_NotSupportedException(TestImageProvider<Rgba32> provider)
=> Assert.Throws<NotSupportedException>(() =>
{
using Image<Rgba32> image = provider.GetImage(IcoDecoder.Instance);

Loading…
Cancel
Save