Skip to content

DivideByZeroException in BmpDecoderCore.ReadRgbPalette with bitsPerPixel=0 #3067

@pawlos

Description

@pawlos

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 DEBUG and RELEASE mode
  • 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 == 0

The 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 DivideByZeroException

Stack 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).

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions