Commit 972fe1ccd3 for ffmpeg
commit 972fe1ccd326538fe9a6b5d5094b7880b5443429
Author: Michael Niedermayer <michael@niedermayer.cc>
Date: Thu Oct 29 00:00:23 2026 +0100
avcodec/flac_parser: score the header chain without recursion
Fixes: iEdHjyvZ3jOg
Fixes: AISLE-2026-0150-00454
Fixes: stack overflow
Stack overflow Replicated through API with a 512 KB stack limit
Found-by: Joshua Rogers <joshua.rogers@aisle.com>
diff --git a/libavcodec/flac_parser.c b/libavcodec/flac_parser.c
index 9a5f5fd03a..f50b0b262d 100644
--- a/libavcodec/flac_parser.c
+++ b/libavcodec/flac_parser.c
@@ -75,6 +75,8 @@ typedef struct FLACHeaderMarker {
struct FLACHeaderMarker *next; /**< next CRC-8 verified header that
immediately follows this one in
the bytestream */
+ struct FLACHeaderMarker *prev; /**< CRC-8 verified header that
+ immediately precedes this one */
struct FLACHeaderMarker *best_child; /**< following frame header with
which this frame has the best
score with */
@@ -321,11 +323,12 @@ static int find_headers_search_validate(FLACParseContext *fpc, int offset)
&fpc->wrap_buf,
&fpc->wrap_buf_allocated_size);
if (frame_header_is_valid(fpc->avctx, header_buf, &fi)) {
- FLACHeaderMarker **end_handle = &fpc->headers;
+ FLACHeaderMarker **end_handle = &fpc->headers, *prev = NULL;
int i;
size = 0;
while (*end_handle) {
+ prev = *end_handle;
end_handle = &(*end_handle)->next;
size++;
}
@@ -338,6 +341,7 @@ static int find_headers_search_validate(FLACParseContext *fpc, int offset)
}
(*end_handle)->fi = fi;
(*end_handle)->offset = offset;
+ (*end_handle)->prev = prev;
for (i = 0; i < FLAC_MAX_SEQUENTIAL_HEADERS; i++)
(*end_handle)->link_penalty[i] = FLAC_HEADER_NOT_PENALIZED_YET;
@@ -615,15 +619,18 @@ static int score_header(FLACParseContext *fpc, FLACHeaderMarker *header)
static void score_sequences(FLACParseContext *fpc)
{
- FLACHeaderMarker *curr;
+ FLACHeaderMarker *curr, *last = NULL;
int best_score = FLAC_HEADER_NOT_SCORED_YET;
/* First pass to clear all old scores. */
- for (curr = fpc->headers; curr; curr = curr->next)
+ for (curr = fpc->headers; curr; curr = curr->next) {
curr->max_score = FLAC_HEADER_NOT_SCORED_YET;
+ last = curr;
+ }
- /* Do a second pass to score them all. */
- for (curr = fpc->headers; curr; curr = curr->next) {
- if (score_header(fpc, curr) > best_score) {
+ /* Score from the last header backwards, so the children of each header
+ are already scored and score_header() does not recurse. */
+ for (curr = last; curr; curr = curr->prev) {
+ if (score_header(fpc, curr) >= best_score) {
fpc->best_header = curr;
best_score = curr->max_score;
}
@@ -728,6 +735,7 @@ static int flac_parse(AVCodecParserContext *s, AVCodecContext *avctx,
curr->offset -= best_child->offset;
best_child->offset = 0;
+ best_child->prev = NULL;
fpc->headers = best_child;
if (fpc->nb_headers_buffered >= FLAC_MIN_HEADERS) {
fpc->best_header = best_child;
@@ -744,6 +752,8 @@ static int flac_parse(AVCodecParserContext *s, AVCodecContext *avctx,
fpc->nb_headers_buffered--;
}
fpc->headers = fpc->best_header->next;
+ if (fpc->headers)
+ fpc->headers->prev = NULL;
av_freep(&fpc->best_header);
fpc->nb_headers_buffered--;
}