File H5O__pline_decode-Make-more-resilient-to-out-of-bounds-read.patch of Package hdf5.28370
From: Egbert Eich <eich@suse.com>
Date: Tue Oct 4 23:09:01 2022 +0200
Subject: H5O__pline_decode() Make more resilient to out-of-bounds read
Patch-mainline: Not yet
Git-repo: https://github.com/HDFGroup/hdf5
Git-commit: f6b32ff25804de122068034409ef4578903e1611
References:
Malformed hdf5 files may have trunkated content which does not match
the expected size. This function attempts to decode these it will read
past the end of the allocated space which may lead to a crash. Make sure
each element is within bounds before reading.
This fixes CVE-2019-8396.
Signed-off-by: Egbert Eich <eich@suse.com>
Signed-off-by: Egbert Eich <eich@suse.de>
---
src/H5Opline.c | 17 +++++++++++++++--
src/H5private.h | 3 +++
2 files changed, 18 insertions(+), 2 deletions(-)
diff --git a/src/H5Opline.c b/src/H5Opline.c
index c679462dd5..b54f300810 100644
--- a/src/H5Opline.c
+++ b/src/H5Opline.c
@@ -109,6 +109,14 @@ H5FL_DEFINE(H5O_pline_t);
*
*-------------------------------------------------------------------------
*/
+static char err[] = "ran off the end of the buffer: current p = %p, p_end = %p";
+
+#define VERIFY_LIMIT(p,s,l) \
+ if (p + s - 1 > l) { \
+ HCOMMON_ERROR(H5E_RESOURCE, H5E_NOSPACE, err, p + s, l); \
+ HGOTO_DONE(NULL) \
+ };
+
static void *
H5O__pline_decode(H5F_t H5_ATTR_UNUSED *f, H5O_t H5_ATTR_UNUSED *open_oh, unsigned H5_ATTR_UNUSED mesg_flags,
unsigned H5_ATTR_UNUSED *ioflags, size_t p_size, const uint8_t *p)
@@ -158,6 +166,7 @@ H5O__pline_decode(H5F_t H5_ATTR_UNUSED *f, H5O_t H5_ATTR_UNUSED *open_oh, unsign
/* Decode filters */
for (i = 0, filter = &pline->filter[0]; i < pline->nused; i++, filter++) {
/* Filter ID */
+ VERIFY_LIMIT(p, 6, p_end) /* 6 bytes minimum */
UINT16DECODE(p, filter->id);
/* Length of filter name */
@@ -167,6 +176,7 @@ H5O__pline_decode(H5F_t H5_ATTR_UNUSED *f, H5O_t H5_ATTR_UNUSED *open_oh, unsign
UINT16DECODE(p, name_length);
if (pline->version == H5O_PLINE_VERSION_1 && name_length % 8)
HGOTO_ERROR(H5E_PLINE, H5E_CANTLOAD, NULL, "filter name length is not a multiple of eight")
+ VERIFY_LIMIT(p, 4, p_end) /* with name_length 4 bytes to go */
} /* end if */
/* Filter flags */
@@ -178,9 +188,12 @@ H5O__pline_decode(H5F_t H5_ATTR_UNUSED *f, H5O_t H5_ATTR_UNUSED *open_oh, unsign
/* Filter name, if there is one */
if (name_length) {
size_t actual_name_length; /* Actual length of name */
-
+ size_t len = (size_t)(p_end - p + 1);
/* Determine actual name length (without padding, but with null terminator) */
- actual_name_length = HDstrlen((const char *)p) + 1;
+ actual_name_length = HDstrnlen((const char *)p, len);
+ if (actual_name_length == len)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "filter name not null terminated")
+ actual_name_length += 1; /* include \0 byte */
HDassert(actual_name_length <= name_length);
/* Allocate space for the filter name, or use the internal buffer */
diff --git a/src/H5private.h b/src/H5private.h
index 931d7b9046..d3ff03eae8 100644
--- a/src/H5private.h
+++ b/src/H5private.h
@@ -1403,6 +1403,9 @@ H5_DLL void HDsrand(unsigned int seed);
#ifndef HDstrlen
#define HDstrlen(S) strlen(S)
#endif /* HDstrlen */
+#ifndef HDstrnlen
+#define HDstrnlen(S,L) strnlen(S,L)
+#endif /* HDstrnlen */
#ifndef HDstrncat
#define HDstrncat(X, Y, Z) strncat(X, Y, Z)
#endif /* HDstrncat */