avif: reject color/alpha picture dimension mismatch instead of silent corruption#3085
Open
scadastrangelove wants to merge 1 commit into
Open
Conversation
… corruption AvifDecoder::read_image (both the 8-bit and 16-bit paths) composited the alpha plane into the output buffer with Iterator::zip, but the primary picture and the alpha picture are decoded independently -- each via its own dav1d::Decoder, from its own coded data (AvifDecoder::new). Nothing checked that the two dav1d::Picture results actually had matching width/height before the zip. Iterator::zip silently stops at the shorter of its two inputs, so a mismatch didn't error, it just corrupted the composited image. Verified against current main with a real dav1d-decoded crafted AVIF (color item 8x8, alpha item's own AV1 bitstream 4x4, re-muxed via avif-serialize): pre-fix, read_image() returned Ok with rows 0-3 getting alpha values from the 4x4 alpha picture and rows 4-7 getting stray alpha bytes not sourced from the visible alpha image at all (dav1d picture-buffer padding beyond the coded height). Post-fix, the same file now returns a clear decode error. Adds a dimension-equality check ahead of both zip loops, plus a regression test that crafts a real dimension-mismatched AVIF (via the crate's own ravif-backed encoder + mp4parse + avif-serialize, no external fixture needed) and asserts decoding now fails instead of silently producing a corrupted image. Addresses image-rs#3084. Discovered by the rust-in-peace security pipeline (https://github.com/scadastrangelove/rust-in-peace/).
197g
reviewed
Jul 19, 2026
197g
left a comment
Member
There was a problem hiding this comment.
Looks like libavif also has an error code for this, so this is reasonable (with the clippy complaint fixed).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #3084.
AvifDecoder::read_image(both the 8-bit and 16-bit paths) composited the alpha plane into the output buffer withIterator::zip, but the primary picture and the alpha picture are decoded independently — each via its owndav1d::Decoder, from its own coded data (AvifDecoder::new). Nothing checked that the twodav1d::Pictureresults actually had matching width/height before thezip.Iterator::zipsilently stops at the shorter of its two inputs, so a mismatch didn't error — it corrupted the composited image instead.Verified against current
mainwith a real dav1d-decoded crafted AVIF (color item 8x8, alpha item's own independently-encoded AV1 bitstream 4x4, re-muxed viaavif-serialize):read_image()returnedOk. Rows 0-3 correctly got alpha values from the 4x4 alpha picture, but rows 4-7 got stray alpha bytes not sourced from the visible alpha image at all —dav1d's picture-buffer padding beyond the coded height happened to satisfy the zip's row count. This is silent corruption, not simple truncation.Err("Format error decoding Avif: Alpha plane dimensions (4x4) do not match color plane dimensions (8x8)").The original issue only flagged the 8-bit path; while fixing it I found the identical unchecked
zipin the 16-bit path (process_16bit_picture) and fixed both.Changes
AvifDecoderError::AlphaPlaneDimensionMismatchinstead of silently compositing.tests/avif_alpha_dimension_mismatch.rs) that crafts a real, dav1d-decodable dimension-mismatched AVIF at test time (via the crate's ownravif-backed encoder +mp4parse+avif-serialize, no external binary fixture needed) and asserts decoding now errors. Confirmed the test fails on unpatchedmainand passes with this fix.Testing
Full suite (
cargo test --features avif,avif-native,default-formats,rayon --lib --tests): all green except one pre-existing, unrelated failure intests/limits.rs::avif(set_limitsnot enforcing width/height before dav1d decode) — reproduces on unmodifiedmaintoo, already tracked as #3076.Discovered by the rust-in-peace security pipeline.