Bug#1145180: trixie-pu: package libsdl3-image/3.2.4+ds-1+deb13u1

Simon McVittie <[email protected]>
Newsgroups gmane.linux.debian.devel.release
Message-ID <aor9V6kZe6gRG9Hy__46605.5424347118$1787493939$gmane$org@definition.pseudorandom.co.uk>
On Sun, 23 Aug 2026 at 14:56:33 +0100, Simon McVittie wrote:
>Fix CVE-2026-35444 and various other out-of-bounds accesses when parsing
>malformed/crafted image files
>
>Related to https://bugs.debian.org/1134510 for libsdl2-image, an older
>branch of the same codebase.

debdiff attached, also in 
<https://people.debian.org/~smcv/13.7/libsdl3-image/>.

A functionally-equivalent test build (differing only in the changelog) 
is in <https://people.debian.org/~smcv/13.7/libsdl3-image/testbuild/>.

     smcv
libsdl3-image_3.2.4+ds-1+deb13u1.diff (text/x-diff, 37.6 KB)
diffstat for libsdl3-image-3.2.4+ds libsdl3-image-3.2.4+ds

 debian/changelog                                                               |   34 +++
 debian/control                                                                 |    2 
 debian/gbp.conf                                                                |    2 
 debian/patches/Fix-heap-buffer-overflow-READ-in-XCF-RLE-decoder-CWE-122.patch  |   49 +++++
 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/Fix-heap-underflow-WRITE-in-XCF-read_string-CWE-787.patch       |   32 +++
 debian/patches/Fixed-out-of-bound-read-in-GIF-decoder.patch                    |   29 +++
 debian/patches/Fixed-out-of-bounds-read-in-XCF-image-loader-thanks-Sebas.patch |   88 ++++++++++
 debian/patches/IMG_xcf.c-read_string-add-back-the-positive-string-size-c.patch |   24 ++
 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 |   23 ++
 debian/patches/xcf-fix-null-pointer-dereference-when-read_xcf_hierarchy-.patch |   38 ++++
 debian/patches/xpm-Remove-QUICK_COLORHASH-replace-it-with-inline-code-th.patch |   44 +++++
 src/IMG_gif.c                                                                  |    6 
 src/IMG_lbm.c                                                                  |    7 
 src/IMG_tga.c                                                                  |    4 
 src/IMG_xcf.c                                                                  |   84 +++++++--
 src/IMG_xpm.c                                                                  |   11 -
 20 files changed, 562 insertions(+), 31 deletions(-)

