From 30a70e8f163e85bb8f91bab517329b093322e175 Mon Sep 17 00:00:00 2001 From: ManasBagul23 Date: Thu, 1 Oct 2026 15:49:12 +0530 Subject: [PATCH] imagetoraster: reject output dimensions that overflow cupsBytesPerLine header.cupsBytesPerLine was computed as: header.cupsBytesPerLine = (header.cupsBitsPerPixel * header.cupsWidth + 7) / 8; Both operands are unsigned 32-bit fields. A PPD offering an extreme RGB16 resolution together with a small, low-PPI image can drive cupsWidth into the tens of millions; multiplied by a wide pixel depth (e.g. 48 bits for RGB16), the product overflows 32-bit unsigned arithmetic and wraps to a small value before the +7/8 rounds it down to bytes. The formatter (format_cmy/format_RGB) still writes a full row's worth of pixels, well past the undersized buffer that was allocated from the wrapped cupsBytesPerLine. Compute the row size in a wider type (size_t, including the CUPS_ORDER_BANDED multiply, which could also push a borderline value over) and reject the page if it doesn't fit in the unsigned field cupsBytesPerLine actually is, instead of silently wrapping and handing a too-small value downstream. Verified by tracing header.cupsBytesPerLine's consumers (the allocation at the cupsRasterOpen/row-buffer setup further down, and the format_cmy/format_RGB write loops that iterate cupsWidth pixels regardless of what cupsBytesPerLine says) to confirm all of them are protected once this guard holds. No C build toolchain available locally to compile-check. Fixes #184 --- cupsfilters/imagetoraster.c | 29 +++++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/cupsfilters/imagetoraster.c b/cupsfilters/imagetoraster.c index e0fbcb7f1..dfcf2f7ed 100644 --- a/cupsfilters/imagetoraster.c +++ b/cupsfilters/imagetoraster.c @@ -38,6 +38,7 @@ #include #include #include +#include // @@ -1351,11 +1352,31 @@ cfFilterImageToRaster(int inputfd, // I - File descriptor input stream header.cupsHeight = (doc.Orientation & 1 ? xprint : yprint) * header.HWResolution[1]; } - header.cupsBytesPerLine = (header.cupsBitsPerPixel * - header.cupsWidth + 7) / 8; + { + // header.cupsBitsPerPixel and header.cupsWidth are both unsigned (32-bit); + // an extreme HWResolution/page-size combination from the PPD can make + // their product wrap before the +7/8 rounds it down to bytes, handing + // the formatter a cupsBytesPerLine far smaller than the row it actually + // writes. Compute in a wider type and reject the page instead of + // silently wrapping. + size_t bytes_per_line = ((size_t)header.cupsBitsPerPixel * + (size_t)header.cupsWidth + 7) / 8; + + if (header.cupsColorOrder == CUPS_ORDER_BANDED) + bytes_per_line *= header.cupsNumColors; + + if (bytes_per_line > UINT_MAX) + { + if (log) + log(ld, CF_LOGLEVEL_ERROR, + "cfFilterImageToRaster: Unsupported output dimensions (row would " + "need %zu bytes).", bytes_per_line); + cfImageClose(img); + return (1); + } - if (header.cupsColorOrder == CUPS_ORDER_BANDED) - header.cupsBytesPerLine *= header.cupsNumColors; + header.cupsBytesPerLine = (unsigned)bytes_per_line; + } header.Margins[0] = doc.PageLeft; header.Margins[1] = doc.PageBottom;