[libbdplus-devel] [Git][videolan/libbdplus][master] Add some basic validity checks for cached conversion table

Petri Hintukainen (@hpi) gitlab at videolan.org
Wed Oct 6 15:31:11 UTC 2021



Petri Hintukainen pushed to branch master at VideoLAN / libbdplus


Commits:
228d22fd by anonymous at 2021-10-06T18:30:03+03:00
Add some basic validity checks for cached conversion table

- - - - -


2 changed files:

- src/examples/convtab_dump.c
- src/libbdplus/bdsvm/segment.c


Changes:

=====================================
src/examples/convtab_dump.c
=====================================
@@ -60,6 +60,7 @@ int main(int argc, char **argv)
     uint32_t numTables, table;
     uint32_t ptr = 0;
     uint32_t offset = 0;
+    int errors = 0;
 
     if (argc < 2) {
         fprintf(stderr, "%s /path/to/conv_tab.bin\n", argv[0]);
@@ -89,6 +90,7 @@ int main(int argc, char **argv)
 
         for (segment = 0; segment < numSegments; segment++) {
             uint32_t numEntries, entry;
+            uint64_t prev_off1 = 0;
 
             offset = FETCH4(&tab[ptr + (segment * 4) ]);
 
@@ -143,6 +145,31 @@ int main(int argc, char **argv)
                 printf("    %08X %08X:  %02X %02X %02X %02X %02X\n",
                        (uint32_t)(off1 >> 32), (uint32_t)(off1 & 0xffffffff),
                        patch1[0], patch1[1], patch1[2], patch1[3], patch1[4]);
+
+                if ((flags >> 6) == 3) {
+                    printf("    *** invalid flags ***\n");
+                    errors++;
+                }
+                if ((flags >> 6) == 1) {
+                    if (patch0_buffer_offset < 8 || patch1_buffer_offset < 8) {
+                        printf("    *** Invalid in-packet offset (inside ts header) ***\n");
+                        errors++;
+                    }
+                    if (patch0_buffer_offset > 187 || patch1_buffer_offset > 187) {
+                        printf("    *** Invalid in-packet offset (overwrite) ***\n");
+                        errors++;
+                    }
+                    if (off0 >= off1) {
+                        printf("   *** invalid offset (off0 >= off1) ***\n");
+                        errors++;
+                    }
+                    if (off0 < prev_off1) {
+                        printf("    *** invalid offset sequence (not monotonic) ***\n");
+                        errors++;
+                    }
+                    prev_off1 = off1;
+                }
+
             } // for entry
 
         } // for segment
@@ -151,5 +178,5 @@ int main(int argc, char **argv)
 
     } // for table
 
-    return 0;
+    return errors;
 }


=====================================
src/libbdplus/bdsvm/segment.c
=====================================
@@ -143,6 +143,70 @@ struct bdplus_st_s {
     uint64_t next_patch_offset; /* optimize patching */
 };
 
+/*
+ *
+ */
+
+static int64_t _entry_offset0(const entry_t *e)
+{
+    return (((uint64_t)e->index +
+             (uint64_t)e->patch0_address_adjust) *
+            (uint64_t)0xC0 +
+            (uint64_t)e->patch0_buffer_offset);
+}
+
+static int64_t _entry_offset1(const entry_t *e)
+{
+    return (( (uint64_t)e->index +
+              (uint64_t)e->patch0_address_adjust +
+              (uint64_t)e->patch1_address_adjust) *
+            (uint64_t)0xC0 +
+            (uint64_t)e->patch1_buffer_offset);
+}
+
+static int _is_invalid_entry(const entry_t *e, const entry_t *prev)
+{
+    unsigned invalid = 0;
+
+    /*
+      Do some basic sanity checks for conversion table entry.
+      Note: Following checks are incomplete. The idea is to catch tables with
+      random or encrypted data. This works quite well because of there are
+      thousands of entries in the table.
+
+      Checks could be improved a lot if we parse also .clpi file and the stream.
+    */
+
+    if ((e->flags >> 6) == 3) {
+        BD_DEBUG(DBG_BDPLUS, "[segment] invalid flags in entry.\n");
+        return 1;
+    }
+
+    /* Check only unconditionally applied entries. */
+    /* Inactive entries are most likely filled with random data to secure the key. */
+    if ((e->flags >> 6) == 1) {
+        if (e->patch0_buffer_offset < 8 || e->patch0_buffer_offset > 187 ||
+            e->patch1_buffer_offset < 8 || e->patch1_buffer_offset > 187) {
+
+            /* - too easy to reconstruct, would compromize segment key */
+            /* - ATC is used to control buffering and disk spinning at _lower_ layers */
+            /* - not user-visible, useless for watermarking. */
+            BD_DEBUG(DBG_BDPLUS, "[segment] invalid patch buffer offsets in entry.\n");
+            invalid = 1;
+        }
+        if (_entry_offset0(e) >= _entry_offset1(e) ||
+            ( prev && (prev->flags >> 6) == 1 &&
+              _entry_offset0(e) < _entry_offset1(prev))) {
+
+            /* tables are always sorted */
+            BD_DEBUG(DBG_BDPLUS, "[segment] invalid offset in entry.\n");
+            invalid = 1;
+        }
+    }
+
+    return invalid;
+}
+
 /*
  *
  */
@@ -167,6 +231,25 @@ uint32_t segment_numEntries(conv_table_t *ct)
     return entries;
 }
 
+static int32_t segment_validateTable(conv_table_t *ct)
+{
+    uint32_t table, currseg, currentry;
+    int errors = 0;
+
+    for (table = 0; table < ct->numTables; table++) {
+        subtable_t *subtable = &ct->Tables[ table ];
+        for (currseg = 0; currseg < subtable->numSegments; currseg++) {
+            segment_t *segment = &subtable->Segments[ currseg ];
+            for (currentry = 0; currentry < segment->numEntries; currentry++) {
+                entry_t *entry = &segment->Entries[ currentry ];
+                errors += _is_invalid_entry(entry, currentry == 0 ? NULL : (entry - 1));
+            }
+        }
+    }
+    return errors;
+}
+
+
 int32_t segment_setTable(conv_table_t **conv_tab, uint8_t *Table, uint32_t len)
 {
     uint32_t table, currseg, currentry;
@@ -774,9 +857,17 @@ int32_t segment_load(conv_table_t **conv_tab, FILE *fd)
     if (len) {
         // Decode the table into C structures.
         segment_setTable(conv_tab, buffer, fileLen);
-        X_FREE(buffer);
+    }
+
+    X_FREE(buffer);
 
-        if(conv_tab) return 1;
+    if (*conv_tab) {
+        int errors = segment_validateTable(*conv_tab);
+        if (errors == 0) {
+            return 1;
+        }
+        BD_DEBUG(DBG_BDPLUS|DBG_CRIT, "[bdplus] dropping broken cached conversion table (%d invalid entries).\n", errors);
+        segment_freeTable(conv_tab);
     }
     return 0;
 }



View it on GitLab: https://code.videolan.org/videolan/libbdplus/-/commit/228d22fd114b0f6b24841a175fd44a9c95f8e8ba

-- 
View it on GitLab: https://code.videolan.org/videolan/libbdplus/-/commit/228d22fd114b0f6b24841a175fd44a9c95f8e8ba
You're receiving this email because of your account on code.videolan.org.




More information about the libbdplus-devel mailing list