SDL_image: Fixed out of bounds read in XCF image loader (thanks @Sebasteuo!) (678ac)

From 678ac6a4c6021853485050926f45db08ba6aec48 Mon Sep 17 00:00:00 2001
From: Ozkan Sezer <[EMAIL REDACTED]>
Date: Fri, 3 Apr 2026 04:10:24 +0300
Subject: [PATCH] Fixed out of bounds read in XCF image loader (thanks
 @Sebasteuo!)

(manual backport of commit f55d589ba5de11c724afcdcae80b56bf26d91d15)
---
 IMG_xcf.c | 54 ++++++++++++++++++++++++++++++++----------------------
 1 file changed, 32 insertions(+), 22 deletions(-)

diff --git a/IMG_xcf.c b/IMG_xcf.c
index 6277947d8..c5144d809 100644
--- a/IMG_xcf.c
+++ b/IMG_xcf.c
@@ -725,22 +725,28 @@ 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;	    
+	    break;
 	  default:
 	    fprintf (stderr, "Unknown Gimp image type (%d)\n", head->image_type);
 	    if (hierarchy)
@@ -754,22 +760,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++ = 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;	    
+	    break;
 	  default:
 	    fprintf (stderr, "Unknown Gimp image type (%d)\n", head->image_type);
 	    if (tile)