[libbdplus-devel] [Git][videolan/libbdplus][master] 7 commits: Fix leak

Petri Hintukainen (@hpi) gitlab at videolan.org
Sat Oct 2 18:57:28 UTC 2021



Petri Hintukainen pushed to branch master at VideoLAN / libbdplus


Commits:
072544fb by anonymous at 2021-10-02T21:51:57+03:00
Fix leak

- - - - -
76425cfe by anonymous at 2021-10-02T21:52:03+03:00
Fix crash when freeing incomplete tables

- - - - -
c89a9f3b by anonymous at 2021-10-02T21:53:36+03:00
segment_setTable(): fix possible integer overflows on invalid input

- - - - -
de4beece by anonymous at 2021-10-02T21:54:11+03:00
segment_setTable(): Fix error handling

- - - - -
3d4a541e by anonymous at 2021-10-02T21:55:38+03:00
Simplify

- - - - -
2a50ad56 by anonymous at 2021-10-02T21:56:05+03:00
segment_setTable(): sanity check table size

- - - - -
308c4784 by anonymous at 2021-10-02T21:56:55+03:00
segment_setTable(): check for input buffer overflow (read)

- - - - -


1 changed file:

- src/libbdplus/bdsvm/segment.c


Changes:

=====================================
src/libbdplus/bdsvm/segment.c
=====================================
@@ -97,7 +97,7 @@ typedef struct entry_s entry_t;
 
 struct segment_s {
     uint32_t encrypted;
-    uint32_t offset;
+  //uint32_t offset;
     uint32_t numEntries;
     entry_t *Entries;
 
@@ -169,7 +169,7 @@ uint32_t segment_numEntries(conv_table_t *ct)
 
 int32_t segment_setTable(conv_table_t **conv_tab, uint8_t *Table, uint32_t len)
 {
-    uint32_t numTables, table, currseg, currentry;
+    uint32_t table, currseg, currentry;
     uint32_t tmp;
     conv_table_t *ct;
     subtable_t *subtable;
@@ -179,35 +179,23 @@ int32_t segment_setTable(conv_table_t **conv_tab, uint8_t *Table, uint32_t len)
     uint32_t offset = 0;
     uint32_t encrypted_segments = 0;
 
-    if (!Table || !len) return -1;
+    if (!Table || len < 2) return -1;
+    if (len > 0x400000) return -1; /* VM memory size */
 
 
     BD_DEBUG(DBG_BDPLUS,"[segment] Starting decode of conv_tab.bin: %p (%d)\n", Table, len);
 
-    ct = *conv_tab;
-
-
-    // If we do not already have a conv_tab, allocate it.
-    if (!ct) {
-
-        ct = (conv_table_t *) malloc(sizeof(*ct));
-        if (!ct) return -2;
-
-        memset(ct, 0, sizeof(*ct));
-
-        *conv_tab = ct;
-
+    if (*conv_tab) {
+        BD_DEBUG(DBG_BDPLUS|DBG_CRIT,"[segment] ERROR: Table already exists.\n");
+        return -1;
     }
 
+    ct = (conv_table_t *) calloc(1, sizeof(*ct));
+    if (!ct) return -2;
 
-    // Update the number of tables we received
-    numTables = FETCHU2(&Table[ptr]);
-
-    if (ct->numTables && (ct->numTables != numTables)) {
-        BD_DEBUG(DBG_BDPLUS,"[segment] Warning, numTables changed between conv_tab parts!\n");
-    }
 
-    ct->numTables = numTables;
+    // Update the number of tables we received
+    ct->numTables = FETCHU2(&Table[ptr]);
     ptr += 2;
 
     // Let nextSegment() initialise these, So that we can ignore
@@ -215,72 +203,52 @@ int32_t segment_setTable(conv_table_t **conv_tab, uint8_t *Table, uint32_t len)
     ct->current_table   = 0xffffffff;
     ct->current_segment = 0xffffffff;
 
-    // Allocate area to hold all subtable structs, if not already allocated
-    if (!ct->Tables) {
-        ct->Tables = (subtable_t *) malloc(sizeof(subtable_t) * ct->numTables);
-        if (!ct->Tables) return segment_freeTable(conv_tab);
-        memset(ct->Tables,
-               0, sizeof(subtable_t) * numTables);
-    }
+    ct->Tables = (subtable_t *) calloc(ct->numTables, sizeof(subtable_t));
+    if (!ct->Tables) goto error;
+
 
+    BD_DEBUG(DBG_BDPLUS,"[segment] num tables %d\n", ct->numTables);
 
-    BD_DEBUG(DBG_BDPLUS,"[segment] num tables %d\n", numTables);
+    for (table = 0; table < ct->numTables; table++) {
 
-    for (table = 0; table < numTables; table++) {
-        uint32_t tableID;
-        uint32_t numSegments;
+        if (len < 6 || ptr > len - 6)
+            goto error;
 
         // Assign pointer so we don't need to keep dereferencing
         subtable = &ct->Tables[ table ];
 
-        tableID = FETCH4(&Table[ptr]);
+        subtable->tableID = FETCH4(&Table[ptr]);
         ptr += 4;
 
-        if (subtable->tableID && (subtable->tableID != tableID)) {
-            BD_DEBUG(DBG_BDPLUS,"[segment] Warning: tableID changed %08X != %08X\n",
-                   subtable->tableID, tableID);
-        }
-        subtable->tableID = tableID;
-
         // Here, we might increase the number of segments.
 
-        //subtable->numSegments = FETCHU2(&Table[ptr]);
-        numSegments = FETCHU2(&Table[ptr]);
+        subtable->numSegments = FETCHU2(&Table[ptr]);
         ptr += 2;
 
         // Don't allocate if no (new) segments
-        if (!numSegments) continue;
-
-        if (subtable->numSegments && (subtable->numSegments != numSegments)) {
-            BD_DEBUG(DBG_BDPLUS,"[segment] Warning: numSegments changed %08X != %08X\n",
-                   subtable->numSegments, numSegments);
-        }
-
-        subtable->numSegments = numSegments;
+        if (!subtable->numSegments) continue;
 
         BD_DEBUG(DBG_BDPLUS,"[segment] Table %d ID %08X, %u segments\n",
                table, subtable->tableID, subtable->numSegments);
 
-        // Allocate area if required
-        if (!subtable->Segments) {
-            subtable->Segments = (segment_t *) malloc(sizeof(segment_t) *
-                                                      numSegments);
-            if (!subtable->Segments) continue;
-            memset(subtable->Segments, 0,
-                   sizeof(segment_t) *
-                   numSegments);
-        }
-
+        subtable->Segments = (segment_t *) calloc(subtable->numSegments, sizeof(segment_t));
+        if (!subtable->Segments) goto error;
 
         // Loop on all segments
         for (currseg = 0;
-             currseg < numSegments;
+             currseg < subtable->numSegments;
              currseg++) {
 
+            if (ptr + currseg * 4 > len - 4)
+                goto error;
+
             segment = &subtable->Segments[ currseg ];
 
             offset = FETCH4(&Table[ptr + (currseg * 4) ]);
-            segment->offset = offset;  // not really used
+            //segment->offset = offset;  // not really used
+
+            if (offset > len - 4)
+                goto error;
 
             segment->numEntries = FETCH4(&Table[offset]);
             offset += 4;
@@ -291,19 +259,19 @@ int32_t segment_setTable(conv_table_t **conv_tab, uint8_t *Table, uint32_t len)
             BD_DEBUG(DBG_BDPLUS,"   Segment %d offset %08X -> %d entries\n",
                    currseg, offset-4, segment->numEntries);
 
-            segment->Entries = (entry_t *) malloc(sizeof(entry_t) *
-                                                  segment->numEntries);
-            if (!segment->Entries) continue;
+            segment->Entries = (entry_t *) calloc(segment->numEntries, sizeof(entry_t));
+            if (!segment->Entries) goto error;
 
             // If we have non-zero entries, assume they are encrypted
             segment->encrypted = 1;
             encrypted_segments++;
 
-            memset(segment->Entries, 0, sizeof(entry_t) *
-                   segment->numEntries);
-
             // First read in the index table
             for (currentry = 0; currentry < segment->numEntries; currentry++) {
+
+                if (offset > len - 4)
+                    goto error;
+
                 entry = &segment->Entries[ currentry ];
 
                 entry->index = FETCH4(&Table[offset]);
@@ -314,6 +282,9 @@ int32_t segment_setTable(conv_table_t **conv_tab, uint8_t *Table, uint32_t len)
             for (currentry = 0; currentry < segment->numEntries; currentry++) {
                 entry = &segment->Entries[ currentry ];
 
+                if (len < 16 || offset > len - 16)
+                    goto error;
+
                 entry->flags = Table[ offset ];
                 offset += 1;
 
@@ -345,7 +316,13 @@ int32_t segment_setTable(conv_table_t **conv_tab, uint8_t *Table, uint32_t len)
     BD_DEBUG(DBG_BDPLUS,"[segments] Done parsing. %d segments need decrypting.\n",
            encrypted_segments);
 
+    *conv_tab = ct;
     return ct->numTables;
+
+ error:
+    BD_DEBUG(DBG_BDPLUS|DBG_CRIT,"[segments] Conversion table parsing failed.\n");
+    segment_freeTable(&ct);
+    return -1;
 }
 
 
@@ -361,11 +338,13 @@ int32_t segment_freeTable(conv_table_t **Table)
 
     ct = *Table;
 
+    if (ct->Tables)
     for (table = 0; table < ct->numTables; table++) {
 
         // Assign pointer so we don't need to keep dereferencing
         subtable = &ct->Tables[ table ];
 
+        if (subtable->Segments)
         for (currseg = 0; currseg < subtable->numSegments; currseg++) {
 
             segment = &subtable->Segments[ currseg ];
@@ -383,6 +362,8 @@ int32_t segment_freeTable(conv_table_t **Table)
     X_FREE(ct->Tables);
     ct->numTables = 0;
 
+    X_FREE(ct);
+
     *Table = NULL;
 
     return 0;



View it on GitLab: https://code.videolan.org/videolan/libbdplus/-/compare/001e81d9c4057e8375e5a6ca06b0ce99c72f76d4...308c47848f855d207e06e5e0982c18c3ffcf5120

-- 
View it on GitLab: https://code.videolan.org/videolan/libbdplus/-/compare/001e81d9c4057e8375e5a6ca06b0ce99c72f76d4...308c47848f855d207e06e5e0982c18c3ffcf5120
You're receiving this email because of your account on code.videolan.org.




More information about the libbdplus-devel mailing list