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]

Reply via email to