Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions debian/changelog
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
ffmpeg (7:6.1.5-0deepin3) unstable; urgency=medium

* CVE-2026-8461: Fix heap out-of-bounds write in MagicYUV decoder
Complete upstream backport (PR #23159):
- reject slice_height misaligned with chroma vshift
- apply slice-height sanity check to progressive mode
- fix 1-line MEDIAN slice OOB read in magy_decode_slice10

-- Wang Yu <wangyu@uniontech.com> Fri, 26 Jun 2026 16:20:59 +0800

ffmpeg (7:6.1.5-0deepin2) unstable; urgency=medium

* CVE-2026-8461: Fix heap out-of-bounds write in MagicYUV decoder
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,42 +2,75 @@ From: deepin-ci-robot <packages@deepin.org>
Date: Wed, 24 Jun 2026 19:55:10 +0800
Subject: CVE-2026-8461: Fix heap out-of-bounds write in MagicYUV decoder

Move slice_height validation outside of interlaced-only block so it applies
to both interlaced and progressive modes. Otherwise, a crafted video with
odd slice_height can trigger a heap OOB write in the chroma plane.
Backport the complete upstream fix for CVE-2026-8461 (out-of-array access
in the MagicYUV decoder). A crafted video with a slice_height that is not
aligned to the chroma vertical subsampling, or with a degenerate 1-line
MEDIAN slice, can trigger a heap out-of-bounds write/read.

Three upstream commits are applied:

1. avcodec/magicyuv: reject slice_height misaligned with chroma vshift
Reject slice_height values that are not a multiple of the chroma
vertical subsampling factor (the original PoC trigger path).
(ed834bd0a291eca7b7093632a6995f3a27077376)

2. avcodec/magicyuv: Expand the s->interlaced slice-height sanity check
Apply the slice_height lower-bound check in both progressive and
interlaced modes by using `<= s->interlaced` instead of `< 2`
guarded behind `if (s->interlaced)`.
(aa7b8bd2a32d3d24b650649efd5be8bb51d4a43c)

3. avcodec/magicyuv: Fix 1 line MEDIAN slices
Guard `lefttop = left = dst[0]` in the 10-bit MEDIAN path so a
degenerate 1-line slice does not read out of bounds.
(b8f8dac0cf49918c19f5612c9d2bd4461a6efd99)

Origin: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/23159
Bug: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/23159
Bug-Debian: https://security-tracker.debian.org/tracker/CVE-2026-8461
Last-Update: 2026-06-24
---
libavcodec/magicyuv.c | 12 +++++-------
1 file changed, 5 insertions(+), 7 deletions(-)

diff --git a/libavcodec/magicyuv.c b/libavcodec/magicyuv.c
index 27f899e..41d2222 100644
index 27f899e..1de42f7 100644
--- a/libavcodec/magicyuv.c
+++ b/libavcodec/magicyuv.c
@@ -593,15 +593,13 @@ static int magy_decode_frame(AVCodecContext *avctx, AVFrame *p,
@@ -224,7 +224,8 @@ static int magy_decode_slice10(AVCodecContext *avctx, void *tdata,
s->llviddsp.add_left_pred_int16(dst, dst, max, width, 0);
dst += stride;
}
- lefttop = left = dst[0];
+ if (1 + interlaced < height)
+ lefttop = left = dst[0];
for (k = 1 + interlaced; k < height; k++) {
magicyuv_median_pred16(dst, dst - fake_stride, dst, width, &left, &lefttop, max);
lefttop = left = dst[0];
@@ -583,6 +584,13 @@ static int magy_decode_frame(AVCodecContext *avctx, AVFrame *p,
"invalid slice height: %d\n", s->slice_height);
return AVERROR_INVALIDDATA;
}
+ if (s->vshift[1] && (s->slice_height & ((1 << s->vshift[1]) - 1))) {
+ av_log(avctx, AV_LOG_ERROR,
+ "slice_height %d is not aligned to chroma vertical "
+ "subsampling (must be a multiple of %d)\n",
+ s->slice_height, 1 << s->vshift[1]);
+ return AVERROR_INVALIDDATA;
+ }

bytestream2_skipu(&gb, 4);

@@ -593,11 +601,11 @@ static int magy_decode_frame(AVCodecContext *avctx, AVFrame *p,
return AVERROR_INVALIDDATA;
}

- if (s->interlaced) {
- if ((s->slice_height >> s->vshift[1]) < 2) {
- av_log(avctx, AV_LOG_ERROR, "impossible slice height\n");
- return AVERROR_INVALIDDATA;
- }
- if ((avctx->coded_height % s->slice_height) && ((avctx->coded_height % s->slice_height) >> s->vshift[1]) < 2) {
- av_log(avctx, AV_LOG_ERROR, "impossible height\n");
- return AVERROR_INVALIDDATA;
- }
+ if ((s->slice_height >> s->vshift[1]) <= s->interlaced) {
+ av_log(avctx, AV_LOG_ERROR, "impossible slice height\n");
+ return AVERROR_INVALIDDATA;
+ }
+ if ((avctx->coded_height % s->slice_height) && ((avctx->coded_height % s->slice_height) >> s->vshift[1]) <= s->interlaced) {
+ av_log(avctx, AV_LOG_ERROR, "impossible height\n");
+ return AVERROR_INVALIDDATA;
}

if (bytestream2_get_bytes_left(&gb) <= s->nb_slices * s->planes * 5)
if (s->interlaced) {
- if ((s->slice_height >> s->vshift[1]) < 2) {
- av_log(avctx, AV_LOG_ERROR, "impossible slice height\n");
- return AVERROR_INVALIDDATA;
- }
if ((avctx->coded_height % s->slice_height) && ((avctx->coded_height % s->slice_height) >> s->vshift[1]) < 2) {
av_log(avctx, AV_LOG_ERROR, "impossible height\n");
return AVERROR_INVALIDDATA;
Loading