From 054dffd13368f8d7d024dbdfdce7454e6e547c5f Mon Sep 17 00:00:00 2001 From: Michael Niedermayer Date: Thu, 7 May 2026 03:03:31 +0200 Subject: [PATCH] avcodec/bsf/dts2pts: fix binary tree invariant violation on selective dec_poc Modifying the keys of a sorted structure, be that a tree or other can lead to changes in the ordering and undefined behavior. It can also lead to collisions with existing keys. All these cases need to be handled unless there is a bug elsewhere that would prevent them. Fixes: out of array access Fixes: 504281984/clusterfuzz-testcase-minimized-ffmpeg_BSF_DTS2PTS_fuzzer-6032368162111488 Found-by: continuous fuzzing process https://github.com/google/oss-fuzz/tree/master/projects/ffmpeg Signed-off-by: Michael Niedermayer --- libavcodec/bsf/dts2pts.c | 40 ++++++++++++++++++++++++++++++++++------ 1 file changed, 34 insertions(+), 6 deletions(-) diff --git a/libavcodec/bsf/dts2pts.c b/libavcodec/bsf/dts2pts.c index ff03508c18..6e391c291f 100644 --- a/libavcodec/bsf/dts2pts.c +++ b/libavcodec/bsf/dts2pts.c @@ -413,11 +413,23 @@ static int hevc_init_nb_frame(AVBSFContext *ctx, int poc) return 0; } -static int same_gop(void *opaque, void *elem) +typedef struct DTS2PTSCollect { + int gop; + DTS2PTSNode **out; + int count; + int max; +} DTS2PTSCollect; + +static int collect_same_gop(void *opaque, void *elem) { + DTS2PTSCollect *c = opaque; DTS2PTSNode *node = elem; - int gop = ((int *)opaque)[1]; - return FFDIFFSIGN(gop, node->gop); + if (node->gop == c->gop) { + if (c->count < c->max) + c->out[c->count] = node; + c->count++; + } + return 0; } static int hevc_queue_frame(AVBSFContext *ctx, AVPacket *pkt, int poc, bool *queued) @@ -441,10 +453,26 @@ static int hevc_queue_frame(AVBSFContext *ctx, AVPacket *pkt, int poc, bool *que } if (poc < s->nb_frame && hevc->gop == s->gop) { - int tmp[] = {s->nb_frame - poc, s->gop}; + int dec = s->nb_frame - poc; + DTS2PTSNode *nodes[HEVC_MAX_DPB_SIZE * 2]; + DTS2PTSCollect c = { s->gop, nodes, 0, FF_ARRAY_ELEMS(nodes) }; - s->nb_frame -= tmp[0]; - av_tree_enumerate(s->root, tmp, same_gop, dec_poc); + s->nb_frame -= dec; + + av_tree_enumerate(s->root, &c, NULL, collect_same_gop); + av_assert0(c.count <= c.max); + for (int i = 0; i < c.count; i++) { + struct AVTreeNode *tnode = NULL; + DTS2PTSNode *r; + av_tree_insert(&s->root, nodes[i], cmp_insert, &tnode); + nodes[i]->poc -= dec; + r = av_tree_insert(&s->root, nodes[i], cmp_insert, &tnode); + if (r && r != nodes[i]) { + *r = *nodes[i]; + av_refstruct_unref(&nodes[i]); + av_free(tnode); + } + } } ret = alloc_and_insert_node(ctx, pkt->dts, pkt->duration, s->nb_frame, 1, s->gop);