diff -Nru libsdl3-image-3.2.4+ds/debian/changelog libsdl3-image-3.2.4+ds/debian/changelog
--- libsdl3-image-3.2.4+ds/debian/changelog	2025-03-04 10:00:27.000000000 +0000
+++ libsdl3-image-3.2.4+ds/debian/changelog	2026-08-23 14:44:26.000000000 +0100
@@ -1,3 +1,37 @@
+libsdl3-image (3.2.4+ds-1+deb13u1) trixie; urgency=medium
+
+  * d/control, d/gbp.conf: Branch for trixie
+  * d/patches: Add a malformed-image parser robustness fix from 3.4.2:
+    - d/p/Fixed-out-of-bounds-read-in-XCF-image-loader-thanks-Sebas.patch:
+      Avoid an out-of-bounds read when loading invalid XCF images
+      (CVE-2026-35444, same issue as #1133010 in libsdl2-image)
+  * d/patches: Add selected upstream malformed-image parser robustness
+    fixes from 3.4.4:
+    - d/p/xpm-Remove-QUICK_COLORHASH-replace-it-with-inline-code-th.patch:
+      Check XPM colour hash entries before use
+    - d/p/Fix-heap-buffer-overflow-WRITE-in-LBM-palette-CWE-122.patch
+      Avoid an out-of-bounds write when parsing LBM images
+    - d/p/Fix-heap-underflow-WRITE-in-XCF-read_string-CWE-787.patch
+      Avoid an out-of-bounds write if XCF files contain a zero-length string
+    - 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:
+      Avoid an out-of-bounds read when parsing XCF file tile data, and
+      report the resulting error correctly
+    - d/p/Fix-heap-buffer-overflow-READ-in-XCF-RLE-decoder-CWE-122.patch:
+      Avoid an out-of-bounds read when parsing XCF files with RLE encoding
+    - 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 zero-sized TGA images as invalid
+    - d/p/Fixed-out-of-bound-read-in-GIF-decoder.patch:
+      Avoid out-of-bounds reads in the GIF decoder
+  * d/patches: Add an additional parser robustness fix from upstream git:
+    - d/p/IMG_xcf.c-read_string-add-back-the-positive-string-size-c.patch
+      Harden XCF parsing against extremely long strings
+  * Thanks to Aquila Macedo Costa
+
+ -- Simon McVittie <[email protected]>  Sun, 23 Aug 2026 14:44:26 +0100
+
 libsdl3-image (3.2.4+ds-1) unstable; urgency=medium
 
   * New upstream stable release
diff -Nru libsdl3-image-3.2.4+ds/debian/control libsdl3-image-3.2.4+ds/debian/control
--- libsdl3-image-3.2.4+ds/debian/control	2025-03-04 10:00:27.000000000 +0000
+++ libsdl3-image-3.2.4+ds/debian/control	2026-08-23 14:44:26.000000000 +0100
@@ -17,7 +17,7 @@
 Standards-Version: 4.7.2
 Homepage: https://github.com/libsdl-org/SDL_image
 Vcs-Browser: https://salsa.debian.org/sdl-team/libsdl3-image
-Vcs-Git: https://salsa.debian.org/sdl-team/libsdl3-image.git
+Vcs-Git: https://salsa.debian.org/sdl-team/libsdl3-image.git -b debian/trixie
 
 Package: libsdl3-image0
 Architecture: any
diff -Nru libsdl3-image-3.2.4+ds/debian/gbp.conf libsdl3-image-3.2.4+ds/debian/gbp.conf
--- libsdl3-image-3.2.4+ds/debian/gbp.conf	2025-03-04 10:00:27.000000000 +0000
+++ libsdl3-image-3.2.4+ds/debian/gbp.conf	2026-08-23 14:44:26.000000000 +0100
@@ -1,4 +1,4 @@
 [DEFAULT]
 pristine-tar = True
-debian-branch = debian/latest
+debian-branch = debian/trixie
 upstream-branch = upstream/latest
diff -Nru libsdl3-image-3.2.4+ds/debian/patches/Fixed-out-of-bound-read-in-GIF-decoder.patch libsdl3-image-3.2.4+ds/debian/patches/Fixed-out-of-bound-read-in-GIF-decoder.patch
--- libsdl3-image-3.2.4+ds/debian/patches/Fixed-out-of-bound-read-in-GIF-decoder.patch	1970-01-01 01:00:00.000000000 +0100
+++ libsdl3-image-3.2.4+ds/debian/patches/Fixed-out-of-bound-read-in-GIF-decoder.patch	2026-08-23 14:44:26.000000000 +0100
@@ -0,0 +1,29 @@
+From: Sam Lantinga <[email protected]>
+Date: Wed, 29 Apr 2026 08:18:09 -0700
+Subject: Fixed out of bound read in GIF decoder
+
+(cherry picked from commit e2b258927d11438cbf4ee55a5c4ff059a6e32d08)
+
+Bug: https://github.com/libsdl-org/SDL_image/issues/724
+Origin: upstream, 3.4.4, commit:377d1fbb2ec4ea73e0b99fb926b38cee8e1afea1
+---
+ 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 7775ca5..0124f0f 100644
+--- a/src/IMG_gif.c
++++ b/src/IMG_gif.c
+@@ -466,8 +466,10 @@ GetCode(SDL_IOStream *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 libsdl3-image-3.2.4+ds/debian/patches/Fixed-out-of-bounds-read-in-XCF-image-loader-thanks-Sebas.patch libsdl3-image-3.2.4+ds/debian/patches/Fixed-out-of-bounds-read-in-XCF-image-loader-thanks-Sebas.patch
--- libsdl3-image-3.2.4+ds/debian/patches/Fixed-out-of-bounds-read-in-XCF-image-loader-thanks-Sebas.patch	1970-01-01 01:00:00.000000000 +0100
+++ libsdl3-image-3.2.4+ds/debian/patches/Fixed-out-of-bounds-read-in-XCF-image-loader-thanks-Sebas.patch	2026-08-23 14:44:26.000000000 +0100
@@ -0,0 +1,88 @@
+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)
+
+Origin: upstream, 3.4.2, commit:c3f6f82d44e416f5d7e31e2692b9ff452c2b183a
+Bug-CVE: https://security-tracker.debian.org/tracker/CVE-2026-35444
+---
+ 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 dd991cf..df1df2d 100644
+--- a/src/IMG_xcf.c
++++ b/src/IMG_xcf.c
+@@ -808,20 +808,26 @@ do_layer_surface(SDL_Surface *surface, SDL_IOStream *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:
+@@ -839,20 +845,24 @@ do_layer_surface(SDL_Surface *surface, SDL_IOStream *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 libsdl3-image-3.2.4+ds/debian/patches/Fix-heap-buffer-overflow-READ-in-XCF-do_layer_surface-CWE.patch libsdl3-image-3.2.4+ds/debian/patches/Fix-heap-buffer-overflow-READ-in-XCF-do_layer_surface-CWE.patch
--- libsdl3-image-3.2.4+ds/debian/patches/Fix-heap-buffer-overflow-READ-in-XCF-do_layer_surface-CWE.patch	1970-01-01 01:00:00.000000000 +0100
+++ libsdl3-image-3.2.4+ds/debian/patches/Fix-heap-buffer-overflow-READ-in-XCF-do_layer_surface-CWE.patch	2026-08-23 14:44:26.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: upstream, 3.4.4, commit:cc81c460428b5032e190445910eae786a433231e
+---
+ src/IMG_xcf.c | 9 +++++++++
+ 1 file changed, 9 insertions(+)
+
+diff --git a/src/IMG_xcf.c b/src/IMG_xcf.c
+index ef1136a..3fe4c7a 100644
+--- a/src/IMG_xcf.c
++++ b/src/IMG_xcf.c
+@@ -791,6 +791,15 @@ do_layer_surface(SDL_Surface *surface, SDL_IOStream *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 libsdl3-image-3.2.4+ds/debian/patches/Fix-heap-buffer-overflow-READ-in-XCF-RLE-decoder-CWE-122.patch libsdl3-image-3.2.4+ds/debian/patches/Fix-heap-buffer-overflow-READ-in-XCF-RLE-decoder-CWE-122.patch
--- libsdl3-image-3.2.4+ds/debian/patches/Fix-heap-buffer-overflow-READ-in-XCF-RLE-decoder-CWE-122.patch	1970-01-01 01:00:00.000000000 +0100
+++ libsdl3-image-3.2.4+ds/debian/patches/Fix-heap-buffer-overflow-READ-in-XCF-RLE-decoder-CWE-122.patch	2026-08-23 14:44:26.000000000 +0100
@@ -0,0 +1,49 @@
+From: Jorge Barredo Ferreira <[email protected]>
+Date: Mon, 6 Apr 2026 19:31:36 +0200
+Subject: Fix heap-buffer-overflow READ in XCF RLE decoder (CWE-122)
+
+Add destination pointer bounds check in load_xcf_tile_rle.
+
+(cherry picked from commit 6c804082117c95c24b3d3af886319e8c21fcd8e0)
+
+Origin: upstream, 3.4.4, commit:2c9d2d84b000a6a6892fefbd6effaf3452a4609d
+---
+ src/IMG_xcf.c | 11 +++++++++++
+ 1 file changed, 11 insertions(+)
+
+diff --git a/src/IMG_xcf.c b/src/IMG_xcf.c
+index b65061e..482c2a5 100644
+--- a/src/IMG_xcf.c
++++ b/src/IMG_xcf.c
+@@ -640,6 +640,11 @@ static unsigned char *load_xcf_tile_rle(SDL_IOStream *src, size_t len, int bpp,
+     }
+ 
+     data = (unsigned char *)SDL_calloc(1, x*y*bpp);
++    if (!data) {
++        SDL_free(load);
++        return NULL;
++    }
++    unsigned char *data_end = data + x*y*bpp;
+     for (i = 0; i < bpp; i++) {
+         d = data + i;
+         size = x*y;
+@@ -664,6 +669,9 @@ static unsigned char *load_xcf_tile_rle(SDL_IOStream *src, size_t len, int bpp,
+                 size -= length;
+ 
+                 while (length-- > 0) {
++                    if (d >= data_end) {
++                        break;
++                    }
+                     *d = *t++;
+                     d += bpp;
+                 }
+@@ -685,6 +693,9 @@ static unsigned char *load_xcf_tile_rle(SDL_IOStream *src, size_t len, int bpp,
+                 val = *t++;
+ 
+                 for (j = 0; j < length; j++) {
++                    if (d >= data_end) {
++                        break;
++                    }
+                     *d = val;
+                     d += bpp;
+                 }
diff -Nru libsdl3-image-3.2.4+ds/debian/patches/Fix-heap-buffer-overflow-WRITE-in-LBM-palette-CWE-122.patch libsdl3-image-3.2.4+ds/debian/patches/Fix-heap-buffer-overflow-WRITE-in-LBM-palette-CWE-122.patch
--- libsdl3-image-3.2.4+ds/debian/patches/Fix-heap-buffer-overflow-WRITE-in-LBM-palette-CWE-122.patch	1970-01-01 01:00:00.000000000 +0100
+++ libsdl3-image-3.2.4+ds/debian/patches/Fix-heap-buffer-overflow-WRITE-in-LBM-palette-CWE-122.patch	2026-08-23 14:44:26.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: upstream, 3.4.4, commit:20a4b7686bfeda6551c739f4a4f1feaf63979375
+---
+ src/IMG_lbm.c | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+diff --git a/src/IMG_lbm.c b/src/IMG_lbm.c
+index 577ca19..af6ba78 100644
+--- a/src/IMG_lbm.c
++++ b/src/IMG_lbm.c
+@@ -234,6 +234,13 @@ SDL_Surface *IMG_LoadLBM_IO(SDL_IOStream *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 libsdl3-image-3.2.4+ds/debian/patches/Fix-heap-underflow-WRITE-in-XCF-read_string-CWE-787.patch libsdl3-image-3.2.4+ds/debian/patches/Fix-heap-underflow-WRITE-in-XCF-read_string-CWE-787.patch
--- libsdl3-image-3.2.4+ds/debian/patches/Fix-heap-underflow-WRITE-in-XCF-read_string-CWE-787.patch	1970-01-01 01:00:00.000000000 +0100
+++ libsdl3-image-3.2.4+ds/debian/patches/Fix-heap-underflow-WRITE-in-XCF-read_string-CWE-787.patch	2026-08-23 14:44:26.000000000 +0100
@@ -0,0 +1,32 @@
+From: Jorge Barredo Ferreira <[email protected]>
+Date: Mon, 6 Apr 2026 19:30:06 +0200
+Subject: Fix heap underflow WRITE in XCF read_string (CWE-787)
+
+When string length is 0, data[-1] writes before heap allocation.
+Guard tmp == 0 before the null-terminator write.
+
+(cherry picked from commit becd2b6fb242ba9ac60c66a4f3f77d1849aa2a02)
+
+Origin: upstream, 3.4.4, commit:bfaefe1bcdf8731c8e343b3bbcb15e2a445ea318
+---
+ src/IMG_xcf.c | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+diff --git a/src/IMG_xcf.c b/src/IMG_xcf.c
+index df1df2d..ef1136a 100644
+--- a/src/IMG_xcf.c
++++ b/src/IMG_xcf.c
+@@ -237,6 +237,13 @@ static char *read_string(SDL_IOStream *src)
+     char *data = NULL;
+ 
+     if (SDL_ReadU32BE(src, &tmp)) {
++        if (tmp == 0) {
++            data = (char *) SDL_malloc(1);
++            if (data) {
++                data[0] = 0;
++            }
++            return data;
++        }
+         remaining = SDL_GetIOSize(src) - SDL_TellIO(src);
+         if (tmp <= remaining) {
+             data = (char *)SDL_malloc(tmp);
diff -Nru libsdl3-image-3.2.4+ds/debian/patches/IMG_xcf.c-read_string-add-back-the-positive-string-size-c.patch libsdl3-image-3.2.4+ds/debian/patches/IMG_xcf.c-read_string-add-back-the-positive-string-size-c.patch
--- libsdl3-image-3.2.4+ds/debian/patches/IMG_xcf.c-read_string-add-back-the-positive-string-size-c.patch	1970-01-01 01:00:00.000000000 +0100
+++ libsdl3-image-3.2.4+ds/debian/patches/IMG_xcf.c-read_string-add-back-the-positive-string-size-c.patch	2026-08-23 14:44:26.000000000 +0100
@@ -0,0 +1,24 @@
+From: Ozkan Sezer <[email protected]>
+Date: Wed, 13 May 2026 14:51:28 +0300
+Subject: IMG_xcf.c (read_string): add back the positive string size check
+
+(cherry picked from commit 2eda043e2c4cabd565f7d8e04893fb53efd857ef)
+
+Origin: upstream, 3.4.6, commit:15cb42b7fd270aa5dc12d097f964d24c33d7f18b
+---
+ 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 e0360f9..9ea21ec 100644
+--- a/src/IMG_xcf.c
++++ b/src/IMG_xcf.c
+@@ -245,7 +245,7 @@ static char *read_string(SDL_IOStream *src)
+             return data;
+         }
+         remaining = SDL_GetIOSize(src) - SDL_TellIO(src);
+-        if (tmp <= remaining) {
++        if ((Sint32)tmp > 0 && tmp <= remaining) {
+             data = (char *)SDL_malloc(tmp);
+             if (data) {
+                 if (SDL_ReadIO(src, data, tmp) == tmp) {
diff -Nru libsdl3-image-3.2.4+ds/debian/patches/series libsdl3-image-3.2.4+ds/debian/patches/series
--- libsdl3-image-3.2.4+ds/debian/patches/series	1970-01-01 01:00:00.000000000 +0100
+++ libsdl3-image-3.2.4+ds/debian/patches/series	2026-08-23 14:44:26.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
+Fix-heap-underflow-WRITE-in-XCF-read_string-CWE-787.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
+Fix-heap-buffer-overflow-READ-in-XCF-RLE-decoder-CWE-122.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 libsdl3-image-3.2.4+ds/debian/patches/tga-reject-images-with-zero-width-or-height.patch libsdl3-image-3.2.4+ds/debian/patches/tga-reject-images-with-zero-width-or-height.patch
--- libsdl3-image-3.2.4+ds/debian/patches/tga-reject-images-with-zero-width-or-height.patch	1970-01-01 01:00:00.000000000 +0100
+++ libsdl3-image-3.2.4+ds/debian/patches/tga-reject-images-with-zero-width-or-height.patch	2026-08-23 14:44:26.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)
+
+Origin: upstream, 3.4.4, commit:f5c0968ec14318ab489740877f1e66d32b014fbc
+---
+ src/IMG_tga.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+diff --git a/src/IMG_tga.c b/src/IMG_tga.c
+index 92ace3d..1593cdb 100644
+--- a/src/IMG_tga.c
++++ b/src/IMG_tga.c
+@@ -178,6 +178,10 @@ SDL_Surface *IMG_LoadTGA_IO(SDL_IOStream *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_CreateSurface(w, h, format);
+     if (img == NULL) {
+         error = "Out of memory";
diff -Nru libsdl3-image-3.2.4+ds/debian/patches/xcf-Added-an-SDL_SetError-when-rejecting-out-of-bounds-ti.patch libsdl3-image-3.2.4+ds/debian/patches/xcf-Added-an-SDL_SetError-when-rejecting-out-of-bounds-ti.patch
--- libsdl3-image-3.2.4+ds/debian/patches/xcf-Added-an-SDL_SetError-when-rejecting-out-of-bounds-ti.patch	1970-01-01 01:00:00.000000000 +0100
+++ libsdl3-image-3.2.4+ds/debian/patches/xcf-Added-an-SDL_SetError-when-rejecting-out-of-bounds-ti.patch	2026-08-23 14:44:26.000000000 +0100
@@ -0,0 +1,23 @@
+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)
+
+Origin: upstream, 3.4.4, commit:58133e6df69a0107e1ab34e8e564a1ab8706edb8
+---
+ src/IMG_xcf.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/src/IMG_xcf.c b/src/IMG_xcf.c
+index 3fe4c7a..b65061e 100644
+--- a/src/IMG_xcf.c
++++ b/src/IMG_xcf.c
+@@ -794,6 +794,7 @@ do_layer_surface(SDL_Surface *surface, SDL_IOStream *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 libsdl3-image-3.2.4+ds/debian/patches/xcf-fix-null-pointer-dereference-when-read_xcf_hierarchy-.patch libsdl3-image-3.2.4+ds/debian/patches/xcf-fix-null-pointer-dereference-when-read_xcf_hierarchy-.patch
--- libsdl3-image-3.2.4+ds/debian/patches/xcf-fix-null-pointer-dereference-when-read_xcf_hierarchy-.patch	1970-01-01 01:00:00.000000000 +0100
+++ libsdl3-image-3.2.4+ds/debian/patches/xcf-fix-null-pointer-dereference-when-read_xcf_hierarchy-.patch	2026-08-23 14:44:26.000000000 +0100
@@ -0,0 +1,38 @@
+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)
+
+Origin: upstream, 3.4.4, commit:1e81a7f9618a244964387bc18f1451c759841931
+---
+ src/IMG_xcf.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+diff --git a/src/IMG_xcf.c b/src/IMG_xcf.c
+index 482c2a5..e0360f9 100644
+--- a/src/IMG_xcf.c
++++ b/src/IMG_xcf.c
+@@ -753,6 +753,10 @@ do_layer_surface(SDL_Surface *surface, SDL_IOStream *src, xcf_header *head, xcf_
+         return 1;
+     }
+     hierarchy = read_xcf_hierarchy(src, head);
++    if (!hierarchy) {
++        SDL_SetError("Failed to read XCF image hierarchy");
++        return 1;
++    }
+ 
+     if (hierarchy->bpp > 4) {  /* unsupported. */
+         SDL_SetError("Unknown Gimp image bpp (%u)", (unsigned int) hierarchy->bpp);
diff -Nru libsdl3-image-3.2.4+ds/debian/patches/xpm-Remove-QUICK_COLORHASH-replace-it-with-inline-code-th.patch libsdl3-image-3.2.4+ds/debian/patches/xpm-Remove-QUICK_COLORHASH-replace-it-with-inline-code-th.patch
--- libsdl3-image-3.2.4+ds/debian/patches/xpm-Remove-QUICK_COLORHASH-replace-it-with-inline-code-th.patch	1970-01-01 01:00:00.000000000 +0100
+++ libsdl3-image-3.2.4+ds/debian/patches/xpm-Remove-QUICK_COLORHASH-replace-it-with-inline-code-th.patch	2026-08-23 14:44:26.000000000 +0100
@@ -0,0 +1,44 @@
+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, 3.4.4, commit:8ffec045db5cd309f89b07edb7196815b3ba4a08
+Bug: https://github.com/libsdl-org/SDL_image/pull/721
+---
+ 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 8b67f59..47a56f1 100644
+--- a/src/IMG_xpm.c
++++ b/src/IMG_xpm.c
+@@ -159,9 +159,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)];
+@@ -1144,9 +1141,11 @@ static SDL_Surface *load_xpm(char **xpm, SDL_IOStream *src, 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 libsdl3-image-3.2.4+ds/src/IMG_gif.c libsdl3-image-3.2.4+ds/src/IMG_gif.c
--- libsdl3-image-3.2.4+ds/src/IMG_gif.c	2025-01-01 15:38:05.000000000 +0000
+++ libsdl3-image-3.2.4+ds/src/IMG_gif.c	2026-08-23 14:49:29.000000000 +0100
@@ -466,8 +466,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 libsdl3-image-3.2.4+ds/src/IMG_lbm.c libsdl3-image-3.2.4+ds/src/IMG_lbm.c
--- libsdl3-image-3.2.4+ds/src/IMG_lbm.c	2025-01-01 15:38:05.000000000 +0000
+++ libsdl3-image-3.2.4+ds/src/IMG_lbm.c	2026-08-23 14:49:29.000000000 +0100
@@ -234,6 +234,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 libsdl3-image-3.2.4+ds/src/IMG_tga.c libsdl3-image-3.2.4+ds/src/IMG_tga.c
--- libsdl3-image-3.2.4+ds/src/IMG_tga.c	2025-01-01 15:38:05.000000000 +0000
+++ libsdl3-image-3.2.4+ds/src/IMG_tga.c	2026-08-23 14:49:29.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_CreateSurface(w, h, format);
     if (img == NULL) {
         error = "Out of memory";
diff -Nru libsdl3-image-3.2.4+ds/src/IMG_xcf.c libsdl3-image-3.2.4+ds/src/IMG_xcf.c
--- libsdl3-image-3.2.4+ds/src/IMG_xcf.c	2025-01-01 15:38:05.000000000 +0000
+++ libsdl3-image-3.2.4+ds/src/IMG_xcf.c	2026-08-23 14:49:29.000000000 +0100
@@ -237,8 +237,15 @@
     char *data = NULL;
 
     if (SDL_ReadU32BE(src, &tmp)) {
+        if (tmp == 0) {
+            data = (char *) SDL_malloc(1);
+            if (data) {
+                data[0] = 0;
+            }
+            return data;
+        }
         remaining = SDL_GetIOSize(src) - SDL_TellIO(src);
-        if (tmp <= remaining) {
+        if ((Sint32)tmp > 0 && tmp <= remaining) {
             data = (char *)SDL_malloc(tmp);
             if (data) {
                 if (SDL_ReadIO(src, data, tmp) == tmp) {
@@ -633,6 +640,11 @@
     }
 
     data = (unsigned char *)SDL_calloc(1, x*y*bpp);
+    if (!data) {
+        SDL_free(load);
+        return NULL;
+    }
+    unsigned char *data_end = data + x*y*bpp;
     for (i = 0; i < bpp; i++) {
         d = data + i;
         size = x*y;
@@ -657,6 +669,9 @@
                 size -= length;
 
                 while (length-- > 0) {
+                    if (d >= data_end) {
+                        break;
+                    }
                     *d = *t++;
                     d += bpp;
                 }
@@ -678,6 +693,9 @@
                 val = *t++;
 
                 for (j = 0; j < length; j++) {
+                    if (d >= data_end) {
+                        break;
+                    }
                     *d = val;
                     d += bpp;
                 }
@@ -735,6 +753,10 @@
         return 1;
     }
     hierarchy = read_xcf_hierarchy(src, head);
+    if (!hierarchy) {
+        SDL_SetError("Failed to read XCF image hierarchy");
+        return 1;
+    }
 
     if (hierarchy->bpp > 4) {  /* unsupported. */
         SDL_SetError("Unknown Gimp image bpp (%u)", (unsigned int) hierarchy->bpp);
@@ -784,6 +806,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;
@@ -808,20 +840,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:
@@ -839,20 +877,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 libsdl3-image-3.2.4+ds/src/IMG_xpm.c libsdl3-image-3.2.4+ds/src/IMG_xpm.c
--- libsdl3-image-3.2.4+ds/src/IMG_xpm.c	2025-01-01 15:38:05.000000000 +0000
+++ libsdl3-image-3.2.4+ds/src/IMG_xpm.c	2026-08-23 14:49:29.000000000 +0100
@@ -159,9 +159,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)];
@@ -1144,9 +1141,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,
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.