Commit b182ac87 for libheif
commit b182ac87d5f45a4c0098c26e0ea381b23425dd8a
Author: Dirk Farin <dirk.farin@gmail.com>
Date: Sat Mar 28 00:10:07 2026 +0100
check validity of number of tilC tiles against overflow and security limits
diff --git a/libheif/api/libheif/heif_context.cc b/libheif/api/libheif/heif_context.cc
index f0985061..b45595c2 100644
--- a/libheif/api/libheif/heif_context.cc
+++ b/libheif/api/libheif/heif_context.cc
@@ -270,7 +270,10 @@ heif_error heif_context_write(heif_context* ctx,
}
StreamWriter swriter;
- ctx->context->write(swriter);
+ Error err = ctx->context->write(swriter);
+ if (err) {
+ return err.error_struct(ctx->context.get());
+ }
const auto& data = swriter.get_data();
heif_error writer_error = writer->write(ctx, data.data(), data.size(), userdata);
diff --git a/libheif/context.cc b/libheif/context.cc
index 943eb40f..8b7841c3 100644
--- a/libheif/context.cc
+++ b/libheif/context.cc
@@ -328,7 +328,7 @@ static uint64_t rescale(uint64_t duration, uint32_t old_base, uint32_t new_base)
}
-void HeifContext::write(StreamWriter& writer)
+Error HeifContext::write(StreamWriter& writer)
{
// --- finalize some parameters
@@ -389,7 +389,9 @@ void HeifContext::write(StreamWriter& writer)
for (auto& region : m_region_items) {
std::vector<uint8_t> data_array;
Error err = region->encode(data_array);
- // TODO: err
+ if (err) {
+ return err;
+ }
m_heif_file->append_iloc_data(region->item_id, data_array, 0);
}
@@ -412,7 +414,10 @@ void HeifContext::write(StreamWriter& writer)
// --- post-process images
for (auto& img : m_all_images) {
- img.second->process_before_write();
+ Error err = img.second->process_before_write();
+ if (err) {
+ return err;
+ }
}
// --- sort item properties
@@ -452,6 +457,8 @@ void HeifContext::write(StreamWriter& writer)
// --- write to file
m_heif_file->write(writer);
+
+ return {};
}
std::string HeifContext::debug_dump_boxes() const
diff --git a/libheif/context.h b/libheif/context.h
index de1bb859..0cc58034 100644
--- a/libheif/context.h
+++ b/libheif/context.h
@@ -136,7 +136,7 @@ public:
// === writing ===
- void write(StreamWriter& writer);
+ [[nodiscard]] Error write(StreamWriter& writer);
// Create all boxes necessary for an empty HEIF file.
// Note that this is no valid HEIF file, since some boxes (e.g. pitm) are generated, but
diff --git a/libheif/image-items/image_item.h b/libheif/image-items/image_item.h
index 8c0abe8e..389ff747 100644
--- a/libheif/image-items/image_item.h
+++ b/libheif/image-items/image_item.h
@@ -170,7 +170,7 @@ public:
Error postprocess_coded_image_colorspace(heif_colorspace* inout_colorspace, heif_chroma* inout_chroma) const;
- virtual void process_before_write() { }
+ virtual Error process_before_write() { return {}; }
// -- thumbnails
diff --git a/libheif/image-items/tiled.cc b/libheif/image-items/tiled.cc
index 5eef9af8..4ae467ef 100644
--- a/libheif/image-items/tiled.cc
+++ b/libheif/image-items/tiled.cc
@@ -42,7 +42,7 @@ static uint64_t readvec(const std::vector<uint8_t>& data, size_t& ptr, int len)
}
-uint64_t number_of_tiles(const heif_tiled_image_parameters& params)
+Result<uint64_t> number_of_tiles(const heif_tiled_image_parameters& params, const heif_security_limits* limits)
{
uint64_t nTiles = nTiles_h(params) * static_cast<uint64_t>(nTiles_v(params));
@@ -52,7 +52,32 @@ uint64_t number_of_tiles(const heif_tiled_image_parameters& params)
break;
}
+ if (params.extra_dimensions[i] != 0 &&
+ nTiles > UINT64_MAX / params.extra_dimensions[i]) {
+ return Error{
+ heif_error_Unsupported_filetype,
+ heif_suberror_Unspecified,
+ "Number of tiles exceeds uint64 maximum."
+ };
+ }
+
+ if (params.extra_dimensions[i] == 0) {
+ return Error{
+ heif_error_Unsupported_filetype,
+ heif_suberror_Unspecified,
+ "Zero extra dimension size."
+ };
+ }
+
nTiles *= params.extra_dimensions[i];
+
+ if (limits && nTiles > limits->max_number_of_tiles) {
+ return Error{
+ heif_error_Unsupported_filetype,
+ heif_suberror_Security_limit_exceeded,
+ "Number of tiles exceeds security limit"
+ };
+ }
}
return nTiles;
@@ -305,15 +330,12 @@ Error TiledHeader::set_parameters(const heif_tiled_image_parameters& params)
{
m_parameters = params;
- auto max_tiles = heif_get_global_security_limits()->max_number_of_tiles;
-
- if (max_tiles && number_of_tiles(params) > max_tiles) {
- return {heif_error_Unsupported_filetype,
- heif_suberror_Security_limit_exceeded,
- "Number of tiles exceeds security limit"};
+ Result<uint64_t> num_tiles_result = number_of_tiles(params, heif_get_global_security_limits());
+ if (auto err = num_tiles_result.error()) {
+ return err;
}
- m_offsets.resize(number_of_tiles(params));
+ m_offsets.resize(*num_tiles_result);
for (auto& tile: m_offsets) {
tile.offset = TILD_OFFSET_NOT_LOADED;
@@ -325,16 +347,12 @@ Error TiledHeader::set_parameters(const heif_tiled_image_parameters& params)
Error TiledHeader::read_full_offset_table(const std::shared_ptr<HeifFile>& file, heif_item_id tild_id, const heif_security_limits* limits)
{
- auto max_tiles = heif_get_global_security_limits()->max_number_of_tiles;
-
- uint64_t nTiles = number_of_tiles(m_parameters);
- if (max_tiles && nTiles > max_tiles) {
- return {heif_error_Invalid_input,
- heif_suberror_Security_limit_exceeded,
- "Number of tiles exceeds security limit."};
+ Result<uint64_t> nTiles_result = number_of_tiles(m_parameters, limits);
+ if (auto err = nTiles_result.error()) {
+ return err;
}
- return read_offset_table_range(file, tild_id, 0, nTiles);
+ return read_offset_table_range(file, tild_id, 0, *nTiles_result);
}
@@ -440,12 +458,16 @@ void writevec(uint8_t* data, size_t& idx, I value, int len)
}
-std::vector<uint8_t> TiledHeader::write_offset_table()
+Result<std::vector<uint8_t>> TiledHeader::write_offset_table()
{
- uint64_t nTiles = number_of_tiles(m_parameters);
+ Result<uint64_t> nTiles_result = number_of_tiles(m_parameters, nullptr);
+ if (auto err = nTiles_result.error()) {
+ return err;
+ }
+
int offset_entry_size = (m_parameters.offset_field_length + m_parameters.size_field_length) / 8;
- uint64_t size = nTiles * offset_entry_size;
+ uint64_t size = *nTiles_result * offset_entry_size;
std::vector<uint8_t> data;
data.resize(size);
@@ -642,14 +664,11 @@ ImageItem_Tiled::add_new_tiled_item(HeifContext* ctx, const heif_tiled_image_par
const heif_encoder* encoder,
const heif_encoding_options* encoding_options)
{
- auto max_tild_tiles = ctx->get_security_limits()->max_number_of_tiles;
- if (max_tild_tiles && number_of_tiles(*parameters) > max_tild_tiles) {
- return Error{heif_error_Usage_error,
- heif_suberror_Security_limit_exceeded,
- "Number of tiles exceeds security limit."};
+ Result<uint64_t> num_tiles_result = number_of_tiles(*parameters, ctx->get_security_limits());
+ if (auto err = num_tiles_result.error()) {
+ return err;
}
-
// Create 'tili' Item
auto file = ctx->get_heif_file();
@@ -685,10 +704,13 @@ ImageItem_Tiled::add_new_tiled_item(HeifContext* ctx, const heif_tiled_image_par
tild_header.set_parameters(*parameters);
tild_header.set_compression_format(encoder->plugin->compression_format);
- std::vector<uint8_t> header_data = tild_header.write_offset_table();
+ Result<std::vector<uint8_t>> header_data_result = tild_header.write_offset_table();
+ if (auto err = header_data_result.error()) {
+ return err;
+ }
const int construction_method = 0; // 0=mdat 1=idat
- file->append_iloc_data(tild_id, header_data, construction_method);
+ file->append_iloc_data(tild_id, *header_data_result, construction_method);
if (parameters->image_width > 0xFFFFFFFF || parameters->image_height > 0xFFFFFFFF) {
@@ -711,7 +733,7 @@ ImageItem_Tiled::add_new_tiled_item(HeifContext* ctx, const heif_tiled_image_par
#endif
tild_image->set_tild_header(tild_header);
- tild_image->set_next_tild_position(header_data.size());
+ tild_image->set_next_tild_position(header_data_result->size());
// Set Brands
//m_heif_file->set_brand(encoder->plugin->compression_format,
@@ -828,14 +850,19 @@ Error ImageItem_Tiled::add_image_tile(uint32_t tile_x, uint32_t tile_y,
}
-void ImageItem_Tiled::process_before_write()
+Error ImageItem_Tiled::process_before_write()
{
// overwrite offsets
const int construction_method = 0; // 0=mdat 1=idat
- std::vector<uint8_t> header_data = m_tild_header.write_offset_table();
- get_file()->replace_iloc_data(get_id(), 0, header_data, construction_method);
+ Result<std::vector<uint8_t>> header_data_result = m_tild_header.write_offset_table();
+ if (auto err = header_data_result.error()) {
+ return err;
+ }
+
+ get_file()->replace_iloc_data(get_id(), 0, *header_data_result, construction_method);
+ return {};
}
diff --git a/libheif/image-items/tiled.h b/libheif/image-items/tiled.h
index 19ba8d20..6ced023a 100644
--- a/libheif/image-items/tiled.h
+++ b/libheif/image-items/tiled.h
@@ -33,7 +33,7 @@
#include <set>
-uint64_t number_of_tiles(const heif_tiled_image_parameters& params);
+Result<uint64_t> number_of_tiles(const heif_tiled_image_parameters& params, const heif_security_limits* limits);
uint32_t nTiles_h(const heif_tiled_image_parameters& params);
@@ -103,7 +103,7 @@ public:
Error read_offset_table_range(const std::shared_ptr<HeifFile>& file, heif_item_id tild_id,
uint64_t start, uint64_t end);
- std::vector<uint8_t> write_offset_table();
+ Result<std::vector<uint8_t>> write_offset_table();
std::string dump() const;
@@ -167,7 +167,7 @@ public:
Error initialize_decoder() override;
- void process_before_write() override;
+ Error process_before_write() override;
Error get_coded_image_colorspace(heif_colorspace* out_colorspace, heif_chroma* out_chroma) const override;