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)