From a353823a7529a115f058444671919490a768b5d4 Mon Sep 17 00:00:00 2001 From: tanjiro Kamado Date: Fri, 23 Oct 2026 14:10:13 +0530 Subject: [PATCH 1/2] reject jobs exceeding XFORM_MAX_PAGES in ipptransform prepare_pages() walks the fixed-size p.outpages[XFORM_MAX_PAGES] array without a bounds check, so a document with more than 10000 pages writes past the end of the array. Reject such jobs in prepare_documents before laying out pages. --- CHANGES.md | 2 ++ tools/ipptransform.c | 9 +++++++++ 2 files changed, 11 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index 2894a7773..91fcbfcb3 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -42,6 +42,8 @@ v3.0.4 - YYYY-MM-DD - Fixed error checking in `cupsOAuthGetAuthorizationCode` (Issue #182) - Fixed a potential race condition in `cupsEnumDests` (Issue #186) - Fixed a bug in `cupsJSONExportString` when exporting a child node (Issue #187) +- Fixed a potential buffer overflow in `ipptransform` when transforming a + document with more than 10000 pages - Fixed PAM support in `ippeveprinter`. - Fixed a typo in the JWT HS verification code. - Fixed `ippValidateAttribute` not returning `false` for too-long URIs. diff --git a/tools/ipptransform.c b/tools/ipptransform.c index 7e3e75e61..92b71eca9 100644 --- a/tools/ipptransform.c +++ b/tools/ipptransform.c @@ -3366,6 +3366,15 @@ prepare_documents( p.num_inpages += d->num_pages; } + // Reject a job with more pages than the fixed-size output page array can + // hold - prepare_pages() walks p.outpages without a bounds check and + // num_outpages never exceeds num_inpages... + if (p.num_inpages > XFORM_MAX_PAGES) + { + cupsLangPrintf(stderr, _("%s: Too many pages to transform (%d maximum)."), Prefix, XFORM_MAX_PAGES); + goto done; + } + // When doing N-up or booklet printing, the default is to scale to fit unless // fill is explicitly chosen... if (p.num_layout > 1 && options->print_scaling != IPPOPT_SCALING_FILL) From acf4fcd848ae528a953341347ff469d2a66aa7aa Mon Sep 17 00:00:00 2001 From: tanjiro Kamado Date: Sat, 24 Oct 2026 11:56:20 +0530 Subject: [PATCH 2/2] bound output pages instead of input pages in prepare_pages --- CHANGES.md | 2 +- tools/ipptransform.c | 27 +++++++++++++++------------ 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 91fcbfcb3..616c7042b 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -43,7 +43,7 @@ v3.0.4 - YYYY-MM-DD - Fixed a potential race condition in `cupsEnumDests` (Issue #186) - Fixed a bug in `cupsJSONExportString` when exporting a child node (Issue #187) - Fixed a potential buffer overflow in `ipptransform` when transforming a - document with more than 10000 pages + job with more than 10000 output pages - Fixed PAM support in `ippeveprinter`. - Fixed a typo in the JWT HS verification code. - Fixed `ippValidateAttribute` not returning `false` for too-long URIs. diff --git a/tools/ipptransform.c b/tools/ipptransform.c index 92b71eca9..46700e256 100644 --- a/tools/ipptransform.c +++ b/tools/ipptransform.c @@ -213,7 +213,7 @@ static pdfio_stream_t *pdfio_start_page(xform_prepare_t *p, pdfio_dict_t *dict); static bool prepare_documents(size_t num_documents, xform_document_t *documents, ipp_options_t *options, const char *sheet_back, char *outfile, size_t outsize, const char *outformat, unsigned *outpages, bool generate_copies); static void prepare_log(xform_prepare_t *p, bool error, const char *message, ...); static void prepare_number_up(xform_prepare_t *p); -static void prepare_pages(xform_prepare_t *p, size_t num_documents, xform_document_t *documents); +static bool prepare_pages(xform_prepare_t *p, size_t num_documents, xform_document_t *documents); static void raster_end_job(xform_raster_t *ras, xform_write_cb_t cb, void *ctx); static void raster_end_page(xform_raster_t *ras, unsigned page, xform_write_cb_t cb, void *ctx); static void raster_init(xform_raster_t *ras); @@ -3366,22 +3366,17 @@ prepare_documents( p.num_inpages += d->num_pages; } - // Reject a job with more pages than the fixed-size output page array can - // hold - prepare_pages() walks p.outpages without a bounds check and - // num_outpages never exceeds num_inpages... - if (p.num_inpages > XFORM_MAX_PAGES) - { - cupsLangPrintf(stderr, _("%s: Too many pages to transform (%d maximum)."), Prefix, XFORM_MAX_PAGES); - goto done; - } - // When doing N-up or booklet printing, the default is to scale to fit unless // fill is explicitly chosen... if (p.num_layout > 1 && options->print_scaling != IPPOPT_SCALING_FILL) options->print_scaling = IPPOPT_SCALING_FIT; // Prepare output pages... - prepare_pages(&p, num_documents, documents); + if (!prepare_pages(&p, num_documents, documents)) + { + cupsLangPrintf(stderr, _("%s: Too many pages to transform (%d maximum)."), Prefix, XFORM_MAX_PAGES); + goto done; + } // Add job-sheets content... if (options->job_sheets[0] && strcmp(options->job_sheets, "none")) @@ -3740,7 +3735,7 @@ prepare_number_up(xform_prepare_t *p) // I - Preparation data // 'prepare_pages()' - Prepare the pages for the output document. // -static void +static bool // O - `true` on success, `false` if too many pages prepare_pages( xform_prepare_t *p, // I - Preparation data size_t num_documents, // I - Number of documents @@ -3763,6 +3758,9 @@ prepare_pages( if (p->num_outpages & 1) p->num_outpages ++; + if (p->num_outpages > XFORM_MAX_PAGES) + return (false); + for (current = 0, layout = 0, page = 1, i = num_documents, d = documents; i > 0; i --, d ++) { while (page <= d->last_page) @@ -3806,6 +3804,9 @@ prepare_pages( if (use_page) { + if (current >= XFORM_MAX_PAGES) + return (false); + outpage->pdf = p->pdf; outpage->input[layout] = pdfioFileGetPage(d->pdf, (size_t)(page - d->first_page)); @@ -3848,6 +3849,8 @@ prepare_pages( p->num_outpages = current; } + + return (true); }