From 146721324b8eab1a480dda86b5addae6c1820818 Mon Sep 17 00:00:00 2001
From: John Thacker <johnthacker@gmail.com>
Date: Sun, 28 May 2023 07:14:52 -0400
Subject: [PATCH] kafka: Don't use after free

Neither tvb_new_child_real_data() nor tvb_composite_append() copy
the real data buffer that they're given. So we can't free a
decompressed buffer after making it a tvb.

We can realloc if the output size is smaller.

Fix #19105


(cherry picked from commit b673bc022aa28c2c381cb96cae09357bd27eb0df)
---
 epan/dissectors/packet-kafka.c | 24 +++++++++++++++++-------
 1 file changed, 17 insertions(+), 7 deletions(-)

diff --git a/epan/dissectors/packet-kafka.c b/epan/dissectors/packet-kafka.c
index b530d2cf787..eabcc5d264d 100644
--- a/epan/dissectors/packet-kafka.c
+++ b/epan/dissectors/packet-kafka.c
@@ -1677,7 +1677,6 @@ decompress_lz4(tvbuff_t *tvb, packet_info *pinfo, int offset, guint32 length, tv
         dst_size = (size_t)lz4_info.contentSize;
     }
 
-    decompressed_buffer = wmem_alloc(pinfo->pool, dst_size);
     size_t out_size;
     int count = 0;
 
@@ -1687,12 +1686,16 @@ decompress_lz4(tvbuff_t *tvb, packet_info *pinfo, int offset, guint32 length, tv
             goto end;
         }
 
+        decompressed_buffer = wmem_alloc(pinfo->pool, dst_size);
         out_size = dst_size;
         rc = LZ4F_decompress(lz4_ctxt, decompressed_buffer, &out_size,
                               &data[src_offset], &src_size, NULL);
         if (LZ4F_isError(rc)) {
             goto end;
         }
+        if (out_size != dst_size) {
+            decompressed_buffer = (guint8 *)wmem_realloc(pinfo->pool, decompressed_buffer, out_size);
+        }
         if (out_size == 0) {
             goto end;
         }
@@ -1734,7 +1737,7 @@ static gboolean
 decompress_snappy(tvbuff_t *tvb, packet_info *pinfo, int offset, guint32 length, tvbuff_t **decompressed_tvb, int *decompressed_offset)
 {
     guint8 *data = (guint8*)tvb_memdup(pinfo->pool, tvb, offset, length);
-    size_t uncompressed_size;
+    size_t uncompressed_size, out_size;
     snappy_status rc = SNAPPY_OK;
     tvbuff_t *composite_tvb = NULL;
     gboolean ret = FALSE;
@@ -1771,18 +1774,21 @@ decompress_snappy(tvbuff_t *tvb, packet_info *pinfo, int offset, guint32 length,
                 goto end;
             }
             guint8 *decompressed_buffer = (guint8*)wmem_alloc(pinfo->pool, uncompressed_size);
-            rc = snappy_uncompress(&data[pos], chunk_size, decompressed_buffer, &uncompressed_size);
+            out_size = uncompressed_size;
+            rc = snappy_uncompress(&data[pos], chunk_size, decompressed_buffer, &out_size);
             if (rc != SNAPPY_OK) {
                 goto end;
             }
+            if (out_size != uncompressed_size) {
+                decompressed_buffer = (guint8 *)wmem_realloc(pinfo->pool, decompressed_buffer, out_size);
+            }
 
             if (!composite_tvb) {
                 composite_tvb = tvb_new_composite();
             }
             tvb_composite_append(composite_tvb,
-                      tvb_new_child_real_data(tvb, decompressed_buffer, (guint)uncompressed_size, (gint)uncompressed_size));
+                      tvb_new_child_real_data(tvb, decompressed_buffer, (guint)out_size, (gint)out_size));
             pos += chunk_size;
-            wmem_free(pinfo->pool, decompressed_buffer);
             count++;
             DISSECTOR_ASSERT_HINT(count < MAX_LOOP_ITERATIONS, "MAX_LOOP_ITERATIONS exceeded");
         }
@@ -1797,12 +1803,16 @@ decompress_snappy(tvbuff_t *tvb, packet_info *pinfo, int offset, guint32 length,
 
         guint8 *decompressed_buffer = (guint8*)wmem_alloc(pinfo->pool, uncompressed_size);
 
-        rc = snappy_uncompress(data, length, decompressed_buffer, &uncompressed_size);
+        out_size = uncompressed_size;
+        rc = snappy_uncompress(data, length, decompressed_buffer, &out_size);
         if (rc != SNAPPY_OK) {
             goto end;
         }
+        if (out_size != uncompressed_size) {
+            decompressed_buffer = (guint8 *)wmem_realloc(pinfo->pool, decompressed_buffer, out_size);
+        }
 
-        *decompressed_tvb = tvb_new_child_real_data(tvb, decompressed_buffer, (guint)uncompressed_size, (gint)uncompressed_size);
+        *decompressed_tvb = tvb_new_child_real_data(tvb, decompressed_buffer, (guint)out_size, (gint)out_size);
         *decompressed_offset = 0;
 
     }
-- 
GitLab

