Control: tags -1 - moreinfo [ Reason ] Fix CVE-2026-35444 and various other out-of-bounds accesses when parsing malformed/crafted image files
[ Impact ] If not fixed, games/applications that load untrusted images using SDL2_image could be subject to denial-of-service (crash) or possibly exploitable. [ Tests ] autopkgtest (automated smoke-tests loading images in various formats) passes. Some sample games from trixie that depend on this library (assaultcube, wesnoth) appear to run normally. As with SDL3_image, I haven't attempted to load malformed/crafted/malicious images. A test-build (equivalent except for the changelog) is available from <https://people.debian.org/~smcv/13.7/libsdl2-image/testbuild/>. [ Risks ] Could regress image loading in SDL2 games, especially in weird/rare formats. I suspect that in practice, none of our games/applications rely on being able to load the affected formats (*maybe* GIF and TGA). [ Checklist ] [x] *all* changes are documented in the d/changelog [x] I reviewed all changes and I approve them [x] attach debdiff against the package in (old)stable [x] the issue is verified as fixed in unstable [ Changes ] All changes are robustness fixes from upstream. Most are fixed in 3.4.2 or 3.4.4 upstream. One is not in an upstream release yet, I backported it into forky already. [ Other info ] Related to https://bugs.debian.org/1145180 for libsdl3-image, a newer branch of the same codebase. Compared with the earlier proposal from Aquila Macedo Costa, this one addresses all known out-of-bounds accesses, not just the one that (for whatever reason) had a CVE ID allocated upstream.
diffstat for libsdl2-image-2.8.8+dfsg libsdl2-image-2.8.8+dfsg debian/changelog | 38 ++++ debian/control | 2 debian/gbp.conf | 2 debian/patches/Fix-heap-buffer-overflow-READ-in-XCF-do_layer_surface-CWE.patch | 33 +++ debian/patches/Fix-heap-buffer-overflow-WRITE-in-LBM-palette-CWE-122.patch | 33 +++ debian/patches/Fixed-out-of-bound-read-in-GIF-decoder.patch | 31 +++ debian/patches/Fixed-out-of-bounds-read-in-XCF-image-loader-thanks-Sebas.patch | 90 ++++++++++ debian/patches/IMG_xcf.c-read_string-add-back-the-positive-string-size-c.patch | 25 ++ debian/patches/series | 11 + debian/patches/tga-reject-images-with-zero-width-or-height.patch | 39 ++++ debian/patches/xcf-Added-an-SDL_SetError-when-rejecting-out-of-bounds-ti.patch | 24 ++ debian/patches/xcf-Fix-heap-buffer-overflow-READ-in-XCF-RLE-decoder-CWE-.patch | 60 ++++++ debian/patches/xcf-Permit-empty-strings-in-read_string.patch | 34 +++ debian/patches/xcf-fix-null-pointer-dereference-when-read_xcf_hierarchy-.patch | 39 ++++ debian/patches/xpm-Remove-QUICK_COLORHASH-replace-it-with-inline-code-th.patch | 43 ++++ src/IMG_gif.c | 6 src/IMG_lbm.c | 7 src/IMG_tga.c | 4 src/IMG_xcf.c | 87 +++++++-- src/IMG_xpm.c | 11 - 20 files changed, 587 insertions(+), 32 deletions(-) diff -Nru libsdl2-image-2.8.8+dfsg/debian/changelog libsdl2-image-2.8.8+dfsg/debian/changelog --- libsdl2-image-2.8.8+dfsg/debian/changelog 2025-03-04 09:59:59.000000000 +0000 +++ libsdl2-image-2.8.8+dfsg/debian/changelog 2026-08-23 14:45:36.000000000 +0100 @@ -1,3 +1,41 @@ +libsdl2-image (2.8.8+dfsg-1+deb13u1) trixie; urgency=medium + + [ Aquila Macedo Costa ] + * d/p/Fixed-out-of-bounds-read-in-XCF-image-loader-thanks-Sebas.patch: + Import upstream patch for CVE-2026-35444 (Closes: #1133010) + * d/patches: Add selected upstream malformed-image parser robustness fixes: + - d/p/xpm-Remove-QUICK_COLORHASH-replace-it-with-inline-code-th.patch: + check XPM color hash entries before use + - d/p/Fix-heap-buffer-overflow-WRITE-in-LBM-palette-CWE-122.patch: + fix LBM palette overflow + - d/p/xcf-Fix-heap-buffer-overflow-READ-in-XCF-RLE-decoder-CWE-.patch: + add XCF RLE decoder bounds checks + - d/p/Fix-heap-buffer-overflow-READ-in-XCF-do_layer_surface-CWE.patch, + d/p/xcf-Added-an-SDL_SetError-when-rejecting-out-of-bounds-ti.patch: + add XCF do_layer_surface tile bounds check, report invalid XCF tile data + through SDL_SetError() + - d/p/xcf-fix-null-pointer-dereference-when-read_xcf_hierarchy-.patch: + check XCF hierarchy read failures before dereferencing + - d/p/tga-reject-images-with-zero-width-or-height.patch: + reject TGA images with zero width or height + - d/p/Fixed-out-of-bound-read-in-GIF-decoder.patch: + fix out-of-bounds reads in the GIF decoder + + [ Simon McVittie ] + * d/control, d/gbp.conf: Branch for trixie + * d/patches: Improve patch metadata: add CVE ID, Debian bug number, + upstream commit references, etc. + * d/patches: Re-export patches with their mechanically-generated names and + apply them in the same order that upstream did, to make it more obvious + how this version compares with 2.8.12 + * d/patches: Add additional robustness fixes for parsing malformed images: + - d/p/xcf-Permit-empty-strings-in-read_string.patch: + Avoid an out-of-bounds write if XCF files contain a zero-length string + - d/p/IMG_xcf.c-read_string-add-back-the-positive-string-size-c.patch: + Harden XCF parsing against extremely long strings + + -- Simon McVittie <[email protected]> Sun, 23 Aug 2026 14:45:36 +0100 + libsdl2-image (2.8.8+dfsg-1) unstable; urgency=medium * New upstream stable release diff -Nru libsdl2-image-2.8.8+dfsg/debian/control libsdl2-image-2.8.8+dfsg/debian/control --- libsdl2-image-2.8.8+dfsg/debian/control 2025-03-04 09:59:59.000000000 +0000 +++ libsdl2-image-2.8.8+dfsg/debian/control 2026-08-23 14:45:36.000000000 +0100 @@ -15,7 +15,7 @@ Standards-Version: 4.7.2 Homepage: https://github.com/libsdl-org/SDL_image Vcs-Browser: https://salsa.debian.org/sdl-team/libsdl2-image -Vcs-Git: https://salsa.debian.org/sdl-team/libsdl2-image.git +Vcs-Git: https://salsa.debian.org/sdl-team/libsdl2-image.git -b debian/trixie Package: libsdl2-image-2.0-0 Architecture: any diff -Nru libsdl2-image-2.8.8+dfsg/debian/gbp.conf libsdl2-image-2.8.8+dfsg/debian/gbp.conf --- libsdl2-image-2.8.8+dfsg/debian/gbp.conf 2025-03-04 09:59:59.000000000 +0000 +++ libsdl2-image-2.8.8+dfsg/debian/gbp.conf 2026-08-23 14:45:36.000000000 +0100 @@ -1,6 +1,6 @@ [DEFAULT] pristine-tar = True -debian-branch = debian/latest +debian-branch = debian/trixie upstream-branch = upstream/latest [tag] diff -Nru libsdl2-image-2.8.8+dfsg/debian/patches/Fixed-out-of-bound-read-in-GIF-decoder.patch libsdl2-image-2.8.8+dfsg/debian/patches/Fixed-out-of-bound-read-in-GIF-decoder.patch --- libsdl2-image-2.8.8+dfsg/debian/patches/Fixed-out-of-bound-read-in-GIF-decoder.patch 1970-01-01 01:00:00.000000000 +0100 +++ libsdl2-image-2.8.8+dfsg/debian/patches/Fixed-out-of-bound-read-in-GIF-decoder.patch 2026-08-23 14:45:36.000000000 +0100 @@ -0,0 +1,31 @@ +From: Sam Lantinga <[email protected]> +Date: Wed, 29 Apr 2026 08:18:09 -0700 +Subject: Fixed out of bound read in GIF decoder + +Fixes https://github.com/libsdl-org/SDL_image/issues/724 + +(cherry picked from commit e2b258927d11438cbf4ee55a5c4ff059a6e32d08) +(cherry picked from commit 2c02f371f55a2f74a291639d95761066ac2afff0) +Bug: https://github.com/libsdl-org/SDL_image/issues/724 +Origin: upstream, 2.8.12, commit:38fdd07d43a01b604fffb7453bff3ae2e9fd339a +--- + src/IMG_gif.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/src/IMG_gif.c b/src/IMG_gif.c +index 58667e9..240bb7d 100644 +--- a/src/IMG_gif.c ++++ b/src/IMG_gif.c +@@ -469,8 +469,10 @@ GetCode(SDL_RWops *src, int code_size, int flag, State_t * state) + RWSetMsg("ran off the end of my bits"); + return -1; + } +- state->buf[0] = state->buf[state->last_byte - 2]; +- state->buf[1] = state->buf[state->last_byte - 1]; ++ if (state->last_byte > 2) { ++ state->buf[0] = state->buf[state->last_byte - 2]; ++ state->buf[1] = state->buf[state->last_byte - 1]; ++ } + + if ((ret = GetDataBlock(src, &state->buf[2], state)) > 0) + count = (unsigned char) ret; diff -Nru libsdl2-image-2.8.8+dfsg/debian/patches/Fixed-out-of-bounds-read-in-XCF-image-loader-thanks-Sebas.patch libsdl2-image-2.8.8+dfsg/debian/patches/Fixed-out-of-bounds-read-in-XCF-image-loader-thanks-Sebas.patch --- libsdl2-image-2.8.8+dfsg/debian/patches/Fixed-out-of-bounds-read-in-XCF-image-loader-thanks-Sebas.patch 1970-01-01 01:00:00.000000000 +0100 +++ libsdl2-image-2.8.8+dfsg/debian/patches/Fixed-out-of-bounds-read-in-XCF-image-loader-thanks-Sebas.patch 2026-08-23 14:45:36.000000000 +0100 @@ -0,0 +1,90 @@ +From: Sam Lantinga <[email protected]> +Date: Thu, 2 Apr 2026 08:41:46 -0700 +Subject: Fixed out of bounds read in XCF image loader (thanks @Sebasteuo!) + +(cherry picked from commit f55d589ba5de11c724afcdcae80b56bf26d91d15) +(cherry picked from commit a1a06276a51ca7e6e63908b200df8a278d8c5039) +Origin: upstream, 2.8.10, commit:fa9ffb8cced56aba2a2ab27d7c4388278e6b70c0 +Bug: https://github.com/libsdl-org/SDL_image/security/advisories/GHSA-gq8w-x74c-h6p7 +Bug-CVE: https://security-tracker.debian.org/tracker/CVE-2026-35444 +Bug-Debian: https://bugs.debian.org/1133010 +--- + src/IMG_xcf.c | 50 ++++++++++++++++++++++++++++++-------------------- + 1 file changed, 30 insertions(+), 20 deletions(-) + +diff --git a/src/IMG_xcf.c b/src/IMG_xcf.c +index 95c1526..a1683ec 100644 +--- a/src/IMG_xcf.c ++++ b/src/IMG_xcf.c +@@ -716,20 +716,26 @@ do_layer_surface(SDL_Surface * surface, SDL_RWops * src, xcf_header * head, xcf_ + switch (head->image_type) { + case IMAGE_INDEXED: + for (x = tx; x < tx + ox; x++) { +- *row = ((Uint32)(head->cm_map[*p8 * 3]) << 16); +- *row |= ((Uint32)(head->cm_map[*p8 * 3 + 1]) << 8); +- *row |= ((Uint32)(head->cm_map[*p8++ * 3 + 2]) << 0); +- *row |= ((Uint32)*p8++ << 24); +- row++; ++ Uint8 c = *p8++; ++ Uint8 a = *p8++; ++ if (c < head->cm_num) { ++ *row++ = ((Uint32)(head->cm_map[c * 3]) << 16) | ++ ((Uint32)(head->cm_map[c * 3 + 1]) << 8) | ++ ((Uint32)(head->cm_map[c * 3 + 2]) << 0) | ++ ((Uint32)a << 24); ++ } else { ++ *row++ = 0; ++ } + } + break; + case IMAGE_GREYSCALE: + for (x = tx; x < tx + ox; x++) { +- *row = ((Uint32)*p8 << 16); +- *row |= ((Uint32)*p8 << 8); +- *row |= ((Uint32)*p8++ << 0); +- *row |= ((Uint32)*p8++ << 24); +- row++; ++ Uint8 c = *p8++; ++ Uint8 a = *p8++; ++ *row++ = ((Uint32)c << 16) | ++ ((Uint32)c << 8) | ++ ((Uint32)c << 0) | ++ ((Uint32)a << 24); + } + break; + default: +@@ -747,20 +753,24 @@ do_layer_surface(SDL_Surface * surface, SDL_RWops * src, xcf_header * head, xcf_ + switch (head->image_type) { + case IMAGE_INDEXED: + for (x = tx; x < tx + ox; x++) { +- *row++ = 0xFF000000 +- | ((Uint32)(head->cm_map[*p8 * 3]) << 16) +- | ((Uint32)(head->cm_map[*p8 * 3 + 1]) << 8) +- | ((Uint32)(head->cm_map[*p8 * 3 + 2]) << 0); +- p8++; ++ Uint8 c = *p8++; ++ if (c < head->cm_num) { ++ *row++ = 0xFF000000 | ++ ((Uint32)(head->cm_map[c * 3]) << 16) | ++ ((Uint32)(head->cm_map[c * 3 + 1]) << 8) | ++ ((Uint32)(head->cm_map[c * 3 + 2]) << 0); ++ } else { ++ *row++ = 0; ++ } + } + break; + case IMAGE_GREYSCALE: + for (x = tx; x < tx + ox; x++) { +- *row++ = 0xFF000000 +- | (((Uint32)(*p8)) << 16) +- | (((Uint32)(*p8)) << 8) +- | (((Uint32)(*p8)) << 0); +- ++p8; ++ Uint8 c = *p8++; ++ *row++ = 0xFF000000 | ++ (((Uint32)c) << 16) | ++ (((Uint32)c) << 8) | ++ (((Uint32)c) << 0); + } + break; + default: diff -Nru libsdl2-image-2.8.8+dfsg/debian/patches/Fix-heap-buffer-overflow-READ-in-XCF-do_layer_surface-CWE.patch libsdl2-image-2.8.8+dfsg/debian/patches/Fix-heap-buffer-overflow-READ-in-XCF-do_layer_surface-CWE.patch --- libsdl2-image-2.8.8+dfsg/debian/patches/Fix-heap-buffer-overflow-READ-in-XCF-do_layer_surface-CWE.patch 1970-01-01 01:00:00.000000000 +0100 +++ libsdl2-image-2.8.8+dfsg/debian/patches/Fix-heap-buffer-overflow-READ-in-XCF-do_layer_surface-CWE.patch 2026-08-23 14:45:36.000000000 +0100 @@ -0,0 +1,33 @@ +From: Jorge Barredo Ferreira <[email protected]> +Date: Mon, 6 Apr 2026 19:30:53 +0200 +Subject: Fix heap-buffer-overflow READ in XCF do_layer_surface (CWE-122) + +Add bounds check for tile buffer access in do_layer_surface. + +(cherry picked from commit 5b0d414cae99b2e162a1e46ecba4fcd7ac8c5d85) +Origin: https://github.com/libsdl-org/SDL_image/pull/719 +Applied-upstream: 2.8.12, commit:3796a0bc0c45c1a3fed4b43c697e75c5061d4d67 +--- + src/IMG_xcf.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/src/IMG_xcf.c b/src/IMG_xcf.c +index ed7d203..f067746 100644 +--- a/src/IMG_xcf.c ++++ b/src/IMG_xcf.c +@@ -700,6 +700,15 @@ do_layer_surface(SDL_Surface * surface, SDL_RWops * src, xcf_header * head, xcf_ + + p8 = tile; + p = (Uint32 *) p8; ++ ++ /* Bounds check: reject layer if tile data exceeds buffer */ ++ if ((Uint64)ox * oy * hierarchy->bpp > (Uint64)(hierarchy->width * hierarchy->height * hierarchy->bpp)) { ++ free_xcf_tile(tile); ++ free_xcf_level(level); ++ free_xcf_hierarchy(hierarchy); ++ return 1; ++ } ++ + for (y = ty; y < ty + oy; y++) { + if ((y >= (Uint32)surface->h) || ((tx+ox) > (Uint32)surface->w)) { + break; diff -Nru libsdl2-image-2.8.8+dfsg/debian/patches/Fix-heap-buffer-overflow-WRITE-in-LBM-palette-CWE-122.patch libsdl2-image-2.8.8+dfsg/debian/patches/Fix-heap-buffer-overflow-WRITE-in-LBM-palette-CWE-122.patch --- libsdl2-image-2.8.8+dfsg/debian/patches/Fix-heap-buffer-overflow-WRITE-in-LBM-palette-CWE-122.patch 1970-01-01 01:00:00.000000000 +0100 +++ libsdl2-image-2.8.8+dfsg/debian/patches/Fix-heap-buffer-overflow-WRITE-in-LBM-palette-CWE-122.patch 2026-08-23 14:45:36.000000000 +0100 @@ -0,0 +1,33 @@ +From: Jorge Barredo Ferreira <[email protected]> +Date: Mon, 6 Apr 2026 19:29:38 +0200 +Subject: Fix heap-buffer-overflow WRITE in LBM palette (CWE-122) + +When nbplanes > 8 without HAM flag, nbrcolorsfinal exceeds 256, +causing writes past the palette buffer. Reject nbplanes > 8 for +paletted images. + +(cherry picked from commit 2fe0746733c9f280d2c344bce231dd70fdf3bdb8) +Origin: https://github.com/libsdl-org/SDL_image/pull/717 +Applied-upstream: 2.8.12, commit:695a166b94d772e9da4597682858dc27f870a013 +--- + src/IMG_lbm.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/src/IMG_lbm.c b/src/IMG_lbm.c +index 66215e6..bb10f90 100644 +--- a/src/IMG_lbm.c ++++ b/src/IMG_lbm.c +@@ -232,6 +232,13 @@ SDL_Surface *IMG_LoadLBM_RW( SDL_RWops *src ) + + nbplanes = bmhd.planes; + ++ /* Sanity check: nbplanes must not exceed 8 for paletted images. ++ Higher values cause 1<<nbplanes to exceed the 256-entry palette. */ ++ if ( !pbm && nbplanes > 8 && nbplanes != 24 && flagHAM == 0 ) { ++ SDL_SetError("LBM: invalid number of bitplanes (%u)", nbplanes); ++ goto done; ++ } ++ + if ( pbm ) /* File format : 'Packed Bitmap' */ + { + bytesperline *= 8; diff -Nru libsdl2-image-2.8.8+dfsg/debian/patches/IMG_xcf.c-read_string-add-back-the-positive-string-size-c.patch libsdl2-image-2.8.8+dfsg/debian/patches/IMG_xcf.c-read_string-add-back-the-positive-string-size-c.patch --- libsdl2-image-2.8.8+dfsg/debian/patches/IMG_xcf.c-read_string-add-back-the-positive-string-size-c.patch 1970-01-01 01:00:00.000000000 +0100 +++ libsdl2-image-2.8.8+dfsg/debian/patches/IMG_xcf.c-read_string-add-back-the-positive-string-size-c.patch 2026-08-23 14:45:36.000000000 +0100 @@ -0,0 +1,25 @@ +From: Ozkan Sezer <[email protected]> +Date: Wed, 13 May 2026 14:51:47 +0300 +Subject: IMG_xcf.c (read_string): add back the positive string size check + +[Otherwise a claimed size >= 2**31 bytes could lead to underflow. -smcv] + +(cherry picked from commit cdbe3bf771606a3502c1c5994812bfc48d4814a0) +Origin: upstream, 2.8.12, commit:d23a437d9b620cfca437ffa5aa332799435973bd +--- + src/IMG_xcf.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/IMG_xcf.c b/src/IMG_xcf.c +index b513448..4e2e635 100644 +--- a/src/IMG_xcf.c ++++ b/src/IMG_xcf.c +@@ -241,7 +241,7 @@ static char * read_string (SDL_RWops * src) { + return data; + } + +- if ((Sint32)tmp <= remaining) { ++ if ((Sint32)tmp > 0 && (Sint32)tmp <= remaining) { + data = (char *) SDL_malloc (sizeof (char) * tmp); + if (data) { + SDL_RWread(src, data, tmp, 1); diff -Nru libsdl2-image-2.8.8+dfsg/debian/patches/series libsdl2-image-2.8.8+dfsg/debian/patches/series --- libsdl2-image-2.8.8+dfsg/debian/patches/series 1970-01-01 01:00:00.000000000 +0100 +++ libsdl2-image-2.8.8+dfsg/debian/patches/series 2026-08-23 14:45:36.000000000 +0100 @@ -0,0 +1,11 @@ +Fixed-out-of-bounds-read-in-XCF-image-loader-thanks-Sebas.patch +xpm-Remove-QUICK_COLORHASH-replace-it-with-inline-code-th.patch +Fix-heap-buffer-overflow-WRITE-in-LBM-palette-CWE-122.patch +xcf-Permit-empty-strings-in-read_string.patch +Fix-heap-buffer-overflow-READ-in-XCF-do_layer_surface-CWE.patch +xcf-Added-an-SDL_SetError-when-rejecting-out-of-bounds-ti.patch +xcf-Fix-heap-buffer-overflow-READ-in-XCF-RLE-decoder-CWE-.patch +xcf-fix-null-pointer-dereference-when-read_xcf_hierarchy-.patch +tga-reject-images-with-zero-width-or-height.patch +Fixed-out-of-bound-read-in-GIF-decoder.patch +IMG_xcf.c-read_string-add-back-the-positive-string-size-c.patch diff -Nru libsdl2-image-2.8.8+dfsg/debian/patches/tga-reject-images-with-zero-width-or-height.patch libsdl2-image-2.8.8+dfsg/debian/patches/tga-reject-images-with-zero-width-or-height.patch --- libsdl2-image-2.8.8+dfsg/debian/patches/tga-reject-images-with-zero-width-or-height.patch 1970-01-01 01:00:00.000000000 +0100 +++ libsdl2-image-2.8.8+dfsg/debian/patches/tga-reject-images-with-zero-width-or-height.patch 2026-08-23 14:45:36.000000000 +0100 @@ -0,0 +1,39 @@ +From: Jorge Barredo Ferreira <[email protected]> +Date: Thu, 23 Apr 2026 11:20:40 -0700 +Subject: tga: reject images with zero width or height + +When SDL_CreateSurface() is called with w=0 or h=0 it may return a +non-NULL surface but with a NULL pixels pointer (zero-size allocation). +Subsequent code at IMG_LoadTGA_IO accesses img->pixels unconditionally, +resulting in undefined behavior: UBSan reports "applying zero offset to +null pointer" for the expression (Uint8*)img->pixels + (h-1)*img->pitch +when pitch is 0. + +Reject zero-dimension images early before creating the surface. + +CWE-476 (NULL Pointer Dereference) +Found by: NORAI fuzzer (libFuzzer + UBSan) +PoC: poc_sdl007_tga_null_pixels.tga + +(cherry picked from commit 4ba58feebaf87ad80b8ab3971ea8f82132884c54) +(cherry picked from commit 9f1318e7c112493fcd224eafe8809d4001d1bb33) +Origin: upstream, 2.8.12, commit:67c8f531ad09ddc0e6d4c7b1468c863235711ed4 +--- + src/IMG_tga.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/src/IMG_tga.c b/src/IMG_tga.c +index 537f2ee..8d6d52f 100644 +--- a/src/IMG_tga.c ++++ b/src/IMG_tga.c +@@ -178,6 +178,10 @@ SDL_Surface *IMG_LoadTGA_RW(SDL_RWops *src) + + w = LE16(hdr.width); + h = LE16(hdr.height); ++ if (w == 0 || h == 0) { ++ error = "TGA image with zero width or height"; ++ goto error; ++ } + img = SDL_CreateRGBSurfaceWithFormat(0, w, h, 0, format); + if (img == NULL) { + error = "Out of memory"; diff -Nru libsdl2-image-2.8.8+dfsg/debian/patches/xcf-Added-an-SDL_SetError-when-rejecting-out-of-bounds-ti.patch libsdl2-image-2.8.8+dfsg/debian/patches/xcf-Added-an-SDL_SetError-when-rejecting-out-of-bounds-ti.patch --- libsdl2-image-2.8.8+dfsg/debian/patches/xcf-Added-an-SDL_SetError-when-rejecting-out-of-bounds-ti.patch 1970-01-01 01:00:00.000000000 +0100 +++ libsdl2-image-2.8.8+dfsg/debian/patches/xcf-Added-an-SDL_SetError-when-rejecting-out-of-bounds-ti.patch 2026-08-23 14:45:36.000000000 +0100 @@ -0,0 +1,24 @@ +From: "Ryan C. Gordon" <[email protected]> +Date: Mon, 6 Apr 2026 14:58:56 -0400 +Subject: xcf: Added an SDL_SetError when rejecting out-of-bounds tile data. + +(cherry picked from commit 1aedddcbd205c4e1ea0f99fdb2c785acc8e2489b) + +[This fixes incorrect error reporting by #719 -smcv] +Origin: upstream, 2.8.12, commit:cde1749f5223d7b99750fb79e7822fe11797a2a8 +--- + src/IMG_xcf.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/src/IMG_xcf.c b/src/IMG_xcf.c +index f067746..4e9f157 100644 +--- a/src/IMG_xcf.c ++++ b/src/IMG_xcf.c +@@ -703,6 +703,7 @@ do_layer_surface(SDL_Surface * surface, SDL_RWops * src, xcf_header * head, xcf_ + + /* Bounds check: reject layer if tile data exceeds buffer */ + if ((Uint64)ox * oy * hierarchy->bpp > (Uint64)(hierarchy->width * hierarchy->height * hierarchy->bpp)) { ++ SDL_SetError("Gimp image invalid tile"); + free_xcf_tile(tile); + free_xcf_level(level); + free_xcf_hierarchy(hierarchy); diff -Nru libsdl2-image-2.8.8+dfsg/debian/patches/xcf-Fix-heap-buffer-overflow-READ-in-XCF-RLE-decoder-CWE-.patch libsdl2-image-2.8.8+dfsg/debian/patches/xcf-Fix-heap-buffer-overflow-READ-in-XCF-RLE-decoder-CWE-.patch --- libsdl2-image-2.8.8+dfsg/debian/patches/xcf-Fix-heap-buffer-overflow-READ-in-XCF-RLE-decoder-CWE-.patch 1970-01-01 01:00:00.000000000 +0100 +++ libsdl2-image-2.8.8+dfsg/debian/patches/xcf-Fix-heap-buffer-overflow-READ-in-XCF-RLE-decoder-CWE-.patch 2026-08-23 14:45:36.000000000 +0100 @@ -0,0 +1,60 @@ +From: "Ryan C. Gordon" <[email protected]> +Date: Mon, 6 Apr 2026 15:09:55 -0400 +Subject: xcf: Fix heap-buffer-overflow READ in XCF RLE decoder (CWE-122) + +Add destination pointer bounds check in load_xcf_tile_rle. + +This fix backported to SDL2 from 6c804082117c95c24b3d3af886319e8c21fcd8e0. + +(cherry picked from commit 3ce6cb6f968427cd1041f9dc7b0bb6024fd4c782) +Origin: backport, https://github.com/libsdl-org/SDL_image/pull/720 +Applied-upstream: 2.8.12, commit:f4a54104604dacd44bd43a4502c70926ca79902f +--- + src/IMG_xcf.c | 13 ++++++++++++- + 1 file changed, 12 insertions(+), 1 deletion(-) + +diff --git a/src/IMG_xcf.c b/src/IMG_xcf.c +index 4e9f157..f768049 100644 +--- a/src/IMG_xcf.c ++++ b/src/IMG_xcf.c +@@ -537,7 +537,7 @@ static unsigned char * load_xcf_tile_none (SDL_RWops * src, Uint64 len, int bpp, + } + + static unsigned char * load_xcf_tile_rle (SDL_RWops * src, Uint64 len, int bpp, int x, int y) { +- unsigned char * load, * t, * data, * d; ++ unsigned char * load, * t, * data, * data_end, * d; + int i, size, count, j, length; + unsigned char val; + +@@ -552,6 +552,11 @@ static unsigned char * load_xcf_tile_rle (SDL_RWops * src, Uint64 len, int bpp, + SDL_RWread (src, t, 1, (size_t)len); /* reallen */ + + data = (unsigned char *) SDL_calloc (1, x*y*bpp); ++ if (!data) { ++ SDL_free(load); ++ return NULL; ++ } ++ data_end = data + x*y*bpp; + for (i = 0; i < bpp; i++) { + d = data + i; + size = x*y; +@@ -578,6 +583,9 @@ static unsigned char * load_xcf_tile_rle (SDL_RWops * src, Uint64 len, int bpp, + size -= length; + + while (length-- > 0) { ++ if (d >= data_end) { ++ break; ++ } + *d = *t++; + d += bpp; + } +@@ -600,6 +608,9 @@ static unsigned char * load_xcf_tile_rle (SDL_RWops * src, Uint64 len, int bpp, + val = *t++; + + for (j = 0; j < length; j++) { ++ if (d >= data_end) { ++ break; ++ } + *d = val; + d += bpp; + } diff -Nru libsdl2-image-2.8.8+dfsg/debian/patches/xcf-fix-null-pointer-dereference-when-read_xcf_hierarchy-.patch libsdl2-image-2.8.8+dfsg/debian/patches/xcf-fix-null-pointer-dereference-when-read_xcf_hierarchy-.patch --- libsdl2-image-2.8.8+dfsg/debian/patches/xcf-fix-null-pointer-dereference-when-read_xcf_hierarchy-.patch 1970-01-01 01:00:00.000000000 +0100 +++ libsdl2-image-2.8.8+dfsg/debian/patches/xcf-fix-null-pointer-dereference-when-read_xcf_hierarchy-.patch 2026-08-23 14:45:36.000000000 +0100 @@ -0,0 +1,39 @@ +From: Jorge Barredo Ferreira <[email protected]> +Date: Tue, 7 Apr 2026 17:16:58 +0200 +Subject: xcf: fix null pointer dereference when read_xcf_hierarchy() fails + +read_xcf_hierarchy() can return NULL when SDL_calloc() fails or when +SDL_ReadU32BE() fails to read the width/height/bpp fields. The return +value was not checked before dereferencing hierarchy->bpp at line 755 +in do_layer_surface(), leading to a null pointer dereference. + +Add a NULL check immediately after the call to return early with an +error in that case. + +CWE-476 (NULL Pointer Dereference) +Found by: NORAI fuzzer (libFuzzer + ASan/UBSan) +PoC: poc_sdl006_xcf_hierarchy_null.xcf + +(cherry picked from commit 336fb104494815984250c40f8ee6bd1325b7ba1e) +(cherry picked from commit be7fee9064ed15d88e0bc573c018045daacfd01a) +Origin: https://github.com/libsdl-org/SDL_image/pull/722 +Applied-upstream: 2.8.12, commit:aa03c0f5d0a2a8ba42c719de672650a0dda939e2 +--- + src/IMG_xcf.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/src/IMG_xcf.c b/src/IMG_xcf.c +index f768049..b513448 100644 +--- a/src/IMG_xcf.c ++++ b/src/IMG_xcf.c +@@ -666,6 +666,10 @@ do_layer_surface(SDL_Surface * surface, SDL_RWops * src, xcf_header * head, xcf_ + + SDL_RWseek(src, layer->hierarchy_file_offset, RW_SEEK_SET); + hierarchy = read_xcf_hierarchy(src, head); ++ if (!hierarchy) { ++ SDL_SetError("Failed to read XCF image hierarchy"); ++ return 1; ++ } + + if (hierarchy->bpp > 4) { /* unsupported. */ + SDL_Log("Unknown Gimp image bpp (%u)\n", (unsigned int) hierarchy->bpp); diff -Nru libsdl2-image-2.8.8+dfsg/debian/patches/xcf-Permit-empty-strings-in-read_string.patch libsdl2-image-2.8.8+dfsg/debian/patches/xcf-Permit-empty-strings-in-read_string.patch --- libsdl2-image-2.8.8+dfsg/debian/patches/xcf-Permit-empty-strings-in-read_string.patch 1970-01-01 01:00:00.000000000 +0100 +++ libsdl2-image-2.8.8+dfsg/debian/patches/xcf-Permit-empty-strings-in-read_string.patch 2026-08-23 14:45:36.000000000 +0100 @@ -0,0 +1,34 @@ +From: "Ryan C. Gordon" <[email protected]> +Date: Mon, 6 Apr 2026 14:53:45 -0400 +Subject: xcf: Permit empty strings in read_string(). + +Reference Issue #716. + +(cherry picked from commit 1da905ae95748edbf063102574be5f25ff42ae39) +Origin: upstream, 2.8.12, commit:2d2928376e1e044fd9e501d25e6e39e71b8fb85c +Bug: https://github.com/libsdl-org/SDL_image/issues/716 +--- + src/IMG_xcf.c | 10 +++++++++- + 1 file changed, 9 insertions(+), 1 deletion(-) + +diff --git a/src/IMG_xcf.c b/src/IMG_xcf.c +index a1683ec..ed7d203 100644 +--- a/src/IMG_xcf.c ++++ b/src/IMG_xcf.c +@@ -233,7 +233,15 @@ static char * read_string (SDL_RWops * src) { + + tmp = SDL_ReadBE32(src); + remaining = SDL_RWsize(src) - SDL_RWtell(src); +- if (tmp > 0 && (Sint32)tmp <= remaining) { ++ if (tmp == 0) { ++ data = (char *) SDL_malloc(1); ++ if (data) { ++ data[0] = 0; ++ } ++ return data; ++ } ++ ++ if ((Sint32)tmp <= remaining) { + data = (char *) SDL_malloc (sizeof (char) * tmp); + if (data) { + SDL_RWread(src, data, tmp, 1); diff -Nru libsdl2-image-2.8.8+dfsg/debian/patches/xpm-Remove-QUICK_COLORHASH-replace-it-with-inline-code-th.patch libsdl2-image-2.8.8+dfsg/debian/patches/xpm-Remove-QUICK_COLORHASH-replace-it-with-inline-code-th.patch --- libsdl2-image-2.8.8+dfsg/debian/patches/xpm-Remove-QUICK_COLORHASH-replace-it-with-inline-code-th.patch 1970-01-01 01:00:00.000000000 +0100 +++ libsdl2-image-2.8.8+dfsg/debian/patches/xpm-Remove-QUICK_COLORHASH-replace-it-with-inline-code-th.patch 2026-08-23 14:45:36.000000000 +0100 @@ -0,0 +1,43 @@ +From: "Ryan C. Gordon" <[email protected]> +Date: Mon, 6 Apr 2026 14:24:56 -0400 +Subject: xpm: Remove QUICK_COLORHASH, + replace it with inline code that checks for NULL. + +Closes #721. + +(cherry picked from commit bc17bc7c6a2767e342ebb6d3fd37c8e323c8dd70) +Origin: upstream, 2.8.12, commit:5df1ec7d9dda53c02f251971e2169690c50211d8 +Bug: https://github.com/libsdl-org/SDL_image/issues/715 +--- + src/IMG_xpm.c | 11 +++++------ + 1 file changed, 5 insertions(+), 6 deletions(-) + +diff --git a/src/IMG_xpm.c b/src/IMG_xpm.c +index 2b2f119..09441b9 100644 +--- a/src/IMG_xpm.c ++++ b/src/IMG_xpm.c +@@ -157,9 +157,6 @@ static int add_colorhash(struct color_hash *hash, + return 1; + } + +-/* fast lookup that works if cpp == 1 */ +-#define QUICK_COLORHASH(hash, key) ((hash)->table[*(Uint8 *)(key)]->color) +- + static Uint32 get_colorhash(struct color_hash *hash, const char *key, int cpp) + { + struct hash_entry *entry = hash->table[hash_key(key, cpp, hash->size)]; +@@ -1132,9 +1129,11 @@ static SDL_Surface *load_xpm(char **xpm, SDL_RWops *src, SDL_bool force_32bit) + if (indexed) { + /* optimization for some common cases */ + if (cpp == 1) +- for (x = 0; x < w; x++) +- dst[x] = (Uint8)QUICK_COLORHASH(colors, +- line + x); ++ for (x = 0; x < w; x++) { ++ /* fast lookup that works if cpp == 1 */ ++ const struct hash_entry *entry = colors->table[*(Uint8 *)(line + x)]; ++ dst[x] = entry ? (Uint8) entry->color : 0; ++ } + else + for (x = 0; x < w; x++) + dst[x] = (Uint8)get_colorhash(colors, diff -Nru libsdl2-image-2.8.8+dfsg/src/IMG_gif.c libsdl2-image-2.8.8+dfsg/src/IMG_gif.c --- libsdl2-image-2.8.8+dfsg/src/IMG_gif.c 2025-02-07 18:01:45.000000000 +0000 +++ libsdl2-image-2.8.8+dfsg/src/IMG_gif.c 2026-08-23 15:03:00.000000000 +0100 @@ -469,8 +469,10 @@ RWSetMsg("ran off the end of my bits"); return -1; } - state->buf[0] = state->buf[state->last_byte - 2]; - state->buf[1] = state->buf[state->last_byte - 1]; + if (state->last_byte > 2) { + state->buf[0] = state->buf[state->last_byte - 2]; + state->buf[1] = state->buf[state->last_byte - 1]; + } if ((ret = GetDataBlock(src, &state->buf[2], state)) > 0) count = (unsigned char) ret; diff -Nru libsdl2-image-2.8.8+dfsg/src/IMG_lbm.c libsdl2-image-2.8.8+dfsg/src/IMG_lbm.c --- libsdl2-image-2.8.8+dfsg/src/IMG_lbm.c 2025-02-07 18:01:45.000000000 +0000 +++ libsdl2-image-2.8.8+dfsg/src/IMG_lbm.c 2026-08-23 15:03:00.000000000 +0100 @@ -232,6 +232,13 @@ nbplanes = bmhd.planes; + /* Sanity check: nbplanes must not exceed 8 for paletted images. + Higher values cause 1<<nbplanes to exceed the 256-entry palette. */ + if ( !pbm && nbplanes > 8 && nbplanes != 24 && flagHAM == 0 ) { + SDL_SetError("LBM: invalid number of bitplanes (%u)", nbplanes); + goto done; + } + if ( pbm ) /* File format : 'Packed Bitmap' */ { bytesperline *= 8; diff -Nru libsdl2-image-2.8.8+dfsg/src/IMG_tga.c libsdl2-image-2.8.8+dfsg/src/IMG_tga.c --- libsdl2-image-2.8.8+dfsg/src/IMG_tga.c 2025-02-07 18:01:45.000000000 +0000 +++ libsdl2-image-2.8.8+dfsg/src/IMG_tga.c 2026-08-23 15:03:00.000000000 +0100 @@ -178,6 +178,10 @@ w = LE16(hdr.width); h = LE16(hdr.height); + if (w == 0 || h == 0) { + error = "TGA image with zero width or height"; + goto error; + } img = SDL_CreateRGBSurfaceWithFormat(0, w, h, 0, format); if (img == NULL) { error = "Out of memory"; diff -Nru libsdl2-image-2.8.8+dfsg/src/IMG_xcf.c libsdl2-image-2.8.8+dfsg/src/IMG_xcf.c --- libsdl2-image-2.8.8+dfsg/src/IMG_xcf.c 2025-02-07 18:01:45.000000000 +0000 +++ libsdl2-image-2.8.8+dfsg/src/IMG_xcf.c 2026-08-23 15:03:00.000000000 +0100 @@ -233,7 +233,15 @@ tmp = SDL_ReadBE32(src); remaining = SDL_RWsize(src) - SDL_RWtell(src); - if (tmp > 0 && (Sint32)tmp <= remaining) { + if (tmp == 0) { + data = (char *) SDL_malloc(1); + if (data) { + data[0] = 0; + } + return data; + } + + if ((Sint32)tmp > 0 && (Sint32)tmp <= remaining) { data = (char *) SDL_malloc (sizeof (char) * tmp); if (data) { SDL_RWread(src, data, tmp, 1); @@ -529,7 +537,7 @@ } static unsigned char * load_xcf_tile_rle (SDL_RWops * src, Uint64 len, int bpp, int x, int y) { - unsigned char * load, * t, * data, * d; + unsigned char * load, * t, * data, * data_end, * d; int i, size, count, j, length; unsigned char val; @@ -544,6 +552,11 @@ SDL_RWread (src, t, 1, (size_t)len); /* reallen */ data = (unsigned char *) SDL_calloc (1, x*y*bpp); + if (!data) { + SDL_free(load); + return NULL; + } + data_end = data + x*y*bpp; for (i = 0; i < bpp; i++) { d = data + i; size = x*y; @@ -570,6 +583,9 @@ size -= length; while (length-- > 0) { + if (d >= data_end) { + break; + } *d = *t++; d += bpp; } @@ -592,6 +608,9 @@ val = *t++; for (j = 0; j < length; j++) { + if (d >= data_end) { + break; + } *d = val; d += bpp; } @@ -647,6 +666,10 @@ SDL_RWseek(src, layer->hierarchy_file_offset, RW_SEEK_SET); hierarchy = read_xcf_hierarchy(src, head); + if (!hierarchy) { + SDL_SetError("Failed to read XCF image hierarchy"); + return 1; + } if (hierarchy->bpp > 4) { /* unsupported. */ SDL_Log("Unknown Gimp image bpp (%u)\n", (unsigned int) hierarchy->bpp); @@ -692,6 +715,16 @@ p8 = tile; p = (Uint32 *) p8; + + /* Bounds check: reject layer if tile data exceeds buffer */ + if ((Uint64)ox * oy * hierarchy->bpp > (Uint64)(hierarchy->width * hierarchy->height * hierarchy->bpp)) { + SDL_SetError("Gimp image invalid tile"); + free_xcf_tile(tile); + free_xcf_level(level); + free_xcf_hierarchy(hierarchy); + return 1; + } + for (y = ty; y < ty + oy; y++) { if ((y >= (Uint32)surface->h) || ((tx+ox) > (Uint32)surface->w)) { break; @@ -716,20 +749,26 @@ switch (head->image_type) { case IMAGE_INDEXED: for (x = tx; x < tx + ox; x++) { - *row = ((Uint32)(head->cm_map[*p8 * 3]) << 16); - *row |= ((Uint32)(head->cm_map[*p8 * 3 + 1]) << 8); - *row |= ((Uint32)(head->cm_map[*p8++ * 3 + 2]) << 0); - *row |= ((Uint32)*p8++ << 24); - row++; + Uint8 c = *p8++; + Uint8 a = *p8++; + if (c < head->cm_num) { + *row++ = ((Uint32)(head->cm_map[c * 3]) << 16) | + ((Uint32)(head->cm_map[c * 3 + 1]) << 8) | + ((Uint32)(head->cm_map[c * 3 + 2]) << 0) | + ((Uint32)a << 24); + } else { + *row++ = 0; + } } break; case IMAGE_GREYSCALE: for (x = tx; x < tx + ox; x++) { - *row = ((Uint32)*p8 << 16); - *row |= ((Uint32)*p8 << 8); - *row |= ((Uint32)*p8++ << 0); - *row |= ((Uint32)*p8++ << 24); - row++; + Uint8 c = *p8++; + Uint8 a = *p8++; + *row++ = ((Uint32)c << 16) | + ((Uint32)c << 8) | + ((Uint32)c << 0) | + ((Uint32)a << 24); } break; default: @@ -747,20 +786,24 @@ switch (head->image_type) { case IMAGE_INDEXED: for (x = tx; x < tx + ox; x++) { - *row++ = 0xFF000000 - | ((Uint32)(head->cm_map[*p8 * 3]) << 16) - | ((Uint32)(head->cm_map[*p8 * 3 + 1]) << 8) - | ((Uint32)(head->cm_map[*p8 * 3 + 2]) << 0); - p8++; + Uint8 c = *p8++; + if (c < head->cm_num) { + *row++ = 0xFF000000 | + ((Uint32)(head->cm_map[c * 3]) << 16) | + ((Uint32)(head->cm_map[c * 3 + 1]) << 8) | + ((Uint32)(head->cm_map[c * 3 + 2]) << 0); + } else { + *row++ = 0; + } } break; case IMAGE_GREYSCALE: for (x = tx; x < tx + ox; x++) { - *row++ = 0xFF000000 - | (((Uint32)(*p8)) << 16) - | (((Uint32)(*p8)) << 8) - | (((Uint32)(*p8)) << 0); - ++p8; + Uint8 c = *p8++; + *row++ = 0xFF000000 | + (((Uint32)c) << 16) | + (((Uint32)c) << 8) | + (((Uint32)c) << 0); } break; default: diff -Nru libsdl2-image-2.8.8+dfsg/src/IMG_xpm.c libsdl2-image-2.8.8+dfsg/src/IMG_xpm.c --- libsdl2-image-2.8.8+dfsg/src/IMG_xpm.c 2025-02-07 18:01:45.000000000 +0000 +++ libsdl2-image-2.8.8+dfsg/src/IMG_xpm.c 2026-08-23 15:03:00.000000000 +0100 @@ -157,9 +157,6 @@ return 1; } -/* fast lookup that works if cpp == 1 */ -#define QUICK_COLORHASH(hash, key) ((hash)->table[*(Uint8 *)(key)]->color) - static Uint32 get_colorhash(struct color_hash *hash, const char *key, int cpp) { struct hash_entry *entry = hash->table[hash_key(key, cpp, hash->size)]; @@ -1132,9 +1129,11 @@ if (indexed) { /* optimization for some common cases */ if (cpp == 1) - for (x = 0; x < w; x++) - dst[x] = (Uint8)QUICK_COLORHASH(colors, - line + x); + for (x = 0; x < w; x++) { + /* fast lookup that works if cpp == 1 */ + const struct hash_entry *entry = colors->table[*(Uint8 *)(line + x)]; + dst[x] = entry ? (Uint8) entry->color : 0; + } else for (x = 0; x < w; x++) dst[x] = (Uint8)get_colorhash(colors,

