AAC decoding overlaps each frame with the previous one, so the first
frame decoded after a seek is only reliable once the frame before it has
been decoded. Opus declares its pre-roll in AVCodecParameters.seek_preroll,
AAC did not.
Have the decoder export its pre-roll, as it knows the frame length: 1024
or 960 samples, half of it for LD and ELD, and 1024 or 768 for USAC.
ELD needs three frames, as its low delay filterbank uses a window four
frames long. SBR keeps the state of the frame before, in its
filterbanks, its high-frequency generator and its gain smoothing, and
codes its envelopes and noise floors relative to the frame before, so
it needs one more frame, of twice as many output samples when it
doubles the sample rate. Without it, the first 256 samples decoded
after a seek into HE-AAC differ from continuous decoding by -36.6 dB
with one frame of pre-roll, and not at all with two.
Implicit SBR is only known once found in a frame, so the pre-roll is
raised then, as it is for USAC, whose frame length depends on its SBR
ratio. Demuxers get it through the stream probing, whatever the
container. A larger pre-roll declared by the container is kept, and the
documentation of AVCodecContext.seek_preroll now says a decoder may
raise it.
The output of an AAC-LC stream decoded after a seek has an error of
-9.5 dB in the first 1024 samples, against -85 dB elsewhere, which one
frame of pre-roll removes.
The pre-roll tests now show the declared value, for AAC in every
container, 4096 samples for HE-AAC, explicit or implicit, 2048 for SBR
that does not double the sample rate, and 1536 for ELD.
During USAC decoding (ff_aac_usac_decode_frame), configuration elements
can be mapped and instantiated via che_configure(). For newly allocated
ChannelElement structs, che_configure calls sbr_ctx_alloc_init() which
dynamically allocates ac->che[type][id]. However, che_configure did not
subsequently map the output pointer of the nested SingleChannelElement
elements back to their statically-sized internal ret_buf arrays, causing
a null pointer dereference during IMDCT windowing.
The fix explicitly initializes these pointers following allocation.
Signed-off-by: Marvin Scholz <epirat07@gmail.com>
Found during triage/review of the security report GITTfi6VsK4u
(ANT-2026-5KX1BXM6), which does not report this.
Fixes: use of uninitialized memory
Fixes: A-codecs/AAC/xhe-aac/Sintel_24kbps_rap5s.mp4
Use of uninitialized memory Replicated through API with MSAN
Undefined shift Replicated through API with UBSAN
Fixes: left shift of negative value -1
Fixes: 536321788/clusterfuzz-testcase-minimized-ffmpeg_AV_CODEC_ID_AAC_DEC_fuzzer-4601480396210176
Fixes: IsFvv6HEhVCP
Found-by: continuous fuzzing process https://github.com/google/oss-fuzz/tree/master/projects/ffmpeg
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
The buffers of fragmented extension payloads were lost when a new
configuration was parsed.
Fixes: memleak
Fixes: yxoDgZkJaJ4D
Regression since: eee5fa0808
Found during the review of https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/24677
Memleak Replicated through UnModified FFmpeg with ASAN
ff_aac_output_configure() copies the restored layout into avctx->ch_layout,
the plain assignment before it dropped whatever avctx->ch_layout owned.
This is hardening, no leak was replicated.
Found during the review of https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/24677
OutputConfiguration is copied by value between oc[0] and oc[1]. A custom
channel layout built from bsOutputChannelPos that cannot be retyped to a
native layout owns a heap allocated map, the copies alias it and it is
freed twice.
The layout only reaches avctx->ch_layout and is replaced by the one derived
from the elements when the configuration is parsed completely.
Fixes: double free
Fixes: Qn47KDJBCeGk
Regression since: eee5fa0808
Found during the review of https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/24677
Double free Replicated through UnModified FFmpeg with ASAN
Real-world xHE-AAC streams and the ISO/IEC 23003-3 conformance
sequences carry their loudness metadata exclusively as loudnessInfoV1()
inside loudnessInfoSetExtension(), which was previously rejected with
AVERROR_PATCHWELCOME, making such streams undecodable and loudness
normalization inoperative on them.
loudnessInfoV1() is identical to loudnessInfo() apart from an added
eqSetId field. Parse it, restrict measurement selection to
eqSetId == 0 (in line with the downmixId/drcSetId restrictions), and
skip unknown loudnessInfoSetExtension() payloads using their explicitly
coded size instead of erroring out.
decode_tsd() computes the binomial coefficient c = C(k, p) incrementally.
this commit makes it less overflow prone
Fixes: 515703905/clusterfuzz-testcase-minimized-ffmpeg_AV_CODEC_ID_AAC_DEC_fuzzer-4890954254581760
Found-by: continuous fuzzing process https://github.com/google/oss-fuzz/tree/master/projects/ffmpeg
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
Later code will turn this into AVERROR_BUG
When returning sample_rate == 0 samples is considered a bug, we have no
nice choice but to error out cleanly
Fixes: assertion failure
Fixes: ffmpeg_AV_CODEC_ID_AAC_DEC_fuzzer crash-0a86d46fef2442b222ee34403c21f7f582ffccb0
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
This also reverts: c2364e9222
Fixes: out of array access (testcase exists but did not replicate for me)
Founbd-by: Gil Portnoy <dddhkts1@gmail.com>
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
`spectrum_decode` currently executes Frequency Domain (FD) decoding steps
for all channels, regardless of their `core_mode`. When a channel is in
Linear Prediction Domain (LPD) mode (`core_mode == 1`), FD-specific
parameters such as scalefactor offsets (`sfo`) and individual channel
stream (`ics`) information are not parsed.
This causes a global-buffer-overflow in `dequant_scalefactors`. Because
`spectrum_scale` is called on LPD channels, it uses stale or
uninitialized `sfo` values to index `ff_aac_pow2sf_tab`. In the reported
crash, a stale `sfo` value of 240 resulted in an index of 440
(240 + POW_SF2_ZERO), exceeding the table's size of 428.
Fix this by ensuring `spectrum_scale` and `imdct_and_windowing` are only
called for channels where `core_mode == 0` (FD).
Co-authored-by: CodeMender <codemender-patching@google.com>
Fixes: https://issues.oss-fuzz.com/486160985
Without the specification, limiting the index is the best that can be done.
Fixes: out of array access
Fixes: 487591441/clusterfuzz-testcase-minimized-ffmpeg_AV_CODEC_ID_AAC_LATM_fuzzer-6205915698364416
Found-by: continuous fuzzing process https://github.com/google/oss-fuzz/tree/master/projects/ffmpeg
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
fix a simple index bug in ff_aac_usac_reset_state()
that writes past the end of ChannelElement.ch[2] for CPE
ff_aac_usac_reset_state() loops over channels with j < ch, but
incorrectly takes &che->ch[ch]. For CPE (ch == 2) this becomes
che->ch[2], which is one past the end of ChannelElement.ch[2], and the
subsequent memset() causes an intra-object out-of-bounds write.
index the channel element with the loop variable (j).
A heap-use-after-free vulnerability was identified in
`libavcodec/aac/aacdec.c`. When `che_configure` frees a
`ChannelElement` (`ac->che[type][id]`), it failed to clear all
references to it in `ac->tag_che_map`. `ac->tag_che_map` caches
pointers to `ChannelElement`s and can contain cross-type mappings (e.g.,
a `TYPE_SCE` tag mapping to a `TYPE_LFE` element).
In a USAC stream reconfiguration scenario, an LFE element was freed, but
a stale pointer remained in `ac->tag_che_map`. Subsequent calls to
`ff_aac_get_che` returned this dangling pointer, leading to a crash in
`decode_usac_core_coder`.
This commit fixes the issue by iterating over the entire
`ac->tag_che_map` in `che_configure` and clearing any entries that point
to the `ChannelElement` about to be freed, ensuring no dangling pointers
remain.
Fixes: https://issues.oss-fuzz.com/issues/440220467