From 338a9e4f2066b7e6a8d3fec88a76a026e31c6508 Mon Sep 17 00:00:00 2001 From: Dirk Farin Date: Sun, 20 Oct 2024 16:52:51 +0200 Subject: [PATCH] fix bits/bytes confusion and disable security limits for edge-case test --- libheif/api/libheif/heif.cc | 6 ++++++ libheif/api/libheif/heif.h | 4 ++++ libheif/bitstream.cc | 2 ++ libheif/codecs/uncompressed/unc_boxes.cc | 18 +++++++++--------- libheif/security_limits.cc | 5 +++++ libheif/security_limits.h | 1 + tests/uncompressed_box.cc | 2 +- 7 files changed, 28 insertions(+), 10 deletions(-) diff --git a/libheif/api/libheif/heif.cc b/libheif/api/libheif/heif.cc index 3a328223e6..64b74c8f9d 100644 --- a/libheif/api/libheif/heif.cc +++ b/libheif/api/libheif/heif.cc @@ -512,6 +512,12 @@ const struct heif_security_limits* heif_get_global_security_limits() } +const struct heif_security_limits* heif_get_disabled_security_limits() +{ + return &disabled_security_limits; +} + + struct heif_security_limits* heif_context_get_security_limits(const struct heif_context* ctx) { if (!ctx) { diff --git a/libheif/api/libheif/heif.h b/libheif/api/libheif/heif.h index 9c6fc36dad..4a7e0b2604 100644 --- a/libheif/api/libheif/heif.h +++ b/libheif/api/libheif/heif.h @@ -1149,6 +1149,10 @@ struct heif_security_limits { LIBHEIF_API const struct heif_security_limits* heif_get_global_security_limits(); +// Returns a set of fully disabled security limits. Use with care and only after user confirmation. +LIBHEIF_API +const struct heif_security_limits* heif_get_disabled_security_limits(); + // Returns the security limits for a heif_context. // By default, the limits are set to the global limits, but you can change them in the returned object. LIBHEIF_API diff --git a/libheif/bitstream.cc b/libheif/bitstream.cc index d0962750ec..bdaa31bfa5 100644 --- a/libheif/bitstream.cc +++ b/libheif/bitstream.cc @@ -280,6 +280,8 @@ uint64_t BitstreamRange::read_uint(int len) return read8(); case 16: return read16(); + case 24: + return read24(); case 32: return read32(); case 64: diff --git a/libheif/codecs/uncompressed/unc_boxes.cc b/libheif/codecs/uncompressed/unc_boxes.cc index 4485ed7c19..a5077289b9 100644 --- a/libheif/codecs/uncompressed/unc_boxes.cc +++ b/libheif/codecs/uncompressed/unc_boxes.cc @@ -487,8 +487,8 @@ Error Box_cmpC::write(StreamWriter& writer) const } -static uint8_t unit_offset_length_table[] = { 0,2,3,4,8 }; -static uint8_t unit_size_length_table[] = { 1,2,3,4,8 }; +static uint8_t unit_offset_bits_table[] = {0, 16, 24, 32, 64 }; +static uint8_t unit_size_bits_table[] = {8, 16, 24, 32, 64 }; Error Box_icef::parse(BitstreamRange& range, const heif_security_limits* limits) { @@ -513,14 +513,14 @@ Error Box_icef::parse(BitstreamRange& range, const heif_security_limits* limits) // --- precompute fields lengths - uint8_t unit_offset_length = unit_offset_length_table[unit_offset_code]; - uint8_t unit_size_length = unit_size_length_table[unit_size_code]; + uint8_t unit_offset_bits = unit_offset_bits_table[unit_offset_code]; + uint8_t unit_size_bits = unit_size_bits_table[unit_size_code]; // --- check if box is large enough for all the data - uint64_t data_size = num_compressed_units * (unit_offset_length + unit_size_length); - if (data_size > range.get_remaining_bytes()) { - uint64_t contained_units = range.get_remaining_bytes() / (unit_offset_length + unit_size_length); + uint64_t data_size_bytes = num_compressed_units * (unit_offset_bits + unit_size_bits) / 8; + if (data_size_bytes > range.get_remaining_bytes()) { + uint64_t contained_units = range.get_remaining_bytes() / ((unit_offset_bits + unit_size_bits) * 8); std::stringstream sstr; sstr << "icef box declares " << num_compressed_units << " units, but only " << contained_units << " were contained in the file"; @@ -540,10 +540,10 @@ Error Box_icef::parse(BitstreamRange& range, const heif_security_limits* limits) if (unit_offset_code == 0) { unitInfo.unit_offset = implied_offset; } else { - unitInfo.unit_offset = range.read_uint(unit_offset_length); + unitInfo.unit_offset = range.read_uint(unit_offset_bits); } - unitInfo.unit_size = range.read_uint(unit_size_length); + unitInfo.unit_size = range.read_uint(unit_size_bits); if (unitInfo.unit_size >= UINT64_MAX - implied_offset) { return {heif_error_Invalid_input, diff --git a/libheif/security_limits.cc b/libheif/security_limits.cc index fb3880305f..56b03a6450 100644 --- a/libheif/security_limits.cc +++ b/libheif/security_limits.cc @@ -45,6 +45,11 @@ struct heif_security_limits global_security_limits { }; +struct heif_security_limits disabled_security_limits{ + .version = 1 +}; + + Error check_for_valid_image_size(const heif_security_limits* limits, uint32_t width, uint32_t height) { uint64_t maximum_image_size_limit = limits->max_image_size_pixels; diff --git a/libheif/security_limits.h b/libheif/security_limits.h index aece26191e..bcb11c6331 100644 --- a/libheif/security_limits.h +++ b/libheif/security_limits.h @@ -27,6 +27,7 @@ extern heif_security_limits global_security_limits; +extern heif_security_limits disabled_security_limits; // Maximum nesting level of boxes in input files. // We put a limit on this to avoid unlimited stack usage by malicious input files. diff --git a/tests/uncompressed_box.cc b/tests/uncompressed_box.cc index c717f2d8be..aa155e7763 100644 --- a/tests/uncompressed_box.cc +++ b/tests/uncompressed_box.cc @@ -296,7 +296,7 @@ TEST_CASE("uncC_parse_no_overflow") { BitstreamRange range(reader, byteArray.size()); std::shared_ptr box; - Error error = Box::read(range, &box, heif_get_global_security_limits()); + Error error = Box::read(range, &box, heif_get_disabled_security_limits()); REQUIRE(error == Error::Ok); REQUIRE(range.error() == 0);