PR #21047 opened by russelltg
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/21047
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/21047.patch
Reading the spec for what this flag means, it copies the data verbatim,
including any swizzling/tiling, this has two issues
1. the format may not be what ffmpeg expects elsewhere, as it is expecing
normal pitch linear host memeory in `swf`
2. the size of the copied data may not match the size of buffer provided,
causing heap buffer overflow
It seems like addition of this flag is an oversight as it seems to be for
caching/backups of image data, just to be used with copying back to the GPU
with the MEMCPY flag, which is *not* how its used in ffmpeg.
Additionally, set memoryRowLength as if it isn't set, it assumes pitch =
width_in_bytes, which I don't think is necessarily the case
This fixed a heap buffer overflow & garbled video (due to the tiled image data
being treated as pitch linear). This was with a vulkan video filter with a
`hwdownload` at the end of it. I could probably get commandline arguments that
would repro it if that's helpful. This was using my ffmpeg-based screen
recording application.
```
==234154==ERROR: AddressSanitizer: heap-buffer-overflow on address
0xfbffd50ac810 at pc 0xaaaaaae60f60 bp 0xffffffff9f70 sp 0xffffffff9760
WRITE of size 4259840 at 0xfbffd50ac810 thread T0
#0 0xaaaaaae60f5c in __asan_memcpy
(/home/russell/wl-screenrec/target/aarch64-unknown-linux-gnu/debug/wl-screenrec+0x3c0f5c)
(BuildId: 1ddba63896f47bdea3338258712251d7e4fc2265)
#1 0xfbffea52c8fc in hk_copy_image_to_memory
/home/russell/mesa/build/../src/asahi/vulkan/hk_image.c:1538:10
#2 0xfbffea52be34 in hk_CopyImageToMemoryEXT
/home/russell/mesa/build/../src/asahi/vulkan/hk_image.c:1562:7
#3 0xfffff0ebdadc in vulkan_transfer_host
/home/russell/ffmpeg/libavutil/hwcontext_vulkan.c:4488:13
#4 0xfffff0eb9dbc in vulkan_transfer_frame
/home/russell/ffmpeg/libavutil/hwcontext_vulkan.c:4536:16
#5 0xfffff0e9f1dc in vulkan_transfer_data_from
/home/russell/ffmpeg/libavutil/hwcontext_vulkan.c:4798:20
#6 0xfffff0e6b734 in av_hwframe_transfer_data
/home/russell/ffmpeg/libavutil/hwcontext.c:490:19
#7 0xfffff38c2504 in hwdownload_filter_frame
/home/russell/ffmpeg/libavfilter/vf_hwdownload.c:141:11
#8 0xfffff343e1b0 in filter_frame_framed
/home/russell/ffmpeg/libavfilter/avfilter.c:1058:11
#9 0xfffff343d3dc in filter_frame_to_filter
/home/russell/ffmpeg/libavfilter/avfilter.c:1214:11
#10 0xfffff3439554 in filter_activate_default
/home/russell/ffmpeg/libavfilter/avfilter.c:1276:20
#11 0xfffff3439024 in ff_filter_activate
/home/russell/ffmpeg/libavfilter/avfilter.c:1458:49
#12 0xfffff3443f3c in ff_filter_graph_run_once
/home/russell/ffmpeg/libavfilter/avfiltergraph.c:1631:12
#13 0xfffff3454bec in get_frame_internal
/home/russell/ffmpeg/libavfilter/buffersink.c:139:19
#14 0xfffff34547d0 in av_buffersink_get_frame_flags
/home/russell/ffmpeg/libavfilter/buffersink.c:157:12
#15 0xfffff34546cc in av_buffersink_get_frame
/home/russell/ffmpeg/libavfilter/buffersink.c:96:12
#16 0xaaaaab5a1704 in <ffmpeg_next::filter::context::sink::Sink>::frame
/home/russell/rust-ffmpeg/src/filter/context/sink.rs:19:19
#17 0xaaaaaaf00400 in <wl_screenrec::EncState>::process_ready
/home/russell/wl-screenrec/src/main.rs:2002:14
#18 0xaaaaaaf0912c in <wl_screenrec::EncState>::push
/home/russell/wl-screenrec/src/main.rs:2156:14
#19 0xaaaaaaf033e4 in <wl_screenrec::EncState>::push_with_fpslimit
/home/russell/wl-screenrec/src/main.rs:2166:18
#20 0xaaaaab048f5c in
<wl_screenrec::State<wl_screenrec::cap_ext_image_copy::CapExtImageCopy>>::on_copy_complete
/home/russell/wl-screenrec/src/main.rs:1388:13
#21 0xaaaaaaf0d008 in
<wl_screenrec::State<wl_screenrec::cap_ext_image_copy::CapExtImageCopy> as
wayland_client::event_queue::Dispatch<wayland_protocols::ext::image_copy_capture::v1::generated::client::ext_image_copy_capture_frame_v1::ExtImageCopyCaptureFrameV1,
()>>::event /home/russell/wl-screenrec/src/cap_ext_image_copy.rs:148:23
#22 0xaaaaab08a104 in
wayland_client::event_queue::queue_callback::<wayland_protocols::ext::image_copy_capture::v1::generated::client::ext_image_copy_capture_frame_v1::ExtImageCopyCaptureFrameV1,
(), wl_screenrec::State<wl_screenrec::cap_ext_image_copy::CapExtImageCopy>>
/home/russell/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/wayland-client-0.31.11/src/event_queue.rs:660:5
#23 0xaaaaab091838 in
<wayland_client::event_queue::EventQueue<wl_screenrec::State<wl_screenrec::cap_ext_image_copy::CapExtImageCopy>>>::dispatching_impl
/home/russell/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/wayland-client-0.31.11/src/event_queue.rs:482:13
#24 0xaaaaab0914e0 in
<wayland_client::event_queue::EventQueue<wl_screenrec::State<wl_screenrec::cap_ext_image_copy::CapExtImageCopy>>>::dispatch_pending
/home/russell/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/wayland-client-0.31.11/src/event_queue.rs:388:9
#25 0xaaaaab036da8 in
wl_screenrec::execute::<wl_screenrec::cap_ext_image_copy::CapExtImageCopy>
/home/russell/wl-screenrec/src/main.rs:2408:27
#26 0xaaaaaaefd7b0 in wl_screenrec::main
/home/russell/wl-screenrec/src/main.rs:2309:17
#27 0xaaaaaafbe220 in <fn() as core::ops::function::FnOnce<()>>::call_once
/home/russell/.rustup/toolchains/nightly-aarch64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/ops/function.rs:250:5
#28 0xaaaaab0b7464 in
std::sys::backtrace::__rust_begin_short_backtrace::<fn(), ()>
/home/russell/.rustup/toolchains/nightly-aarch64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/sys/backtrace.rs:160:18
#29 0xaaaaab0b9bc8 in std::rt::lang_start::<()>::{closure#0}
/home/russell/.rustup/toolchains/nightly-aarch64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/rt.rs:206:18
#30 0xaaaaab7d3b24 in <&dyn core::ops::function::Fn<(), Output = i32> +
core::panic::unwind_safe::RefUnwindSafe + core::marker::Sync as
core::ops::function::FnOnce<()>>::call_once
/home/russell/.rustup/toolchains/nightly-aarch64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/ops/function.rs:287:21
#31 0xaaaaab7499a0 in std::panicking::catch_unwind::do_call::<&dyn
core::ops::function::Fn<(), Output = i32> +
core::panic::unwind_safe::RefUnwindSafe + core::marker::Sync, i32>
/home/russell/.rustup/toolchains/nightly-aarch64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/panicking.rs:581:40
#32 0xaaaaab7657b8 in __rust_try std.4e621071a487158-cgu.10
#33 0xaaaaab746a28 in std::panicking::catch_unwind::<i32, &dyn
core::ops::function::Fn<(), Output = i32> +
core::panic::unwind_safe::RefUnwindSafe + core::marker::Sync>
/home/russell/.rustup/toolchains/nightly-aarch64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/panicking.rs:544:19
#34 0xaaaaab7b3e68 in std::panic::catch_unwind::<&dyn
core::ops::function::Fn<(), Output = i32> +
core::panic::unwind_safe::RefUnwindSafe + core::marker::Sync, i32>
/home/russell/.rustup/toolchains/nightly-aarch64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/panic.rs:359:14
#35 0xaaaaab7fc2d0 in std::rt::lang_start_internal::{closure#0}
/home/russell/.rustup/toolchains/nightly-aarch64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/rt.rs:175:24
#36 0xaaaaab749824 in
std::panicking::catch_unwind::do_call::<std::rt::lang_start_internal::{closure#0},
isize>
/home/russell/.rustup/toolchains/nightly-aarch64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/panicking.rs:581:40
#37 0xaaaaab7657b8 in __rust_try std.4e621071a487158-cgu.10
#38 0xaaaaab746740 in std::panicking::catch_unwind::<isize,
std::rt::lang_start_internal::{closure#0}>
/home/russell/.rustup/toolchains/nightly-aarch64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/panicking.rs:544:19
#39 0xaaaaab7b3db8 in
std::panic::catch_unwind::<std::rt::lang_start_internal::{closure#0}, isize>
/home/russell/.rustup/toolchains/nightly-aarch64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/panic.rs:359:14
#40 0xaaaaab809504 in std::rt::lang_start_internal
/home/russell/.rustup/toolchains/nightly-aarch64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/rt.rs:171:5
#41 0xaaaaab0b9b04 in std::rt::lang_start::<()>
/home/russell/.rustup/toolchains/nightly-aarch64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/rt.rs:205:5
#42 0xaaaaaaf27350 in main
(/home/russell/wl-screenrec/target/aarch64-unknown-linux-gnu/debug/wl-screenrec+0x487350)
(BuildId: 1ddba63896f47bdea3338258712251d7e4fc2265)
#43 0xfffff0476558 in __libc_start_call_main (/lib64/libc.so.6+0x26558)
(BuildId: 53942cc539ef341e28bf18b9f8441e5f82590bfb)
#44 0xfffff0476638 in __libc_start_main@GLIBC_2.17
(/lib64/libc.so.6+0x26638) (BuildId: 53942cc539ef341e28bf18b9f8441e5f82590bfb)
#45 0xaaaaaadbe46c in _start
(/home/russell/wl-screenrec/target/aarch64-unknown-linux-gnu/debug/wl-screenrec+0x31e46c)
(BuildId: 1ddba63896f47bdea3338258712251d7e4fc2265)
0xfbffd50ac810 is located 0 bytes after 4096016-byte region
[0xfbffd4cc4800,0xfbffd50ac810)
allocated by thread T0 here:
#0 0xaaaaaae63e00 in posix_memalign
(/home/russell/wl-screenrec/target/aarch64-unknown-linux-gnu/debug/wl-screenrec+0x3c3e00)
(BuildId: 1ddba63896f47bdea3338258712251d7e4fc2265)
#1 0xfffff0edde8c in av_malloc /home/russell/ffmpeg/libavutil/mem.c:107:9
#2 0xfffff0e12c34 in av_buffer_alloc
/home/russell/ffmpeg/libavutil/buffer.c:82:12
#3 0xfffff0e12d40 in av_buffer_allocz
/home/russell/ffmpeg/libavutil/buffer.c:95:24
#4 0xfffff0e15428 in pool_alloc_buffer
/home/russell/ffmpeg/libavutil/buffer.c:369:26
#5 0xfffff0e14ec4 in av_buffer_pool_get
/home/russell/ffmpeg/libavutil/buffer.c:407:15
#6 0xfffff350ada0 in ff_frame_pool_get
/home/russell/ffmpeg/libavfilter/framepool.c:220:29
#7 0xfffff3e45c28 in ff_default_get_video_buffer2
/home/russell/ffmpeg/libavfilter/video.c:100:13
#8 0xfffff3e45fc4 in ff_default_get_video_buffer
/home/russell/ffmpeg/libavfilter/video.c:114:12
#9 0xfffff3e454b4 in ff_get_video_buffer
/home/russell/ffmpeg/libavfilter/video.c:127:15
#10 0xfffff38c24cc in hwdownload_filter_frame
/home/russell/ffmpeg/libavfilter/vf_hwdownload.c:134:14
#11 0xfffff343e1b0 in filter_frame_framed
/home/russell/ffmpeg/libavfilter/avfilter.c:1058:11
#12 0xfffff343d3dc in filter_frame_to_filter
/home/russell/ffmpeg/libavfilter/avfilter.c:1214:11
#13 0xfffff3439554 in filter_activate_default
/home/russell/ffmpeg/libavfilter/avfilter.c:1276:20
#14 0xfffff3439024 in ff_filter_activate
/home/russell/ffmpeg/libavfilter/avfilter.c:1458:49
#15 0xfffff3443f3c in ff_filter_graph_run_once
/home/russell/ffmpeg/libavfilter/avfiltergraph.c:1631:12
#16 0xfffff3454bec in get_frame_internal
/home/russell/ffmpeg/libavfilter/buffersink.c:139:19
#17 0xfffff34547d0 in av_buffersink_get_frame_flags
/home/russell/ffmpeg/libavfilter/buffersink.c:157:12
#18 0xfffff34546cc in av_buffersink_get_frame
/home/russell/ffmpeg/libavfilter/buffersink.c:96:12
#19 0xaaaaab5a1704 in <ffmpeg_next::filter::context::sink::Sink>::frame
/home/russell/rust-ffmpeg/src/filter/context/sink.rs:19:19
#20 0xaaaaaaf00400 in <wl_screenrec::EncState>::process_ready
/home/russell/wl-screenrec/src/main.rs:2002:14
#21 0xaaaaaaf0912c in <wl_screenrec::EncState>::push
/home/russell/wl-screenrec/src/main.rs:2156:14
#22 0xaaaaaaf033e4 in <wl_screenrec::EncState>::push_with_fpslimit
/home/russell/wl-screenrec/src/main.rs:2166:18
#23 0xaaaaab048f5c in
<wl_screenrec::State<wl_screenrec::cap_ext_image_copy::CapExtImageCopy>>::on_copy_complete
/home/russell/wl-screenrec/src/main.rs:1388:13
#24 0xaaaaaaf0d008 in
<wl_screenrec::State<wl_screenrec::cap_ext_image_copy::CapExtImageCopy> as
wayland_client::event_queue::Dispatch<wayland_protocols::ext::image_copy_capture::v1::generated::client::ext_image_copy_capture_frame_v1::ExtImageCopyCaptureFrameV1,
()>>::event /home/russell/wl-screenrec/src/cap_ext_image_copy.rs:148:23
#25 0xaaaaab08a104 in
wayland_client::event_queue::queue_callback::<wayland_protocols::ext::image_copy_capture::v1::generated::client::ext_image_copy_capture_frame_v1::ExtImageCopyCaptureFrameV1,
(), wl_screenrec::State<wl_screenrec::cap_ext_image_copy::CapExtImageCopy>>
/home/russell/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/wayland-client-0.31.11/src/event_queue.rs:660:5
#26 0xaaaaab091838 in
<wayland_client::event_queue::EventQueue<wl_screenrec::State<wl_screenrec::cap_ext_image_copy::CapExtImageCopy>>>::dispatching_impl
/home/russell/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/wayland-client-0.31.11/src/event_queue.rs:482:13
#27 0xaaaaab0914e0 in
<wayland_client::event_queue::EventQueue<wl_screenrec::State<wl_screenrec::cap_ext_image_copy::CapExtImageCopy>>>::dispatch_pending
/home/russell/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/wayland-client-0.31.11/src/event_queue.rs:388:9
#28 0xaaaaab036da8 in
wl_screenrec::execute::<wl_screenrec::cap_ext_image_copy::CapExtImageCopy>
/home/russell/wl-screenrec/src/main.rs:2408:27
#29 0xaaaaaaefd7b0 in wl_screenrec::main
/home/russell/wl-screenrec/src/main.rs:2309:17
SUMMARY: AddressSanitizer: heap-buffer-overflow
(/home/russell/wl-screenrec/target/aarch64-unknown-linux-gnu/debug/wl-screenrec+0x3c0f5c)
(BuildId: 1ddba63896f47bdea3338258712251d7e4fc2265) in __asan_memcpy
Shadow bytes around the buggy address:
0xfbffd50ac580: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0xfbffd50ac600: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0xfbffd50ac680: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0xfbffd50ac700: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0xfbffd50ac780: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0xfbffd50ac800: 00 00[fa]fa fa fa fa fa fa fa fa fa fa fa fa fa
0xfbffd50ac880: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0xfbffd50ac900: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0xfbffd50ac980: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0xfbffd50aca00: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0xfbffd50aca80: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable: 00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone: fa
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user: f7
Container overflow: fc
Array cookie: ac
Intra object redzone: bb
ASan internal: fe
Left alloca redzone: ca
Right alloca redzone: cb
==234154==ABORTING
```
>From d854561cfed51fbdca279e984c304aff9bf3f864 Mon Sep 17 00:00:00 2001
From: Russell Greene <[email protected]>
Date: Sat, 29 Nov 2025 12:42:13 -0700
Subject: [PATCH] hwcontext_vulkan: remove VK_HOST_IMAGE_COPY_MEMCPY flag
Reading the spec for what this flag means, it copies the data verbatim,
including any swizzling/tiling, this has two issues
1. the format may not be what ffmpeg expects elsewhere, as it is expecing
normal pitch linear host memeory in `swf`
2. the size of the copied data may not match the size of buffer provided,
causing heap buffer overflow
It seems like addition of this flag is an oversight as it seems to be for
caching/backups of image data, just to be used with copying back to the GPU
with the MEMCPY flag, which is *not* how its used in ffmpeg.
Additionally, set memoryRowLength as if it isn't set, it assumes pitch =
width_in_bytes, which I don't think is necessarily the case
---
libavutil/hwcontext_vulkan.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/libavutil/hwcontext_vulkan.c b/libavutil/hwcontext_vulkan.c
index a2caaa0959..aac7768033 100644
--- a/libavutil/hwcontext_vulkan.c
+++ b/libavutil/hwcontext_vulkan.c
@@ -4440,7 +4440,6 @@ static int vulkan_transfer_host(AVHWFramesContext *hwfc,
AVFrame *hwf,
};
VkCopyMemoryToImageInfoEXT copy_info = {
.sType = VK_STRUCTURE_TYPE_COPY_MEMORY_TO_IMAGE_INFO_EXT,
- .flags = VK_HOST_IMAGE_COPY_MEMCPY_EXT,
.regionCount = 1,
.pRegions = ®ion_info,
};
@@ -4466,7 +4465,6 @@ static int vulkan_transfer_host(AVHWFramesContext *hwfc,
AVFrame *hwf,
};
VkCopyImageToMemoryInfoEXT copy_info = {
.sType = VK_STRUCTURE_TYPE_COPY_IMAGE_TO_MEMORY_INFO_EXT,
- .flags = VK_HOST_IMAGE_COPY_MEMCPY_EXT,
.regionCount = 1,
.pRegions = ®ion_info,
};
@@ -4476,6 +4474,7 @@ static int vulkan_transfer_host(AVHWFramesContext *hwfc,
AVFrame *hwf,
get_plane_wh(&p_w, &p_h, swf->format, swf->width, swf->height, i);
region_info.pHostPointer = swf->data[i];
+ region_info.memoryRowLength = swf->linesize[i];
region_info.imageSubresource.aspectMask = ff_vk_aspect_flag(hwf,
i);
region_info.imageExtent = (VkExtent3D){ p_w, p_h, 1 };
copy_info.srcImage = hwf_vk->img[img_idx];
--
2.49.1
_______________________________________________
ffmpeg-devel mailing list -- [email protected]
To unsubscribe send an email to [email protected]