Skip to content

Commit c42cfd7

Browse files
committed
fix(dds): corruption protection: validate resolution + overflow care
Signed-off-by: Larry Gritz <lg@larrygritz.com>
1 parent c75e31f commit c42cfd7

1 file changed

Lines changed: 30 additions & 25 deletions

File tree

src/dds.imageio/ddsinput.cpp

Lines changed: 30 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -97,11 +97,11 @@ class DDSInput final : public ImageInput {
9797

9898
/// Helper function: performs the actual file seeking.
9999
///
100-
void internal_seek_subimage(int cubeface, int miplevel, unsigned int& w,
101-
unsigned int& h, unsigned int& d);
100+
void internal_seek_subimage(int cubeface, int miplevel, size_t& w,
101+
size_t& h, size_t& d);
102102

103103
/// Helper function: performs the actual pixel decoding.
104-
bool internal_readimg(unsigned char* dst, int w, int h, int d);
104+
bool internal_readimg(unsigned char* dst, size_t w, size_t h, size_t d);
105105

106106
static bool validate_signature(uint32_t signature);
107107
};
@@ -671,8 +671,8 @@ DDSInput::calc_shifts(uint32_t mask, uint32_t& count, uint32_t& right)
671671
// NOTE: This function has no sanity checks! It's a private method and relies
672672
// on the input being correct and valid!
673673
void
674-
DDSInput::internal_seek_subimage(int cubeface, int miplevel, unsigned int& w,
675-
unsigned int& h, unsigned int& d)
674+
DDSInput::internal_seek_subimage(int cubeface, int miplevel, size_t& w,
675+
size_t& h, size_t& d)
676676
{
677677
// early out for cubemaps that don't contain the requested face
678678
if (m_dds.caps.flags2 & DDS_CAPS2_CUBEMAP
@@ -683,10 +683,10 @@ DDSInput::internal_seek_subimage(int cubeface, int miplevel, unsigned int& w,
683683
// we can easily calculate the offsets because both compressed and
684684
// uncompressed images have predictable length
685685
// calculate the offset; start with after the header
686-
unsigned int ofs = sizeof(dds_header);
686+
size_t ofs = sizeof(dds_header);
687687
if (m_dds.fmt.fourCC == DDS_4CC_DX10)
688688
ofs += sizeof(dds_header_dx10);
689-
unsigned int len;
689+
size_t len;
690690
// this loop is used to iterate over cube map sides, or run once in the
691691
// case of ordinary 2D or 3D images
692692
for (int j = 0; j <= cubeface; j++) {
@@ -754,7 +754,7 @@ DDSInput::seek_subimage(int subimage, int miplevel)
754754
m_buf.clear();
755755

756756
// for cube maps, the seek will be performed when reading a tile instead
757-
unsigned int w = 0, h = 0, d = 0;
757+
size_t w = 0, h = 0, d = 0;
758758
TypeDesc::BASETYPE basetype = GetBaseType(m_compression);
759759
if (m_dds.caps.flags2 & DDS_CAPS2_CUBEMAP) {
760760
// calc sizes separately for cube maps
@@ -898,13 +898,17 @@ DDSInput::seek_subimage(int subimage, int miplevel)
898898
m_spec.attribute("textureformat", "Plain Texture");
899899
}
900900

901+
// Check validity of resolutions.
902+
if (!check_open(m_spec, { 0, 32768, 0, 32768, 0, 1, 0, 4 }))
903+
return false;
904+
901905
m_subimage = subimage;
902906
m_miplevel = miplevel;
903907
return true;
904908
}
905909

906910
bool
907-
DDSInput::internal_readimg(unsigned char* dst, int w, int h, int d)
911+
DDSInput::internal_readimg(unsigned char* dst, size_t w, size_t h, size_t d)
908912
{
909913
if (m_compression != Compression::None) {
910914
// compressed image
@@ -915,15 +919,15 @@ DDSInput::internal_readimg(unsigned char* dst, int w, int h, int d)
915919
if (!ioread(tmp.get(), bufsize, 1))
916920
return false;
917921
// decompress image
918-
DecompressImage(dst, w, h, tmp.get(), m_compression, m_dds.fmt,
919-
threads());
922+
DecompressImage(dst, int(w), int(h), tmp.get(), m_compression,
923+
m_dds.fmt, threads());
920924
tmp.reset();
921925
// correct pre-multiplied alpha, if necessary
922926
if (m_compression == Compression::DXT2
923927
|| m_compression == Compression::DXT4) {
924-
int k;
925-
for (int y = 0; y < h; y++) {
926-
for (int x = 0; x < w; x++) {
928+
size_t k;
929+
for (size_t y = 0; y < h; y++) {
930+
for (size_t x = 0; x < w; x++) {
927931
k = (y * w + x) * 4;
928932
if (dst[k + 3]) {
929933
dst[k + 0] = (unsigned char)((int)dst[k + 0] * 255
@@ -956,12 +960,12 @@ DDSInput::internal_readimg(unsigned char* dst, int w, int h, int d)
956960
}
957961

958962
std::unique_ptr<uint8_t[]> tmp(new uint8_t[w * m_Bpp]);
959-
for (int z = 0; z < d; z++) {
960-
for (int y = 0; y < h; y++) {
963+
for (size_t z = 0; z < d; z++) {
964+
for (size_t y = 0; y < h; y++) {
961965
if (!ioread(tmp.get(), w, m_Bpp))
962966
return false;
963967
size_t k = (z * h * w + y * w) * m_spec.nchannels;
964-
for (int x = 0; x < w; x++, k += m_spec.nchannels) {
968+
for (size_t x = 0; x < w; x++, k += m_spec.nchannels) {
965969
uint32_t pixel = 0;
966970
memcpy(&pixel, tmp.get() + x * m_Bpp, m_Bpp);
967971
for (int ch = 0; ch < m_spec.nchannels; ++ch) {
@@ -987,8 +991,8 @@ DDSInput::readimg_scanlines()
987991
m_buf.resize(m_spec.scanline_bytes() * m_spec.height * m_spec.depth
988992
/*/ (1 << m_miplevel)*/);
989993

990-
return internal_readimg(&m_buf[0], m_spec.width, m_spec.height,
991-
m_spec.depth);
994+
return internal_readimg(&m_buf[0], size_t(m_spec.width),
995+
size_t(m_spec.height), size_t(m_spec.depth));
992996
}
993997

994998

@@ -998,8 +1002,9 @@ DDSInput::readimg_tiles()
9981002
{
9991003
// resize destination buffer
10001004
OIIO_ASSERT(m_buf.size() >= m_spec.tile_bytes());
1001-
return internal_readimg(&m_buf[0], m_spec.tile_width, m_spec.tile_height,
1002-
m_spec.tile_depth);
1005+
return internal_readimg(&m_buf[0], size_t(m_spec.tile_width),
1006+
size_t(m_spec.tile_height),
1007+
size_t(m_spec.tile_depth));
10031008
}
10041009

10051010

@@ -1053,10 +1058,10 @@ DDSInput::read_native_tile(int subimage, int miplevel, int x, int y, int z,
10531058
|| z % m_spec.tile_width)
10541059
return false;
10551060
if (m_buf.empty() || x != lastx || y != lasty || z != lastz) {
1056-
lastx = x;
1057-
lasty = y;
1058-
lastz = z;
1059-
unsigned int w = 0, h = 0, d = 0;
1061+
lastx = x;
1062+
lasty = y;
1063+
lastz = z;
1064+
size_t w = 0, h = 0, d = 0;
10601065
#ifdef DDS_3X2_CUBE_MAP_LAYOUT
10611066
internal_seek_subimage(((x / m_spec.tile_width) << 1)
10621067
+ y / m_spec.tile_height,

0 commit comments

Comments
 (0)