From 8e5d36c7465699671b89023f752a378f5ee8b7cb Mon Sep 17 00:00:00 2001
From: starlet-dx <15929766099@163.com>
Date: Tue, 28 Mar 2023 17:31:29 +0800
Subject: [PATCH 1/1] H5O__pline_decode() Make more resilient to out-of-bounds read (#2210)

Malformed hdf5 files may have trunkated content which does not match the expected size. When this function attempts to decode these it may read past the end of the allocated space leading to heap overflows as bounds checking is incomplete.
Make sure each element is within bounds before reading.

This fixes CVE-2019-8396 / HDFFV-10712 / github bug #2209.

Signed-off-by: Egbert Eich <eich@suse.com>

Signed-off-by: Egbert Eich <eich@suse.com>
---
 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 4b76da9..eacf81a 100644
--- a/src/H5Opline.c
+++ b/src/H5Opline.c
@@ -110,6 +110,7 @@ H5FL_DEFINE(H5O_pline_t);
  *
  *-------------------------------------------------------------------------
  */
+
 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)
@@ -131,6 +132,9 @@ H5O__pline_decode(H5F_t H5_ATTR_UNUSED *f, H5O_t H5_ATTR_UNUSED *open_oh, unsign
         HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
 
     /* Version */
+    if (p + 4 - 1 > p_end) /* 4 byte is minimum for all versions */
+        HGOTO_ERROR(H5E_OHDR, H5E_NOSPACE, NULL, "ran off the end of the buffer: current p = %p, p_end = %p",
+                    p + 4, p_end)
     pline->version = *p++;
     if (pline->version < H5O_PLINE_VERSION_1 || pline->version > H5O_PLINE_VERSION_LATEST)
         HGOTO_ERROR(H5E_PLINE, H5E_CANTLOAD, NULL, "bad version number for filter pipeline message")
@@ -159,6 +163,9 @@ 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 */
+        if (p + 6 - 1 > p_end) /* 6 bytes minimum */
+            HGOTO_ERROR(H5E_OHDR, H5E_NOSPACE, NULL,
+                        "ran off the end of the buffer: current p = %p, p_end = %p", p + 6, p_end)
         UINT16DECODE(p, filter->id);
 
         /* Length of filter name */
@@ -168,6 +175,9 @@ 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")
+            if (p + 4 - 1 > p_end) /* with name_length 4 bytes to go */
+                HGOTO_ERROR(H5E_OHDR, H5E_NOSPACE, NULL,
+                            "ran off the end of the buffer: current p = %p, p_end = %p", p + 4, p_end)
         } /* end if */
 
         /* Filter flags */
@@ -179,9 +189,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_OHDR, 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 56ded14..58ccfef 100644
--- a/src/H5private.h
+++ b/src/H5private.h
@@ -1444,6 +1444,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
 #ifndef HDstrncat
 #define HDstrncat(X, Y, Z) strncat(X, Y, Z)
 #endif /* HDstrncat */
-- 
2.30.0

