Skip to content

Valid 1-bit and 4-bit indexed BMPs with clrUsed at 0 crash with IndexDefect #561

@hourianto

Description

@hourianto

src/pixie/fileformats/bmp.nim:77, src/pixie/fileformats/bmp.nim:80, and src/pixie/fileformats/bmp.nim:130 only synthesize a default palette size for 8-bit BMPs. Valid 1-bit and 4-bit indexed BMPs are allowed by the format to leave clrUsed at 0, but this decoder leaves the palette empty and then indexes it during decode. Verified locally with a valid 1-bit BMP repro, which crashed with IndexDefect.

# Run: nim r --path:src pocs/bmp_1bit_default_palette_crash.nim
import pixie

proc addLe16(data: var string, value: int) =
  data.add(char(value and 0xff))
  data.add(char((value shr 8) and 0xff))

proc addLe32(data: var string, value: int) =
  data.add(char(value and 0xff))
  data.add(char((value shr 8) and 0xff))
  data.add(char((value shr 16) and 0xff))
  data.add(char((value shr 24) and 0xff))

let pixelDataOffset = 14 + 40 + 8
let fileSize = pixelDataOffset + 4

var payload = "BM"
payload.addLe32(fileSize)
payload.addLe16(0)
payload.addLe16(0)
payload.addLe32(pixelDataOffset)

payload.addLe32(40) # BITMAPINFOHEADER
payload.addLe32(1)  # width
payload.addLe32(1)  # height
payload.addLe16(1)  # planes
payload.addLe16(1)  # 1-bit indexed BMP
payload.addLe32(0)  # BI_RGB
payload.addLe32(4)  # padded pixel data size
payload.addLe32(0)
payload.addLe32(0)
payload.addLe32(0)  # clrUsed = 0, meaning default palette size should apply
payload.addLe32(0)

# Valid 1-bit palette: black and white.
payload.add("\x00\x00\x00\x00")
payload.add("\xff\xff\xff\x00")

# One white pixel, padded to a 4-byte row.
payload.add("\x80\x00\x00\x00")

echo "parsing valid 1-bit BMP with clrUsed == 0"
discard decodeImage(payload)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions