PR #25100 opened by michaelni URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/25100 Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/25100.patch
>From 5ff0a62159ee6567e9c6d915ec5beddd36e9d1f6 Mon Sep 17 00:00:00 2001 From: zhang xingxing <[email protected]> Date: Thu, 15 Oct 2026 04:13:26 +0200 Subject: [PATCH 1/8] avcodec/vvc/dec: return the error code of a failed frame submission Fixes: Q85BEVq7MjZZ Fixes: swarm-Operator-precedence-masks-hardware-frame-submit-error-code-9c3184 Found-by: zhang xingxing <[email protected]> Masked decoder error Replicated through UnModified FFmpeg with the decoder log Signed-off-by: Michael Niedermayer <[email protected]> --- libavcodec/vvc/dec.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libavcodec/vvc/dec.c b/libavcodec/vvc/dec.c index f7c51f01a1..c1326fe17c 100644 --- a/libavcodec/vvc/dec.c +++ b/libavcodec/vvc/dec.c @@ -1145,14 +1145,14 @@ static int submit_frame(VVCContext *s, VVCFrameContext *fc, AVFrame *output, int int ret; if (s->avctx->hwaccel) { - if (ret = FF_HW_SIMPLE_CALL(s->avctx, end_frame) < 0) { + if ((ret = FF_HW_SIMPLE_CALL(s->avctx, end_frame)) < 0) { av_log(s->avctx, AV_LOG_ERROR, "Hardware accelerator failed to decode picture\n"); ff_vvc_unref_frame(fc, fc->ref, ~0); return ret; } } else { - if (ret = ff_vvc_frame_submit(s, fc) < 0) { + if ((ret = ff_vvc_frame_submit(s, fc)) < 0) { ff_vvc_report_frame_finished(fc->ref); return ret; } -- 2.52.0 >From 22a343977aea9cfe90a7e2c0ecfcaf2419a1bf47 Mon Sep 17 00:00:00 2001 From: Michael Niedermayer <[email protected]> Date: Thu, 15 Oct 2026 04:17:31 +0200 Subject: [PATCH 2/8] avcodec/flacenc: clamp the minimum LPC prediction order to 1 This is not a security issue. Fixes: Qzx1V8a6y8DL Fixes: swarm-Out-of-bounds-reads-on-coefs-shift-bits-when-min_prediction_order-is-0-0468ca Found-by: zhang xingxing <[email protected]> The report suggested ensuring min_order >= 1. Out of array write Replicated through UnModified FFmpeg with ASAN Signed-off-by: Michael Niedermayer <[email protected]> --- libavcodec/flacenc.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/libavcodec/flacenc.c b/libavcodec/flacenc.c index ead2c55f10..8d1c76870e 100644 --- a/libavcodec/flacenc.c +++ b/libavcodec/flacenc.c @@ -401,6 +401,11 @@ static av_cold int flac_encode_init(AVCodecContext *avctx) s->options.max_prediction_order, MAX_FIXED_ORDER); s->options.max_prediction_order = MAX_FIXED_ORDER; } + } else if (s->options.min_prediction_order < MIN_LPC_ORDER) { + av_log(avctx, AV_LOG_WARNING, + "invalid min prediction order %d, clamped to %d\n", + s->options.min_prediction_order, MIN_LPC_ORDER); + s->options.min_prediction_order = MIN_LPC_ORDER; } if (s->options.max_prediction_order < s->options.min_prediction_order) { -- 2.52.0 >From 476836916e4920040c18772ba2037e5bad60770e Mon Sep 17 00:00:00 2001 From: zhang xingxing <[email protected]> Date: Thu, 15 Oct 2026 04:20:11 +0200 Subject: [PATCH 3/8] avfilter/vf_dblur: copy each float row once Fixes: Timeout Fixes: zr8SXnvvQBqZ Fixes: swarm-Quadratic-memcpy-loop-in-F32-pixel-path-causes-input-driven-CPU-DoS-71c857 Found-by: zhang xingxing <[email protected]> Timeout Replicated through UnModified FFmpeg with time measurement Signed-off-by: Michael Niedermayer <[email protected]> --- libavfilter/vf_dblur.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/libavfilter/vf_dblur.c b/libavfilter/vf_dblur.c index 517d4e5617..0b5085b92b 100644 --- a/libavfilter/vf_dblur.c +++ b/libavfilter/vf_dblur.c @@ -247,9 +247,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) } } else { for (y = 0; y < height; y++) { - for (x = 0; x < width; x++) { - memcpy(bptr, src32, width * sizeof(float)); - } + memcpy(bptr, src32, width * sizeof(float)); bptr += width; src32 += in->linesize[plane] / 4; } @@ -276,9 +274,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) } } else { for (y = 0; y < height; y++) { - for (x = 0; x < width; x++) { - memcpy(dst32, bptr, width * sizeof(float)); - } + memcpy(dst32, bptr, width * sizeof(float)); bptr += width; dst32 += out->linesize[plane] / 4; } -- 2.52.0 >From a6ccf80cb0d30839919fd89cd80a006ad3c9ae49 Mon Sep 17 00:00:00 2001 From: Michael Niedermayer <[email protected]> Date: Thu, 15 Oct 2026 04:27:22 +0200 Subject: [PATCH 4/8] avfilter/vf_fieldmatch: reject heights too small for the comb detection Fixes: out of array read Fixes: 0fHkOzVCAhre Fixes: swarm-OOB-read-in-combed-score-when-height-3-df4610 Found-by: zhang xingxing <[email protected]> A height check in config_input() was suggested in the report. Out of array read Replicated through UnModified FFmpeg with ASAN Signed-off-by: Michael Niedermayer <[email protected]> --- libavfilter/vf_fieldmatch.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/libavfilter/vf_fieldmatch.c b/libavfilter/vf_fieldmatch.c index d806910364..7ce5d23fdb 100644 --- a/libavfilter/vf_fieldmatch.c +++ b/libavfilter/vf_fieldmatch.c @@ -955,6 +955,11 @@ static int config_input(AVFilterLink *inlink) const int w = inlink->w; const int h = inlink->h; + if (h <= fm->blocky / 2 || AV_CEIL_RSHIFT(h, pix_desc->log2_chroma_h) < 4) { + av_log(ctx, AV_LOG_ERROR, "Height %d is too small\n", h); + return AVERROR(EINVAL); + } + fm->scthresh = (int64_t)((w * h * 255.0 * fm->scthresh_flt) / 100.0); if ((ret = av_image_alloc(fm->map_data, fm->map_linesize, w, h, inlink->format, 32)) < 0 || -- 2.52.0 >From 7082d37d6ea602de04f2c00969dcf7d1fe13c1c1 Mon Sep 17 00:00:00 2001 From: Michael Niedermayer <[email protected]> Date: Thu, 15 Oct 2026 04:29:34 +0200 Subject: [PATCH 5/8] avfilter/vf_fieldmatch: stop compare_fields() at the last complete field line Fixes: out of array read Fixes: 8Vo2w4S3WNCd Found during triage/review of the security report 0fHkOzVCAhre Out of array read Replicated through UnModified FFmpeg with ASAN Signed-off-by: Michael Niedermayer <[email protected]> --- libavfilter/vf_fieldmatch.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/libavfilter/vf_fieldmatch.c b/libavfilter/vf_fieldmatch.c index 7ce5d23fdb..384714f23d 100644 --- a/libavfilter/vf_fieldmatch.c +++ b/libavfilter/vf_fieldmatch.c @@ -496,7 +496,7 @@ static int compare_fields(FieldMatchContext *fm, int match1, int match2, int fie const AVFrame *src = fm->src; for (plane = 0; plane < (fm->mchroma ? 3 : 1); plane++) { - int x, y, temp1, temp2, fbase; + int x, y, temp1, temp2, fbase, stopy; const AVFrame *prev, *next; uint8_t *mapp = fm->map_data[plane]; int map_linesize = fm->map_linesize[plane]; @@ -519,6 +519,7 @@ static int compare_fields(FieldMatchContext *fm, int match1, int match2, int fie /* match1 */ fbase = get_field_base(match1, field); srcf = srcp + (fbase + 1) * src_linesize; + stopy = height - 1 - fbase; srcpf = srcf - srcf_linesize; srcnf = srcf + srcf_linesize; mapp = mapp + fbase * map_linesize; @@ -544,7 +545,7 @@ static int compare_fields(FieldMatchContext *fm, int match1, int match2, int fie build_diff_map(fm, prvnf, prvf_linesize, nxtnf, nxtf_linesize, mapp + map_linesize, map_linesize, height, width, plane); - for (y = 2; y < height - 2; y += 2) { + for (y = 2; y < stopy; y += 2) { if (y0a == y1a || y < y0a || y > y1a) { for (x = startx; x < stopx; x++) { if (mapp[x] > 0 || mapp[x + map_linesize] > 0) { -- 2.52.0 >From 583e5b42308acf49eb935acc7db3251375724b0b Mon Sep 17 00:00:00 2001 From: Michael Niedermayer <[email protected]> Date: Thu, 15 Oct 2026 04:32:07 +0200 Subject: [PATCH 6/8] avfilter/vf_fieldmatch: use the chroma subsampling when marking combed chroma Fixes: out of array write Fixes: z4YbWg6eX0Hr Found during triage/review of the security report 0fHkOzVCAhre Out of array write Replicated through UnModified FFmpeg with ASAN Signed-off-by: Michael Niedermayer <[email protected]> --- libavfilter/vf_fieldmatch.c | 26 +++++++++++--------------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/libavfilter/vf_fieldmatch.c b/libavfilter/vf_fieldmatch.c index 384714f23d..abbfc0e9cf 100644 --- a/libavfilter/vf_fieldmatch.c +++ b/libavfilter/vf_fieldmatch.c @@ -271,21 +271,14 @@ static int calc_combed_score(const FieldMatchContext *fm, const AVFrame *src) } if (fm->chroma) { - uint8_t *cmkp = fm->cmask_data[0]; uint8_t *cmkpU = fm->cmask_data[1]; uint8_t *cmkpV = fm->cmask_data[2]; - const int width = AV_CEIL_RSHIFT(src->width, fm->hsub[INPUT_MAIN]); - const int height = AV_CEIL_RSHIFT(src->height, fm->vsub[INPUT_MAIN]); - const int cmk_linesize = fm->cmask_linesize[0] << 1; + const int hsub = fm->hsub[INPUT_MAIN]; + const int vsub = fm->vsub[INPUT_MAIN]; + const int width = AV_CEIL_RSHIFT(src->width, hsub); + const int height = AV_CEIL_RSHIFT(src->height, vsub); const int cmk_linesizeUV = fm->cmask_linesize[2]; - uint8_t *cmkpp = cmkp - (cmk_linesize>>1); - uint8_t *cmkpn = cmkp + (cmk_linesize>>1); - uint8_t *cmkpnn = cmkp + cmk_linesize; for (y = 1; y < height - 1; y++) { - cmkpp += cmk_linesize; - cmkp += cmk_linesize; - cmkpn += cmk_linesize; - cmkpnn += cmk_linesize; cmkpV += cmk_linesizeUV; cmkpU += cmk_linesizeUV; for (x = 1; x < width - 1; x++) { @@ -294,10 +287,13 @@ static int calc_combed_score(const FieldMatchContext *fm, const AVFrame *src) p[(x)-1 + (lz)] == 0xff || p[(x) + (lz)] == 0xff || p[(x)+1 + (lz)] == 0xff) if ((cmkpV[x] == 0xff && HAS_FF_AROUND(cmkpV, cmk_linesizeUV)) || (cmkpU[x] == 0xff && HAS_FF_AROUND(cmkpU, cmk_linesizeUV))) { - ((uint16_t*)cmkp)[x] = 0xffff; - ((uint16_t*)cmkpn)[x] = 0xffff; - if (y&1) ((uint16_t*)cmkpp)[x] = 0xffff; - else ((uint16_t*)cmkpnn)[x] = 0xffff; + int ystart = y << vsub, yend = (y + 1) << vsub; + if (vsub) { + ystart -= y & 1; + yend += !(y & 1); + } + for (int yy = ystart; yy < yend; yy++) + memset(fm->cmask_data[0] + yy * fm->cmask_linesize[0] + (x << hsub), 0xff, 1 << hsub); } } } -- 2.52.0 >From b1ebde40ea470a162438e0169735301fd6196609 Mon Sep 17 00:00:00 2001 From: zhang xingxing <[email protected]> Date: Thu, 15 Oct 2026 04:35:32 +0200 Subject: [PATCH 7/8] avformat/dashdec: do not seek before the first segment Fixes: lyANsYWHaqPo Fixes: swarm-Out-of-bounds-fragments-array-index-lacks-sign-check-38a148 Found-by: zhang xingxing <[email protected]> Request of nonexistent segments Replicated through UnModified FFmpeg with the demuxer log Signed-off-by: Michael Niedermayer <[email protected]> --- libavformat/dashdec.c | 1 + 1 file changed, 1 insertion(+) diff --git a/libavformat/dashdec.c b/libavformat/dashdec.c index 90a5897b38..8a25d0b4d5 100644 --- a/libavformat/dashdec.c +++ b/libavformat/dashdec.c @@ -2498,6 +2498,7 @@ set_seq_num: (int64_t)pls->cur_seq_no); } else if (pls->fragment_duration > 0) { pls->cur_seq_no = pls->first_seq_no + ((seek_pos_msec * pls->fragment_timescale) / pls->fragment_duration) / 1000; + pls->cur_seq_no = FFMAX(pls->cur_seq_no, pls->first_seq_no); } else { av_log(pls->parent, AV_LOG_ERROR, "dash_seek missing timeline or fragment_duration\n"); pls->cur_seq_no = pls->first_seq_no; -- 2.52.0 >From 1840b6e8e2a709e2288d3d3ef668bc67ce73ddf1 Mon Sep 17 00:00:00 2001 From: Michael Niedermayer <[email protected]> Date: Thu, 15 Oct 2026 04:39:11 +0200 Subject: [PATCH 8/8] avformat/r3d: seek through an index built from the RDVO offsets Fixes: nLpmeA2sqSrC Fixes: swarm-r3d_seek-uses-count-as-byte-offset-seeks-to-wrong-location-74db25 Found-by: zhang xingxing <[email protected]> The report suggested seeking to the frame offsets of the RDVO atom. Failing seek Replicated through UnModified FFmpeg with the R3D samples Signed-off-by: Michael Niedermayer <[email protected]> --- libavformat/r3d.c | 30 ++++-------------------------- 1 file changed, 4 insertions(+), 26 deletions(-) diff --git a/libavformat/r3d.c b/libavformat/r3d.c index 7abbea3c41..663c40d9eb 100644 --- a/libavformat/r3d.c +++ b/libavformat/r3d.c @@ -129,6 +129,10 @@ static int r3d_read_rdvo(AVFormatContext *s, Atom *atom) break; } av_log(s, AV_LOG_TRACE, "video offset %d: %#x\n", i, video_offset); + if (st->avg_frame_rate.num) + av_add_index_entry(st, video_offset, + av_rescale_q(i, av_inv_q(st->avg_frame_rate), st->time_base), + 0, 0, AVINDEX_KEYFRAME); } if (st->avg_frame_rate.num) @@ -377,31 +381,6 @@ static int r3d_probe(const AVProbeData *p) return 0; } -static int r3d_seek(AVFormatContext *s, int stream_index, int64_t sample_time, int flags) -{ - AVStream *st = s->streams[0]; // video stream - R3DContext *r3d = s->priv_data; - int frame_num; - - if (!st->avg_frame_rate.num) - return -1; - - frame_num = av_rescale_q(sample_time, st->time_base, - av_inv_q(st->avg_frame_rate)); - av_log(s, AV_LOG_TRACE, "seek frame num %d timestamp %"PRId64"\n", - frame_num, sample_time); - - if (frame_num < r3d->video_offsets_count) { - if (avio_seek(s->pb, r3d->video_offsets_count, SEEK_SET) < 0) - return -1; - } else { - av_log(s, AV_LOG_ERROR, "could not seek to frame %d\n", frame_num); - return -1; - } - - return 0; -} - const FFInputFormat ff_r3d_demuxer = { .p.name = "r3d", .p.long_name = NULL_IF_CONFIG_SMALL("REDCODE R3D"), @@ -409,5 +388,4 @@ const FFInputFormat ff_r3d_demuxer = { .read_probe = r3d_probe, .read_header = r3d_read_header, .read_packet = r3d_read_packet, - .read_seek = r3d_seek, }; -- 2.52.0 _______________________________________________ ffmpeg-devel mailing list -- [email protected] To unsubscribe send an email to [email protected]
