fix(Video): bounds-check bitstream indices in Vc1/Mpegv/Mpeg4v Streams_Fill - #2679
Merged
JeromeMartinez merged 1 commit intoSep 24, 2026
Conversation
…s_Fill
Three video parsers use bitstream-decoded 8-bit fields as direct indices
into fixed-size static tables in Streams_Fill(), guarded only by their
'unset' sentinel (0xFF) or nothing at all. A crafted stream can supply
any value up to 0xFE and slip past the sentinel into a small table:
File_Vc1.cpp:293 (Vc1_ChromaSubsamplingFormat[4], gh#2611)
also lines 279 (Vc1_PixelAspectRatio[16]) and 287 (Vc1_Profile[4])
File_Mpegv.cpp:1277-1278 (Mpegv_chroma_format[4] and
Mpegv_chroma_format_Colorspace[4], gh#2612)
File_Mpeg4v.cpp:422 (Mpegv_frame_rate[16], gh#2608)
The reporter's PoCs (sigdevel/pocs mediainfo/{5,8,9}) supply 190 in each
field. On the OOB reads, the value that comes back is either a garbage
'const char*' near-zero pointer that later faults inside strlen() during
Fill()/From_UTF8() (Vc1, Mpegv chroma), or a global-buffer-overflow
picked up by ASan for the float64 table (Mpeg4v frame_rate).
Guard each access with 'idx < sizeof(table)/sizeof(*table)' before use.
Where the existing sentinel guard was semantically meaningful (e.g. 0x0F
'custom AR' in Vc1) it stays; only the missing size check is added.
While in File_Mpegv.cpp:Streams_Fill I applied the same class of guard
to the neighbouring aspect_ratio_information and frame_rate_code accesses
(Mpegv_aspect_ratio1/2 and Mpegv_frame_rate) and to
profile_and_level_indication_profile/_level - these are all the same
'bitstream field used as raw index' pattern, and defending against them
consistently avoids a follow-up on the same class in the same function.
The same PoC input still trips separate, pre-existing UBSan warnings
elsewhere in these parsers (bool fields loaded with non-{0,1} values,
plus a small handful of other unchecked table accesses further down
Streams_Fill for MPEG-2). Those are a separate class from the reported
memory-safety bugs and are out of scope here.
Reported-by: Alexander Shvedov <sigdevel>
Closes MediaArea#2611
Closes MediaArea#2612
Closes MediaArea#2608
Signed-off-by: Brandon Barrante <aetherai@aethersystems.net>
Member
|
Thank you for the fixes, I definitely need to improve the handling of such cases. |
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.
Closes #2611.
Closes #2612.
Closes #2608.
Three video parsers use
int8ubitstream fields as direct indices into small static tables inStreams_Fill(), guarded only by an(int8u)-1"unset" sentinel (0xFF) or nothing at all. @sigdevel's PoCs (mediainfo/{8,9,5}) supply190in each field — slips past the sentinel and reads garbage:File_Vc1.cpp:293—Vc1_ChromaSubsamplingFormat[colordiff_format](table has 4 entries; reporter also notes unchecked accesses at lines 279Vc1_PixelAspectRatio[16]and 287Vc1_Profile[4])File_Mpegv.cpp:1277-1278—Mpegv_chroma_format[chroma_format]andMpegv_chroma_format_Colorspace[chroma_format](bothchar *[4])File_Mpeg4v.cpp:422—Mpegv_frame_rate[frame_rate_code](const float64[16])The garbage
const char *read from the OOB slot is a near-zero pointer that later faults insidestrlen()on the way throughFill()→From_UTF8()(VC-1, MPEG video), or ASan reports theglobal-buffer-overflowdirectly on thefloat64table (MPEG-4 Visual).Add
idx < sizeof(table)/sizeof(*table)bounds checks at each site — compile-time constant, tautology on well-formed inputs (valid indices are strictly less than the table size), safe reject on malformed. Every existing semantic guard (AspectRatio != 0x0F"custom AR",profile_and_level_indication_escape, the(int8u)-1sentinels) stays as it was; only the missing size check is added.While in
File_Mpegv::Streams_FillI applied the same class of guard to the neighbouringaspect_ratio_informationandframe_rate_codeaccesses (Mpegv_aspect_ratio1/2andMpegv_frame_rate) and toprofile_and_level_indication_profile/_level. These are all the same "bitstream field used as raw index" pattern in the same function, and guarding them consistently avoids a follow-up on the same class in the same code.The same PoC input still trips separate, pre-existing UBSan warnings elsewhere in these parsers (bool fields loaded with non-
{0,1}values, plus a small handful of other unchecked table accesses further downStreams_Fillfor MPEG-2). Those are a separate class from the reported memory-safety bugs and are out of scope here.Reported-by: @sigdevel — thanks for the report and reproducers.