java-topology/whitepaper/outreach/libjpeg-turbo-0001.md
russell@unturf.com 652608142a feat: close outreach doc gap — 276 docs (batches 11-16)
All projects with patches now have outreach docs. 276 new docs covering
CWE-407, CWE-312, CWE-362 across C, C++, Java, Python, Go, Rust, C#,
PHP, Ruby, JavaScript, Dart, Erlang, R, and more.

Outreach gap: 276 -> 0.
2026-04-15 13:57:42 -04:00

2.8 KiB
Raw Blame History

libjpeg-turbo — CWE-407 Disclosure Brief (libjpeg-turbo-0001)

2026-04-13 · Patch available — awaiting upstream merge

Finding

One O(PC) defect in libjpeg-turbo's PPM colormap reader. The add_map_entry() function in rdcolmap.c uses a linear scan to check for duplicate palette colors, producing O(PC) total cost where P = pixels read and C = palette size (up to 256).

The Defect

libjpeg-turbo-0001 (PATCHED — MEDIUM): src/rdcolmap.c:20

LOCAL(void)
add_map_entry(j_decompress_ptr cinfo, int R, int G, int B)
{
    int ncolors = cinfo->actual_number_of_colors;
    int index;
    // O(C) linear scan for each pixel
    for (index = 0; index < ncolors; index++) {
        if (colormap0[index] == R && colormap1[index] == G &&
            colormap2[index] == B)
            return;  // already in map
    }
}

Called once per pixel in read_ppm_map(). For a PPM color map image with P pixels (up to 65500x65500) and C unique colors (up to 256), total comparisons reach O(P*C). For large PPM files that exhaust the palette early, every subsequent pixel pays the full O(256) scan.

Complexity Proof

At P=100,000 pixels, C=256 colors (palette exhausted early):

  • Defective: 100,000 × 256 = 25,600,000 comparisons
  • Fixed: 100,000 × O(1) hash lookups = 100,000 operations
  • ~256× op reduction.

Impact

libjpeg-turbo is the most widely deployed JPEG codec, used in web browsers (Firefox, Chrome), image editors, and virtually every system that handles JPEG images. The PPM colormap reader processes quantized color palette images. Large PPM files with many pixels trigger the quadratic path.

The Fix

Add a 512-slot open-addressing hash set for O(1) color membership testing:

// Hash table for O(1) color membership
#define CMAP_HASH_SIZE 512
static CmapSlot cmap_seen[CMAP_HASH_SIZE];

LOCAL(int) cmap_hash_seen(int R, int G, int B) {
    unsigned int key = (1u << 24) | (R << 16) | (G << 8) | B;
    // Fibonacci hashing + linear probe
    int slot = ((key & 0xFFFFFFu) * 2654435761u) >> (32 - 9);
    // ... O(1) average lookup
}

Patch

Fix available: defects/libjpeg-turbo-0001/patch/libjpeg-turbo-0001-rdcolmap-ppm-color-dedup.patch

Single-file patch in src/rdcolmap.c. Adds static hash set, resets in _read_color_map(). ~256× speedup at 256 palette colors.

What We Ask

A patch is ready for review.

  1. Confirm receipt and assign a GitHub issue reference (libjpeg-turbo/libjpeg-turbo).
  2. Assess severity — fires per pixel during PPM colormap processing.
  3. Coordinate a disclosure date — we are targeting 90 days from first contact.
  4. We will credit the libjpeg-turbo team in the public disclosure. Preferred acknowledgment format welcome.

Contact: see cover email. This brief is confidential until coordinated disclosure.