-
-
Notifications
You must be signed in to change notification settings - Fork 891
Description
Prerequisites
- I have written a descriptive issue title
- I have verified that I am running the latest version of ImageSharp
- I have verified if the problem exist in both
DEBUGandRELEASEmode - I have searched open and closed issues to ensure it has not already been reported
ImageSharp version
3.1.12
Other ImageSharp packages and versions
N/A — only SixLabors.ImageSharp
Environment (Operating system, version and so on)
Linux (WSL2, Ubuntu 22.04) and Windows 11
.NET Framework version
.NET 10.0
Description
A crafted BMP file with bitsPerPixel = 0 in the DIB header causes an unhandled DivideByZeroException in BmpDecoderCore.ReadRgbPalette. This exception is not part of the ImageSharp exception hierarchy (ImageFormatException / InvalidImageContentException / UnknownImageFormatException), so applications following the documented error handling pattern cannot catch it.
For comparison, other malformed inputs (truncated PNG, random garbage, etc.) correctly throw InvalidImageContentException or UnknownImageFormatException.
The root cause is in BmpDecoderCore.ReadRgbPalette:
int ppb = 8 / bitsPerPixel; // DivideByZeroException when bitsPerPixel == 0The Decode() method routes to ReadRgbPalette when BmpCompression.RGB and BitsPerPixel <= 8 — a value of 0 matches this condition.
A suggested fix would be to validate bitsPerPixel before the switch:
if (bitsPerPixel is not (1 or 2 or 4 or 8 or 16 or 24 or 32))
{
BmpThrowHelper.ThrowInvalidImageContentException($"Invalid bits per pixel: {bitsPerPixel}");
}Found by coverage-guided fuzzing with SharpFuzz + AFL++.
Steps to Reproduce
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.PixelFormats;
// Construct minimal BMP with bitsPerPixel = 0
var 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 var stream = new MemoryStream(bmp);
using var image = Image.Load<Rgba32>(stream); // throws DivideByZeroExceptionStack trace:
System.DivideByZeroException: Attempted to divide by zero.
at SixLabors.ImageSharp.Formats.Bmp.BmpDecoderCore.ReadRgbPalette[TPixel](
BufferedReadStream stream, Buffer2D`1 pixels, Byte[] colors,
Int32 width, Int32 height, Int32 bitsPerPixel,
Int32 bytesPerColorMapEntry, Boolean inverted)
at SixLabors.ImageSharp.Formats.Bmp.BmpDecoderCore.Decode[TPixel](
BufferedReadStream stream, CancellationToken cancellationToken)
at SixLabors.ImageSharp.Formats.ImageDecoderCore.Decode[TPixel](...)
at SixLabors.ImageSharp.Image.Load[TPixel](Stream stream)
Images
N/A — the reproduction is fully inline above (54-byte constructed BMP).