@@ -225,8 +225,9 @@ static int op_pass_setup(const SwsFrame *out, const SwsFrame *in,
for (int i = 0; i < p->planes_in; i++) {
const int idx = p->idx_in[i];
size_t input_bytes = in->linesize[idx];
- if (p->filter_size_h && float_in) {
- /* Floating point inputs may contain NaN / Infinity in the padding */
+ if (!pass->input || (p->filter_size_h && float_in)) {
+ /* Caller frames may be unpadded, and floating point inputs
+ * may contain NaN / Infinity in the padding */
const int plane_w = AV_CEIL_RSHIFT(in->width, exec->in_sub_x[i]);
input_bytes = pixel_bytes(plane_w, p->pixel_bits_in, AV_ROUND_UP);
}
@@ -256,7 +257,11 @@ static int op_pass_setup(const SwsFrame *out, const SwsFrame *in,
for (int i = 0; i < p->planes_out; i++) {
const int idx = p->idx_out[i];
- size_t safe_bytes = safe_bytes_pad(out->linesize[idx], comp->over_write[i]);
+ size_t output_bytes = out->linesize[idx];
+ if (!pass->output->avframe)
+ output_bytes = pixel_bytes(AV_CEIL_RSHIFT(out->width, exec->out_sub_x[i]),
+ p->pixel_bits_out, AV_ROUND_UP);
+ size_t safe_bytes = safe_bytes_pad(output_bytes, comp->over_write[i]);
size_t safe_blocks_out = safe_bytes / exec->block_size_out[i];
if (safe_blocks_out < num_blocks) {
p->memcpy_out = true;
--
2.52.0
>From 8042f48e893ffaf0847b3964851f0446abf397b8 Mon Sep 17 00:00:00 2001
From: Michael Niedermayer <michael@niedermayer.cc>
Date: Fri, 2 Oct 2026 03:25:33 +0200
Subject: [PATCH 2/4] swscale/graph: do not copy past the last line in
run_copy()
Use ff_copyPlane() with the width of the line. It still copies equal
positive linesizes as one block, but ends it with the last line.
Found during triage of the security report edlOwd4qVGBw.
Fixes: out of array read
Fixes: out of array write
Fixes: negative size memcpy()
Fixes: xvstjaVdxtut
Regression since: bf738412e8
Replicated through API
---
libswscale/graph.c | 11 +++--------
1 file changed, 3 insertions(+), 8 deletions(-)
@@ -292,15 +292,10 @@ static void run_copy(const SwsFrame *out, const SwsFrame *in, int y, int h,
if (in_data[i] == out_data[i]) {
av_assert0(in->linesize[i] == out->linesize[i]);
- } else if (in->linesize[i] == out->linesize[i]) {
- memcpy(out_data[i], in_data[i], lines * out->linesize[i]);
} else {
- const int linesize = FFMIN(out->linesize[i], in->linesize[i]);
- for (int j = 0; j < lines; j++) {
- memcpy(out_data[i], in_data[i], linesize);
- in_data[i] += in->linesize[i];
- out_data[i] += out->linesize[i];
- }
+ ff_copyPlane(in_data[i], in->linesize[i], 0, lines,
+ av_image_get_linesize(out->format, out->width, i),
+ out_data[i], out->linesize[i]);
}
}
}
--
2.52.0
>From 3fba40598e8300481f53dcf1964bef4ed9dd0ce9 Mon Sep 17 00:00:00 2001
From: Michael Niedermayer <michael@niedermayer.cc>
Date: Fri, 2 Oct 2026 03:35:17 +0200
Subject: [PATCH 3/4] swscale/swscale_unscaled: do not copy past the last line
in packedCopyWrapper()
Use ff_copyPlane()
Found during triage of the security report edlOwd4qVGBw.
Fixes: out of array read
Fixes: out of array write
Fixes: IhE83jd9Xs9n
Replicated through API
---
libswscale/swscale_unscaled.c | 18 ++++--------------
1 file changed, 4 insertions(+), 14 deletions(-)
@@ -32,6 +32,7 @@
#include "libavutil/mathematics.h"
#include "libavutil/mem_internal.h"
#include "libavutil/bswap.h"
+#include "libavutil/imgutils.h"
#include "libavutil/pixdesc.h"
#include "libavutil/avassert.h"
#include "libavutil/avconfig.h"
@@ -2139,20 +2140,9 @@ static int packedCopyWrapper(SwsInternal *c, const uint8_t *const src[],
const int srcStride[], int srcSliceY, int srcSliceH,
uint8_t *const dst[], const int dstStride[])
{
- if (dstStride[0] == srcStride[0] && srcStride[0] > 0)
- memcpy(dst[0] + dstStride[0] * srcSliceY, src[0], srcSliceH * dstStride[0]);
- else {
- int i;
- const uint8_t *srcPtr = src[0];
- uint8_t *dstPtr = dst[0] + dstStride[0] * srcSliceY;
-
- const int length = FFMIN(FFABS(dstStride[0]), FFABS(srcStride[0]));
- for (i = 0; i < srcSliceH; i++) {
- memcpy(dstPtr, srcPtr, length);
- srcPtr += srcStride[0];
- dstPtr += dstStride[0];
- }
- }
+ ff_copyPlane(src[0], srcStride[0], srcSliceY, srcSliceH,
+ av_image_get_linesize(c->opts.src_format, c->opts.src_w, 0),
+ dst[0], dstStride[0]);
return srcSliceH;
}
--
2.52.0
>From f7ae08b9704550dc7726ebd15119c1a8200130a1 Mon Sep 17 00:00:00 2001
From: Michael Niedermayer <michael@niedermayer.cc>
Date: Fri, 2 Oct 2026 06:01:09 +0200
Subject: [PATCH 4/4] swscale/ops_memcpy: do not clear or copy past the last
line
Found during triage of the security report edlOwd4qVGBw.
Fixes: out of array read
Fixes: out of array write
Fixes: negative size memset() / memcpy()
Fixes: orU7yZg5HmsB
Regression since: a151b426f9
Replicated through API
Replicated through UnModified FFmpeg
---
libswscale/ops_memcpy.c | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
@@ -49,9 +49,11 @@ static void process(const SwsOpExec *exec, const void *priv,
uint8_t *out = exec->out[i];
const int idx = p->index[i];
const int bytes = x_end * exec->block_size_out[i];
- const int use_loop = exec->out_stride[i] > bytes + SWS_MAX_PADDING;
+ const int use_loop = exec->out_stride[i] < 0 ||
+ exec->out_stride[i] > bytes + SWS_MAX_PADDING;
+ const int span = (lines - 1) * exec->out_stride[i] + bytes;
if (idx < 0 && !use_loop) {
- memset(out, p->clear_value[i], exec->out_stride[i] * lines);
+ memset(out, p->clear_value[i], span);
} else if (idx < 0) {
for (int y = y_start; y < y_end; y++) {
memset(out, p->clear_value[i], bytes);
@@ -61,7 +63,7 @@ static void process(const SwsOpExec *exec, const void *priv,
av_assert1(exec->out_stride[i] == exec->in_stride[idx]);
continue; /* plane was already ref'd */
} else if (exec->out_stride[i] == exec->in_stride[idx] && !use_loop) {
- memcpy(out, exec->in[idx], exec->out_stride[i] * lines);
+ memcpy(out, exec->in[idx], span);
} else {
const uint8_t *in = exec->in[idx];
for (int y = y_start; y < y_end; y++) {