Version in base suite: 0.7.0-10 Base version: jpeg-xl_0.7.0-10 Target version: jpeg-xl_0.7.0-10+deb12u1 Base file: /srv/ftp-master.debian.org/ftp/pool/main/j/jpeg-xl/jpeg-xl_0.7.0-10.dsc Target file: /srv/ftp-master.debian.org/policy/pool/main/j/jpeg-xl/jpeg-xl_0.7.0-10+deb12u1.dsc changelog | 12 +++++ patches/CVE-2023-0645.patch | 51 +++++++++++++++++++++ patches/CVE-2023-35790.patch | 49 +++++++++++++++++++++ patches/CVE-2024-11403.patch | 42 ++++++++++++++++++ patches/CVE-2024-11498.patch | 100 +++++++++++++++++++++++++++++++++++++++++++ patches/series | 4 + 6 files changed, 258 insertions(+) diff -Nru jpeg-xl-0.7.0/debian/changelog jpeg-xl-0.7.0/debian/changelog --- jpeg-xl-0.7.0/debian/changelog 2023-01-29 12:01:36.000000000 +0000 +++ jpeg-xl-0.7.0/debian/changelog 2025-07-03 08:06:10.000000000 +0000 @@ -1,3 +1,15 @@ +jpeg-xl (0.7.0-10+deb12u1) bookworm-security; urgency=high + + * Non-maintainer upload by the Security Team. + * CVE-2023-0645: out of bounds read in the exif handler (Closes: #1034722) + * CVE-2023-35790: integer underflow in patch decoding can lead to a denial + of service issue. (Closes: #1055306) + * CVE-2024-11403: out-of-bounds write in the JPEG decoder when doing + recompression. (Closes: #1088818) + * CVE-2024-11498: stack buffer overflow in modular trees (Closes: #1088818) + + -- Aron Xu Thu, 03 Jul 2025 16:06:10 +0800 + jpeg-xl (0.7.0-10) unstable; urgency=medium * d/patches: Improve cjxl/djxl manpages. Closes: #1023641 diff -Nru jpeg-xl-0.7.0/debian/patches/CVE-2023-0645.patch jpeg-xl-0.7.0/debian/patches/CVE-2023-0645.patch --- jpeg-xl-0.7.0/debian/patches/CVE-2023-0645.patch 1970-01-01 00:00:00.000000000 +0000 +++ jpeg-xl-0.7.0/debian/patches/CVE-2023-0645.patch 2025-07-03 08:05:53.000000000 +0000 @@ -0,0 +1,51 @@ +From a7c8428b61299f3b055cbbdbba3fbcd8cb38d084 Mon Sep 17 00:00:00 2001 +From: a-shvedov <60114847+a-shvedov@users.noreply.github.com> +Date: Wed, 1 Feb 2023 12:17:22 +0300 +Subject: [PATCH] Update exif.h (#2101) + +* Update exif.h + +* Update lib/jxl/exif.h + +Co-authored-by: Moritz Firsching + +* fix AUTHORS + +* fix lint + +--------- + +Co-authored-by: Moritz Firsching +--- + AUTHORS | 1 + + lib/jxl/exif.h | 3 ++- + 2 files changed, 3 insertions(+), 1 deletion(-) + +Index: jpeg-xl-0.7.0/AUTHORS +=================================================================== +--- jpeg-xl-0.7.0.orig/AUTHORS ++++ jpeg-xl-0.7.0/AUTHORS +@@ -16,6 +16,7 @@ Cloudinary Ltd. <*@cloudinary.com> + Google LLC <*@google.com> + + # Individuals: ++a-shvedov + Alex Xu (Hello71) + Alexander Sago + Andrius Lukas Narbutas +Index: jpeg-xl-0.7.0/lib/jxl/exif.h +=================================================================== +--- jpeg-xl-0.7.0.orig/lib/jxl/exif.h ++++ jpeg-xl-0.7.0/lib/jxl/exif.h +@@ -38,9 +38,10 @@ inline size_t FindExifTagPosition(const + bool bigendian; + if (!IsExif(exif, &bigendian)) return 0; + const uint8_t* t = exif.data() + 4; +- uint32_t offset = (bigendian ? LoadBE32(t) : LoadLE32(t)); ++ uint64_t offset = (bigendian ? LoadBE32(t) : LoadLE32(t)); + if (exif.size() < 12 + offset + 2 || offset < 8) return 0; + t += offset - 4; ++ if (offset + 2 >= exif.size()) return 0; + uint16_t nb_tags = (bigendian ? LoadBE16(t) : LoadLE16(t)); + t += 2; + while (nb_tags > 0) { diff -Nru jpeg-xl-0.7.0/debian/patches/CVE-2023-35790.patch jpeg-xl-0.7.0/debian/patches/CVE-2023-35790.patch --- jpeg-xl-0.7.0/debian/patches/CVE-2023-35790.patch 1970-01-01 00:00:00.000000000 +0000 +++ jpeg-xl-0.7.0/debian/patches/CVE-2023-35790.patch 2025-07-03 08:05:22.000000000 +0000 @@ -0,0 +1,49 @@ +From d4e67a644d8babe7cb68de122d8b5ccb2ad8f226 Mon Sep 17 00:00:00 2001 +From: Luca Versari +Date: Fri, 9 Jun 2023 21:26:57 +0200 +Subject: [PATCH] Fix an integer underflow bug in patch decoding. + +When reading patches, the code doesn't properly check that all patches +are in bounds. + +In particular, if the start of a patch becomes negative (due to the +delta coding of patch positions), but not negative *enough* to cause +`start + size` to still be negative, the decoder happily accepted the +patch. Such a patch would then lead the interval tree building code to +run into an infinite loop. +--- + lib/jxl/dec_patch_dictionary.cc | 18 ++++++++++++++---- + 1 file changed, 14 insertions(+), 4 deletions(-) + +diff --git a/lib/jxl/dec_patch_dictionary.cc b/lib/jxl/dec_patch_dictionary.cc +index 85e5de3c..56538bc2 100644 +--- a/lib/jxl/dec_patch_dictionary.cc ++++ b/lib/jxl/dec_patch_dictionary.cc +@@ -107,10 +107,20 @@ Status PatchDictionary::Decode(BitReader* br, size_t xsize, size_t ysize, + pos.x = read_num(kPatchPositionContext); + pos.y = read_num(kPatchPositionContext); + } else { +- pos.x = +- positions_.back().x + UnpackSigned(read_num(kPatchOffsetContext)); +- pos.y = +- positions_.back().y + UnpackSigned(read_num(kPatchOffsetContext)); ++ ssize_t deltax = UnpackSigned(read_num(kPatchOffsetContext)); ++ if (deltax < 0 && static_cast(-deltax) > positions_.back().x) { ++ return JXL_FAILURE("Invalid patch: negative x coordinate (%" PRIuS ++ " base x %" PRIdS " delta x)", ++ positions_.back().x, deltax); ++ } ++ pos.x = positions_.back().x + deltax; ++ ssize_t deltay = UnpackSigned(read_num(kPatchOffsetContext)); ++ if (deltay < 0 && static_cast(-deltay) > positions_.back().y) { ++ return JXL_FAILURE("Invalid patch: negative y coordinate (%" PRIuS ++ " base y %" PRIdS " delta y)", ++ positions_.back().y, deltay); ++ } ++ pos.y = positions_.back().y + deltay; + } + if (pos.x + ref_pos.xsize > xsize) { + return JXL_FAILURE("Invalid patch x: at %" PRIuS " + %" PRIuS +-- +2.39.5 + diff -Nru jpeg-xl-0.7.0/debian/patches/CVE-2024-11403.patch jpeg-xl-0.7.0/debian/patches/CVE-2024-11403.patch --- jpeg-xl-0.7.0/debian/patches/CVE-2024-11403.patch 1970-01-01 00:00:00.000000000 +0000 +++ jpeg-xl-0.7.0/debian/patches/CVE-2024-11403.patch 2025-07-03 08:06:10.000000000 +0000 @@ -0,0 +1,42 @@ +Reviewed-by: Aron Xu + +From 9cc451b91b74ba470fd72bd48c121e9f33d24c99 Mon Sep 17 00:00:00 2001 +From: szabadka <9074039+szabadka@users.noreply.github.com> +Date: Thu, 3 Oct 2024 18:07:38 +0200 +Subject: [PATCH] Port the Huffman lookup table size fix from brunsli. (#3871) + +See also: https://www.youtube.com/watch?v=_ACCK0AUQ8Q&t=696s +--- + lib/jxl/jpeg/enc_jpeg_huffman_decode.h | 16 ++++++++++++---- + 1 file changed, 12 insertions(+), 4 deletions(-) + +diff --git a/lib/jxl/jpeg/enc_jpeg_huffman_decode.h b/lib/jxl/jpeg/enc_jpeg_huffman_decode.h +index b8a60e41..fc9bd17b 100644 +--- a/lib/jxl/jpeg/enc_jpeg_huffman_decode.h ++++ b/lib/jxl/jpeg/enc_jpeg_huffman_decode.h +@@ -15,10 +15,18 @@ namespace jpeg { + + constexpr int kJpegHuffmanRootTableBits = 8; + // Maximum huffman lookup table size. +-// According to zlib/examples/enough.c, 758 entries are always enough for +-// an alphabet of 257 symbols (256 + 1 special symbol for the all 1s code) and +-// max bit length 16 if the root table has 8 bits. +-constexpr int kJpegHuffmanLutSize = 758; ++// Requirements: alphabet of 257 symbols (256 + 1 special symbol for the all 1s ++// code) and max bit length 16, the root table has 8 bits. ++// zlib/examples/enough.c works with an assumption that Huffman code is ++// "complete". Input JPEGs might have this assumption broken, hence the ++// following sum is used as estimate: ++// + number of 1-st level cells ++// + number of symbols ++// + asymptotic amount of repeated 2nd level cells ++// The third number is 1 + 3 + ... + 255 i.e. it is assumed that sub-table of ++// each "size" might be almost completely be filled with repetitions. ++// Total sum is slightly less than 1024,... ++constexpr int kJpegHuffmanLutSize = 1024; + + struct HuffmanTableEntry { + // Initialize the value to an invalid symbol so that we can recognize it +-- +2.39.5 + diff -Nru jpeg-xl-0.7.0/debian/patches/CVE-2024-11498.patch jpeg-xl-0.7.0/debian/patches/CVE-2024-11498.patch --- jpeg-xl-0.7.0/debian/patches/CVE-2024-11498.patch 1970-01-01 00:00:00.000000000 +0000 +++ jpeg-xl-0.7.0/debian/patches/CVE-2024-11498.patch 2025-07-03 08:06:10.000000000 +0000 @@ -0,0 +1,100 @@ +Reviewed-by: Aron Xu + +From bf4781a2eed2eef664790170977d1d3d8347efb9 Mon Sep 17 00:00:00 2001 +From: Luca Versari +Date: Thu, 21 Nov 2024 16:33:08 +0100 +Subject: [PATCH] Check height limit in modular trees. (#3943) + +Also rewrite the implementation to use iterative checking instead of +recursive checking of tree property values, to ensure stack usage is +low. + +Before, it was possible for appropriately-crafted files to use a +significant amount of stack (in the order of hundreds of MB). +--- + lib/jxl/modular/encoding/dec_ma.cc | 66 ++++++++++++++++++++---------- + 1 file changed, 45 insertions(+), 21 deletions(-) + +Index: jpeg-xl-0.7.0/lib/jxl/modular/encoding/dec_ma.cc +=================================================================== +--- jpeg-xl-0.7.0.orig/lib/jxl/modular/encoding/dec_ma.cc ++++ jpeg-xl-0.7.0/lib/jxl/modular/encoding/dec_ma.cc +@@ -14,23 +14,49 @@ namespace jxl { + + namespace { + +-Status ValidateTree( +- const Tree &tree, +- const std::vector> &prop_bounds, +- size_t root) { +- if (tree[root].property == -1) return true; +- size_t p = tree[root].property; +- int val = tree[root].splitval; +- if (prop_bounds[p].first > val) return JXL_FAILURE("Invalid tree"); +- // Splitting at max value makes no sense: left range will be exactly same +- // as parent, right range will be invalid (min > max). +- if (prop_bounds[p].second <= val) return JXL_FAILURE("Invalid tree"); +- auto new_bounds = prop_bounds; +- new_bounds[p].first = val + 1; +- JXL_RETURN_IF_ERROR(ValidateTree(tree, new_bounds, tree[root].lchild)); +- new_bounds[p] = prop_bounds[p]; +- new_bounds[p].second = val; +- return ValidateTree(tree, new_bounds, tree[root].rchild); ++Status ValidateTree(const Tree &tree) { ++ int num_properties = 0; ++ for (auto node : tree) { ++ if (node.property >= num_properties) { ++ num_properties = node.property + 1; ++ } ++ } ++ std::vector height(tree.size()); ++ std::vector> property_ranges( ++ num_properties * tree.size()); ++ for (int i = 0; i < num_properties; i++) { ++ property_ranges[i].first = std::numeric_limits::min(); ++ property_ranges[i].second = std::numeric_limits::max(); ++ } ++ const int kHeightLimit = 2048; ++ for (size_t i = 0; i < tree.size(); i++) { ++ if (height[i] > kHeightLimit) { ++ return JXL_FAILURE("Tree too tall: %d", height[i]); ++ } ++ if (tree[i].property == -1) continue; ++ height[tree[i].lchild] = height[i] + 1; ++ height[tree[i].rchild] = height[i] + 1; ++ for (size_t p = 0; p < static_cast(num_properties); p++) { ++ if (p == static_cast(tree[i].property)) { ++ pixel_type l = property_ranges[i * num_properties + p].first; ++ pixel_type u = property_ranges[i * num_properties + p].second; ++ pixel_type val = tree[i].splitval; ++ if (l > val || u <= val) { ++ return JXL_FAILURE("Invalid tree"); ++ } ++ property_ranges[tree[i].lchild * num_properties + p] = ++ std::make_pair(val + 1, u); ++ property_ranges[tree[i].rchild * num_properties + p] = ++ std::make_pair(l, val); ++ } else { ++ property_ranges[tree[i].lchild * num_properties + p] = ++ property_ranges[i * num_properties + p]; ++ property_ranges[tree[i].rchild * num_properties + p] = ++ property_ranges[i * num_properties + p]; ++ } ++ } ++ } ++ return true; + } + + Status DecodeTree(BitReader *br, ANSSymbolReader *reader, +@@ -79,10 +105,7 @@ Status DecodeTree(BitReader *br, ANSSymb + tree->size() + to_decode + 2, Predictor::Zero, 0, 1); + to_decode += 2; + } +- std::vector> prop_bounds; +- prop_bounds.resize(256, {std::numeric_limits::min(), +- std::numeric_limits::max()}); +- return ValidateTree(*tree, prop_bounds, 0); ++ return ValidateTree(*tree); + } + } // namespace + diff -Nru jpeg-xl-0.7.0/debian/patches/series jpeg-xl-0.7.0/debian/patches/series --- jpeg-xl-0.7.0/debian/patches/series 2023-01-29 11:59:42.000000000 +0000 +++ jpeg-xl-0.7.0/debian/patches/series 2025-07-03 08:05:41.000000000 +0000 @@ -4,3 +4,7 @@ de08116d14db785431f3efb651dcf2af15bbb682.patch 1a36db0bf452a2232f0a15d7d8edb542e8196401.patch manpages.patch +CVE-2023-0645.patch +CVE-2023-35790.patch +CVE-2024-11403.patch +CVE-2024-11498.patch