Fix out-of-bounds reads in drflac_read_pcm_frames_* when reusing an inconsistent frame (crafted FLAC) - #330
Closed
Alb3e3 wants to merge 1 commit into
Closed
Conversation
drflac_read_pcm_frames_s32/s16/f32 reuse the current frame whenever
pcmFramesRemaining > 0, indexing subframes[j].pSamplesS32[iFirstPCMFrame + i].
A crafted FLAC can leave that frame inconsistent with the decoded-sample
buffer (which only holds maxBlockSizeInPCMFrames samples per channel):
* after a seek, subframes[1..] can be NULL while pcmFramesRemaining > 0
(NULL dereference); and
* on open, header.blockSizeInPCMFrames can exceed maxBlockSizeInPCMFrames
(or pcmFramesRemaining can exceed the block size), so iFirstPCMFrame runs
the read thousands of samples past the buffer (heap-buffer-overflow).
Before reusing the current frame, verify it is self-consistent (block size
within the maximum, pcmFramesRemaining within the block size, and all
channelCount subframe pointers non-NULL); otherwise drop it and decode a
fresh frame. No change for valid streams.
Author
|
Runnable reproducers (standalone Both abort under ASan on current |
Owner
|
This has been fixed manually. Please do not submit AI-generated bug reports in the future. |
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.
Title
Fix out-of-bounds reads in drflac_read_pcm_frames_* when reusing an inconsistent frame (crafted FLAC)
Body
Summary
Two crafted-FLAC inputs cause
drflac_read_pcm_frames_s32/s16/f32to read out of bounds of thedecoded-sample buffer, crashing in release/NDEBUG builds via the ordinary public API. Any app
that opens an untrusted
.flacis affected (audio players, game engines, media tooling).Both stem from the same place: the readers reuse the current frame whenever
currentFLACFrame.pcmFramesRemaining > 0, indexingcurrentFLACFrame.subframes[j].pSamplesS32[iFirstPCMFrame + i]— but a crafted stream can leave thecurrent frame in a state that is inconsistent with the decoded-sample buffer.
Bug 1 — NULL subframe dereference after a seek
Sequence (public API):
open → read → drflac_seek_to_pcm_frame(N)(returns success) →read→ SEGV.After the seek,
pcmFramesRemaining > 0but onlysubframes[0]is populated andsubframes[1..]are NULL (left over from a prior partially-decoded frame). The read dereferences
NULL + iFirstPCMFrame.poc/min.flac(1106 bytes) +poc/repro.c. SEGV indrflac_read_pcm_frames_s32.Bug 2 — heap-buffer-overflow on open (block size exceeds the maximum)
Reachable during
drflac_open_memory_with_metadataalone (no seek). The current frame'sheader.blockSizeInPCMFrames(e.g. 4096) is far larger than the STREAMINFOmaxBlockSizeInPCMFrames(e.g. 16) the decode buffer was sized for, whilesubframes[j]still pointat the small buffer.
iFirstPCMFrame = blockSize - pcmFramesRemainingbecomes huge (~2142), and theread runs thousands of int32s past the allocation.
poc/min_open_overflow.flac. ASan:heap-buffer-overflow ... READ of size 16, locatedthousands of bytes after the decoded-sample region allocated in
drflac_open_with_metadata_private.Root cause
drflac_read_pcm_frames_*trustspcmFramesRemaining/header.blockSizeInPCMFrames/subframes[j]without checking they are mutually consistent and consistent with the decoded-sample buffer (which
only holds
maxBlockSizeInPCMFramessamples per channel). A crafted stream can leave that stateinconsistent after a seek or during open.
Fix
Before reusing the current frame in each of the three readers, verify it is self-consistent:
header.blockSizeInPCMFrames <= maxBlockSizeInPCMFrames(buffer can hold it),pcmFramesRemaining <= header.blockSizeInPCMFrames(noiFirstPCMFrameunderflow),subframes[j].pSamplesS32(j < channelCount) is non-NULL.If not, drop the stale frame (
pcmFramesRemaining = 0) and decode a fresh one instead ofdereferencing invalid state. (Could be factored into a small helper — happy to do that if preferred.)
Verification
files, and seek+read still works.
harness only exercises
open_memory+read_s32, never seeks).