avutil/opt: do not free a custom channel map the source still points to

av_opt_copy() documents that after it returns, allocated options in src
and dst no longer alias each other, even when dst was memdup'ed from src.
For AV_OPT_TYPE_CHLAYOUT it passed such aliased layouts straight to
av_channel_layout_copy(), which frees the custom map in dst and then
copies from the now freed map in src.

Handle this in opt_copy_elem(), like the AV_OPT_TYPE_DICT case, by
forgetting the aliased map in dst before the copy.

Fixes: heap-use-after-free
Fixes: BTOI3sLHWE0g
Found-by: Joshua Rogers <joshua.rogers@aisle.com>
This commit is contained in:
James Almer authored and michaelni committed 2026-10-10 21:27:56 +00:00
1 parent 4b924c367f
commit e70b1eddba
1 file changed
+8 -1
+8 -1
View File
@@ -2169,8 +2169,15 @@ static int opt_copy_elem(void *logctx, enum AVOptionType type,
*ddictp = NULL;
return av_dict_copy(ddictp, sdict, 0);
} else if (type == AV_OPT_TYPE_CHLAYOUT) {
if (dst != src)
const AVChannelLayout *slayout = (const AVChannelLayout *)src;
AVChannelLayout *dlayout = (AVChannelLayout *)dst;
if (dlayout != slayout) {
if (dlayout->order == AV_CHANNEL_ORDER_CUSTOM &&
slayout->order == AV_CHANNEL_ORDER_CUSTOM &&
dlayout->u.map == slayout->u.map)
dlayout->u.map = NULL;
return av_channel_layout_copy(dst, src);
}
} else if (opt_is_pod(type)) {
size_t size = opt_type_desc[type].size;
memcpy(dst, src, size);