Commit 2d7eacee24 for ffmpeg

commit 2d7eacee24b6dc5a150ccbd4f71a4f17cb8efe96
Author: Jun Zhao <barryjzhao@tencent.com>
Date:   Fri Nov 6 15:03:34 2026 +0800

    avcodec/flac_parser: reject variable-blocksize false syncs in fixed streams

    A false sync inside the final frame of a short stream can survive the
    header CRC and subframe sanity checks, then be emitted again on flush.

    Reject variable-blocksize candidates when STREAMINFO declares equal
    minimum and maximum block sizes. This rejects the false header in the
    sample from #25766 without rejecting supported sample-rate or channel
    changes. Apply the check only during sync search: complete container
    packets already have boundaries, and chained Ogg packets can carry new
    STREAMINFO only on the first packet of a link.

    This narrows candidate selection; it does not change the EOF handling of
    other false headers or streams without STREAMINFO.

    Fixes: https://code.ffmpeg.org/FFmpeg/FFmpeg/issues/25766
    Signed-off-by: Jun Zhao <barryjzhao@tencent.com>

diff --git a/libavcodec/flac_parser.c b/libavcodec/flac_parser.c
index f50b0b262d..8ee7439f7c 100644
--- a/libavcodec/flac_parser.c
+++ b/libavcodec/flac_parser.c
@@ -34,7 +34,10 @@

 #include "libavutil/attributes.h"
 #include "libavutil/crc.h"
+#include "libavutil/intreadwrite.h"
+#include "libavutil/macros.h"
 #include "libavutil/mem.h"
+#include "flac.h"
 #include "flac_parse.h"
 #include "parser_internal.h"

@@ -102,6 +105,41 @@ typedef struct FLACParseContext {
     int last_fi_valid;             /**< set if last_fi is valid               */
 } FLACParseContext;

+/**
+ * Reject a variable-blocksize candidate when STREAMINFO declares a fixed
+ * blocksize.  This is only a sync-search check: complete container packets
+ * already have known boundaries, and their STREAMINFO can change mid-stream.
+ */
+static int flac_blocking_strategy_matches(const AVCodecContext *avctx,
+                                          const FLACFrameInfo *fi)
+{
+    const uint8_t *si = avctx->extradata;
+    int size = avctx->extradata_size;
+    int min_blocksize, max_blocksize;
+
+    /* Raw/headerless FLAC has no STREAMINFO to validate against. */
+    if (!si || size < FLAC_STREAMINFO_SIZE)
+        return 1;
+
+    /* Also accept a 4-byte marker + metadata block header before STREAMINFO. */
+    if (AV_RL32(si) == MKTAG('f', 'L', 'a', 'C')) {
+        if (size < 8 + FLAC_STREAMINFO_SIZE)
+            return 1;
+        si += 8;
+    }
+
+    min_blocksize = AV_RB16(si);
+    max_blocksize = AV_RB16(si + 2);
+    /* A fixed-blocksize stream cannot contain variable-blocksize frames.
+     * Compare the strategy bit, not the blocksize: the final frame of a
+     * fixed stream may legitimately be shorter than the declared size. */
+    if (min_blocksize && max_blocksize && min_blocksize == max_blocksize &&
+        fi->is_var_size)
+        return 0;
+
+    return 1;
+}
+
 static int frame_header_is_valid(AVCodecContext *avctx, const uint8_t *buf,
                                  FLACFrameInfo *fi)
 {
@@ -322,7 +360,8 @@ static int find_headers_search_validate(FLACParseContext *fpc, int offset)
                                      MAX_FRAME_VERIFY_SIZE + AV_INPUT_BUFFER_PADDING_SIZE,
                                      &fpc->wrap_buf,
                                      &fpc->wrap_buf_allocated_size);
-    if (frame_header_is_valid(fpc->avctx, header_buf, &fi)) {
+    if (frame_header_is_valid(fpc->avctx, header_buf, &fi) &&
+        flac_blocking_strategy_matches(fpc->avctx, &fi)) {
         FLACHeaderMarker **end_handle = &fpc->headers, *prev = NULL;
         int i;