From 5393f1a525dac2728f6f343607ebe42edfa6b0a1 Mon Sep 17 00:00:00 2001 From: Sahana Bogar Date: Sat, 11 Jul 2026 21:00:25 +0530 Subject: [PATCH 1/2] reject undersized payload in load_ktx_compressed_image --- Source/astcenccli_image_load_store.cpp | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/Source/astcenccli_image_load_store.cpp b/Source/astcenccli_image_load_store.cpp index 9efb62f4..1aadcdfe 100644 --- a/Source/astcenccli_image_load_store.cpp +++ b/Source/astcenccli_image_load_store.cpp @@ -1361,6 +1361,29 @@ bool load_ktx_compressed_image( data_len = reverse_bytes_u32(data_len); } + // The imageSize and pixel dimensions are independent header fields, so + // reject a payload that is too small for the block grid the dimensions + // describe (load_cimage derives the size from the dimensions instead). + size_t block_x = fmt->x; + size_t block_y = fmt->y; + size_t block_z = fmt->z == 0 ? 1 : fmt->z; + + size_t dim_z = hdr.pixel_depth == 0 ? 1 : hdr.pixel_depth; + size_t blocks_x = (static_cast(hdr.pixel_width) + block_x - 1) / block_x; + size_t blocks_y = (static_cast(hdr.pixel_height) + block_y - 1) / block_y; + size_t blocks_z = (dim_z + block_z - 1) / block_z; + + bool overflow { false }; + size_t size_needed = astc::mul_safe(blocks_x, blocks_y, overflow); + size_needed = astc::mul_safe(size_needed, blocks_z, overflow); + size_needed = astc::mul_safe(size_needed, 16, overflow); + + if (overflow || data_len < size_needed) + { + print_error("ERROR: Image header corrupt '%s'\n", filename); + return true; + } + // Read the data img.data.resize(data_len); file.read(reinterpret_cast(img.data.data()), data_len); From cc1c638caa4d2986af643de6290e7dee7fe87cea Mon Sep 17 00:00:00 2001 From: Peter Harris Date: Sat, 18 Jul 2026 11:26:11 +0100 Subject: [PATCH 2/2] Use block_size helper to improve readability --- Source/astcenccli_image_load_store.cpp | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/Source/astcenccli_image_load_store.cpp b/Source/astcenccli_image_load_store.cpp index 1aadcdfe..8708d30a 100644 --- a/Source/astcenccli_image_load_store.cpp +++ b/Source/astcenccli_image_load_store.cpp @@ -1361,17 +1361,16 @@ bool load_ktx_compressed_image( data_len = reverse_bytes_u32(data_len); } - // The imageSize and pixel dimensions are independent header fields, so - // reject a payload that is too small for the block grid the dimensions - // describe (load_cimage derives the size from the dimensions instead). + // The data size and pixel dimensions are independent header fields, so + // reject a data size that is too small for the given image dimensions size_t block_x = fmt->x; size_t block_y = fmt->y; size_t block_z = fmt->z == 0 ? 1 : fmt->z; size_t dim_z = hdr.pixel_depth == 0 ? 1 : hdr.pixel_depth; - size_t blocks_x = (static_cast(hdr.pixel_width) + block_x - 1) / block_x; - size_t blocks_y = (static_cast(hdr.pixel_height) + block_y - 1) / block_y; - size_t blocks_z = (dim_z + block_z - 1) / block_z; + size_t blocks_x = astc::get_block_count_safe(hdr.pixel_width, block_x); + size_t blocks_y = astc::get_block_count_safe(hdr.pixel_height, block_y); + size_t blocks_z = astc::get_block_count_safe(dim_z, block_z); bool overflow { false }; size_t size_needed = astc::mul_safe(blocks_x, blocks_y, overflow); @@ -1495,8 +1494,8 @@ static bool store_ktx_uncompressed_image( // Size of image data padded to a multiple of 4 bytes size_t image_write_bytes = (image_bytes + 3) & ~3; - // The KTX imageSize field is a fixed 32-bit value, so check that the size_t - /// value can be safely narrowed, and does not wrap when padded + // The KTX data size field is a fixed 32-bit value, so check that the + // size_t value can be safely narrowed and does not wrap when padded uint32_t image_bytes_field = static_cast(image_bytes); if ((image_bytes_field != image_bytes) || (image_write_bytes < image_bytes)) {