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);
+}