Backport of:

From 7f85ba6f76d704b506c76cc572bf3bee3cf8a3e0 Mon Sep 17 00:00:00 2001
From: Michael R Sweet <msweet@msweet.org>
Date: Tue, 3 Mar 2026 15:27:34 -0500
Subject: [PATCH] Improve page header validation in cupsRasterReadHeader (Issue
 #1501)

---
 CHANGES.md           |  2 ++
 cups/raster-error.c  | 10 +++---
 cups/raster-stream.c | 73 +++++++++++++++++++++++++++++++++++++++++---
 3 files changed, 74 insertions(+), 11 deletions(-)

#diff --git a/CHANGES.md b/CHANGES.md
#index f46d3dab41..6180933961 100644
#--- a/CHANGES.md
#+++ b/CHANGES.md
#@@ -8,6 +8,8 @@ Changes in CUPS v2.4.17 (YYYY-MM-DD)
# - The scheduler followed symbolic links when cleaning out its temporary
#   directory (Issue #1448)
# - Updated `cupsFileGetConf` and `cupsFilePutConf` to escape more characters.
#+- Updated `cupsRasterReadHeader` to validate more of the page header values
#+  (Issue #1501)
# - Fixed an issue with the class/printer CGI name checking.
# - Fixed notifier logging bug that would result in nul bytes getting into the
#   log (Issue #1450)
--- a/cups/raster-error.c
+++ b/cups/raster-error.c
@@ -8,10 +8,6 @@
  * information.
  */
 
-/*
- * Include necessary headers...
- */
-
 #include "cups-private.h"
 #include "raster-private.h"
 #include "debug-internal.h"
@@ -59,7 +55,6 @@ _cupsRasterAddError(const char *f,	/* I
     char	*temp;			/* New buffer */
     size_t	size;			/* Size of buffer */
 
-
     size = (size_t)(buf->end - buf->start + 2 * bytes + 1024);
 
     if (buf->start)
@@ -83,6 +78,9 @@ _cupsRasterAddError(const char *f,	/* I
   * Append the message to the end of the current string...
   */
 
+  if (buf->current > buf->start)
+    *(buf->current ++) = ' ';
+
   memcpy(buf->current, s, (size_t)bytes);
   buf->current += bytes - 1;
 }
--- a/cups/raster-stream.c
+++ b/cups/raster-stream.c
@@ -22,6 +22,17 @@
 
 
 /*
+ * Limits...
+ */
+
+#define _CUPS_MAX_BYTES_PER_LINE	(16 * 1024 * 1024)
+#define _CUPS_MAX_BITS_PER_COLOR	16
+#define _CUPS_MAX_BITS_PER_PIXEL	240
+#define _CUPS_MAX_HEIGHT		0x00ffffff
+#define _CUPS_MAX_WIDTH			0x00ffffff
+
+
+/*
  * Private structures...
  */
 
@@ -1558,6 +1569,9 @@ cups_raster_read(cups_raster_t *r,	/* I
 static int				/* O - 1 on success, 0 on failure */
 cups_raster_update(cups_raster_t *r)	/* I - Raster stream */
 {
+  int	ret = 1;			/* Return value */
+
+
   if (r->sync == CUPS_RASTER_SYNCv1 || r->sync == CUPS_RASTER_REVSYNCv1 ||
       r->header.cupsNumColors == 0)
   {
@@ -1665,10 +1679,59 @@ cups_raster_update(cups_raster_t *r)	/*
     r->remaining = r->header.cupsHeight;
 
  /*
+  * Validate the page header...
+  */
+
+  if (r->header.cupsBitsPerColor != 1 &&  r->header.cupsBitsPerColor != 2 &&  r->header.cupsBitsPerColor != 4 &&  r->header.cupsBitsPerColor != 8 &&  r->header.cupsBitsPerColor != 16)
+  {
+    _cupsRasterAddError("Invalid bits per color %u.", r->header.cupsBitsPerColor);
+    ret = 0;
+  }
+
+  if ((r->header.cupsColorOrder != CUPS_ORDER_CHUNKED && r->header.cupsBitsPerPixel != r->header.cupsBitsPerColor) || (r->header.cupsColorOrder == CUPS_ORDER_CHUNKED && r->header.cupsBitsPerPixel != (r->header.cupsBitsPerColor * r->header.cupsNumColors)))
+  {
+    _cupsRasterAddError("Invalid bits per pixel %u.", r->header.cupsBitsPerPixel);
+    ret = 0;
+  }
+
+  if (r->header.cupsBytesPerLine == 0)
+  {
+    _cupsRasterAddError("Invalid raster line length 0.");
+    ret = 0;
+  }
+  else if (r->header.cupsBytesPerLine > _CUPS_MAX_BYTES_PER_LINE)
+  {
+    _cupsRasterAddError("Raster line length %u is greater than %d bytes.", r->header.cupsBytesPerLine, _CUPS_MAX_BYTES_PER_LINE);
+    ret = 0;
+  }
+  else if ((r->header.cupsBytesPerLine % r->bpp) != 0)
+  {
+    _cupsRasterAddError("Raster line length %u is not a multiple of the pixel size (%d).", r->header.cupsBytesPerLine, r->bpp);
+    ret = 0;
+  }
+  else if (r->header.cupsBytesPerLine != ((r->header.cupsWidth * r->header.cupsBitsPerPixel + 7) / 8))
+  {
+    _cupsRasterAddError("Raster line length %u does not match width (%u) and bits per pixel (%u).", r->header.cupsBytesPerLine, r->header.cupsWidth, r->header.cupsBitsPerPixel);
+    ret = 0;
+  }
+
+  if (r->header.cupsWidth == 0 || r->header.cupsWidth > _CUPS_MAX_WIDTH)
+  {
+    _cupsRasterAddError("Invalid raster width %u.", r->header.cupsWidth);
+    ret = 0;
+  }
+
+  if (r->header.cupsHeight == 0 || r->header.cupsHeight > _CUPS_MAX_HEIGHT)
+  {
+    _cupsRasterAddError("Invalid raster height %u.", r->header.cupsHeight);
+    ret = 0;
+  }
+
+ /*
   * Allocate the compression buffer...
   */
 
-  if (r->compressed)
+  if (ret && r->compressed)
   {
     if (r->pixels != NULL)
       free(r->pixels);
@@ -1687,7 +1750,7 @@ cups_raster_update(cups_raster_t *r)	/*
     r->count    = 0;
   }
 
-  return (1);
+  return (ret);
 }
 
 
