[FFmpeg-devel] [PATCH] avdevice/decklink_dec: Handle time code data presence in CDP packets

Sebastian Dröge slomo at coaxion.net
Wed Nov 25 21:33:59 EET 2020


From: Sebastian Dröge <sebastian at centricular.com>

Instead of failing to parse such CDP packets, simply skip over the time
code data and read the CC data following it.

Also add some more length checks in related to this and the existing
parsing code to prevent reading out of bounds memory.
---
 libavdevice/decklink_dec.cpp | 60 ++++++++++++++++++++++++++++--------
 1 file changed, 47 insertions(+), 13 deletions(-)

diff --git a/libavdevice/decklink_dec.cpp b/libavdevice/decklink_dec.cpp
index 2e41b587e8..2194e84226 100644
--- a/libavdevice/decklink_dec.cpp
+++ b/libavdevice/decklink_dec.cpp
@@ -329,18 +329,30 @@ static uint8_t* teletext_data_unit_from_ancillary_packet(uint16_t *py, uint16_t
 static uint8_t *vanc_to_cc(AVFormatContext *avctx, uint16_t *buf, size_t words,
                            unsigned &cc_count)
 {
-    size_t i, len = (buf[5] & 0xff) + 6 + 1;
+    size_t i, len;
     uint8_t cdp_sum, rate;
     uint16_t hdr, ftr;
+    uint8_t flags;
     uint8_t *cc;
-    uint16_t *cdp = &buf[6]; // CDP follows
+    uint16_t *cdp;
+
+    /* validity of this length is already checked by the caller */
+    len = (buf[5] & 0xff) + 6 + 1;
+
+    cdp = &buf[6]; // CDP follows
+    len -= 7; // remove VANC header and checksum
+
+    /* 7 bytes CDP header, 4 bytes CDP footer */
+    if (len < 7 + 4) {
+        av_log(avctx, AV_LOG_WARNING, "Invalid CDP packet length %zu < %d\n", len, 7 + 4);
+        return NULL;
+    }
+
     if (cdp[0] != 0x96 || cdp[1] != 0x69) {
         av_log(avctx, AV_LOG_WARNING, "Invalid CDP header 0x%.2x 0x%.2x\n", cdp[0], cdp[1]);
         return NULL;
     }
 
-    len -= 7; // remove VANC header and checksum
-
     if (cdp[2] != len) {
         av_log(avctx, AV_LOG_WARNING, "CDP len %d != %zu\n", cdp[2], len);
         return NULL;
@@ -366,26 +378,48 @@ static uint8_t *vanc_to_cc(AVFormatContext *avctx, uint16_t *buf, size_t words,
         return NULL;
     }
 
-    if (!(cdp[4] & 0x43)) /* ccdata_present | caption_service_active | reserved */ {
-        av_log(avctx, AV_LOG_WARNING, "CDP flags invalid (0x%.2x)\n", cdp[4]);
+    flags = cdp[4];
+    if (!(flags & 0x43)) /* ccdata_present | caption_service_active | reserved */ {
+        av_log(avctx, AV_LOG_WARNING, "CDP flags invalid (0x%.2x)\n", flags);
         return NULL;
     }
 
     hdr = (cdp[5] << 8) | cdp[6];
-    if (cdp[7] != 0x72) /* ccdata_id */ {
+
+    /* skip over the CDP header parsed above */
+    cdp += 7;
+    len -= 7;
+
+    if ((flags & 0x80)) /* time_code_present */ {
+      /* time code is stored in 5 bytes, skip over them */
+      if (len < 5) {
+        av_log(avctx, AV_LOG_WARNING, "CDP length too small for time code section\n");
+        return NULL;
+      }
+      cdp += 5;
+      len -= 5;
+    }
+
+    if (len < 2) {
+      av_log(avctx, AV_LOG_WARNING, "CDP length too small for CC data section\n");
+      return NULL;
+    }
+
+    if (cdp[0] != 0x72) /* ccdata_id */ {
         av_log(avctx, AV_LOG_WARNING, "Invalid ccdata_id 0x%.2x\n", cdp[7]);
         return NULL;
     }
 
-    cc_count = cdp[8];
+    cc_count = cdp[1];
     if (!(cc_count & 0xe0)) {
         av_log(avctx, AV_LOG_WARNING, "Invalid cc_count 0x%.2x\n", cc_count);
         return NULL;
     }
 
     cc_count &= 0x1f;
-    if ((len - 13) < cc_count * 3) {
-        av_log(avctx, AV_LOG_WARNING, "Invalid cc_count %d (> %zu)\n", cc_count * 3, len - 13);
+    /* 6 = 2 bytes for the CC data header read above and 4 bytes for the CDP footer */
+    if (len < cc_count * 3 + 6) {
+        av_log(avctx, AV_LOG_WARNING, "Invalid cc_count %d (> %zu)\n", cc_count * 3, len - 6);
         return NULL;
     }
 
@@ -407,9 +441,9 @@ static uint8_t *vanc_to_cc(AVFormatContext *avctx, uint16_t *buf, size_t words,
     }
 
     for (size_t i = 0; i < cc_count; i++) {
-        cc[3*i + 0] = cdp[9 + 3*i+0] /* & 3 */;
-        cc[3*i + 1] = cdp[9 + 3*i+1];
-        cc[3*i + 2] = cdp[9 + 3*i+2];
+        cc[3*i + 0] = cdp[2 + 3*i+0] /* & 3 */;
+        cc[3*i + 1] = cdp[2 + 3*i+1];
+        cc[3*i + 2] = cdp[2 + 3*i+2];
     }
 
     cc_count *= 3;
-- 
2.29.2



More information about the ffmpeg-devel mailing list