summaryrefslogtreecommitdiffstats
path: root/src/H5Fsuper_cache.c
diff options
context:
space:
mode:
authorDana Robinson <43805+derobins@users.noreply.github.com>2023-09-03 18:12:53 (GMT)
committerGitHub <noreply@github.com>2023-09-03 18:12:53 (GMT)
commit90852b28c729e963a7ebf4b21fe216a44ce7ad2b (patch)
treeecf4e03b91bedd929bef5babeea8b2d9dc004ae3 /src/H5Fsuper_cache.c
parentb1e65333b5c19457c53d5d6e7fd5e9add81e307d (diff)
downloadhdf5-90852b28c729e963a7ebf4b21fe216a44ce7ad2b.zip
hdf5-90852b28c729e963a7ebf4b21fe216a44ce7ad2b.tar.gz
hdf5-90852b28c729e963a7ebf4b21fe216a44ce7ad2b.tar.bz2
Cherry-pick of CVE fixes from 1.10 (#3490)
* CVE-2016-4332 * CVE-2018-11202 * CVE-2018-11205 * CVE-2018-13866 * CVE-2018-13867 * CVE-2018-13871 * CVE-2018-15671
Diffstat (limited to 'src/H5Fsuper_cache.c')
-rw-r--r--src/H5Fsuper_cache.c106
1 files changed, 72 insertions, 34 deletions
diff --git a/src/H5Fsuper_cache.c b/src/H5Fsuper_cache.c
index df61252..0c29756 100644
--- a/src/H5Fsuper_cache.c
+++ b/src/H5Fsuper_cache.c
@@ -409,13 +409,13 @@ H5F__cache_superblock_verify_chksum(const void *_image, size_t len, void *_udata
*-------------------------------------------------------------------------
*/
static void *
-H5F__cache_superblock_deserialize(const void *_image, size_t H5_ATTR_NDEBUG_UNUSED len, void *_udata,
- hbool_t H5_ATTR_UNUSED *dirty)
+H5F__cache_superblock_deserialize(const void *_image, size_t len, void *_udata, hbool_t H5_ATTR_UNUSED *dirty)
{
H5F_super_t *sblock = NULL; /* File's superblock */
H5F_superblock_cache_ud_t *udata = (H5F_superblock_cache_ud_t *)_udata; /* User data */
- const uint8_t *image = _image; /* Pointer into raw data buffer */
- H5F_super_t *ret_value = NULL; /* Return value */
+ const uint8_t *image = _image; /* Pointer into raw data buffer */
+ const uint8_t *end = image + len - 1; /* Pointer to end of buffer */
+ H5F_super_t *ret_value = NULL;
FUNC_ENTER_STATIC
@@ -427,11 +427,11 @@ H5F__cache_superblock_deserialize(const void *_image, size_t H5_ATTR_NDEBUG_UNUS
/* Allocate space for the superblock */
if (NULL == (sblock = H5FL_CALLOC(H5F_super_t)))
- HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed");
/* Deserialize the file superblock's prefix */
if (H5F__superblock_prefix_decode(sblock, &image, udata, FALSE) < 0)
- HGOTO_ERROR(H5E_FILE, H5E_CANTDECODE, NULL, "can't decode file superblock prefix")
+ HGOTO_ERROR(H5E_FILE, H5E_CANTDECODE, NULL, "can't decode file superblock prefix");
/* Check for older version of superblock format */
if (sblock->super_vers < HDF5_SUPERBLOCK_VERSION_2) {
@@ -441,85 +441,113 @@ H5F__cache_superblock_deserialize(const void *_image, size_t H5_ATTR_NDEBUG_UNUS
unsigned chunk_btree_k; /* B-tree chunk internal node 'K' value */
/* Freespace version (hard-wired) */
+ if (H5_IS_BUFFER_OVERFLOW(image, 1, end))
+ HGOTO_ERROR(H5E_FILE, H5E_OVERFLOW, NULL, "image pointer is out of bounds");
if (HDF5_FREESPACE_VERSION != *image++)
- HGOTO_ERROR(H5E_FILE, H5E_BADVALUE, NULL, "bad free space version number")
+ HGOTO_ERROR(H5E_FILE, H5E_BADVALUE, NULL, "bad free space version number");
/* Root group version number (hard-wired) */
+ if (H5_IS_BUFFER_OVERFLOW(image, 1, end))
+ HGOTO_ERROR(H5E_FILE, H5E_OVERFLOW, NULL, "image pointer is out of bounds");
if (HDF5_OBJECTDIR_VERSION != *image++)
- HGOTO_ERROR(H5E_FILE, H5E_BADVALUE, NULL, "bad object directory version number")
+ HGOTO_ERROR(H5E_FILE, H5E_BADVALUE, NULL, "bad object directory version number");
/* Skip over reserved byte */
+ if (H5_IS_BUFFER_OVERFLOW(image, 1, end))
+ HGOTO_ERROR(H5E_FILE, H5E_OVERFLOW, NULL, "image pointer is out of bounds");
image++;
/* Shared header version number (hard-wired) */
+ if (H5_IS_BUFFER_OVERFLOW(image, 1, end))
+ HGOTO_ERROR(H5E_FILE, H5E_OVERFLOW, NULL, "image pointer is out of bounds");
if (HDF5_SHAREDHEADER_VERSION != *image++)
- HGOTO_ERROR(H5E_FILE, H5E_BADVALUE, NULL, "bad shared-header format version number")
+ HGOTO_ERROR(H5E_FILE, H5E_BADVALUE, NULL, "bad shared-header format version number");
/* Skip over size of file addresses (already decoded) */
+ if (H5_IS_BUFFER_OVERFLOW(image, 1, end))
+ HGOTO_ERROR(H5E_FILE, H5E_OVERFLOW, NULL, "image pointer is out of bounds");
image++;
udata->f->shared->sizeof_addr = sblock->sizeof_addr; /* Keep a local copy also */
/* Skip over size of file sizes (already decoded) */
+ if (H5_IS_BUFFER_OVERFLOW(image, 1, end))
+ HGOTO_ERROR(H5E_FILE, H5E_OVERFLOW, NULL, "image pointer is out of bounds");
image++;
udata->f->shared->sizeof_size = sblock->sizeof_size; /* Keep a local copy also */
/* Skip over reserved byte */
+ if (H5_IS_BUFFER_OVERFLOW(image, 1, end))
+ HGOTO_ERROR(H5E_FILE, H5E_OVERFLOW, NULL, "image pointer is out of bounds");
image++;
/* Various B-tree sizes */
+ if (H5_IS_BUFFER_OVERFLOW(image, 2, end))
+ HGOTO_ERROR(H5E_FILE, H5E_OVERFLOW, NULL, "image pointer is out of bounds");
UINT16DECODE(image, sym_leaf_k);
if (sym_leaf_k == 0)
- HGOTO_ERROR(H5E_FILE, H5E_BADRANGE, NULL, "bad symbol table leaf node 1/2 rank")
+ HGOTO_ERROR(H5E_FILE, H5E_BADRANGE, NULL, "bad symbol table leaf node 1/2 rank");
udata->sym_leaf_k = sym_leaf_k; /* Keep a local copy also */
/* Need 'get' call to set other array values */
+ if (H5_IS_BUFFER_OVERFLOW(image, 2, end))
+ HGOTO_ERROR(H5E_FILE, H5E_OVERFLOW, NULL, "image pointer is out of bounds");
UINT16DECODE(image, snode_btree_k);
if (snode_btree_k == 0)
- HGOTO_ERROR(H5E_FILE, H5E_BADRANGE, NULL, "bad 1/2 rank for btree internal nodes")
+ HGOTO_ERROR(H5E_FILE, H5E_BADRANGE, NULL, "bad 1/2 rank for btree internal nodes");
udata->btree_k[H5B_SNODE_ID] = snode_btree_k;
- /*
- * Delay setting the value in the property list until we've checked
+ /* Delay setting the value in the property list until we've checked
* for the indexed storage B-tree internal 'K' value later.
*/
/* File status flags (not really used yet) */
+ if (H5_IS_BUFFER_OVERFLOW(image, 4, end))
+ HGOTO_ERROR(H5E_FILE, H5E_OVERFLOW, NULL, "image pointer is out of bounds");
UINT32DECODE(image, status_flags);
- HDassert(status_flags <= 255);
+ if (status_flags > 255)
+ HGOTO_ERROR(H5E_FILE, H5E_BADVALUE, NULL, "bad superblock status flags");
sblock->status_flags = (uint8_t)status_flags;
if (sblock->status_flags & ~H5F_SUPER_ALL_FLAGS)
- HGOTO_ERROR(H5E_FILE, H5E_BADVALUE, NULL, "bad flag value for superblock")
+ HGOTO_ERROR(H5E_FILE, H5E_BADVALUE, NULL, "bad flag value for superblock");
- /*
- * If the superblock version # is greater than 0, read in the indexed
+ /* If the superblock version # is greater than 0, read in the indexed
* storage B-tree internal 'K' value
*/
if (sblock->super_vers > HDF5_SUPERBLOCK_VERSION_DEF) {
+ if (H5_IS_BUFFER_OVERFLOW(image, 2, end))
+ HGOTO_ERROR(H5E_FILE, H5E_OVERFLOW, NULL, "image pointer is out of bounds");
UINT16DECODE(image, chunk_btree_k);
/* Reserved bytes are present only in version 1 */
- if (sblock->super_vers == HDF5_SUPERBLOCK_VERSION_1)
- image += 2; /* reserved */
- } /* end if */
+ if (sblock->super_vers == HDF5_SUPERBLOCK_VERSION_1) {
+ /* Reserved */
+ if (H5_IS_BUFFER_OVERFLOW(image, 2, end))
+ HGOTO_ERROR(H5E_FILE, H5E_OVERFLOW, NULL, "image pointer is out of bounds");
+ image += 2;
+ }
+ }
else
chunk_btree_k = HDF5_BTREE_CHUNK_IK_DEF;
udata->btree_k[H5B_CHUNK_ID] = chunk_btree_k;
/* Remainder of "variable-sized" portion of superblock */
+ if (H5_IS_BUFFER_OVERFLOW(image, H5F_sizeof_addr(udata->f) * 4, end))
+ HGOTO_ERROR(H5E_FILE, H5E_OVERFLOW, NULL, "image pointer is out of bounds");
H5F_addr_decode(udata->f, (const uint8_t **)&image, &sblock->base_addr /*out*/);
H5F_addr_decode(udata->f, (const uint8_t **)&image, &sblock->ext_addr /*out*/);
H5F_addr_decode(udata->f, (const uint8_t **)&image, &udata->stored_eof /*out*/);
H5F_addr_decode(udata->f, (const uint8_t **)&image, &sblock->driver_addr /*out*/);
/* Allocate space for the root group symbol table entry */
- HDassert(!sblock->root_ent);
+ if (sblock->root_ent)
+ HGOTO_ERROR(H5E_FILE, H5E_BADVALUE, NULL, "root entry should not exist yet");
if (NULL == (sblock->root_ent = (H5G_entry_t *)H5MM_calloc(sizeof(H5G_entry_t))))
HGOTO_ERROR(H5E_FILE, H5E_CANTALLOC, NULL,
- "can't allocate space for root group symbol table entry")
+ "can't allocate space for root group symbol table entry");
- /* decode the root group symbol table entry */
+ /* Decode the root group symbol table entry */
if (H5G_ent_decode(udata->f, (const uint8_t **)&image, sblock->root_ent) < 0)
- HGOTO_ERROR(H5E_FILE, H5E_CANTDECODE, NULL, "can't decode root group symbol table entry")
+ HGOTO_ERROR(H5E_FILE, H5E_CANTDECODE, NULL, "can't decode root group symbol table entry");
/* Set the root group address to the correct value */
sblock->root_addr = sblock->root_ent->header;
@@ -533,26 +561,32 @@ H5F__cache_superblock_deserialize(const void *_image, size_t H5_ATTR_NDEBUG_UNUS
/* Eliminate the driver info */
sblock->driver_addr = HADDR_UNDEF;
udata->drvrinfo_removed = TRUE;
- } /* end if */
+ }
/* NOTE: Driver info block is decoded separately, later */
-
- } /* end if */
+ }
else {
uint32_t read_chksum; /* Checksum read from file */
/* Skip over size of file addresses (already decoded) */
image++;
udata->f->shared->sizeof_addr = sblock->sizeof_addr; /* Keep a local copy also */
-
/* Skip over size of file sizes (already decoded) */
image++;
udata->f->shared->sizeof_size = sblock->sizeof_size; /* Keep a local copy also */
+ /* Check whether the image pointer is out of bounds */
+ if (H5_IS_BUFFER_OVERFLOW(image, 1, end))
+ HGOTO_ERROR(H5E_FILE, H5E_OVERFLOW, NULL, "image pointer is out of bounds");
+
/* File status flags (not really used yet) */
sblock->status_flags = *image++;
if (sblock->status_flags & ~H5F_SUPER_ALL_FLAGS)
- HGOTO_ERROR(H5E_FILE, H5E_BADVALUE, NULL, "bad flag value for superblock")
+ HGOTO_ERROR(H5E_FILE, H5E_BADVALUE, NULL, "bad flag value for superblock");
+
+ /* Check whether the image pointer will be out of bounds */
+ if (H5_IS_BUFFER_OVERFLOW(image, H5F_SIZEOF_ADDR(udata->f) * 4, end))
+ HGOTO_ERROR(H5E_FILE, H5E_OVERFLOW, NULL, "image pointer is out of bounds");
/* Base, superblock extension, end of file & root group object header addresses */
H5F_addr_decode(udata->f, (const uint8_t **)&image, &sblock->base_addr /*out*/);
@@ -562,6 +596,10 @@ H5F__cache_superblock_deserialize(const void *_image, size_t H5_ATTR_NDEBUG_UNUS
/* checksum verification already done in verify_chksum cb */
+ /* Check whether the image pointer will be out of bounds */
+ if (H5_IS_BUFFER_OVERFLOW(image, sizeof(uint32_t), end))
+ HGOTO_ERROR(H5E_FILE, H5E_OVERFLOW, NULL, "image pointer is out of bounds");
+
/* Decode checksum */
UINT32DECODE(image, read_chksum);
@@ -571,19 +609,19 @@ H5F__cache_superblock_deserialize(const void *_image, size_t H5_ATTR_NDEBUG_UNUS
* any attempt to load the Driver Information Block.
*/
sblock->driver_addr = HADDR_UNDEF;
- } /* end else */
+ }
- /* Sanity check */
- HDassert((size_t)(image - (const uint8_t *)_image) <= len);
+ /* Size check */
+ if ((size_t)(image - (const uint8_t *)_image) > len)
+ HDONE_ERROR(H5E_FILE, H5E_BADVALUE, NULL, "bad decoded superblock size");
- /* Set return value */
ret_value = sblock;
done:
/* Release the [possibly partially initialized] superblock on error */
if (!ret_value && sblock)
if (H5F__super_free(sblock) < 0)
- HDONE_ERROR(H5E_FILE, H5E_CANTFREE, NULL, "unable to destroy superblock data")
+ HDONE_ERROR(H5E_FILE, H5E_CANTFREE, NULL, "unable to destroy superblock data");
FUNC_LEAVE_NOAPI(ret_value)
} /* end H5F__cache_superblock_deserialize() */