From e1f398a2cf390befda1140e1cdc88719060fc6d0 Mon Sep 17 00:00:00 2001 From: jhendersonHDF Date: Fri, 14 Apr 2023 19:23:52 -0500 Subject: H5O__pline_decode() Make more resilient to out-of-bounds read (#2210) (#2733) 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. --- release_docs/RELEASE.txt | 10 ++++++++++ src/H5Opline.c | 17 +++++++++++++++-- src/H5private.h | 3 +++ 3 files changed, 28 insertions(+), 2 deletions(-) diff --git a/release_docs/RELEASE.txt b/release_docs/RELEASE.txt index c938ce0..61a2d40 100644 --- a/release_docs/RELEASE.txt +++ b/release_docs/RELEASE.txt @@ -223,6 +223,16 @@ Bug Fixes since HDF5-1.12.1 release =================================== Library ------- + - Fix for CVE-2019-8396 + + Malformed HDF5 files may have truncated content which does not match + the expected size. When H5O__pline_decode() attempts to decode these it + may read past the end of the allocated space leading to heap overflows + as bounds checking is incomplete. + + The fix ensures each element is within bounds before reading. + + (2023/04/13 - HDFFV-10712, CVE-2019-8396, GitHub #2209) - Memory leak diff --git a/src/H5Opline.c b/src/H5Opline.c index 1ef18ee..2babcc0 100644 --- a/src/H5Opline.c +++ b/src/H5Opline.c @@ -109,6 +109,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) @@ -130,6 +131,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") @@ -158,6 +162,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 */ @@ -167,6 +174,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 */ @@ -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_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 3929ac3..a82796e 100644 --- a/src/H5private.h +++ b/src/H5private.h @@ -1469,6 +1469,9 @@ H5_DLL H5_ATTR_CONST int Nflock(int fd, int operation); #ifndef HDstrlen #define HDstrlen(S) strlen(S) #endif +#ifndef HDstrnlen +#define HDstrnlen(S, L) strnlen(S, L) +#endif #ifndef HDstrncat #define HDstrncat(X, Y, Z) strncat(X, Y, Z) #endif -- cgit v0.12