Fix T86952: Buffer overflow reading specific DDS images
Add a data boundary check in the flipping code. This code now also communicates the number of mipmap levels it processed with an intent to avoid GPU texture from using more levels than there are in the DDS data. Differential Revision: https://developer.blender.org/D13755
This commit is contained in:
parent
29e33cfff5
commit
bef2412ca2
Notes:
blender-bot
2023-02-14 08:08:56 +01:00
Referenced by issue #88449: Blender LTS: Maintenance Task 2.93 Referenced by issue #88449, Blender LTS: Maintenance Task 2.93 Referenced by issue #86952, Heap Buffer Overflow when viewing dds thumbnails in the file browser. Referenced by issue #77348, Blender LTS: Maintenance Task 2.83
|
@ -168,9 +168,16 @@ static void FlipDXT5BlockHalf(uint8_t *block)
|
|||
FlipDXT1BlockHalf(block + 8);
|
||||
}
|
||||
|
||||
int FlipDXTCImage(
|
||||
unsigned int width, unsigned int height, unsigned int levels, int fourcc, uint8_t *data)
|
||||
int FlipDXTCImage(unsigned int width,
|
||||
unsigned int height,
|
||||
unsigned int levels,
|
||||
int fourcc,
|
||||
uint8_t *data,
|
||||
int data_size,
|
||||
unsigned int *r_num_valid_levels)
|
||||
{
|
||||
*r_num_valid_levels = 0;
|
||||
|
||||
/* Must have valid dimensions. */
|
||||
if (width == 0 || height == 0) {
|
||||
return 0;
|
||||
|
@ -204,14 +211,25 @@ int FlipDXTCImage(
|
|||
return 0;
|
||||
}
|
||||
|
||||
*r_num_valid_levels = levels;
|
||||
|
||||
unsigned int mip_width = width;
|
||||
unsigned int mip_height = height;
|
||||
|
||||
const uint8_t *data_end = data + data_size;
|
||||
|
||||
for (unsigned int i = 0; i < levels; i++) {
|
||||
unsigned int blocks_per_row = (mip_width + 3) / 4;
|
||||
unsigned int blocks_per_col = (mip_height + 3) / 4;
|
||||
unsigned int blocks = blocks_per_row * blocks_per_col;
|
||||
|
||||
if (data + block_bytes * blocks > data_end) {
|
||||
/* Stop flipping when running out of data to be modified, avoiding possible buffer overrun
|
||||
* on a malformed files. */
|
||||
*r_num_valid_levels = i;
|
||||
break;
|
||||
}
|
||||
|
||||
if (mip_height == 1) {
|
||||
/* no flip to do, and we're done. */
|
||||
break;
|
||||
|
|
|
@ -23,5 +23,10 @@
|
|||
*
|
||||
* Use to flip vertically to fit OpenGL convention.
|
||||
*/
|
||||
int FlipDXTCImage(
|
||||
unsigned int width, unsigned int height, unsigned int levels, int fourcc, uint8_t *data);
|
||||
int FlipDXTCImage(unsigned int width,
|
||||
unsigned int height,
|
||||
unsigned int levels,
|
||||
int fourcc,
|
||||
uint8_t *data,
|
||||
int data_size,
|
||||
unsigned int *r_num_valid_levels);
|
||||
|
|
|
@ -186,8 +186,13 @@ struct ImBuf *imb_load_dds(const unsigned char *mem,
|
|||
|
||||
/* flip compressed texture */
|
||||
if (ibuf->dds_data.data) {
|
||||
FlipDXTCImage(
|
||||
dds.width(), dds.height(), dds.mipmapCount(), dds.fourCC(), ibuf->dds_data.data);
|
||||
FlipDXTCImage(dds.width(),
|
||||
dds.height(),
|
||||
ibuf->dds_data.nummipmaps,
|
||||
dds.fourCC(),
|
||||
ibuf->dds_data.data,
|
||||
ibuf->dds_data.size,
|
||||
&ibuf->dds_data.nummipmaps);
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
|
Loading…
Reference in New Issue