File Add-sanity-and-overrun-checks-to-H5HG__cache_heap_deserialize.patch of Package hdf5.34857

From: Egbert Eich <eich@suse.com>
Date: Thu Jun 6 16:49:57 2024 +0200
Subject: Add sanity and overrun checks to H5HG__cache_heap_deserialize()
Patch-mainline: Upstream
Git-repo: https://github.com/HDFGroup/hdf5
Git-commit: 0c52624fc47dd61f87c5e93da01cefc71a295326
References: bsc#124158

These checks help to prevent to make sure the
advertised size of the heap and its elements
match its content and will not cause overflows.

This fixes CVE-2024-29158.

Signed-off-by: Egbert Eich <eich@suse.com>
Signed-off-by: Egbert Eich <eich@suse.de>
---
 src/H5HGcache.c | 39 +++++++++++++++++++++++++++++++--------
 1 file changed, 31 insertions(+), 8 deletions(-)
diff --git a/src/H5HGcache.c b/src/H5HGcache.c
index f982c34937..662c92a138 100644
--- a/src/H5HGcache.c
+++ b/src/H5HGcache.c
@@ -233,6 +233,7 @@ H5HG__cache_heap_deserialize(const void *_image, size_t len, void *_udata, hbool
     H5F_t       *f    = (H5F_t *)_udata; /* File pointer -- obtained from user data */
     H5HG_heap_t *heap = NULL;            /* New global heap */
     uint8_t     *image;                  /* Pointer to image to decode */
+    const uint8_t *image_end = NULL;     /* End of (copied) image buffer */
     size_t       max_idx = 0;            /* Maximum heap object index seen */
     size_t       nalloc;                 /* Number of objects allocated */
     void        *ret_value = NULL;       /* Return value */
@@ -255,7 +256,11 @@ H5HG__cache_heap_deserialize(const void *_image, size_t len, void *_udata, hbool
     /* Copy the image buffer into the newly allocate chunk */
     H5MM_memcpy(heap->chunk, _image, len);
 
+    image_end = heap->chunk + len - 1;
+
     /* Deserialize the heap's header */
+    if (H5_IS_BUFFER_OVERFLOW(heap->chunk, H5HG_SIZEOF_HDR(f), image_end))
+        HGOTO_ERROR(H5E_HEAP, H5E_OVERFLOW, NULL, "ran off end of input buffer while decoding");
     if (H5HG__hdr_deserialize(heap, (const uint8_t *)heap->chunk, f) < 0)
         HGOTO_ERROR(H5E_HEAP, H5E_CANTDECODE, NULL, "can't decode global heap header")
 
@@ -276,16 +281,21 @@ H5HG__cache_heap_deserialize(const void *_image, size_t len, void *_udata, hbool
              * The last bit of space is too tiny for an object header, so
              * we assume that it's free space.
              */
-            HDassert(NULL == heap->obj[0].begin);
+	    if (NULL != heap->obj[0].begin)
+                HGOTO_ERROR(H5E_HEAP, H5E_BADVALUE, NULL, "object 0 should not be set");
             heap->obj[0].size  = (size_t)(((const uint8_t *)heap->chunk + heap->size) - image);
             heap->obj[0].begin = image;
             image += heap->obj[0].size;
+
         } /* end if */
         else {
             size_t   need = 0;
             unsigned idx;
             uint8_t *begin = image;
 
+	    if (H5_IS_BUFFER_OVERFLOW(image, 2, image_end))
+                HGOTO_ERROR(H5E_HEAP, H5E_OVERFLOW, NULL, "ran off end of input buffer while decoding");
+
             UINT16DECODE(image, idx);
 
             /* Check if we need more room to store heap objects */
@@ -295,7 +305,8 @@ H5HG__cache_heap_deserialize(const void *_image, size_t len, void *_udata, hbool
 
                 /* Determine the new number of objects to index */
                 new_alloc = MAX(heap->nalloc * 2, (idx + 1));
-                HDassert(idx < new_alloc);
+		if (idx >= new_alloc)
+                    HGOTO_ERROR(H5E_HEAP, H5E_BADVALUE, NULL, "inappropriate heap index");
 
                 /* Reallocate array of objects */
                 if (NULL == (new_obj = H5FL_SEQ_REALLOC(H5HG_obj_t, heap->obj, new_alloc)))
@@ -307,11 +318,18 @@ H5HG__cache_heap_deserialize(const void *_image, size_t len, void *_udata, hbool
                 /* Update heap information */
                 heap->nalloc = new_alloc;
                 heap->obj    = new_obj;
-                HDassert(heap->nalloc > heap->nused);
+                if (heap->nalloc <= heap->nused)
+                    HGOTO_ERROR(H5E_HEAP, H5E_BADVALUE, NULL, "inappropriate # allocated slots");
             } /* end if */
 
+	    if (H5_IS_BUFFER_OVERFLOW(image, 2, image_end))
+                HGOTO_ERROR(H5E_HEAP, H5E_OVERFLOW, NULL, "ran off end of input buffer while decoding");
             UINT16DECODE(image, heap->obj[idx].nrefs);
+	    if (H5_IS_BUFFER_OVERFLOW(image, 4, image_end))
+                HGOTO_ERROR(H5E_HEAP, H5E_OVERFLOW, NULL, "ran off end of input buffer while decoding");
             image += 4; /*reserved*/
+	    if (H5_IS_BUFFER_OVERFLOW(image, H5F_sizeof_size(f), image_end))
+                HGOTO_ERROR(H5E_HEAP, H5E_OVERFLOW, NULL, "ran off end of input buffer while decoding");
             H5F_DECODE_LENGTH(f, image, heap->obj[idx].size);
             heap->obj[idx].begin = begin;
 
@@ -324,20 +342,24 @@ H5HG__cache_heap_deserialize(const void *_image, size_t len, void *_udata, hbool
              * already includes the object header.
              */
             if (idx > 0) {
-                need = H5HG_SIZEOF_OBJHDR(f) + H5HG_ALIGN(heap->obj[idx].size);
+	         need = H5HG_SIZEOF_OBJHDR(f) + H5HG_ALIGN(heap->obj[idx].size);
                 if (idx > max_idx)
                     max_idx = idx;
             } /* end if */
             else
-                need = heap->obj[idx].size;
+	         need = heap->obj[idx].size;
 
+	    if (H5_IS_BUFFER_OVERFLOW(begin, need, image_end))
+                HGOTO_ERROR(H5E_HEAP, H5E_OVERFLOW, NULL, "ran off end of input buffer while decoding");
             image = begin + need;
         } /* end else */
     }     /* end while */
 
     /* Sanity checks */
-    HDassert(image == heap->chunk + heap->size);
-    HDassert(H5HG_ISALIGNED(heap->obj[0].size));
+   if (image != heap->chunk + heap->size)
+        HGOTO_ERROR(H5E_HEAP, H5E_BADVALUE, NULL, "partially decoded global heap");
+    if (false == H5HG_ISALIGNED(heap->obj[0].size))
+        HGOTO_ERROR(H5E_HEAP, H5E_BADVALUE, NULL, "decoded global heap is not aligned");
 
     /* Set the next index value to use */
     if (max_idx > 0)
@@ -346,7 +368,8 @@ H5HG__cache_heap_deserialize(const void *_image, size_t len, void *_udata, hbool
         heap->nused = 1;
 
     /* Sanity check */
-    HDassert(max_idx < heap->nused);
+   if (max_idx >= heap->nused)
+        HGOTO_ERROR(H5E_HEAP, H5E_BADVALUE, NULL, "bad `next unused` heap index value");
 
     /* Add the new heap to the CWFS list for the file */
     if (H5F_cwfs_add(f, heap) < 0)
openSUSE Build Service is sponsored by