PR #22887 opened by padenot
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/22887
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/22887.patch

`ff_parse_a53_cc()` uses `get_bits()` which performs AV_RB32 loads and
requires `AV_INPUT_BUFFER_PADDING_SIZE` trailing bytes past the logical
end of its input. `dav1d`'s ITU-T T.35 payload buffers carry no such
padding, so passing `gb.buffer` directly caused a heap-buffer-overflow
read of up to 3 bytes past the end of the allocation.

Copy the remaining bytes into a freshly-allocated, zero-padded buffer
before calling `ff_parse_a53_cc()`.

A python script that can generate an av1 frame that triggers this is attached, 
alongside its output (for convenience).
Using an ASAN-enabled `ffmpeg` built from a recent revision,  `ffmpeg -f  obu 
-i repro.obu -f null -` will crash with the following stack:

```
==38960==ERROR: AddressSanitizer: heap-buffer-overflow on address 
0x50200000201a at pc 0x56c245667070 bp 0x784b82476130 sp
  0x784b82476120
  READ of size 4 at 0x50200000201a thread T67 (dec0:0:libdav1d)
      #0 0x56c24566706f in get_bits libavcodec/get_bits.h:342
      #1 0x56c245667b82 in ff_parse_a53_cc libavcodec/atsc_a53.c:115
      #2 0x56c24564551f in parse_itut_t35_metadata libavcodec/libdav1d.c:387
      #3 0x56c245647e43 in libdav1d_receive_frame libavcodec/libdav1d.c:622
      #4 0x56c245619204 in ff_decode_receive_frame_internal 
libavcodec/decode.c:629
      #5 0x56c24561950e in decode_receive_frame_internal libavcodec/decode.c:662
      #6 0x56c24561a595 in ff_decode_receive_frame libavcodec/decode.c:816
      #7 0x56c2455b2dde in avcodec_receive_frame_flags libavcodec/avcodec.c:719
      #8 0x56c2453d0a9c in packet_decode fftools/ffmpeg_dec.c:754
      #9 0x56c2453d2552 in decoder_thread fftools/ffmpeg_dec.c:955
      #10 0x56c24545f318 in task_wrapper fftools/ffmpeg_sched.c:2694

  0x50200000201d is located 0 bytes after 13-byte region 
[0x502000002010,0x50200000201d)
  allocated by thread T67 (dec0:0:libdav1d) here:
      #0 0x784bb96fd9c7 in malloc 
../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:69
      #1 0x784bb93fde8c in dav1d_parse_obus ../src/obu.c:1488
```

This has been found by internal fuzzing in Firefox but is unlikely to be an 
exploitable problem in practice, since it's just a small OOB read past a 
heap-allocated buffer. Maybe if we're really unlucky it can crash.



>From 12df5c04354b2205f266fcab8cc31c7eecceaab5 Mon Sep 17 00:00:00 2001
From: Paul Adenot <[email protected]>
Date: Wed, 22 Apr 2026 11:27:16 +0000
Subject: [PATCH] avcodec/libdav1d: copy A/53 CC payload into a padded buffer

ff_parse_a53_cc() uses get_bits() which performs AV_RB32 loads and
requires AV_INPUT_BUFFER_PADDING_SIZE trailing bytes past the logical
end of its input. dav1d's ITU-T T.35 payload buffers carry no such
padding, so passing gb.buffer directly caused a heap-buffer-overflow
read of up to 3 bytes past the end of the allocation.

Copy the remaining bytes into a freshly-allocated, zero-padded buffer
before calling ff_parse_a53_cc().
---
 libavcodec/libdav1d.c | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/libavcodec/libdav1d.c b/libavcodec/libdav1d.c
index 2eaeefc71a..2a81392c34 100644
--- a/libavcodec/libdav1d.c
+++ b/libavcodec/libdav1d.c
@@ -23,6 +23,7 @@
 
 #include "libavutil/avassert.h"
 #include "libavutil/cpu.h"
+#include "libavutil/mem.h"
 #include "libavutil/film_grain_params.h"
 #include "libavutil/hdr_dynamic_metadata.h"
 #include "libavutil/mastering_display_metadata.h"
@@ -383,8 +384,14 @@ static int parse_itut_t35_metadata(Libdav1dContext *dav1d, 
Dav1dPicture *p,
             switch (user_identifier) {
             case MKBETAG('G', 'A', '9', '4'): { // closed captions
                 AVBufferRef *buf = NULL;
+                int cc_size = bytestream2_get_bytes_left(&gb);
+                uint8_t *padded = av_mallocz(cc_size + 
AV_INPUT_BUFFER_PADDING_SIZE);
+                if (!padded)
+                    return AVERROR(ENOMEM);
+                memcpy(padded, gb.buffer, cc_size);
 
-                res = ff_parse_a53_cc(&buf, gb.buffer, 
bytestream2_get_bytes_left(&gb));
+                res = ff_parse_a53_cc(&buf, padded, cc_size);
+                av_freep(&padded);
                 if (res < 0)
                     return res;
                 if (!res)
-- 
2.52.0

_______________________________________________
ffmpeg-devel mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to