PR #23143 opened by Niklas Haas (haasn)
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/23143
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/23143.patch

These loops were both assuming that `h` lines need to be copied; but this
varies. First of all, for plane subsampling; but more importantly, when
vertically scaling, the input line count may be substantially lower than the
actual line count.

This fixes an out-of-bounds read/write when vertically upscaling with a tail
buffer.

Sponsored-by: Sovereign Tech Fund
Signed-off-by: Niklas Haas <[email protected]>


>From 4b9b13bb17168d53ae3fe1d7243ef5b4d3bf2e7e Mon Sep 17 00:00:00 2001
From: Niklas Haas <[email protected]>
Date: Mon, 18 May 2026 15:27:50 +0200
Subject: [PATCH] swscale/ops_dispatch: calculate correct slice line count for
 tail copy

These loops were both assuming that `h` lines need to be copied; but this
varies. First of all, for plane subsampling; but more importantly, when
vertically scaling, the input line count may be substantially lower than the
actual line count.

This fixes an out-of-bounds read/write when vertically upscaling with a tail
buffer.

Sponsored-by: Sovereign Tech Fund
Signed-off-by: Niklas Haas <[email protected]>
---
 libswscale/ops_dispatch.c | 18 ++++++++++++++++--
 1 file changed, 16 insertions(+), 2 deletions(-)

diff --git a/libswscale/ops_dispatch.c b/libswscale/ops_dispatch.c
index f477c7839a..fa233fb71e 100644
--- a/libswscale/ops_dispatch.c
+++ b/libswscale/ops_dispatch.c
@@ -143,6 +143,18 @@ static inline void get_row_data(const SwsOpPass *p, const 
int y_dst,
         out[i] = base->out[i] + (y_dst >> base->out_sub_y[i]) * 
base->out_stride[i];
 }
 
+static inline int get_lines_in(const SwsOpPass *p, const int y, const int h,
+                               const int plane)
+{
+    const SwsOpExec *base = &p->exec_base;
+    if (!p->offsets_y)
+        return h >> base->in_sub_y[plane];
+
+    const int y0 = p->offsets_y[y] >> base->in_sub_y[plane];
+    const int y1 = p->offsets_y[y + h - 1] >> base->in_sub_y[plane];
+    return y1 - y0 + 1;
+}
+
 static inline size_t pixel_bytes(size_t pixels, int pixel_bits,
                                  enum AVRounding rounding)
 {
@@ -414,8 +426,9 @@ static void op_pass_run(const SwsFrame *out, const SwsFrame 
*in, const int y,
 
     for (int i = 0; i < p->planes_in; i++) {
         if (memcpy_in) {
+            const int lines = get_lines_in(p, y, h, i);
             copy_lines((uint8_t *) tail.in[i], tail.in_stride[i],
-                       exec.in[i], exec.in_stride[i], h, p->tail_size_in);
+                       exec.in[i], exec.in_stride[i], lines, p->tail_size_in);
         } else {
             /* Reuse input pointers directly */
             const size_t loop_size = tail_blocks * exec.block_size_in;
@@ -438,8 +451,9 @@ static void op_pass_run(const SwsFrame *out, const SwsFrame 
*in, const int y,
     comp->func(&tail, comp->priv, num_blocks - tail_blocks, y, num_blocks, y + 
h);
 
     for (int i = 0; memcpy_out && i < p->planes_out; i++) {
+        const int lines = h >> tail.out_sub_y[i];
         copy_lines(exec.out[i], exec.out_stride[i],
-                   tail.out[i], tail.out_stride[i], h, p->tail_size_out);
+                   tail.out[i], tail.out_stride[i], lines, p->tail_size_out);
     }
 }
 
-- 
2.52.0

_______________________________________________
ffmpeg-devel mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to