mirror of
https://github.com/BinomialLLC/basis_universal.git
synced 2026-08-13 08:39:50 +00:00
- .basis transcoder class now validates the basis_slice_desc structs to ensure the original (unpadded) dimensions are valid, not too large (beyond 16K on either dimension), and are in sync with the slice's block dimensions. All methods that parse the slice desc structs now validate the contents first.
- basisu_lowlevel_etc1s_transcoder::transcode_slice(): Added PVRTC temp buf malloc buffer size sanity checking Thanks to Canxuepiao Jian for the report.
This commit is contained in:
@@ -8593,12 +8593,20 @@ namespace basist
|
||||
uint32_t* pPVRTC_endpoints = nullptr;
|
||||
if ((fmt == block_format::cPVRTC1_4_RGB) || (fmt == block_format::cPVRTC1_4_RGBA))
|
||||
{
|
||||
pPVRTC_work_mem = malloc(num_blocks_x * num_blocks_y * (sizeof(decoder_etc_block) + sizeof(uint32_t)));
|
||||
const uint64_t alloc_size = (uint64_t)num_blocks_x * (uint64_t)num_blocks_y * (sizeof(decoder_etc_block) + sizeof(uint32_t));
|
||||
if (alloc_size > (256u * 1024u * 1024u)) // sanity check, 16384x16384=192MB
|
||||
{
|
||||
BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_slice: malloc would be too large\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
pPVRTC_work_mem = malloc(alloc_size);
|
||||
if (!pPVRTC_work_mem)
|
||||
{
|
||||
BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_slice: malloc failed\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
pPVRTC_endpoints = (uint32_t*)&((decoder_etc_block*)pPVRTC_work_mem)[num_blocks_x * num_blocks_y];
|
||||
}
|
||||
|
||||
@@ -11984,6 +11992,44 @@ namespace basist
|
||||
return (basis_tex_format)(uint32_t)pHeader->m_tex_format;
|
||||
}
|
||||
|
||||
static bool check_slice_desc(const basis_slice_desc& slice_desc, uint32_t block_width, uint32_t block_height)
|
||||
{
|
||||
// calculated by us from the source format
|
||||
assert((block_width >= 4) && (block_width <= 12));
|
||||
assert((block_height >= 4) && (block_height <= 12));
|
||||
|
||||
// ensure the unpadded image dimensions are valid
|
||||
if ((!slice_desc.m_orig_width) || (!slice_desc.m_orig_height))
|
||||
return false;
|
||||
|
||||
if ((slice_desc.m_orig_width > BASISU_MAX_SUPPORTED_TEXTURE_DIMENSION) || (slice_desc.m_orig_height > BASISU_MAX_SUPPORTED_TEXTURE_DIMENSION))
|
||||
return false;
|
||||
|
||||
// now calculate the number of expected blocks on each dimension given the source format's block size
|
||||
const uint32_t num_blocks_x_expected = (slice_desc.m_orig_width + block_width - 1) / block_width;
|
||||
const uint32_t num_blocks_y_expected = (slice_desc.m_orig_height + block_height - 1) / block_height;
|
||||
|
||||
// ensure the slice has the exact number of expected blocks on each dimension
|
||||
if ((slice_desc.m_num_blocks_x != num_blocks_x_expected) || (slice_desc.m_num_blocks_y != num_blocks_y_expected))
|
||||
return false;
|
||||
|
||||
// at this point the original texture dimensions are valid, and the stored block dimensions
|
||||
// exactly match the padded dimensions implied by those original dimensions
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool check_slice_desc(const basis_file_header* pHeader, const basis_slice_desc& slice_desc)
|
||||
{
|
||||
if (pHeader->m_tex_format >= (uint32_t)basis_tex_format::cTotalFormats)
|
||||
return false;
|
||||
|
||||
const uint32_t block_width = basis_tex_format_get_block_width((basis_tex_format)((uint32_t)pHeader->m_tex_format));
|
||||
const uint32_t block_height = basis_tex_format_get_block_height((basis_tex_format)((uint32_t)pHeader->m_tex_format));
|
||||
|
||||
return check_slice_desc(slice_desc, block_width, block_height);
|
||||
}
|
||||
|
||||
bool basisu_transcoder::get_image_info(const void* pData, uint32_t data_size, basisu_image_info& image_info, uint32_t image_index) const
|
||||
{
|
||||
if (!validate_header_quick(pData, data_size))
|
||||
@@ -12023,12 +12069,18 @@ namespace basist
|
||||
}
|
||||
|
||||
const basis_slice_desc& slice_desc = pSlice_descs[slice_index];
|
||||
|
||||
|
||||
image_info.m_image_index = image_index;
|
||||
image_info.m_total_levels = total_levels;
|
||||
|
||||
image_info.m_alpha_flag = false;
|
||||
|
||||
if (pHeader->m_tex_format >= (uint32_t)basis_tex_format::cTotalFormats)
|
||||
{
|
||||
BASISU_DEVEL_ERROR("basisu_transcoder::get_image_info: invalid m_tex_format\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
// For ETC1S, if anything has alpha all images have alpha. For UASTC, we only report alpha when the image actually has alpha.
|
||||
if (pHeader->m_tex_format == (int)basis_tex_format::cETC1S)
|
||||
image_info.m_alpha_flag = (pHeader->m_flags & cBASISHeaderFlagHasAlphaSlices) != 0;
|
||||
@@ -12039,6 +12091,12 @@ namespace basist
|
||||
|
||||
const uint32_t block_width = basis_tex_format_get_block_width((basis_tex_format)((uint32_t)pHeader->m_tex_format));
|
||||
const uint32_t block_height = basis_tex_format_get_block_height((basis_tex_format)((uint32_t)pHeader->m_tex_format));
|
||||
|
||||
if (!check_slice_desc(slice_desc, block_width, block_height))
|
||||
{
|
||||
BASISU_DEVEL_ERROR("basisu_transcoder::get_image_info: invalid slice_desc\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
image_info.m_width = slice_desc.m_num_blocks_x * block_width;
|
||||
image_info.m_height = slice_desc.m_num_blocks_y * block_height;
|
||||
@@ -12119,10 +12177,25 @@ namespace basist
|
||||
return false;
|
||||
}
|
||||
|
||||
if (pHeader->m_tex_format >= (uint32_t)basis_tex_format::cTotalFormats)
|
||||
{
|
||||
BASISU_DEVEL_ERROR("basisu_transcoder::get_image_info: invalid m_tex_format\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
const basis_slice_desc* pSlice_descs = reinterpret_cast<const basis_slice_desc*>(static_cast<const uint8_t*>(pData) + pHeader->m_slice_desc_file_ofs);
|
||||
|
||||
const basis_slice_desc& slice_desc = pSlice_descs[slice_index];
|
||||
|
||||
const uint32_t block_width = basis_tex_format_get_block_width((basis_tex_format)((uint32_t)pHeader->m_tex_format));
|
||||
const uint32_t block_height = basis_tex_format_get_block_height((basis_tex_format)((uint32_t)pHeader->m_tex_format));
|
||||
|
||||
if (!check_slice_desc(slice_desc, block_width, block_height))
|
||||
{
|
||||
BASISU_DEVEL_ERROR("basisu_transcoder::get_image_level_desc: invalid slice_desc\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
orig_width = slice_desc.m_orig_width;
|
||||
orig_height = slice_desc.m_orig_height;
|
||||
total_blocks = slice_desc.m_num_blocks_x * slice_desc.m_num_blocks_y;
|
||||
@@ -12153,6 +12226,12 @@ namespace basist
|
||||
return false;
|
||||
}
|
||||
|
||||
if (pHeader->m_tex_format >= (uint32_t)basis_tex_format::cTotalFormats)
|
||||
{
|
||||
BASISU_DEVEL_ERROR("basisu_transcoder::get_image_info: invalid m_tex_format\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
const basis_slice_desc* pSlice_descs = reinterpret_cast<const basis_slice_desc*>(static_cast<const uint8_t*>(pData) + pHeader->m_slice_desc_file_ofs);
|
||||
|
||||
const basis_slice_desc& slice_desc = pSlice_descs[slice_index];
|
||||
@@ -12169,6 +12248,12 @@ namespace basist
|
||||
const uint32_t block_width = basis_tex_format_get_block_width((basis_tex_format)((uint32_t)pHeader->m_tex_format));
|
||||
const uint32_t block_height = basis_tex_format_get_block_height((basis_tex_format)((uint32_t)pHeader->m_tex_format));
|
||||
|
||||
if (!check_slice_desc(slice_desc, block_width, block_height))
|
||||
{
|
||||
BASISU_DEVEL_ERROR("basisu_transcoder::get_image_level_info: invalid slice_desc\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
image_info.m_iframe_flag = (slice_desc.m_flags & cSliceDescFlagsFrameIsIFrame) != 0;
|
||||
image_info.m_width = slice_desc.m_num_blocks_x * block_width;
|
||||
image_info.m_height = slice_desc.m_num_blocks_y * block_height;
|
||||
@@ -12226,6 +12311,11 @@ namespace basist
|
||||
file_info.m_tables_size = pHeader->m_tables_file_size;
|
||||
|
||||
file_info.m_tex_format = static_cast<basis_tex_format>(static_cast<int>(pHeader->m_tex_format));
|
||||
if (file_info.m_tex_format >= basis_tex_format::cTotalFormats)
|
||||
{
|
||||
BASISU_DEVEL_ERROR("basisu_transcoder::get_file_info: invalid m_tex_format\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
file_info.m_etc1s = (pHeader->m_tex_format == (int)basis_tex_format::cETC1S);
|
||||
|
||||
@@ -12241,7 +12331,7 @@ namespace basist
|
||||
|
||||
file_info.m_tex_type = static_cast<basis_texture_type>(static_cast<uint8_t>(pHeader->m_tex_type));
|
||||
|
||||
if (file_info.m_tex_type > cBASISTexTypeTotal)
|
||||
if (file_info.m_tex_type >= cBASISTexTypeTotal)
|
||||
{
|
||||
BASISU_DEVEL_ERROR("basisu_transcoder::get_file_info: invalid texture type, file is corrupted\n");
|
||||
return false;
|
||||
@@ -12267,6 +12357,12 @@ namespace basist
|
||||
|
||||
basisu_slice_info& slice_info = file_info.m_slice_info[i];
|
||||
|
||||
if (!check_slice_desc(pSlice_descs[i], block_width, block_height))
|
||||
{
|
||||
BASISU_DEVEL_ERROR("basisu_transcoder::get_file_info: invalid slice desc\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
slice_info.m_orig_width = pSlice_descs[i].m_orig_width;
|
||||
slice_info.m_orig_height = pSlice_descs[i].m_orig_height;
|
||||
slice_info.m_width = pSlice_descs[i].m_num_blocks_x * block_width;
|
||||
@@ -12458,6 +12554,12 @@ namespace basist
|
||||
|
||||
const basis_slice_desc& slice_desc = reinterpret_cast<const basis_slice_desc*>(pDataU8 + pHeader->m_slice_desc_file_ofs)[slice_index];
|
||||
|
||||
if (!check_slice_desc(pHeader, slice_desc))
|
||||
{
|
||||
BASISU_DEVEL_ERROR("basisu_transcoder::transcode_slice: invalid basis_slice_desc\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
const uint32_t dst_block_width = get_block_width(fmt), dst_block_height = get_block_height(fmt);
|
||||
|
||||
if (basis_block_format_is_uncompressed(fmt))
|
||||
@@ -12732,7 +12834,7 @@ namespace basist
|
||||
const uint8_t* pDataU8 = static_cast<const uint8_t*>(pData);
|
||||
|
||||
const basis_slice_desc* pSlice_descs = reinterpret_cast<const basis_slice_desc*>(pDataU8 + pHeader->m_slice_desc_file_ofs);
|
||||
|
||||
|
||||
const bool basis_file_has_alpha_slices = (pHeader->m_flags & cBASISHeaderFlagHasAlphaSlices) != 0;
|
||||
|
||||
int slice_index = find_first_slice_index(pData, data_size, image_index, level_index);
|
||||
@@ -12743,6 +12845,12 @@ namespace basist
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!check_slice_desc(pHeader, pSlice_descs[slice_index]))
|
||||
{
|
||||
BASISU_DEVEL_ERROR("basisu_transcoder::transcode_image_level: invalid basis_slice_desc\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((fmt == transcoder_texture_format::cTFPVRTC1_4_RGBA) && (!basis_file_has_alpha_slices))
|
||||
{
|
||||
// Switch to PVRTC1 RGB if the input doesn't have alpha.
|
||||
|
||||
Reference in New Issue
Block a user