[PR] [release/6.0] avcodec/aacenc_tns: fix CVE-2025-1594 (PR #24313)

Forgejo_Fairy via ffmpeg-devel <[email protected]>
Newsgroups gmane.comp.video.ffmpeg.devel
Message-ID <[email protected]>
PR #24313 opened by Forgejo_Fairy
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/24313
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/24313.patch

Backports bedfb6eca402 to release/6.0 and addresses the release/6.0 part of #22696.

AAC Main can select three TNS filters, while the old direction calculation has only two energy measurements and reads beyond that array for the third filter. This patch measures three regions plus the cyclic comparison element, matching the upstream correction.

The patch retains the authorship of the backport submitted by the issue reporter.

Verification on base 3f92512fd1fd:

- The attached #22696 PoC with an explicit AAC Main encode reproduced the ASan stack-buffer-overflow before this commit.
- The same ASan command completed successfully after this commit.
- `make -j8 fate-aac SAMPLES=/opt/fate-suite` passed.
- `git diff --check` passed.


>From ba69be84a1ceabfb39127831ad8da0fd7cb471f3 Mon Sep 17 00:00:00 2001
From: "lizhixuan.HUST" <[email protected]>
Date: Fri, 3 Apr 2026 05:02:06 +0000
Subject: [PATCH] avcodec/aacenc_tns: fix three-filter energy measurement

Backport of bedfb6eca402037f5cbb115fa767d106b8c14f1c to release/6.0.

AAC Main can select three TNS filters, but the old direction calculation only allocates two energy measurements and reads beyond that array for the third filter. Measure all three regions and compare each filter with the following region.

Fixes: CVE-2025-1594
Fixes: https://code.ffmpeg.org/FFmpeg/FFmpeg/issues/22696
Found-by: 0x20z
Signed-off-by: lizhixuan.HUST <[email protected]>
Assisted-by: Fairy
---
 libavcodec/aacenc_tns.c | 33 ++++++++++++++++++++++++---------
 1 file changed, 24 insertions(+), 9 deletions(-)

diff --git a/libavcodec/aacenc_tns.c b/libavcodec/aacenc_tns.c
index 195ff5e2b7..bdd61e4e16 100644
--- a/libavcodec/aacenc_tns.c
+++ b/libavcodec/aacenc_tns.c
@@ -172,6 +172,7 @@ void ff_aac_search_for_tns(AACEncContext *s, SingleChannelElement *sce)
                       sce->ics.window_sequence[0] == LONG_START_SEQUENCE ? 0 : 2;
     const int sfb_len = sfb_end - sfb_start;
     const int coef_len = sce->ics.swb_offset[sfb_end] - sce->ics.swb_offset[sfb_start];
+    const int n_filt = is8 ? 1 : order != TNS_MAX_ORDER ? 2 : 3;
 
     if (coef_len <= 0 || sfb_len <= 0) {
         sce->tns.present = 0;
@@ -179,16 +180,30 @@ void ff_aac_search_for_tns(AACEncContext *s, SingleChannelElement *sce)
     }
 
     for (w = 0; w < sce->ics.num_windows; w++) {
-        float en[2] = {0.0f, 0.0f};
+        float en[4] = {0.0f, 0.0f, 0.0f, 0.0f};
         int oc_start = 0, os_start = 0;
         int coef_start = sce->ics.swb_offset[sfb_start];
 
-        for (g = sfb_start; g < sce->ics.num_swb && g <= sfb_end; g++) {
-            FFPsyBand *band = &s->psy.ch[s->cur_channel].psy_bands[w*16+g];
-            if (g > sfb_start + (sfb_len/2))
-                en[1] += band->energy;
-            else
-                en[0] += band->energy;
+        if (n_filt == 2) {
+            for (g = sfb_start; g < sce->ics.num_swb && g <= sfb_end; g++) {
+                FFPsyBand *band = &s->psy.ch[s->cur_channel].psy_bands[w*16+g];
+                    if (g > sfb_start + (sfb_len/2))
+                        en[1] += band->energy; /* End */
+                    else
+                        en[0] += band->energy; /* Start */
+            }
+            en[2] = en[0];
+        } else {
+            for (g = sfb_start; g < sce->ics.num_swb && g <= sfb_end; g++) {
+                FFPsyBand *band = &s->psy.ch[s->cur_channel].psy_bands[w*16+g];
+                    if (g > sfb_start + (sfb_len/2) + (sfb_len/4))
+                        en[2] += band->energy; /* End */
+                    else if (g > sfb_start + (sfb_len/2) - (sfb_len/4))
+                        en[1] += band->energy; /* Middle */
+                    else
+                        en[0] += band->energy; /* Start */
+            }
+            en[3] = en[0];
         }
 
         /* LPC */
@@ -198,9 +213,9 @@ void ff_aac_search_for_tns(AACEncContext *s, SingleChannelElement *sce)
         if (!order || !isfinite(gain) || gain < TNS_GAIN_THRESHOLD_LOW || gain > TNS_GAIN_THRESHOLD_HIGH)
             continue;
 
-        tns->n_filt[w] = is8 ? 1 : order != TNS_MAX_ORDER ? 2 : 3;
+        tns->n_filt[w] = n_filt;
         for (g = 0; g < tns->n_filt[w]; g++) {
-            tns->direction[w][g] = slant != 2 ? slant : en[g] < en[!g];
+            tns->direction[w][g] = slant != 2 ? slant : en[g] < en[g + 1];
             tns->order[w][g] = g < tns->n_filt[w] ? order/tns->n_filt[w] : order - oc_start;
             tns->length[w][g] = g < tns->n_filt[w] ? sfb_len/tns->n_filt[w] : sfb_len - os_start;
             quantize_coefs(&coefs[oc_start], tns->coef_idx[w][g], tns->coef[w][g],
-- 
2.52.0

_______________________________________________
ffmpeg-devel mailing list -- [email protected]
To unsubscribe send an email to [email protected]
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.