diff --git a/meta-multimedia/recipes-multimedia/libheif/libheif/CVE-2026-62289.patch b/meta-multimedia/recipes-multimedia/libheif/libheif/CVE-2026-62289.patch new file mode 100644 index 0000000000..5473a2ae18 --- /dev/null +++ b/meta-multimedia/recipes-multimedia/libheif/libheif/CVE-2026-62289.patch @@ -0,0 +1,189 @@ +From 49e188ca7a6a81fd1c7d5e76254308c82cbcb5c3 Mon Sep 17 00:00:00 2001 +From: Dirk Farin +Date: Thu, 25 Jun 2026 19:58:57 +0200 +Subject: [PATCH] Fix clap transform double-application in image tiling + (GHSA-jc8f-p23p-5hjg) + +The base ImageItem::get_heif_image_tiling() returned the already +transformed m_width/m_height, but process_image_transformations_on_tiling() +applies the transformative properties (irot, imir, clap) itself. This +applied every transform twice. For a clap that rounds the image down to +zero, the second application passed 0 into Box_clap::left_rounded(), where +`image_width - 1U` underflowed to UINT32_MAX and overflowed the Fraction +constructor (assert abort in debug builds, corrupt crop in release builds). +The grid, unc and tiled overrides already return coded dimensions, so the +base class was the lone outlier. + +Fixes, in three layers: + + - image_item.cc: base get_heif_image_tiling() now reports coded (ispe) + dimensions when available, matching the other overrides, so transforms + are applied exactly once. This also fixes a silent irot/imir + double-transform on the same path. + - context.cc: reject a clap that rounds a dimension to zero or less at + parse time, mirroring the existing ispe zero-size check. + - box.cc: guard left_rounded()/top_rounded() against a zero image + dimension as defense in depth. + +Add tests/clap_zero_size.cc covering the hardened clap helpers. + +(cherry picked from commit f01870c1d7323a3003796d58eba7fff502be994c) + +CVE: CVE-2026-62289 +Upstream-Status: Backport [https://github.com/strukturag/libheif/commit/f01870c1d7323a3003796d58eba7fff502be994c] +Signed-off-by: Ankur Tyagi +--- + libheif/box.cc | 11 ++++++++ + libheif/context.cc | 12 +++++++-- + libheif/image-items/image_item.cc | 23 ++++++++++++++--- + tests/CMakeLists.txt | 1 + + tests/clap_zero_size.cc | 42 +++++++++++++++++++++++++++++++ + 5 files changed, 83 insertions(+), 6 deletions(-) + create mode 100644 tests/clap_zero_size.cc + +diff --git a/libheif/box.cc b/libheif/box.cc +index 76ba0f0a..57912ab0 100644 +--- a/libheif/box.cc ++++ b/libheif/box.cc +@@ -3592,6 +3592,12 @@ int Box_clap::left_rounded(uint32_t image_width) const + + // left = horizOff + (width-1)/2 - (clapWidth-1)/2 + ++ // Guard against image_width==0: `image_width - 1U` would underflow to ++ // UINT32_MAX and overflow the Fraction (GHSA-jc8f-p23p-5hjg). ++ if (image_width == 0) { ++ return 0; ++ } ++ + Fraction pcX = m_horizontal_offset + Fraction(image_width - 1U, 2U); + Fraction left = pcX - (m_clean_aperture_width - 1) / 2; + +@@ -3607,6 +3613,11 @@ int Box_clap::right_rounded(uint32_t image_width) const + + int Box_clap::top_rounded(uint32_t image_height) const + { ++ // Guard against image_height==0 underflowing the Fraction (see left_rounded). ++ if (image_height == 0) { ++ return 0; ++ } ++ + Fraction pcY = m_vertical_offset + Fraction(image_height - 1U, 2U); + Fraction top = pcY - (m_clean_aperture_height - 1) / 2; + +diff --git a/libheif/context.cc b/libheif/context.cc +index a1bcc268..a3371207 100644 +--- a/libheif/context.cc ++++ b/libheif/context.cc +@@ -644,8 +644,16 @@ Error HeifContext::interpret_heif_file_images() + for (const auto& prop : properties) { + auto clap = std::dynamic_pointer_cast(prop); + if (clap) { +- image->set_resolution(clap->get_width_rounded(), +- clap->get_height_rounded()); ++ int clap_width = clap->get_width_rounded(); ++ int clap_height = clap->get_height_rounded(); ++ if (clap_width <= 0 || clap_height <= 0) { ++ return {heif_error_Invalid_input, ++ heif_suberror_Invalid_clean_aperture, ++ "Clean aperture (clap) reduces image to zero size"}; ++ } ++ ++ image->set_resolution(static_cast(clap_width), ++ static_cast(clap_height)); + + if (image->has_intrinsic_matrix()) { + image->get_intrinsic_matrix().apply_clap(clap.get(), image->get_width(), image->get_height()); +diff --git a/libheif/image-items/image_item.cc b/libheif/image-items/image_item.cc +index e803107f..d05536e1 100644 +--- a/libheif/image-items/image_item.cc ++++ b/libheif/image-items/image_item.cc +@@ -967,10 +967,25 @@ heif_image_tiling ImageItem::get_heif_image_tiling() const + tiling.num_columns = 1; + tiling.num_rows = 1; + +- tiling.tile_width = m_width; +- tiling.tile_height = m_height; +- tiling.image_width = m_width; +- tiling.image_height = m_height; ++ // Report the coded (pre-transformation) dimensions here. The caller applies ++ // the transformative properties (irot, imir, clap) via ++ // process_image_transformations_on_tiling(), so handing it the already ++ // transformed m_width/m_height would apply them a second time. For a clap ++ // that shrinks the image to zero this double application underflowed inside ++ // Box_clap::left_rounded() (GHSA-jc8f-p23p-5hjg); for irot/imir it silently ++ // produced wrong dimensions. The grid/unc/tiled overrides likewise report ++ // coded dimensions. ++ uint32_t coded_width = m_width; ++ uint32_t coded_height = m_height; ++ if (has_ispe_resolution()) { ++ coded_width = get_ispe_width(); ++ coded_height = get_ispe_height(); ++ } ++ ++ tiling.tile_width = coded_width; ++ tiling.tile_height = coded_height; ++ tiling.image_width = coded_width; ++ tiling.image_height = coded_height; + + tiling.top_offset = 0; + tiling.left_offset = 0; +diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt +index d8fdfd8b..b52bc202 100644 +--- a/tests/CMakeLists.txt ++++ b/tests/CMakeLists.txt +@@ -38,6 +38,7 @@ if (WITH_REDUCED_VISIBILITY) + else() + add_libheif_test(bitstream_tests) + add_libheif_test(box_equals) ++ add_libheif_test(clap_zero_size) + add_libheif_test(conversion) + add_libheif_test(idat) + add_libheif_test(jpeg2000) +diff --git a/tests/clap_zero_size.cc b/tests/clap_zero_size.cc +new file mode 100644 +index 00000000..eafc1258 +--- /dev/null ++++ b/tests/clap_zero_size.cc +@@ -0,0 +1,42 @@ ++/* ++ libheif clean aperture (clap) zero-size unit tests ++ ++ MIT License ++ ++ Copyright (c) 2026 Dirk Farin ++ ++ Permission is hereby granted, free of charge, to any person obtaining a copy ++ of this software and associated documentation files (the "Software"), to deal ++ in the Software without restriction, including without limitation the rights ++ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell ++ copies of the Software, and to permit persons to whom the Software is ++ furnished to do so, subject to the following conditions: ++ ++ The above copyright notice and this permission notice shall be included in all ++ copies or substantial portions of the Software. ++ ++ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, ++ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE ++ SOFTWARE. ++*/ ++ ++#include "catch_amalgamated.hpp" ++#include "box.h" ++ ++// Regression test for GHSA-jc8f-p23p-5hjg: passing a zero image dimension to ++// the clap rounding helpers used to underflow `image_width - 1U` to UINT32_MAX, ++// which overflowed the Fraction constructor (assert abort in debug builds, ++// corrupt crop in release builds). They must now return 0 without aborting. ++TEST_CASE("clap rounding with zero image size") { ++ std::shared_ptr clap = std::make_shared(); ++ clap->set(100, 200, 150, 250); // clap 100x200 inside a 150x250 image ++ ++ REQUIRE(clap->left_rounded(0) == 0); ++ REQUIRE(clap->right_rounded(0) == 99); // clapWidth - 1 + left(0) ++ REQUIRE(clap->top_rounded(0) == 0); ++ REQUIRE(clap->bottom_rounded(0) == 199); // clapHeight - 1 + top(0) ++} diff --git a/meta-multimedia/recipes-multimedia/libheif/libheif_1.21.2.bb b/meta-multimedia/recipes-multimedia/libheif/libheif_1.21.2.bb index f3f03abdc7..1dfab46513 100644 --- a/meta-multimedia/recipes-multimedia/libheif/libheif_1.21.2.bb +++ b/meta-multimedia/recipes-multimedia/libheif/libheif_1.21.2.bb @@ -14,6 +14,7 @@ SRC_URI = "git://github.com/strukturag/libheif.git;protocol=https;branch=master; file://CVE-2026-32741.patch \ file://CVE-2026-41071-1.patch \ file://CVE-2026-41071-2.patch \ + file://CVE-2026-62289.patch \ " SRCREV = "62f1b8c76ed4d8305071fdacbe74ef9717bacac5"