Commit 7e085d5f for libheif

commit 7e085d5fae54cc427d9dd1809c057d722d3daa92
Author: Darren Carreras <carrerasdarren@gmail.com>
Date:   Fri Aug 21 08:22:20 2026 -0400

    Validate AVC SPS variable-length fields

diff --git a/libheif/codecs/avc_boxes.cc b/libheif/codecs/avc_boxes.cc
index d37808ca..3f3090f5 100644
--- a/libheif/codecs/avc_boxes.cc
+++ b/libheif/codecs/avc_boxes.cc
@@ -302,7 +302,7 @@ void Box_avcC::append_pps_nal(const uint8_t* data, size_t size)
   m_pps.emplace_back(std::move(vec));
 }

-void skip_scaling_list(BitReader& reader, int sizeOfScalingList)
+static bool skip_scaling_list(BitReader& reader, int sizeOfScalingList)
 {
   int lastScale = 8;
   int nextScale = 8;
@@ -314,8 +314,10 @@ void skip_scaling_list(BitReader& reader, int sizeOfScalingList)
   // original version
   for (int j = 0; j < sizeOfScalingList; j++) {
     if (nextScale != 0) {
-      int delta_scale;
-      reader.get_svlc(&delta_scale);
+      int32_t delta_scale;
+      if (!reader.get_svlc(&delta_scale)) {
+        return false;
+      }
       nextScale = (lastScale + delta_scale + 256) % 256;
     }

@@ -325,7 +327,9 @@ void skip_scaling_list(BitReader& reader, int sizeOfScalingList)
   // fast version
   for (int j = 0; j < sizeOfScalingList; j++) {
     int32_t delta_scale;
-    reader.get_svlc(&delta_scale);
+    if (!reader.get_svlc(&delta_scale)) {
+      return false;
+    }
     nextScale = (lastScale + delta_scale + 256) % 256;

     if (nextScale == 0) {
@@ -335,6 +339,8 @@ void skip_scaling_list(BitReader& reader, int sizeOfScalingList)
     lastScale = nextScale;
   }
 #endif
+
+  return true;
 }


@@ -376,7 +382,15 @@ Error parse_sps_for_avcC_configuration(const uint8_t* sps, size_t size,
       return invalidUVLC;
     }

-    config->chroma_format = (heif_chroma) value;
+    if (value > heif_chroma_444) {
+      return {
+        heif_error_Invalid_input,
+        heif_suberror_Unspecified,
+        "Invalid chroma format in AVC SPS header"
+      };
+    }
+
+    config->chroma_format = static_cast<heif_chroma>(value);
     if (config->chroma_format == heif_chroma_444) {
       reader.skip_bits(1);
     }
@@ -397,11 +411,8 @@ Error parse_sps_for_avcC_configuration(const uint8_t* sps, size_t size,
       for (int i = 0; i < ((config->chroma_format != heif_chroma_444) ? 8 : 12); i++) {
         int scaling_list_present_flag = reader.get_bits(1);
         if (scaling_list_present_flag) {
-          if (i < 6) {
-            skip_scaling_list(reader, 16);
-          }
-          else {
-            skip_scaling_list(reader, 64);
+          if (!skip_scaling_list(reader, i < 6 ? 16 : 64)) {
+            return invalidUVLC;
           }
         }
       }
diff --git a/tests/avc_box.cc b/tests/avc_box.cc
index 771ded2e..b5f0edd2 100644
--- a/tests/avc_box.cc
+++ b/tests/avc_box.cc
@@ -82,3 +82,31 @@ TEST_CASE("avcC") {
   const std::vector<uint8_t> bytes = writer.get_data();
   REQUIRE(bytes == byteArray);
 }
+
+TEST_CASE("Reject invalid chroma format in AVC SPS") {
+  const std::vector<uint8_t> sps{
+      0x20, 0x2c, 0x20, 0x20, 0x00, 0x20, 0x20, 0x00, 0x20, 0x20, 0x20, 0x20,
+      0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20};
+  Box_avcC::configuration configuration;
+  uint32_t width = 0;
+  uint32_t height = 0;
+
+  Error error = parse_sps_for_avcC_configuration(
+      sps.data(), sps.size(), &configuration, &width, &height);
+
+  REQUIRE(error.error_code == heif_error_Invalid_input);
+}
+
+TEST_CASE("Reject invalid code in AVC SPS scaling list") {
+  std::vector<uint8_t> sps{
+      0x67, 0x64, 0x00, 0x1f, 0xad, 0x80, 0x00, 0x00, 0x00, 0x3f};
+  sps.insert(sps.end(), 40, 0xff);
+  Box_avcC::configuration configuration;
+  uint32_t width = 0;
+  uint32_t height = 0;
+
+  Error error = parse_sps_for_avcC_configuration(
+      sps.data(), sps.size(), &configuration, &width, &height);
+
+  REQUIRE(error.error_code == heif_error_Invalid_input);
+}