Version in base suite: 8.16.1-1+deb13u1 Base version: vips_8.16.1-1+deb13u1 Target version: vips_8.16.1-1+deb13u2 Base file: /srv/ftp-master.debian.org/ftp/pool/main/v/vips/vips_8.16.1-1+deb13u1.dsc Target file: /srv/ftp-master.debian.org/policy/pool/main/v/vips/vips_8.16.1-1+deb13u2.dsc changelog | 16 patches/0016-tiffload-test-for-jp2k-tiles-that-are-too-small.patch | 26 patches/CVE-2025-59933.patch | 279 ++++++++++ patches/CVE-2026-33327.patch | 116 ++++ patches/CVE-2026-33328.patch | 30 + patches/CVE-2026-35590.patch | 25 patches/CVE-2026-35591.patch | 115 ++++ patches/CVE-2026-69242.patch | 24 patches/CVE-2026-70651.patch | 56 ++ patches/CVE-2026-70653.patch | 80 ++ patches/CVE-2026-70654.patch | 24 patches/series | 10 12 files changed, 801 insertions(+) dpkg-source: warning: cannot verify inline signature for /srv/release.debian.org/tmp/tmpzwhs9wlg/vips_8.16.1-1+deb13u1.dsc: no acceptable signature found dpkg-source: warning: cannot verify inline signature for /srv/release.debian.org/tmp/tmpzwhs9wlg/vips_8.16.1-1+deb13u2.dsc: no acceptable signature found diff -Nru vips-8.16.1/debian/changelog vips-8.16.1/debian/changelog --- vips-8.16.1/debian/changelog 2026-04-06 12:18:12.000000000 +0000 +++ vips-8.16.1/debian/changelog 2026-09-30 09:20:35.000000000 +0000 @@ -1,3 +1,19 @@ +vips (8.16.1-1+deb13u2) trixie-security; urgency=high + + * Non-maintainer upload by the Debian Security Team. + * Fix vulnerabilities: + - CVE-2025-59933: validate image dimensions returned by the PDF and SVG loaders. + - CVE-2026-33327: prevent integer overflow when allocating GIF images. + - CVE-2026-33328: guard against image dimension overflows. + - CVE-2026-35591: validate JPEG and JPEG 2000 components in the TIFF loader. + - CVE-2026-35590: validate EXIF IFD indices. + - CVE-2026-69242: ensure scanlines fit in INT_MAX. + - CVE-2026-70654: fix maximum read size handling in vipsource. + - CVE-2026-70653: avoid unsafe processing of legacy Radiance RLE data. + - CVE-2026-70651: check the final image height of ImageMagick animations. + + -- Tianyu Chen Wed, 30 Sep 2026 17:20:35 +0800 + vips (8.16.1-1+deb13u1) trixie; urgency=medium [ Moritz Mühlenhoff ] diff -Nru vips-8.16.1/debian/patches/0016-tiffload-test-for-jp2k-tiles-that-are-too-small.patch vips-8.16.1/debian/patches/0016-tiffload-test-for-jp2k-tiles-that-are-too-small.patch --- vips-8.16.1/debian/patches/0016-tiffload-test-for-jp2k-tiles-that-are-too-small.patch 1970-01-01 00:00:00.000000000 +0000 +++ vips-8.16.1/debian/patches/0016-tiffload-test-for-jp2k-tiles-that-are-too-small.patch 2026-09-30 09:20:35.000000000 +0000 @@ -0,0 +1,26 @@ +From: John Cupitt +Date: Fri, 4 Sep 2026 13:54:11 +0100 +Subject: tiffload: test for jp2k tiles that are too small + +Thanks Ada Logics +--- + libvips/foreign/jp2kload.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/libvips/foreign/jp2kload.c b/libvips/foreign/jp2kload.c +index 6a08c5a..2992271 100644 +--- a/libvips/foreign/jp2kload.c ++++ b/libvips/foreign/jp2kload.c +@@ -1548,9 +1548,9 @@ vips__foreign_load_jp2k_decompress(VipsImage *out, + if (vips_foreign_load_jp2k_check_supported(decompress.image)) + return -1; + +- if (decompress.image->x1 > width || +- decompress.image->y1 > height || +- decompress.image->numcomps > out->Bands || ++ if (decompress.image->x1 != width || ++ decompress.image->y1 != height || ++ decompress.image->numcomps != out->Bands || + line_size * height > to_length) { + vips_error("jp2kload", "%s", ("bad dimensions")); + vips__foreign_load_jp2k_decompress_free(&decompress); diff -Nru vips-8.16.1/debian/patches/CVE-2025-59933.patch vips-8.16.1/debian/patches/CVE-2025-59933.patch --- vips-8.16.1/debian/patches/CVE-2025-59933.patch 1970-01-01 00:00:00.000000000 +0000 +++ vips-8.16.1/debian/patches/CVE-2025-59933.patch 2026-09-30 09:20:35.000000000 +0000 @@ -0,0 +1,279 @@ +From: John Cupitt +Date: Sun, 3 Aug 2025 11:17:25 +0100 +Subject: validate poppler page size + +Poppler can return pages less than 1 pixel wide or high. Check for this +and flag an error. + +Thanks Yang Luo, Riema Labs +--- + libvips/foreign/popplerload.c | 10 +++++++--- + libvips/foreign/svgload.c | 7 +++++++ + 2 files changed, 14 insertions(+), 3 deletions(-) + +diff --git a/libvips/foreign/popplerload.c b/libvips/foreign/popplerload.c +index 59fcc6e..9d3456d 100644 +--- a/libvips/foreign/popplerload.c ++++ b/libvips/foreign/popplerload.c +@@ -314,7 +314,6 @@ vips_foreign_load_pdf_header(VipsForeignLoad *load) + VipsForeignLoadPdf *pdf = VIPS_FOREIGN_LOAD_PDF(load); + + int top; +- int i; + + #ifdef DEBUG + printf("vips_foreign_load_pdf_header: %p\n", pdf); +@@ -344,7 +343,7 @@ vips_foreign_load_pdf_header(VipsForeignLoad *load) + pdf->image.top = 0; + pdf->image.width = 0; + pdf->image.height = 0; +- for (i = 0; i < pdf->n; i++) { ++ for (int i = 0; i < pdf->n; i++) { + double width; + double height; + +@@ -359,6 +358,11 @@ vips_foreign_load_pdf_header(VipsForeignLoad *load) + */ + pdf->pages[i].width = VIPS_RINT(width * pdf->total_scale); + pdf->pages[i].height = VIPS_RINT(height * pdf->total_scale); ++ if (pdf->pages[i].width <= 0 || ++ pdf->pages[i].height <= 0) { ++ vips_error(class->nickname, "%s", _("zero-sized image")); ++ return -1; ++ } + + if (pdf->pages[i].width > pdf->image.width) + pdf->image.width = pdf->pages[i].width; +@@ -370,7 +374,7 @@ vips_foreign_load_pdf_header(VipsForeignLoad *load) + /* If all pages are the same height, we can tag this as a toilet roll + * image. + */ +- for (i = 1; i < pdf->n; i++) ++ for (int i = 1; i < pdf->n; i++) + if (pdf->pages[i].height != pdf->pages[0].height) + break; + +diff --git a/libvips/foreign/svgload.c b/libvips/foreign/svgload.c +index 76c2199..1888f98 100644 +--- a/libvips/foreign/svgload.c ++++ b/libvips/foreign/svgload.c +@@ -538,12 +538,19 @@ vips_foreign_load_svg_get_scaled_size(VipsForeignLoadSvg *svg, + static int + vips_foreign_load_svg_parse(VipsForeignLoadSvg *svg, VipsImage *out) + { ++ VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(svg); ++ + int width; + int height; + double res; + + if (vips_foreign_load_svg_get_scaled_size(svg, &width, &height)) + return -1; ++ if (width <= 0 || ++ height <= 0) { ++ vips_error(class->nickname, "%s", _("zero-sized image")); ++ return -1; ++ } + + /* We need pixels/mm for vips. + */ +From: John Cupitt +Date: Sun, 3 Aug 2025 14:06:21 +0100 +Subject: add image sanity tests + +--- + libvips/foreign/foreign.c | 7 +++++-- + libvips/iofuncs/generate.c | 7 ++++++- + libvips/iofuncs/image.c | 50 ++++++++++++++++++++++------------------------ + libvips/iofuncs/sink.c | 3 ++- + 4 files changed, 37 insertions(+), 30 deletions(-) + +diff --git a/libvips/foreign/foreign.c b/libvips/foreign/foreign.c +index 7e72610..805f347 100644 +--- a/libvips/foreign/foreign.c ++++ b/libvips/foreign/foreign.c +@@ -1032,6 +1032,7 @@ vips_foreign_load_start(VipsImage *out, void *a, void *b) + * If the load fails, we need to stop. + */ + if (class->load(load) || ++ !vips_object_sanity(VIPS_OBJECT(load->real)) || + vips_image_pio_input(load->real) || + !vips_foreign_load_iscompat(load->real, out)) { + vips_operation_invalidate(VIPS_OPERATION(load)); +@@ -1136,9 +1137,11 @@ vips_foreign_load_build(VipsObject *object) + + /* Read the header into @out. + */ +- if (fclass->header && +- fclass->header(load)) ++ if (fclass->header) { ++ if (fclass->header(load) || ++ !vips_object_sanity(VIPS_OBJECT(load->out))) + return -1; ++ } + + /* If there's no ->load() method then the header read has done + * everything. Otherwise, it's just set fields and we must also +diff --git a/libvips/iofuncs/generate.c b/libvips/iofuncs/generate.c +index 8941762..4e2f7cb 100644 +--- a/libvips/iofuncs/generate.c ++++ b/libvips/iofuncs/generate.c +@@ -377,6 +377,9 @@ int + vips_image_pipeline_array(VipsImage *image, + VipsDemandStyle hint, VipsImage **in) + { ++ if (!vips_object_sanity(VIPS_OBJECT(image))) ++ return -1; ++ + /* This function can be called more than once per output image. For + * example, jpeg header load will call this once on ->out to set the + * default hint, then later call it again to connect the output image +@@ -689,7 +692,9 @@ vips_image_generate(VipsImage *image, + VIPS_DEBUG_MSG("vips_image_generate: %p\n", image); + + g_assert(generate_fn); +- g_assert(vips_object_sanity(VIPS_OBJECT(image))); ++ ++ if (!vips_object_sanity(VIPS_OBJECT(image))) ++ return -1; + + if (!image->hint_set) { + vips_error("vips_image_generate", +diff --git a/libvips/iofuncs/image.c b/libvips/iofuncs/image.c +index e6bcc4c..f360635 100644 +--- a/libvips/iofuncs/image.c ++++ b/libvips/iofuncs/image.c +@@ -672,29 +672,24 @@ vips_image_sanity(VipsObject *object, VipsBuf *buf) + { + VipsImage *image = VIPS_IMAGE(object); + +- /* All 0 means im has been inited but never used. +- */ +- if (image->Xsize != 0 || +- image->Ysize != 0 || +- image->Bands != 0) { +- if (image->Xsize <= 0 || +- image->Ysize <= 0 || +- image->Bands <= 0) +- vips_buf_appends(buf, "bad dimensions\n"); +- if (image->BandFmt < -1 || +- image->BandFmt > VIPS_FORMAT_DPCOMPLEX || +- (image->Coding != -1 && +- image->Coding != VIPS_CODING_NONE && +- image->Coding != VIPS_CODING_LABQ && +- image->Coding != VIPS_CODING_RAD) || +- image->Type >= VIPS_INTERPRETATION_LAST || +- image->dtype > VIPS_IMAGE_PARTIAL || +- image->dhint > VIPS_DEMAND_STYLE_ANY) +- vips_buf_appends(buf, "bad enum\n"); +- if (image->Xres < 0 || +- image->Yres < 0) +- vips_buf_appends(buf, "bad resolution\n"); +- } ++ if (image->Xsize <= 0 || ++ image->Ysize <= 0 || ++ image->Bands <= 0) ++ vips_buf_appends(buf, "bad dimensions\n"); ++ if (image->BandFmt < -1 || ++ image->BandFmt > VIPS_FORMAT_DPCOMPLEX || ++ (image->Coding != -1 && ++ image->Coding != VIPS_CODING_NONE && ++ image->Coding != VIPS_CODING_LABQ && ++ image->Coding != VIPS_CODING_RAD) || ++ image->Type >= VIPS_INTERPRETATION_LAST || ++ image->dtype > VIPS_IMAGE_PARTIAL || ++ image->dhint > VIPS_DEMAND_STYLE_ANY) ++ vips_buf_appends(buf, "bad enum\n"); ++ if (image->Xres < 0 || ++ image->Yres < 0) ++ vips_buf_appends(buf, "bad resolution\n"); ++ + + /* Must lock around inter-image links. + */ +@@ -3137,7 +3132,8 @@ vips_image_hasalpha(VipsImage *image) + int + vips_image_write_prepare(VipsImage *image) + { +- g_assert(vips_object_sanity(VIPS_OBJECT(image))); ++ if (!vips_object_sanity(VIPS_OBJECT(image))) ++ return -1; + + if (image->Xsize <= 0 || + image->Ysize <= 0 || +@@ -3402,7 +3398,8 @@ vips_image_wio_input(VipsImage *image) + { + VipsImage *t1; + +- g_assert(vips_object_sanity(VIPS_OBJECT(image))); ++ if (!vips_object_sanity(VIPS_OBJECT(image))) ++ return -1; + + #ifdef DEBUG_IO + printf("vips_image_wio_input: wio input for %s\n", +@@ -3628,7 +3625,8 @@ vips_image_inplace(VipsImage *image) + int + vips_image_pio_input(VipsImage *image) + { +- g_assert(vips_object_sanity(VIPS_OBJECT(image))); ++ if (!vips_object_sanity(VIPS_OBJECT(image))) ++ return -1; + + #ifdef DEBUG_IO + printf("vips_image_pio_input: enabling partial input for %s\n", +diff --git a/libvips/iofuncs/sink.c b/libvips/iofuncs/sink.c +index 8082185..bf2dfe9 100644 +--- a/libvips/iofuncs/sink.c ++++ b/libvips/iofuncs/sink.c +@@ -474,7 +474,8 @@ vips_sink_tile(VipsImage *im, + Sink sink; + int result; + +- g_assert(vips_object_sanity(VIPS_OBJECT(im))); ++ if (!vips_object_sanity(VIPS_OBJECT(im))) ++ return -1; + + /* We don't use this, but make sure it's set in case any old binaries + * are expecting it. +From: John Cupitt +Date: Mon, 4 Aug 2025 12:17:10 +0100 +Subject: make vips_object_sanity() log an error + +--- + libvips/iofuncs/object.c | 17 ++++++----------- + 1 file changed, 6 insertions(+), 11 deletions(-) + +diff --git a/libvips/iofuncs/object.c b/libvips/iofuncs/object.c +index e0c017d..4da32e1 100644 +--- a/libvips/iofuncs/object.c ++++ b/libvips/iofuncs/object.c +@@ -473,23 +473,18 @@ vips_object_print_name(VipsObject *object) + gboolean + vips_object_sanity(VipsObject *object) + { +- VipsObjectClass *class; +- char str[1000]; +- VipsBuf buf = VIPS_BUF_STATIC(str); +- + if (!object) { +- printf("vips_object_sanity: null object\n"); +- ++ vips_error("vips_object_sanity", _("null object")); + return FALSE; + } + +- class = VIPS_OBJECT_GET_CLASS(object); ++ VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(object); ++ ++ char str[1000]; ++ VipsBuf buf = VIPS_BUF_STATIC(str); + class->sanity(object, &buf); + if (!vips_buf_is_empty(&buf)) { +- printf("sanity failure: "); +- vips_object_print_name(object); +- printf(" %s\n", vips_buf_all(&buf)); +- ++ vips_error(class->nickname, "%s", vips_buf_all(&buf)); + return FALSE; + } + diff -Nru vips-8.16.1/debian/patches/CVE-2026-33327.patch vips-8.16.1/debian/patches/CVE-2026-33327.patch --- vips-8.16.1/debian/patches/CVE-2026-33327.patch 1970-01-01 00:00:00.000000000 +0000 +++ vips-8.16.1/debian/patches/CVE-2026-33327.patch 2026-09-30 09:20:35.000000000 +0000 @@ -0,0 +1,116 @@ +From: Kleis Auke Wolthuizen +Date: Sat, 7 Mar 2026 14:13:51 +0100 +Subject: Guard against dimension overflow (#4934) + +--- + libvips/iofuncs/image.c | 40 ++++++++++++++++++++++++++++------------ + libvips/iofuncs/object.c | 3 +++ + 2 files changed, 31 insertions(+), 12 deletions(-) + +diff --git a/libvips/iofuncs/image.c b/libvips/iofuncs/image.c +index f360635..f41b3be 100644 +--- a/libvips/iofuncs/image.c ++++ b/libvips/iofuncs/image.c +@@ -671,6 +671,7 @@ static void + vips_image_sanity(VipsObject *object, VipsBuf *buf) + { + VipsImage *image = VIPS_IMAGE(object); ++ guint64 es, ps, ls, sizeof_image; + + if (image->Xsize <= 0 || + image->Ysize <= 0 || +@@ -691,6 +692,22 @@ vips_image_sanity(VipsObject *object, VipsBuf *buf) + vips_buf_appends(buf, "bad resolution\n"); + + ++ es = VIPS_IMAGE_SIZEOF_ELEMENT(image); ++ ++ /* Guard for `es * bands * width * height <= UINT64_MAX`, i.e. check ++ * whether the VIPS_IMAGE_SIZEOF_PEL(), VIPS_IMAGE_SIZEOF_LINE() ++ * and VIPS_IMAGE_SIZEOF_IMAGE() macros can be safely used. ++ * ++ * Also ensure that vips_tracked_malloc(VIPS_IMAGE_SIZEOF_IMAGE(image)) ++ * can be called safely for setbuf types. ++ */ ++ if (!g_uint64_checked_mul(&ps, es, image->Bands) || ++ !g_uint64_checked_mul(&ls, ps, image->Xsize) || ++ !g_uint64_checked_mul(&sizeof_image, ls, image->Ysize) || ++ (image->dtype == VIPS_IMAGE_SETBUF && ++ sizeof_image > G_MAXSIZE - 16)) ++ vips_buf_appends(buf, "dimension overflow\n"); ++ + /* Must lock around inter-image links. + */ + g_mutex_lock(vips__global_lock); +@@ -964,9 +981,8 @@ vips_image_build(VipsObject *object) + + /* Very common, so a special message. + */ +- sizeof_image = VIPS_IMAGE_SIZEOF_IMAGE(image) + +- image->sizeof_header; +- if (image->file_length < sizeof_image) { ++ sizeof_image = VIPS_IMAGE_SIZEOF_IMAGE(image); ++ if (image->file_length - image->sizeof_header < sizeof_image) { + vips_error("VipsImage", + _("unable to open \"%s\", file too short"), + image->filename); +@@ -976,7 +992,7 @@ vips_image_build(VipsObject *object) + /* Just weird. Only print a warning for this, since we should + * still be able to process it without coredumps. + */ +- if (image->file_length > sizeof_image) ++ if (image->file_length - image->sizeof_header > sizeof_image) + g_warning(_("%s is longer than expected"), + image->filename); + break; +@@ -2064,7 +2080,7 @@ vips_image_new_from_memory(const void *data, size_t size, + if (size < VIPS_IMAGE_SIZEOF_IMAGE(image)) { + vips_error("VipsImage", + _("memory area too small --- " +- "should be %" G_GINT64_FORMAT " bytes, you passed %zd"), ++ "should be %" G_GUINT64_FORMAT " bytes, you passed %zd"), + VIPS_IMAGE_SIZEOF_IMAGE(image), size); + VIPS_UNREF(image); + return NULL; +@@ -3132,6 +3148,13 @@ vips_image_hasalpha(VipsImage *image) + int + vips_image_write_prepare(VipsImage *image) + { ++ if (image->dtype == VIPS_IMAGE_PARTIAL) { ++ VIPS_DEBUG_MSG("vips_image_write_prepare: old-style output for %s\n", ++ image->filename); ++ ++ image->dtype = VIPS_IMAGE_SETBUF; ++ } ++ + if (!vips_object_sanity(VIPS_OBJECT(image))) + return -1; + +@@ -3147,13 +3170,6 @@ vips_image_write_prepare(VipsImage *image) + */ + image->Bbits = vips_format_sizeof(image->BandFmt) << 3; + +- if (image->dtype == VIPS_IMAGE_PARTIAL) { +- VIPS_DEBUG_MSG("vips_image_write_prepare: old-style output for %s\n", +- image->filename); +- +- image->dtype = VIPS_IMAGE_SETBUF; +- } +- + switch (image->dtype) { + case VIPS_IMAGE_MMAPINRW: + case VIPS_IMAGE_SETBUF_FOREIGN: +diff --git a/libvips/iofuncs/object.c b/libvips/iofuncs/object.c +index 4da32e1..5e4ffaf 100644 +--- a/libvips/iofuncs/object.c ++++ b/libvips/iofuncs/object.c +@@ -1449,6 +1449,9 @@ vips_object_real_build(VipsObject *object) + (void) vips_argument_map(object, + vips_object_check_required, &result, &iomask); + ++ if (!vips_object_sanity(object)) ++ return -1; ++ + return result; + } + diff -Nru vips-8.16.1/debian/patches/CVE-2026-33328.patch vips-8.16.1/debian/patches/CVE-2026-33328.patch --- vips-8.16.1/debian/patches/CVE-2026-33328.patch 1970-01-01 00:00:00.000000000 +0000 +++ vips-8.16.1/debian/patches/CVE-2026-33328.patch 2026-09-30 09:20:35.000000000 +0000 @@ -0,0 +1,30 @@ +From: Kleis Auke Wolthuizen +Date: Thu, 19 Feb 2026 14:11:54 +0100 +Subject: gifload: guard against int overflow on 32-bit platforms + +--- + libvips/foreign/nsgifload.c | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +diff --git a/libvips/foreign/nsgifload.c b/libvips/foreign/nsgifload.c +index 366a3f6..5a97b5c 100644 +--- a/libvips/foreign/nsgifload.c ++++ b/libvips/foreign/nsgifload.c +@@ -630,11 +630,15 @@ static void * + vips_foreign_load_nsgif_bitmap_create(int width, int height) + { + /* GIF has a limit of 64k per axis -- double-check this. ++ * ++ * gifsave also enforces a pixel count limit, apply the same ++ * constraint here. + */ + if (width <= 0 || +- width > 65536 || ++ width > 65535 || + height <= 0 || +- height > 65536) { ++ height > 65535 || ++ (guint64) width * height > INT_MAX / 4) { + vips_error("gifload", + "%s", _("bad image dimensions")); + return NULL; diff -Nru vips-8.16.1/debian/patches/CVE-2026-35590.patch vips-8.16.1/debian/patches/CVE-2026-35590.patch --- vips-8.16.1/debian/patches/CVE-2026-35590.patch 1970-01-01 00:00:00.000000000 +0000 +++ vips-8.16.1/debian/patches/CVE-2026-35590.patch 2026-09-30 09:20:35.000000000 +0000 @@ -0,0 +1,25 @@ +From: John Cupitt +Date: Mon, 23 Mar 2026 11:41:19 +0000 +Subject: validate ifdN in exif decode + +thanks trailofbits +--- + libvips/foreign/exif.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/libvips/foreign/exif.c b/libvips/foreign/exif.c +index a73afbf..9900367 100644 +--- a/libvips/foreign/exif.c ++++ b/libvips/foreign/exif.c +@@ -1263,6 +1263,11 @@ vips_exif_image_field(VipsImage *image, + + p = field + strlen("exif-ifd"); + ifd = atoi(p); ++ if (ifd < 0 || ++ ifd >= EXIF_IFD_COUNT) { ++ g_warning("bad exif ifd %d in \"%s\"", ifd, field); ++ return NULL; ++ } + + for (; g_ascii_isdigit(*p); p++) + ; diff -Nru vips-8.16.1/debian/patches/CVE-2026-35591.patch vips-8.16.1/debian/patches/CVE-2026-35591.patch --- vips-8.16.1/debian/patches/CVE-2026-35591.patch 1970-01-01 00:00:00.000000000 +0000 +++ vips-8.16.1/debian/patches/CVE-2026-35591.patch 2026-09-30 09:20:35.000000000 +0000 @@ -0,0 +1,115 @@ +From: John Cupitt +Date: Thu, 26 Mar 2026 13:02:47 +0000 +Subject: Tiffload validate components (#4973) + +* tiffload: validate jpeg and jp2k components + +thanks wooseokdotkim + +* oops +--- + libvips/foreign/jp2kload.c | 25 ++++++++++++------------- + libvips/foreign/tiff2vips.c | 6 ++++++ + 2 files changed, 18 insertions(+), 13 deletions(-) + +diff --git a/libvips/foreign/jp2kload.c b/libvips/foreign/jp2kload.c +index 05e7442..6a08c5a 100644 +--- a/libvips/foreign/jp2kload.c ++++ b/libvips/foreign/jp2kload.c +@@ -588,17 +588,14 @@ vips_foreign_load_jp2k_set_header(VipsForeignLoadJp2k *jp2k, VipsImage *out) + /* Is an image a type we handle? We don't support various strange jp2k types. + */ + static int +-vips_foreign_load_jp2k_check_supported(VipsForeignLoadJp2k *jp2k, +- opj_image_t *image) ++vips_foreign_load_jp2k_check_supported(opj_image_t *image) + { +- VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(jp2k); +- + if (image->numcomps > MAX_BANDS) { +- vips_error(class->nickname, "%s", _("too many image bands")); ++ vips_error("jp2kload", "%s", _("too many image bands")); + return -1; + } + if (image->numcomps == 0) { +- vips_error(class->nickname, "%s", _("no image components")); ++ vips_error("jp2kload", "%s", _("no image components")); + return -1; + } + +@@ -614,15 +611,13 @@ vips_foreign_load_jp2k_check_supported(VipsForeignLoadJp2k *jp2k, + this->h * this->dy != first->h * first->dy || + this->resno_decoded != first->resno_decoded || + this->factor != first->factor) { +- vips_error(class->nickname, +- "%s", _("components differ in geometry")); ++ vips_error("jp2kload", "%s", _("components differ in geometry")); + return -1; + } + + if (this->prec != first->prec || + this->sgnd != first->sgnd) { +- vips_error(class->nickname, +- "%s", _("components differ in precision")); ++ vips_error("jp2kload", "%s", _("components differ in precision")); + return -1; + } + } +@@ -658,7 +653,7 @@ vips_foreign_load_jp2k_header(VipsForeignLoad *load) + if (!(jp2k->info = opj_get_cstr_info(jp2k->codec))) + return -1; + +- if (vips_foreign_load_jp2k_check_supported(jp2k, jp2k->image)) ++ if (vips_foreign_load_jp2k_check_supported(jp2k->image)) + return -1; + + /* If any dx/dy are not 1, we'll need to upsample components during +@@ -986,7 +981,7 @@ vips_foreign_load_jp2k_generate_untiled(VipsRegion *out, + if (!opj_decode(jp2k->codec, jp2k->stream, jp2k->image)) + return -1; + +- if (vips_foreign_load_jp2k_check_supported(jp2k, jp2k->image)) ++ if (vips_foreign_load_jp2k_check_supported(jp2k->image)) + return -1; + + /* Tragically, jp2k allows the decoded image to not match the wrapper. +@@ -1082,7 +1077,7 @@ vips_foreign_load_jp2k_generate_tiled(VipsRegion *out, + jp2k->stream, jp2k->image, tile_index)) + return -1; + +- if (vips_foreign_load_jp2k_check_supported(jp2k, jp2k->image)) ++ if (vips_foreign_load_jp2k_check_supported(jp2k->image)) + return -1; + + /* Tragically, jp2k allows the decoded image to not match the +@@ -1550,8 +1545,12 @@ vips__foreign_load_jp2k_decompress(VipsImage *out, + return -1; + } + ++ if (vips_foreign_load_jp2k_check_supported(decompress.image)) ++ return -1; ++ + if (decompress.image->x1 > width || + decompress.image->y1 > height || ++ decompress.image->numcomps > out->Bands || + line_size * height > to_length) { + vips_error("jp2kload", "%s", ("bad dimensions")); + vips__foreign_load_jp2k_decompress_free(&decompress); +diff --git a/libvips/foreign/tiff2vips.c b/libvips/foreign/tiff2vips.c +index dbdfe67..6c7d21c 100644 +--- a/libvips/foreign/tiff2vips.c ++++ b/libvips/foreign/tiff2vips.c +@@ -2106,7 +2106,13 @@ rtiff_decompress_jpeg_run(Rtiff *rtiff, j_decompress_ptr cinfo, + break; + } + ++ /* bytes_per_pixel from photometric_interpretation must match the number ++ * of components in the JPEG compressed tile. ++ */ + jpeg_calc_output_dimensions(cinfo); ++ if (cinfo->output_components != bytes_per_pixel) ++ return -1; ++ + bytes_per_scanline = (size_t) cinfo->output_width * bytes_per_pixel; + + /* Double-check tile dimensions. diff -Nru vips-8.16.1/debian/patches/CVE-2026-69242.patch vips-8.16.1/debian/patches/CVE-2026-69242.patch --- vips-8.16.1/debian/patches/CVE-2026-69242.patch 1970-01-01 00:00:00.000000000 +0000 +++ vips-8.16.1/debian/patches/CVE-2026-69242.patch 2026-09-30 09:20:35.000000000 +0000 @@ -0,0 +1,24 @@ +From: John Cupitt +Date: Sat, 25 Apr 2026 10:46:27 +0100 +Subject: ensure scanlines fit in INT_MAX + +--- + libvips/iofuncs/image.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/libvips/iofuncs/image.c b/libvips/iofuncs/image.c +index f41b3be..b1f5ed2 100644 +--- a/libvips/iofuncs/image.c ++++ b/libvips/iofuncs/image.c +@@ -708,6 +708,11 @@ vips_image_sanity(VipsObject *object, VipsBuf *buf) + sizeof_image > G_MAXSIZE - 16)) + vips_buf_appends(buf, "dimension overflow\n"); + ++ /* And a scanline has to fit in INT_MAX. ++ */ ++ if (ls >= INT_MAX) ++ vips_buf_appends(buf, "dimension overflow\n"); ++ + /* Must lock around inter-image links. + */ + g_mutex_lock(vips__global_lock); diff -Nru vips-8.16.1/debian/patches/CVE-2026-70651.patch vips-8.16.1/debian/patches/CVE-2026-70651.patch --- vips-8.16.1/debian/patches/CVE-2026-70651.patch 1970-01-01 00:00:00.000000000 +0000 +++ vips-8.16.1/debian/patches/CVE-2026-70651.patch 2026-09-30 09:20:35.000000000 +0000 @@ -0,0 +1,56 @@ +From: John Cupitt +Date: Thu, 14 May 2026 08:38:23 +0100 +Subject: magickload: check animation height (#5040) + +check final image height for imagemagick animation files + +thanks Himanshu Anand +--- + libvips/foreign/magick2vips.c | 11 ++++++++++- + libvips/foreign/magick7load.c | 11 ++++++++++- + 2 files changed, 20 insertions(+), 2 deletions(-) + +diff --git a/libvips/foreign/magick2vips.c b/libvips/foreign/magick2vips.c +index cb1146d..c2e5459 100644 +--- a/libvips/foreign/magick2vips.c ++++ b/libvips/foreign/magick2vips.c +@@ -549,7 +549,16 @@ parse_header(Read *read) + + if (read->n_frames > 1) { + vips_image_set_int(im, VIPS_META_PAGE_HEIGHT, im->Ysize); +- im->Ysize *= read->n_frames; ++ ++ guint64 total_y; ++ if (!g_uint64_checked_mul(&total_y, ++ (guint64)im->Ysize, read->n_frames) || ++ total_y > VIPS_MAX_COORD) { ++ vips_error("magick2vips", "%s", _("image dimensions overflow")); ++ return -1; ++ } ++ ++ im->Ysize = total_y; + } + + vips_image_set_int(im, VIPS_META_N_PAGES, read->n_pages); +diff --git a/libvips/foreign/magick7load.c b/libvips/foreign/magick7load.c +index 45d2819..996cc98 100644 +--- a/libvips/foreign/magick7load.c ++++ b/libvips/foreign/magick7load.c +@@ -618,7 +618,16 @@ vips_foreign_load_magick7_parse(VipsForeignLoadMagick7 *magick7, + */ + if (magick7->n_frames > 1) { + vips_image_set_int(out, VIPS_META_PAGE_HEIGHT, out->Ysize); +- out->Ysize *= magick7->n_frames; ++ ++ guint64 total_y; ++ if (!g_uint64_checked_mul(&total_y, ++ (guint64)out->Ysize, magick7->n_frames) || ++ total_y > VIPS_MAX_COORD) { ++ vips_error(class->nickname, "%s", _("image dimensions overflow")); ++ return -1; ++ } ++ ++ out->Ysize = total_y; + } + + vips_image_set_int(out, VIPS_META_N_PAGES, magick7->n_pages); diff -Nru vips-8.16.1/debian/patches/CVE-2026-70653.patch vips-8.16.1/debian/patches/CVE-2026-70653.patch --- vips-8.16.1/debian/patches/CVE-2026-70653.patch 1970-01-01 00:00:00.000000000 +0000 +++ vips-8.16.1/debian/patches/CVE-2026-70653.patch 2026-09-30 09:20:35.000000000 +0000 @@ -0,0 +1,80 @@ +From: John Cupitt +Date: Tue, 12 May 2026 12:41:44 +0100 +Subject: radload: deprecate old-style RAD load + +Radiance supports an old style of RLE encoding. Don't include this code +if libvips is built with deprecations disabled. + +Thanks Himanshu Anand +--- + libvips/foreign/radiance.c | 46 +++++++++++++++++++++++++--------------------- + 1 file changed, 25 insertions(+), 21 deletions(-) + +diff --git a/libvips/foreign/radiance.c b/libvips/foreign/radiance.c +index 828ce3c..0126a77 100644 +--- a/libvips/foreign/radiance.c ++++ b/libvips/foreign/radiance.c +@@ -364,29 +364,33 @@ getheader(VipsSbuf *sbuf, gethfunc *f, void *p) + static int + scanline_read_old(VipsSbuf *sbuf, COLR *scanline, int width) + { +- int rshift; ++ int rshift = 0; ++ COLR *q = scanline; ++ int n = width; + +- rshift = 0; +- +- while (width > 0) { ++ while (n > 0) { + if (VIPS_SBUF_REQUIRE(sbuf, 4)) + return -1; + +- scanline[0][RED] = VIPS_SBUF_FETCH(sbuf); +- scanline[0][GRN] = VIPS_SBUF_FETCH(sbuf); +- scanline[0][BLU] = VIPS_SBUF_FETCH(sbuf); +- scanline[0][EXP] = VIPS_SBUF_FETCH(sbuf); +- +- if (scanline[0][RED] == 1 && +- scanline[0][GRN] == 1 && +- scanline[0][BLU] == 1) { +- guint i; +- +- for (i = ((guint32) scanline[0][EXP] << rshift); +- i > 0 && width > 0; i--) { +- copycolr(scanline[0], scanline[-1]); +- scanline += 1; +- width -= 1; ++ q[0][RED] = VIPS_SBUF_FETCH(sbuf); ++ q[0][GRN] = VIPS_SBUF_FETCH(sbuf); ++ q[0][BLU] = VIPS_SBUF_FETCH(sbuf); ++ q[0][EXP] = VIPS_SBUF_FETCH(sbuf); ++ ++ if (q[0][RED] == 1 && ++ q[0][GRN] == 1 && ++ q[0][BLU] == 1) { ++ if (q == scanline) { ++ vips_error("rad2vips", ++ "%s", _("RLE repeat at start of scanline")); ++ return -1; ++ } ++ ++ for (guint i = ((guint32) q[0][EXP] << rshift); ++ i > 0 && n > 0; i--) { ++ copycolr(q[0], q[-1]); ++ q += 1; ++ n -= 1; + } + + rshift += 8; +@@ -397,8 +401,8 @@ scanline_read_old(VipsSbuf *sbuf, COLR *scanline, int width) + return -1; + } + else { +- scanline += 1; +- width -= 1; ++ q += 1; ++ n -= 1; + rshift = 0; + } + } diff -Nru vips-8.16.1/debian/patches/CVE-2026-70654.patch vips-8.16.1/debian/patches/CVE-2026-70654.patch --- vips-8.16.1/debian/patches/CVE-2026-70654.patch 1970-01-01 00:00:00.000000000 +0000 +++ vips-8.16.1/debian/patches/CVE-2026-70654.patch 2026-09-30 09:20:35.000000000 +0000 @@ -0,0 +1,24 @@ +From: John Cupitt +Date: Tue, 12 May 2026 12:52:15 +0100 +Subject: source: fix max/min confusion + +Fix a copy-paste typo in vipssource. + +Thanks Himanshu Anand +--- + libvips/iofuncs/source.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/libvips/iofuncs/source.c b/libvips/iofuncs/source.c +index f4c163f..9d34616 100644 +--- a/libvips/iofuncs/source.c ++++ b/libvips/iofuncs/source.c +@@ -933,7 +933,7 @@ vips_source_read_to_memory(VipsSource *source) + gint64 bytes_read; + + bytes_read = vips_source_read(source, q, +- VIPS_MAX(4096, source->length - read_position)); ++ VIPS_MIN(4096, source->length - read_position)); + if (bytes_read == -1) { + VIPS_FREEF(g_byte_array_unref, byte_array); + return -1; diff -Nru vips-8.16.1/debian/patches/series vips-8.16.1/debian/patches/series --- vips-8.16.1/debian/patches/series 2026-04-06 06:22:03.000000000 +0000 +++ vips-8.16.1/debian/patches/series 2026-09-30 09:20:35.000000000 +0000 @@ -4,3 +4,13 @@ CVE-2026-3147.patch CVE-2026-3145_CVE-2026-3146.patch CVE-2026-2913.patch +CVE-2025-59933.patch +CVE-2026-33327.patch +CVE-2026-33328.patch +CVE-2026-35591.patch +CVE-2026-35590.patch +CVE-2026-69242.patch +CVE-2026-70654.patch +CVE-2026-70653.patch +CVE-2026-70651.patch +0016-tiffload-test-for-jp2k-tiles-that-are-too-small.patch