PR #25656 opened by ffmpeg-devel URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/25656 Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/25656.patch
**Backport:** https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/25523 Hi, the size checks in the cbs slice/OBU writers multiply the data size by 8 before comparing it against the space left in the write buffer. On a 32 bit build that multiplication wraps at 512 MiB, so the check can pass for data that does not fit and the copy then runs past the end of the buffer. cbs_mpeg2 is reachable: a generated 512 MiB slice unit passed through mpeg2_metadata makes the memcpy run off the 1 MiB write buffer (I hit this on an i486 build under qemu). cbs_h2645 and cbs_av1 have the same broken check, but their units are capped earlier (h2645_parse rejects anything over INT_MAX/8, and cbs_av1_split_fragment() does the same), so today they are defensive only. I fixed all three anyway, because a size check should not be correct only thanks to a cap in another module. This is the same rewrite that already landed for cbs_jpeg and cbs_vp9 earlier this month (compare the byte count against put_bits_left() / 8 instead). The slice writers keep the byte reserved for the rbsp_stop_one_bit by comparing data_size + 1; the two forms are the same for every non-wrapping size. What I ran: i486 static build under qemu - old code dies with SIGSEGV on the generated slice, patched code refuses cleanly with "Out of memory", small inputs round-trip fine on both. 64 bit: behaves the same before and after (the multiplication cannot wrap there). Thanks for taking a look. >From f8e017db6bdac7e1d40ce24a286cf91149513877 Mon Sep 17 00:00:00 2001 From: Altaf Khan <[email protected]> Date: Tue, 27 Oct 2026 17:54:18 +0530 Subject: [PATCH] avcodec/cbs: check slice and OBU data sizes without overflowing size_t The checks that compare a data size with the space left in the write buffer multiply the size by 8 first. That multiplication is done in size_t, so with a 32 bit size_t a data size of 2^29 - 1 bytes or more wraps and the check can pass for data that does not fit; the slice data is then copied past the end of the write buffer, which cbs_write_unit_data() caps at INT_MAX / 8 bytes. cbs_mpeg2 is reachable: the demuxer passes an oversized slice unit straight through to the metadata bitstream filter. On a 32 bit build a 512 MiB slice makes the check compare 16 against a non-zero put_bits_left() and the memcpy() runs off the 1 MiB buffer. cbs_h2645 and cbs_av1 cannot be reached today because h2645_parse and cbs_av1_split_fragment() reject units larger than INT_MAX / 8, but their checks are wrong in the same way and should not rely on that. Compare the byte count against put_bits_left() / 8 instead, as was already done for cbs_jpeg and cbs_vp9. The slice writers keep the byte reserved for the rbsp_stop_one_bit by comparing data_size + 1; the two forms are equivalent for every non-wrapping size. Signed-off-by: Altaf Khan <[email protected]> (cherry picked from commit a88838af482100fa22dd22c94be592c35642de46) --- libavcodec/cbs_av1.c | 2 +- libavcodec/cbs_h2645.c | 2 +- libavcodec/cbs_mpeg2.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/libavcodec/cbs_av1.c b/libavcodec/cbs_av1.c index 4bacebf0865..e4b275199ba 100644 --- a/libavcodec/cbs_av1.c +++ b/libavcodec/cbs_av1.c @@ -1199,7 +1199,7 @@ static int cbs_av1_write_obu(CodedBitstreamContext *ctx, flush_put_bits(pbc); av_assert0(data_pos <= start_pos); - if (8 * obu->obu_size > put_bits_left(pbc)) { + if (obu->obu_size > put_bits_left(pbc) / 8) { av_refstruct_unref(&priv->sequence_header_ref); av_buffer_unref(&priv->frame_header_ref); *priv = av1ctx; diff --git a/libavcodec/cbs_h2645.c b/libavcodec/cbs_h2645.c index 61b70f41184..9329554cab9 100644 --- a/libavcodec/cbs_h2645.c +++ b/libavcodec/cbs_h2645.c @@ -272,7 +272,7 @@ int ff_cbs_h2645_write_slice_data(CodedBitstreamContext *ctx, av_assert0(data_bit_start >= 0 && data_size > data_bit_start / 8); - if (data_size * 8 + 8 > put_bits_left(pbc)) + if (data_size + 1 > put_bits_left(pbc) / 8) return AVERROR(ENOSPC); if (!rest) diff --git a/libavcodec/cbs_mpeg2.c b/libavcodec/cbs_mpeg2.c index 87401d15436..57c22053938 100644 --- a/libavcodec/cbs_mpeg2.c +++ b/libavcodec/cbs_mpeg2.c @@ -319,7 +319,7 @@ static int cbs_mpeg2_write_slice(CodedBitstreamContext *ctx, av_assert0(slice->data_bit_start >= 0 && slice->data_size > slice->data_bit_start / 8); - if (slice->data_size * 8 + 8 > put_bits_left(pbc)) + if (slice->data_size + 1 > put_bits_left(pbc) / 8) return AVERROR(ENOSPC); // First copy the remaining bits of the first byte -- 2.54.0 _______________________________________________ ffmpeg-devel mailing list -- [email protected] To unsubscribe send an email to [email protected]
