Skip to content

fix(dds): corruption protection: validate resolution + overflow care - #5131

Merged
lgritz merged 3 commits into
AcademySoftwareFoundation:mainfrom
lgritz:lg-dds
Apr 15, 2026
Merged

fix(dds): corruption protection: validate resolution + overflow care#5131
lgritz merged 3 commits into
AcademySoftwareFoundation:mainfrom
lgritz:lg-dds

Conversation

@lgritz

@lgritz lgritz commented Apr 6, 2026

Copy link
Copy Markdown
Collaborator

No description provided.

@lgritz

lgritz commented Apr 7, 2026

Copy link
Copy Markdown
Collaborator Author

The person who reported the overflow issue to me confirms that this patch addresses the problem.

Would love somebody to give the code a once-over and approve.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR hardens the DDS ImageInput plugin against corrupted/malicious headers by adding resolution validation and reducing integer-overflow risk in internal size/offset calculations.

Changes:

  • Switched several internal dimension/offset variables and function signatures from unsigned int/int to size_t.
  • Added check_open(...) resolution/channel validation during seek_subimage.
  • Updated call sites and loops to use the new size_t-based interfaces (including casting back to int for DecompressImage).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/dds.imageio/ddsinput.cpp Outdated
Comment on lines +901 to +902
// Check validity of resolutions.
if (!check_open(m_spec, { 0, 32768, 0, 32768, 0, 16384, 0, 4 }))

Copilot AI Apr 7, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new check_open(m_spec, { 0, 32768, 0, 32768, ... }) validation uses m_spec.width/height, but for DDS cubemaps this plugin intentionally sets m_spec to an artificial 1x6 (default) or 3x2 layout (e.g. height = face_h * 6). This makes the effective per-face limit much smaller (in 1x6 layout, face_h must be <= 32768/6), rejecting valid cubemap files.

Consider validating the per-face dimensions instead (e.g. full_width/full_height or tile_width/tile_height), or adjust the allowed range based on the chosen cubemap layout so that a face size limit doesn't unintentionally become a layout size limit.

Suggested change
// Check validity of resolutions.
if (!check_open(m_spec, { 0, 32768, 0, 32768, 0, 16384, 0, 4 }))
// Check validity of resolutions. Cubemaps are represented using an
// artificial packed layout (default 1x6, optionally 3x2), so validate
// the per-face dimensions rather than the packed layout dimensions.
ImageSpec validate_spec = m_spec;
if (m_dds.caps.flags2 & DDS_CAPS2_CUBEMAP) {
#ifdef DDS_3X2_CUBE_MAP_LAYOUT
validate_spec.width /= 3;
validate_spec.height /= 2;
#else
validate_spec.height /= 6;
#endif
}
if (!check_open(validate_spec, { 0, 32768, 0, 32768, 0, 16384, 0, 4 }))

Copilot uses AI. Check for mistakes.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point, Copilot!

@lgritz

lgritz commented Apr 7, 2026

Copy link
Copy Markdown
Collaborator Author

Glad I requested that copilot review. I've amended the PR to apply slightly different (and I believe appropriate) resolution limit tests for 2D, cube map, and volume DDS files.

@lgritz lgritz added bug Crash or wrong behavior of an existing feature. file formats Image file formats, ImageInput, ImageOutput labels Apr 11, 2026
@lgritz

lgritz commented Apr 11, 2026

Copy link
Copy Markdown
Collaborator Author

Any comments?

@jessey-git jessey-git left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's one more expression overflow. In read_native_scanline the calculation used in the memcpy can overflow, it's enough to just cast the first variable there (z) to size_t to pull the rest of the expression along for the ride.

lgritz added 3 commits April 15, 2026 14:09
Signed-off-by: Larry Gritz <lg@larrygritz.com>
Signed-off-by: Larry Gritz <lg@larrygritz.com>
Signed-off-by: Larry Gritz <lg@larrygritz.com>
@lgritz

lgritz commented Apr 15, 2026

Copy link
Copy Markdown
Collaborator Author

There's one more expression overflow. In read_native_scanline the calculation used in the memcpy can overflow, it's enough to just cast the first variable there (z) to size_t to pull the rest of the expression along for the ride.

Fixed and pushed, thanks.

@jessey-git jessey-git left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good.

@lgritz
lgritz merged commit 94ec2de into AcademySoftwareFoundation:main Apr 15, 2026
30 checks passed
lgritz added a commit to lgritz/OpenImageIO that referenced this pull request Apr 19, 2026
lgritz added a commit to lgritz/OpenImageIO that referenced this pull request Apr 19, 2026
lgritz added a commit to lgritz/OpenImageIO that referenced this pull request Apr 19, 2026
lgritz added a commit to lgritz/OpenImageIO that referenced this pull request Apr 19, 2026
lgritz added a commit to lgritz/OpenImageIO that referenced this pull request Apr 19, 2026
@lgritz
lgritz deleted the lg-dds branch April 23, 2026 15:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Crash or wrong behavior of an existing feature. file formats Image file formats, ImageInput, ImageOutput

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants