Hi iceray-Li duplicate, fixed by commit 0685766183 in https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/24848 (not on master 12c589a37d yet).
thx
On Sun, Sep 27, 2026 at 04:07:34PM +0800, iceray-Li wrote:
>
> Hello,
>
> we would like to report an `AVERROR_BUG` leak from the decode API that we hit
> while fuzzing `tools/target_dec_fuzzer` built for H.264 on FFmpeg 9.0. There
> is
> no sanitizer finding involved; the failure is FFmpeg's own sentinel
> `av_assert0(ret != AVERROR_BUG)` in the fuzz target firing because
> `avcodec_receive_frame()` returned `AVERROR_BUG`.
>
> ## Summary
>
> When the H.264 decoder outputs a frame in a pixel format whose components are
> 2 bytes wide (`AV_PIX_FMT_YUV444P10LE` in our reproducer) and the stream asks
> for a non-zero horizontal crop, `av_frame_apply_cropping()` fails an internal
> alignment assumption and returns `AVERROR_BUG`. `ff_decode_receive_frame()`
> propagates it to `avcodec_receive_frame()`, so a normal API call returns
> `AVERROR_BUG` to the application.
>
> The condition is not exotic: for any planar format with `comp->step == 2`,
> `ff_ctz(crop_left * step) == ff_ctz(crop_left) + 1`, so the check
> `log2_crop_align < min_log2_align` in `libavutil/frame.c` is always true when
> `crop_left != 0`.
>
> ## Details
>
> ```c
> /* libavutil/frame.c : av_frame_apply_cropping() */
> if (!(flags & AV_FRAME_CROP_UNALIGNED)) {
> int log2_crop_align = frame->crop_left ? ff_ctz(frame->crop_left) :
> INT_MAX;
> int min_log2_align = INT_MAX;
>
> for (int i = 0; frame->data[i]; i++) {
> int log2_align = offsets[i] ? ff_ctz(offsets[i]) : INT_MAX;
> min_log2_align = FFMIN(log2_align, min_log2_align);
> }
>
> /* we assume, and it should always be true, that the data alignment is
> * related to the cropping alignment by a constant power-of-2 factor */
> if (log2_crop_align < min_log2_align)
> return AVERROR_BUG;
> ```
>
> Observed values at the failing call (gdb, `libavutil/frame.c`):
>
> ```text
> frame->format = AV_PIX_FMT_YUV444P10LE (comp->step = 2)
> width x height = 16 x 192
> crop_left/top/right/bot = 2 / 0 / 0 / 0
> linesize[0..2] = 64 / 64 / 64
> offsets[i] = crop_left * step = 4
> log2_crop_align = ff_ctz(2) = 1
> min_log2_align = ff_ctz(4) = 2
> -> return AVERROR_BUG
> ```
>
> The value is then propagated without being converted:
>
> ```text
> #0 ff_decode_receive_frame libavcodec/decode.c:836 (goto fail after
> apply_cropping)
> #1 avcodec_receive_frame_flags libavcodec/avcodec.c:716
> #2 avcodec_receive_frame libavcodec/avcodec.c:722
> #3 audio_video_handler tools/target_dec_fuzzer.c:97
> ```
>
> Note that `apply_cropping` is enabled by default
> (`libavcodec/options_table.h`:
> `apply_cropping` default `1`) and `AV_CODEC_FLAG_UNALIGNED` is not set by
> default, so ordinary applications take this path, not just the fuzzer.
>
> ## Reproduction
>
> - Project/version: FFmpeg 9.0 (`libavutil 61.1.100`)
> - OS: Linux x86_64, clang
> - Target: `tools/target_dec_fuzzer.c` built with `-DFFMPEG_DECODER=h264`
> (unmodified upstream target)
> - Flags: `-fsanitize=address,undefined -fno-sanitize-recover=all
> -fno-omit-frame-pointer -O2 -g`
> - Input: `ffmpeg_h264_apply_cropping_crop_left.poc` (314 bytes,
> sha256 `0ded9dee0af564589805ac923f87cb8c92433c7318ac68a2e149aad9ef2d13c5`)
>
> ```sh
> ./target_dec_fuzzer ffmpeg_h264_apply_cropping_crop_left.poc
> # -> Assertion ret != AVERROR_BUG failed at tools/target_dec_fuzzer.c:98
> # -> SIGABRT (exit 134)
> ```
>
> Replayed on an untouched 9.0 tree; also re-checked that
> `libavutil/frame.c` and `libavcodec/h264_slice.c` are unchanged on current
> `master` (comments and code identical).
>
> ## Impact
>
> `AVERROR_BUG` is documented as an internal error that should never be returned
> by the API. Applications that treat it as fatal (as FFmpeg's own fuzz target
> does) abort when decoding media from an untrusted source — a denial of
> service.
>
> ## Suggested direction
>
> The alignment assumption only holds when `comp->step == 1`. One minimal option
> is to skip the alignment adjustment (falling back to unaligned cropping, which
> is already a supported mode one branch above) instead of treating the
> situation as an internal error:
>
> ```diff
> /* we assume, and it should always be true, that the data alignment
> is
> * related to the cropping alignment by a constant power-of-2 factor
> */
> - if (log2_crop_align < min_log2_align)
> - return AVERROR_BUG;
> + if (log2_crop_align < min_log2_align)
> + log2_crop_align = INT_MAX; /* step > 1: fall back to unaligned
> cropping */
> ```
>
> We built and verified that change on FFmpeg 9.0 (`make -j16
> tools/target_dec_h264_fuzzer`): before the patch the PoC aborts with the
> assertion above, after the patch the same input prints `Execution successful`
> and exits 0. The patch is attached as
> `proposed-fix-frame-apply-cropping.patch` (a few lines, no behaviour change
> for
> formats with single-byte components). We are happy to adapt it if you prefer
> to
> fix it on the decoder side instead.
>
> We can provide the PoC, the full sanitizer output, the gdb session log, and
> the
> fuzzer build instructions.
>
> Best regards,
> iceray-Li
> frame.c | 8 ++++++--
> 1 file changed, 6 insertions(+), 2 deletions(-)
> 6640c44442fe51d9c491cb6627dce43cfd75c32a
> /varproposed-fix-frame-apply-cropping.patch
> --- a/libavutil/frame.c
> +++ b/libavutil/frame.c
> @@ -804,9 +804,13 @@
> }
>
> /* we assume, and it should always be true, that the data alignment
> is
> - * related to the cropping alignment by a constant power-of-2 factor
> */
> + * related to the cropping alignment by a constant power-of-2 factor.
> + * That does not hold for pixel formats whose components are more
> than
> + * one byte wide, where offsets[i] == crop_left * comp->step. In
> that
> + * case fall back to unaligned cropping instead of treating it as an
> + * internal error. */
> if (log2_crop_align < min_log2_align)
> - return AVERROR_BUG;
> + log2_crop_align = INT_MAX;
>
> if (min_log2_align < 5 && log2_crop_align != INT_MAX) {
> frame->crop_left &= ~((1 << (5 + log2_crop_align -
> min_log2_align)) - 1);
--
Michael GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB
Democracy is the form of government in which you can choose your dictator
signature.asc
Description: PGP signature
_______________________________________________ ffmpeg-devel mailing list -- [email protected] To unsubscribe send an email to [email protected]
