Commit f4943490 for libheif
commit f4943490a60e8feddf937ad0f08486fff565132d
Author: Dirk Farin <dirk.farin@gmail.com>
Date: Sun Dec 28 00:42:09 2025 +0100
check for cyclic 'iref' references, but only follow 'dimg' links (clusterfuzz 471853412)
diff --git a/libheif/box.cc b/libheif/box.cc
index 27602ff7..ed38b3a9 100644
--- a/libheif/box.cc
+++ b/libheif/box.cc
@@ -3700,8 +3700,8 @@ Error Box_iref::parse(BitstreamRange& range, const heif_security_limits* limits)
}
-#if 0
- // Note: This input sanity check does not work as expected.
+#if 1
+ // Note: This input sanity check first did not work as expected.
// Its idea was to prevent infinite recursions while decoding when the input file
// contains cyclic references. However, apparently there are cases where cyclic
// references are actually allowed, like with images that have premultiplied alpha channels:
@@ -3710,6 +3710,8 @@ Error Box_iref::parse(BitstreamRange& range, const heif_security_limits* limits)
// | reference with type 'auxl' from ID: 2 to IDs: 1
// | reference with type 'prem' from ID: 1 to IDs: 2
//
+ // We now only follow 'dimg' references. This should be free from cyclic references.
+ //
// TODO: implement the infinite recursion detection in a different way. E.g. by passing down
// the already processed item-ids while decoding an image and checking whether the current
// item has already been decoded before.
@@ -3717,6 +3719,10 @@ Error Box_iref::parse(BitstreamRange& range, const heif_security_limits* limits)
// --- check for cyclic references
for (const auto& ref : m_references) {
+ if (ref.header.get_short_type() != fourcc("dimg")) {
+ continue;
+ }
+
std::set<heif_item_id> reached_ids; // IDs that we have already reached in the DAG
std::set<heif_item_id> todo; // IDs that still need to be followed
@@ -3731,6 +3737,10 @@ Error Box_iref::parse(BitstreamRange& range, const heif_security_limits* limits)
// if this ID refers to another 'iref', follow it
for (const auto& succ_ref : m_references) {
+ if (succ_ref.header.get_short_type() != fourcc("dimg")) {
+ continue;
+ }
+
if (succ_ref.from_item_ID == id) {
// Check whether any successor IDs has been visited yet, which would be an error.
@@ -3740,7 +3750,7 @@ Error Box_iref::parse(BitstreamRange& range, const heif_security_limits* limits)
if (reached_ids.find(succ_ref_id) != reached_ids.end()) {
return Error(heif_error_Invalid_input,
heif_suberror_Unspecified,
- "'iref' has cyclic references");
+ "'iref' has cyclic 'dimg' references");
}
todo.insert(succ_ref_id);