mirror of
https://github.com/openembedded/meta-openembedded.git
synced 2026-11-14 03:57:15 +00:00
hdf5: upgrade 2.0.0 -> 2.2.0
Releases are published on GitHub now. Drop CVE-2026-17572, CVE-2026-17573, CVE-2026-17574, CVE-2026-26197 and CVE-2026-26199 patches, their upstream commits are part of 2.2.0. The other CVE fixes are only on the develop branch and are kept. AI-Generated: Uses Claude Code Signed-off-by: Khem Raj <khem.raj@oss.qualcomm.com>
This commit is contained in:
7 files changed
+7
-1132
No files matched your search
@@ -17,12 +17,12 @@ Signed-off-by: Ankur Tyagi <ankur.tyagi85@gmail.com>
|
||||
2 files changed, 20 insertions(+)
|
||||
|
||||
diff --git a/release_docs/CHANGELOG.md b/release_docs/CHANGELOG.md
|
||||
index c181f174bbb..b5c99cd4b16 100644
|
||||
index d547b36..f8aacb0 100644
|
||||
--- a/release_docs/CHANGELOG.md
|
||||
+++ b/release_docs/CHANGELOG.md
|
||||
@@ -778,6 +778,12 @@ Added Fortran wrapper `h5fdsubfiling_get_file_mapping_f()` for the subfiling fil
|
||||
@@ -232,6 +232,12 @@ The `h5repack` tool now obtains its default low and high library version bounds
|
||||
|
||||
A malformed HDF5 file could have an attribute with a recorded name length of zero.This would lead to an overflow and an invalid memory access. An integrity check has been added to detect this case and safely stop file decoding.
|
||||
`H5S_select_deserialize()` and the per-selection-type deserialize callbacks (all, hyperslab, none, and point) previously computed the pointer to the last valid buffer byte as `buffer + size - 1` without first checking the buffer size. A buffer shorter than the 4-byte selection-type header, or a zero-length selection-info buffer, would underflow this computation and produce an out-of-bounds end pointer, defeating subsequent overflow checks. The deserialize routines now reject a buffer that is too small to hold the selection type, and they reject an empty selection-info buffer before deriving the end pointer. Hyperslab decoding additionally now rejects a serialized rank of 0 or greater than `H5S_MAX_RANK`. As a companion fix, `H5S__hyper_serialize()` now returns an error when asked to serialize a hyperslab selection on a rank-0 (scalar or null) dataspace, a state that can arise when a dataspace extent is collapsed to a scalar after a hyperslab selection has already been made.
|
||||
|
||||
+### Fixed a stack overflow when iterating a corrupted B-tree
|
||||
+
|
||||
@@ -32,9 +32,9 @@ index c181f174bbb..b5c99cd4b16 100644
|
||||
+
|
||||
## Java Library
|
||||
|
||||
### Renamed the Callbacks.java file to H5Callbacks.java
|
||||
### Fixed a datatype ID leak when reading or writing array/vlen datatypes
|
||||
diff --git a/src/H5B.c b/src/H5B.c
|
||||
index c9571708b73..4c6b1a55480 100644
|
||||
index c957170..4c6b1a5 100644
|
||||
--- a/src/H5B.c
|
||||
+++ b/src/H5B.c
|
||||
@@ -1140,6 +1140,20 @@ H5B__iterate_helper(H5F_t *f, const H5B_class_t *type, haddr_t addr, int exp_lev
|
||||
|
||||
@@ -1,253 +0,0 @@
|
||||
From 606bb0a0282d0b056a3bdda1d489a608deee78d2 Mon Sep 17 00:00:00 2001
|
||||
From: Nayyar <nayyar@bugqore.com>
|
||||
Date: Tue, 14 Jul 2026 23:39:56 +0530
|
||||
Subject: [PATCH] reject SOHM list message count exceeding list_max (#6499)
|
||||
|
||||
* bound SOHM list decode to list_max messages
|
||||
|
||||
* Add tsohm test for out-of-range SOHM list message count
|
||||
|
||||
Create a file with a shared-message list index, corrupt the on-disk
|
||||
message count so it exceeds list_max (repairing the table checksum),
|
||||
and confirm reopening rejects the file instead of overrunning the
|
||||
list image buffer and message array.
|
||||
|
||||
---------
|
||||
|
||||
Co-authored-by: H. Joe Lee <hyoklee@hdfgroup.org>
|
||||
Co-authored-by: Larry Knox <lrknox@hdfgroup.org>
|
||||
|
||||
CVE: CVE-2026-17572
|
||||
Upstream-Status: Backport [https://github.com/HDFGroup/hdf5/commit/20f0b9564bc46154e60f8d35578720a599d41552]
|
||||
|
||||
Dropped changes to the CHANGELOG file.
|
||||
|
||||
Signed-off-by: Ankur Tyagi <ankur.tyagi85@gmail.com>
|
||||
---
|
||||
src/H5SMcache.c | 14 ++++
|
||||
test/tsohm.c | 173 ++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
2 files changed, 187 insertions(+)
|
||||
|
||||
diff --git a/src/H5SMcache.c b/src/H5SMcache.c
|
||||
index eb6d612a78..96687ffed9 100644
|
||||
--- a/src/H5SMcache.c
|
||||
+++ b/src/H5SMcache.c
|
||||
@@ -489,6 +489,12 @@ H5SM__cache_list_verify_chksum(const void *_image, size_t H5_ATTR_UNUSED len, vo
|
||||
assert(image);
|
||||
assert(udata);
|
||||
|
||||
+ /* The buffer only holds list_max messages; a corrupted header whose message
|
||||
+ * count exceeds that would size the checksum region past the end of it.
|
||||
+ */
|
||||
+ if (udata->header->num_messages > udata->header->list_max)
|
||||
+ HGOTO_ERROR(H5E_SOHM, H5E_BADVALUE, FAIL, "number of SOHM messages exceeds list size");
|
||||
+
|
||||
/* Exact size with checksum at the end */
|
||||
chk_size = H5SM_LIST_SIZE(udata->f, udata->header->num_messages);
|
||||
|
||||
@@ -552,6 +558,14 @@ H5SM__cache_list_deserialize(const void *_image, size_t H5_ATTR_NDEBUG_UNUSED le
|
||||
HGOTO_ERROR(H5E_SOHM, H5E_CANTLOAD, NULL, "bad SOHM list signature");
|
||||
image += H5_SIZEOF_MAGIC;
|
||||
|
||||
+ /* The message array is sized for list_max entries; a list index always
|
||||
+ * holds at most that many before it is promoted to a B-tree. Reject a
|
||||
+ * corrupted header whose message count would drive the decode loop past
|
||||
+ * the allocation and the input buffer.
|
||||
+ */
|
||||
+ if (udata->header->num_messages > udata->header->list_max)
|
||||
+ HGOTO_ERROR(H5E_SOHM, H5E_CANTLOAD, NULL, "number of SOHM messages exceeds list size");
|
||||
+
|
||||
/* Read messages into the list array */
|
||||
ctx.sizeof_addr = H5F_SIZEOF_ADDR(udata->f);
|
||||
for (u = 0; u < udata->header->num_messages; u++) {
|
||||
diff --git a/test/tsohm.c b/test/tsohm.c
|
||||
index 1652c9b044..61036e7dc3 100644
|
||||
--- a/test/tsohm.c
|
||||
+++ b/test/tsohm.c
|
||||
@@ -3702,6 +3702,175 @@ test_sohm_external_dtype(void)
|
||||
free(orig);
|
||||
} /* test_sohm_external_dtype */
|
||||
|
||||
+/*-------------------------------------------------------------------------
|
||||
+ * Function: test_sohm_reject_bad_count
|
||||
+ *
|
||||
+ * Purpose: A shared-message list index holds at most list_max messages
|
||||
+ * on disk before it is promoted to a B-tree, and both the list
|
||||
+ * image buffer and the in-memory message array are sized for
|
||||
+ * list_max entries. Corrupt the on-disk message count so it
|
||||
+ * exceeds list_max and verify the list load rejects the file
|
||||
+ * instead of sizing a read or indexing the array past its end.
|
||||
+ *
|
||||
+ *-------------------------------------------------------------------------
|
||||
+ */
|
||||
+static void
|
||||
+test_sohm_reject_bad_count(void)
|
||||
+{
|
||||
+ hid_t fcpl_id = H5I_INVALID_HID;
|
||||
+ hid_t fid = H5I_INVALID_HID;
|
||||
+ hid_t sid = H5I_INVALID_HID;
|
||||
+ hid_t did = H5I_INVALID_HID;
|
||||
+ hsize_t dims[1] = {4};
|
||||
+ FILE *fp = NULL;
|
||||
+ uint8_t *buf = NULL;
|
||||
+ long fsize = 0;
|
||||
+ long table_off = -1;
|
||||
+ unsigned list_max = 100;
|
||||
+ uint32_t chksum;
|
||||
+ size_t pos;
|
||||
+ int i;
|
||||
+ herr_t ret;
|
||||
+
|
||||
+ /* On-disk shared-message table layout for a file with a single index and
|
||||
+ * 8-byte addresses: a 4-byte "SMTB" signature, one index record, then a
|
||||
+ * 4-byte checksum. Within the record the 16-bit message count follows the
|
||||
+ * (version, index type, message types, minimum size) prefix and the 16-bit
|
||||
+ * list and B-tree cutoffs.
|
||||
+ */
|
||||
+ const size_t rec_size = 1 + 1 + 2 + 4 + 3 * 2 + 8 + 8; /* 30 */
|
||||
+ const size_t table_body = (size_t)H5_SIZEOF_MAGIC + rec_size; /* 34 */
|
||||
+ const size_t num_msgs_off = (size_t)H5_SIZEOF_MAGIC + (1 + 1 + 2 + 4 + 2 + 2); /* 16 */
|
||||
+
|
||||
+ MESSAGE(5, ("Testing rejection of an out-of-range SOHM list message count\n"));
|
||||
+
|
||||
+ /* Create a file whose single shared-message index is a list that can hold
|
||||
+ * up to list_max messages before converting to a B-tree.
|
||||
+ */
|
||||
+ fcpl_id = H5Pcreate(H5P_FILE_CREATE);
|
||||
+ CHECK_I(fcpl_id, "H5Pcreate");
|
||||
+ ret = H5Pset_shared_mesg_nindexes(fcpl_id, 1);
|
||||
+ CHECK_I(ret, "H5Pset_shared_mesg_nindexes");
|
||||
+ ret = H5Pset_shared_mesg_index(fcpl_id, 0, H5O_SHMESG_SDSPACE_FLAG | H5O_SHMESG_DTYPE_FLAG, 1);
|
||||
+ CHECK_I(ret, "H5Pset_shared_mesg_index");
|
||||
+ ret = H5Pset_shared_mesg_phase_change(fcpl_id, list_max, 0);
|
||||
+ CHECK_I(ret, "H5Pset_shared_mesg_phase_change");
|
||||
+
|
||||
+ fid = H5Fcreate(FILENAME, H5F_ACC_TRUNC, fcpl_id, H5P_DEFAULT);
|
||||
+ CHECK_I(fid, "H5Fcreate");
|
||||
+
|
||||
+ /* Several datasets sharing one dataspace and datatype leave the index a
|
||||
+ * list holding a couple of messages, well under list_max.
|
||||
+ */
|
||||
+ sid = H5Screate_simple(1, dims, NULL);
|
||||
+ CHECK_I(sid, "H5Screate_simple");
|
||||
+ for (i = 0; i < 5; i++) {
|
||||
+ char name[16];
|
||||
+
|
||||
+ snprintf(name, sizeof(name), "dset%d", i);
|
||||
+ did = H5Dcreate2(fid, name, H5T_NATIVE_INT, sid, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
|
||||
+ CHECK_I(did, "H5Dcreate2");
|
||||
+ ret = H5Dclose(did);
|
||||
+ CHECK_I(ret, "H5Dclose");
|
||||
+ }
|
||||
+ ret = H5Sclose(sid);
|
||||
+ CHECK_I(ret, "H5Sclose");
|
||||
+ ret = H5Fclose(fid);
|
||||
+ CHECK_I(ret, "H5Fclose");
|
||||
+
|
||||
+ /* Read the whole file so the shared-message table can be located and edited. */
|
||||
+ fp = fopen(FILENAME, "rb");
|
||||
+ CHECK_PTR(fp, "fopen");
|
||||
+ if (fp) {
|
||||
+ if (fseek(fp, 0, SEEK_END) != 0)
|
||||
+ TestErrPrintf("fseek failed at line %d\n", __LINE__);
|
||||
+ fsize = ftell(fp);
|
||||
+ if (fsize <= (long)(table_body + 4))
|
||||
+ TestErrPrintf("unexpected file size %ld at line %d\n", fsize, __LINE__);
|
||||
+ rewind(fp);
|
||||
+
|
||||
+ buf = (uint8_t *)malloc((size_t)fsize);
|
||||
+ CHECK_PTR(buf, "malloc");
|
||||
+ if (buf && fread(buf, 1, (size_t)fsize, fp) != (size_t)fsize)
|
||||
+ TestErrPrintf("fread failed at line %d\n", __LINE__);
|
||||
+ if (fclose(fp) != 0)
|
||||
+ TestErrPrintf("fclose failed at line %d\n", __LINE__);
|
||||
+ fp = NULL;
|
||||
+ }
|
||||
+
|
||||
+ /* Find the shared-message table by signature, confirming the match with the
|
||||
+ * stored checksum so the correct bytes are edited.
|
||||
+ */
|
||||
+ for (pos = 0; buf && (pos + table_body + 4) <= (size_t)fsize; pos++) {
|
||||
+ if (memcmp(buf + pos, H5SM_TABLE_MAGIC, (size_t)H5_SIZEOF_MAGIC) != 0)
|
||||
+ continue;
|
||||
+
|
||||
+ chksum = (uint32_t)buf[pos + table_body] | ((uint32_t)buf[pos + table_body + 1] << 8) |
|
||||
+ ((uint32_t)buf[pos + table_body + 2] << 16) | ((uint32_t)buf[pos + table_body + 3] << 24);
|
||||
+ if (chksum == H5_checksum_metadata(buf + pos, table_body, 0)) {
|
||||
+ table_off = (long)pos;
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+ if (table_off < 0)
|
||||
+ TestErrPrintf("could not locate the shared-message table in %s\n", FILENAME);
|
||||
+
|
||||
+ if (buf && table_off >= 0) {
|
||||
+ unsigned bad_count = list_max + 200; /* well past the list_max cutoff */
|
||||
+ size_t base = (size_t)table_off;
|
||||
+
|
||||
+ /* Overwrite the 16-bit message count and repair the table checksum so
|
||||
+ * the table loads and the corruption is only caught at the list.
|
||||
+ */
|
||||
+ buf[base + num_msgs_off] = (uint8_t)(bad_count & 0xff);
|
||||
+ buf[base + num_msgs_off + 1] = (uint8_t)((bad_count >> 8) & 0xff);
|
||||
+
|
||||
+ chksum = H5_checksum_metadata(buf + base, table_body, 0);
|
||||
+ buf[base + table_body] = (uint8_t)(chksum & 0xff);
|
||||
+ buf[base + table_body + 1] = (uint8_t)((chksum >> 8) & 0xff);
|
||||
+ buf[base + table_body + 2] = (uint8_t)((chksum >> 16) & 0xff);
|
||||
+ buf[base + table_body + 3] = (uint8_t)((chksum >> 24) & 0xff);
|
||||
+
|
||||
+ fp = fopen(FILENAME, "r+b");
|
||||
+ CHECK_PTR(fp, "fopen");
|
||||
+ if (fp) {
|
||||
+ if (fwrite(buf, 1, (size_t)fsize, fp) != (size_t)fsize)
|
||||
+ TestErrPrintf("fwrite failed at line %d\n", __LINE__);
|
||||
+ if (fclose(fp) != 0)
|
||||
+ TestErrPrintf("fclose failed at line %d\n", __LINE__);
|
||||
+ fp = NULL;
|
||||
+ }
|
||||
+
|
||||
+ /* Reopen and share a new message, which protects the list and drives
|
||||
+ * the vulnerable decode. The load should reject the file cleanly.
|
||||
+ */
|
||||
+ fid = H5Fopen(FILENAME, H5F_ACC_RDWR, H5P_DEFAULT);
|
||||
+ CHECK_I(fid, "H5Fopen");
|
||||
+ sid = H5Screate_simple(1, dims, NULL);
|
||||
+ CHECK_I(sid, "H5Screate_simple");
|
||||
+
|
||||
+ H5E_BEGIN_TRY
|
||||
+ {
|
||||
+ did = H5Dcreate2(fid, "trigger", H5T_NATIVE_INT, sid, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
|
||||
+ }
|
||||
+ H5E_END_TRY
|
||||
+
|
||||
+ if (did >= 0) {
|
||||
+ TestErrPrintf("dataset creation succeeded on a corrupted SOHM list at line %d\n", __LINE__);
|
||||
+ H5Dclose(did);
|
||||
+ }
|
||||
+
|
||||
+ ret = H5Sclose(sid);
|
||||
+ CHECK_I(ret, "H5Sclose");
|
||||
+ ret = H5Fclose(fid);
|
||||
+ CHECK_I(ret, "H5Fclose");
|
||||
+ }
|
||||
+
|
||||
+ free(buf);
|
||||
+ ret = H5Pclose(fcpl_id);
|
||||
+ CHECK_I(ret, "H5Pclose");
|
||||
+} /* test_sohm_reject_bad_count */
|
||||
+
|
||||
/****************************************************************
|
||||
**
|
||||
** test_sohm(): Main Shared Object Header Message testing routine.
|
||||
@@ -3755,6 +3924,10 @@ test_sohm(void H5_ATTR_UNUSED *params)
|
||||
|
||||
test_sohm_extend_dset(); /* Test extending shared datasets */
|
||||
test_sohm_external_dtype(); /* Test using datatype in another file */
|
||||
+
|
||||
+ /* Editing the on-disk table in place needs the single-file sec2 layout */
|
||||
+ if (default_driver)
|
||||
+ test_sohm_reject_bad_count(); /* Test rejecting a bad SOHM list message count */
|
||||
} /* test_sohm */
|
||||
|
||||
/*-------------------------------------------------------------------------
|
||||
@@ -1,53 +0,0 @@
|
||||
From 856e7f1dd23e466ebeab5e454a5891b12e188f6a Mon Sep 17 00:00:00 2001
|
||||
From: jhendersonHDF <jhenderson@hdfgroup.org>
|
||||
Date: Tue, 27 Jan 2026 05:55:38 -0600
|
||||
Subject: [PATCH] Fix double-free issue in H5D__chunk_copy (#6160)
|
||||
|
||||
Fix double-free caused by loss of buffer pointer after re-allocation
|
||||
|
||||
Co-authored-by: Larry Knox <lrknox@hdfgroup.org>
|
||||
|
||||
CVE: CVE-2026-17573
|
||||
Upstream-Status: Backport [https://github.com/HDFGroup/hdf5/commit/dd3080a58cc6bb86f3b34284399915da9e513262]
|
||||
|
||||
Dropped changes to the CHANGELOG file.
|
||||
|
||||
Signed-off-by: Ankur Tyagi <ankur.tyagi85@gmail.com>
|
||||
---
|
||||
src/H5Dchunk.c | 5 ++---
|
||||
1 file changed, 2 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/src/H5Dchunk.c b/src/H5Dchunk.c
|
||||
index f2a0e85c03..5ff537ebde 100644
|
||||
--- a/src/H5Dchunk.c
|
||||
+++ b/src/H5Dchunk.c
|
||||
@@ -7034,7 +7034,7 @@ H5D__chunk_copy(H5F_t *f_src, H5O_layout_t *layout_src, H5F_t *f_dst, H5O_layout
|
||||
const H5S_extent_t *ds_extent_src, H5T_t *dt_src, const H5O_pline_t *pline_src,
|
||||
H5O_copy_t *cpy_info)
|
||||
{
|
||||
- H5D_chunk_it_ud3_t udata; /* User data for iteration callback */
|
||||
+ H5D_chunk_it_ud3_t udata = {0}; /* User data for iteration callback */
|
||||
H5D_chk_idx_info_t idx_info_dst; /* Dest. chunked index info */
|
||||
H5D_chk_idx_info_t idx_info_src; /* Source chunked index info */
|
||||
int sndims; /* Rank of dataspace */
|
||||
@@ -7202,7 +7202,6 @@ H5D__chunk_copy(H5F_t *f_src, H5O_layout_t *layout_src, H5F_t *f_dst, H5O_layout
|
||||
HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for raw data chunk");
|
||||
|
||||
/* Initialize the callback structure for the source */
|
||||
- memset(&udata, 0, sizeof udata);
|
||||
udata.common.layout = &layout_src->u.chunk;
|
||||
udata.common.storage = &layout_src->storage.u.chunk;
|
||||
udata.file_src = f_src;
|
||||
@@ -7253,11 +7252,11 @@ H5D__chunk_copy(H5F_t *f_src, H5O_layout_t *layout_src, H5F_t *f_dst, H5O_layout
|
||||
} /* end for */
|
||||
}
|
||||
|
||||
+done:
|
||||
/* I/O buffers may have been re-allocated */
|
||||
buf = udata.buf;
|
||||
bkg = udata.bkg;
|
||||
|
||||
-done:
|
||||
if (dt_dst && (H5T_close(dt_dst) < 0))
|
||||
HDONE_ERROR(H5E_DATASET, H5E_CANTCLOSEOBJ, FAIL, "can't close temporary datatype");
|
||||
if (dt_mem && (H5T_close(dt_mem) < 0))
|
||||
@@ -1,65 +0,0 @@
|
||||
From e374b227c277e100d9bfa3b1fe5c0b60cdff6c43 Mon Sep 17 00:00:00 2001
|
||||
From: tbeu <tbeu@users.noreply.github.com>
|
||||
Date: Thu, 28 May 2026 17:26:57 +0200
|
||||
Subject: [PATCH] Validate VL datatype type during decode and check file
|
||||
pointer in H5T_set_loc (#6395)
|
||||
|
||||
H5O__dtype_decode_helper() reads vlen.type from the file without
|
||||
validation. With corrupted HDF5 files (e.g. from fuzzing), this field
|
||||
can have an invalid value that is neither H5T_VLEN_SEQUENCE nor
|
||||
H5T_VLEN_STRING, which later triggers assert(0) in H5T__vlen_set_loc()
|
||||
(debug builds) or a NULL pointer dereference / SEGV in release builds.
|
||||
|
||||
Fix by:
|
||||
1. Adding a validation check in H5O__dtype_decode_helper() immediately
|
||||
after reading the vlen.type field, returning an error if the value
|
||||
is invalid.
|
||||
2. Adding a NULL file pointer check in H5T_set_loc() before calling
|
||||
H5T__vlen_set_loc() when loc == H5T_LOC_DISK, so the low-level
|
||||
assert(file) invariant is never violated.
|
||||
|
||||
This fixes the root cause at the decode level where the bad value
|
||||
enters the system, as requested in review of #6378 and #6385.
|
||||
|
||||
Found by OSS-Fuzz via the matio fuzzer (ClusterFuzz testcase
|
||||
5366895365914624).
|
||||
|
||||
(cherry picked from commit 3fa6ed6e9dfeebbc784e21d8c48e31e35a8042bc)
|
||||
|
||||
CVE: CVE-2026-17574
|
||||
Upstream-Status: Backport [https://github.com/HDFGroup/hdf5/commit/3fa6ed6e9dfeebbc784e21d8c48e31e35a8042bc]
|
||||
Signed-off-by: Ankur Tyagi <ankur.tyagi85@gmail.com>
|
||||
---
|
||||
src/H5Odtype.c | 2 ++
|
||||
src/H5T.c | 5 +++++
|
||||
2 files changed, 7 insertions(+)
|
||||
|
||||
diff --git a/src/H5Odtype.c b/src/H5Odtype.c
|
||||
index d6405cdb86..6e622f3ebc 100644
|
||||
--- a/src/H5Odtype.c
|
||||
+++ b/src/H5Odtype.c
|
||||
@@ -751,6 +751,8 @@ H5O__dtype_decode_helper(unsigned *ioflags /*in,out*/, const uint8_t **pp, H5T_t
|
||||
*/
|
||||
/* Set the type of VL information, either sequence or string */
|
||||
dt->shared->u.vlen.type = (H5T_vlen_type_t)(flags & 0x0f);
|
||||
+ if (dt->shared->u.vlen.type != H5T_VLEN_SEQUENCE && dt->shared->u.vlen.type != H5T_VLEN_STRING)
|
||||
+ HGOTO_ERROR(H5E_DATATYPE, H5E_BADVALUE, FAIL, "invalid VL datatype type");
|
||||
if (dt->shared->u.vlen.type == H5T_VLEN_STRING) {
|
||||
dt->shared->u.vlen.pad = (H5T_str_t)((flags >> 4) & 0x0f);
|
||||
dt->shared->u.vlen.cset = (H5T_cset_t)((flags >> 8) & 0x0f);
|
||||
diff --git a/src/H5T.c b/src/H5T.c
|
||||
index 3b2e391a53..e2c9ba9791 100644
|
||||
--- a/src/H5T.c
|
||||
+++ b/src/H5T.c
|
||||
@@ -6953,6 +6953,11 @@ H5T_set_loc(H5T_t *dt, H5VL_object_t *file, H5T_loc_t loc)
|
||||
ret_value = changed;
|
||||
} /* end if */
|
||||
|
||||
+ /* Validate file pointer for disk-based VL types */
|
||||
+ if (loc == H5T_LOC_DISK && NULL == file)
|
||||
+ HGOTO_ERROR(H5E_DATATYPE, H5E_BADVALUE, FAIL,
|
||||
+ "NULL file pointer for disk-based VL datatype");
|
||||
+
|
||||
/* Mark this VL sequence */
|
||||
if ((changed = H5T__vlen_set_loc(dt, file, loc)) < 0)
|
||||
HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "Unable to set VL location");
|
||||
@@ -1,70 +0,0 @@
|
||||
From 7a9f34e150beb688397d3f562d0f6ed1f9cd0e60 Mon Sep 17 00:00:00 2001
|
||||
From: bmribler <39579120+bmribler@users.noreply.github.com>
|
||||
Date: Tue, 3 Feb 2026 16:26:51 -0500
|
||||
Subject: [PATCH] Validate datatype size for consistency (#6173)
|
||||
|
||||
User report:
|
||||
When a file is corrupted such that an array datatype's size, the
|
||||
number of elements, and the element size are not in agreement, it can
|
||||
trigger an out of bounds read.
|
||||
(private GH issue: GHSA-gh44-7wpq-622f)
|
||||
Added a validation to ensure the above are in agreement.
|
||||
|
||||
CVE: CVE-2026-26197
|
||||
Upstream-Status: Backport [https://github.com/HDFGroup/hdf5/commit/8cd9f7a7ba6757fbb72e36bbe23e127f8507c8a6]
|
||||
|
||||
Backport Changes:
|
||||
- Omitted release_docs/CHANGELOG.md because its HDF5 2.1.0 release
|
||||
context does not apply to the 2.0.0 backport.
|
||||
|
||||
(cherry picked from commit 8cd9f7a7ba6757fbb72e36bbe23e127f8507c8a6)
|
||||
Signed-off-by: Devansh Patel <devanshp@cisco.com>
|
||||
---
|
||||
src/H5Odtype.c | 20 +++++++++++++++++++-
|
||||
1 file changed, 19 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/src/H5Odtype.c b/src/H5Odtype.c
|
||||
index f53f608ee..d6405cdb8 100644
|
||||
--- a/src/H5Odtype.c
|
||||
+++ b/src/H5Odtype.c
|
||||
@@ -774,7 +774,8 @@ H5O__dtype_decode_helper(unsigned *ioflags /*in,out*/, const uint8_t **pp, H5T_t
|
||||
HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "invalid datatype location");
|
||||
break;
|
||||
|
||||
- case H5T_ARRAY:
|
||||
+ case H5T_ARRAY: {
|
||||
+ size_t expected_size; /* for validating array datatype size consistency */
|
||||
/*
|
||||
* Array datatypes...
|
||||
*/
|
||||
@@ -816,6 +817,22 @@ H5O__dtype_decode_helper(unsigned *ioflags /*in,out*/, const uint8_t **pp, H5T_t
|
||||
if (H5O__dtype_decode_helper(ioflags, pp, dt->shared->parent, skip, p_end) < 0)
|
||||
HGOTO_ERROR(H5E_DATATYPE, H5E_CANTDECODE, FAIL, "unable to decode array parent type");
|
||||
|
||||
+ /* Check for multiplication overflow */
|
||||
+ if (dt->shared->parent->shared->size > 0 &&
|
||||
+ dt->shared->u.array.nelem > SIZE_MAX / dt->shared->parent->shared->size)
|
||||
+ HGOTO_ERROR(H5E_DATATYPE, H5E_BADVALUE, FAIL,
|
||||
+ "array datatype size calculation would overflow");
|
||||
+
|
||||
+ expected_size = dt->shared->parent->shared->size * dt->shared->u.array.nelem;
|
||||
+
|
||||
+ /* Verify the stored size matches the calculated size */
|
||||
+ if (dt->shared->size != expected_size)
|
||||
+ HGOTO_ERROR(
|
||||
+ H5E_DATATYPE, H5E_BADVALUE, FAIL,
|
||||
+ "array datatype size mismatch: expected %zu (element_size=%zu * nelem=%zu), got %zu",
|
||||
+ expected_size, dt->shared->parent->shared->size, dt->shared->u.array.nelem,
|
||||
+ dt->shared->size);
|
||||
+
|
||||
/* Check if the parent of this array has a version greater than the
|
||||
* array itself. */
|
||||
H5O_DTYPE_CHECK_VERSION(dt, version, dt->shared->parent->shared->version, ioflags, "array", FAIL)
|
||||
@@ -829,6 +846,7 @@ H5O__dtype_decode_helper(unsigned *ioflags /*in,out*/, const uint8_t **pp, H5T_t
|
||||
if (dt->shared->parent->shared->force_conv == true)
|
||||
dt->shared->force_conv = true;
|
||||
break;
|
||||
+ }
|
||||
|
||||
case H5T_COMPLEX: {
|
||||
bool homogeneous;
|
||||
@@ -1,677 +0,0 @@
|
||||
From e26fc8e32247cef9524a539a921ff986bd8cbf66 Mon Sep 17 00:00:00 2001
|
||||
From: bmribler <39579120+bmribler@users.noreply.github.com>
|
||||
Date: Mon, 26 Jan 2026 19:07:23 -0500
|
||||
Subject: [PATCH] Fixes buffer underflow (#6143)
|
||||
|
||||
Fixes security issue by treating non-NULL buffer with size 0 as length-only query in get_name API functions.
|
||||
|
||||
Behavior:
|
||||
Modify get_name API functions to treat (buffer != NULL, size == 0) as length-only queries, preventing undefined behavior.
|
||||
Fix applied to H5Aget_name, H5Aget_name_by_idx, H5Fget_name, H5Gget_objname_by_idx, H5Iget_name, H5Lget_name_by_idx, H5Rget_file_name, H5Rget_obj_name, H5Rget_attr_name, and 8 other functions.
|
||||
Tests:
|
||||
Update test/links.c, test/tattr.c, test/tfile.c, test/titerate.c, and test/trefer.c to verify new behavior with non-null buffer and size 0.
|
||||
Documentation:
|
||||
Update comments in H5A.c, H5F.c, H5Gdeprec.c, H5I.c, H5L.c, H5R.c, and H5Rdeprec.c to reflect new behavior.t]@users.noreply.github.com>
|
||||
|
||||
CVE: CVE-2026-26199
|
||||
Upstream-Status: Backport [https://github.com/HDFGroup/hdf5/commit/9268b803b742f99c1f8793cae74f19e74976b065]
|
||||
|
||||
Backport Changes:
|
||||
- Omitted release_docs/CHANGELOG.md because its HDF5 2.1.0 release context does not apply to the 2.0.0 backport.
|
||||
|
||||
(cherry picked from commit 9268b803b742f99c1f8793cae74f19e74976b065)
|
||||
Signed-off-by: Devansh Patel <devanshp@cisco.com>
|
||||
---
|
||||
src/H5A.c | 11 ++++++++-
|
||||
src/H5F.c | 32 ++++++++++++++++++---------
|
||||
src/H5Gdeprec.c | 32 ++++++++++++++++++---------
|
||||
src/H5I.c | 32 ++++++++++++++++++---------
|
||||
src/H5L.c | 4 ++++
|
||||
src/H5R.c | 59 ++++++++++++++++++++++++++++++++++++++++++++++++-
|
||||
src/H5Rdeprec.c | 22 ++++++++++++++++--
|
||||
test/links.c | 21 ++++++++++++++++--
|
||||
test/tattr.c | 25 +++++++++++++++++++--
|
||||
test/tfile.c | 16 +++++++++++++-
|
||||
test/titerate.c | 16 +++++++++++++-
|
||||
test/trefer.c | 43 +++++++++++++++++++++++++++++------
|
||||
12 files changed, 265 insertions(+), 48 deletions(-)
|
||||
|
||||
diff --git a/src/H5A.c b/src/H5A.c
|
||||
index 0725489bc..9d4862d32 100644
|
||||
--- a/src/H5A.c
|
||||
+++ b/src/H5A.c
|
||||
@@ -1221,7 +1221,8 @@ done:
|
||||
Up to 'buf_size'-1 characters are stored in 'buf' followed by a '\0' string
|
||||
terminator. If the name of the attribute is longer than 'buf_size'-1,
|
||||
the string terminator is stored in the last position of the buffer to
|
||||
- properly terminate the string.
|
||||
+ properly terminate the string. If 'buf' is non-NULL but 'buf_size' is 0,
|
||||
+ treat the call as length being queried.
|
||||
--------------------------------------------------------------------------*/
|
||||
ssize_t
|
||||
H5Aget_name(hid_t attr_id, size_t buf_size, char *buf /*out*/)
|
||||
@@ -1233,6 +1234,10 @@ H5Aget_name(hid_t attr_id, size_t buf_size, char *buf /*out*/)
|
||||
|
||||
FUNC_ENTER_API((-1))
|
||||
|
||||
+ /* If buffer size is zero, treat as length query and do not write, even a '\0' */
|
||||
+ if (buf && buf_size == 0)
|
||||
+ buf = NULL;
|
||||
+
|
||||
/* check arguments */
|
||||
if (NULL == (vol_obj = H5VL_vol_object_verify(attr_id, H5I_ATTR)))
|
||||
HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, (-1), "not an attribute");
|
||||
@@ -1295,6 +1300,10 @@ H5Aget_name_by_idx(hid_t loc_id, const char *obj_name, H5_index_t idx_type, H5_i
|
||||
|
||||
FUNC_ENTER_API(FAIL)
|
||||
|
||||
+ /* If buffer size is zero, treat as length query and do not write, even a '\0' */
|
||||
+ if (name && size == 0)
|
||||
+ name = NULL;
|
||||
+
|
||||
/* Check args */
|
||||
if (H5I_ATTR == H5I_get_type(loc_id))
|
||||
HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "location is not valid for an attribute");
|
||||
diff --git a/src/H5F.c b/src/H5F.c
|
||||
index a0a57d294..2450098b7 100644
|
||||
--- a/src/H5F.c
|
||||
+++ b/src/H5F.c
|
||||
@@ -1972,19 +1972,27 @@ done:
|
||||
* Function: H5Fget_name
|
||||
*
|
||||
* Purpose: Gets the name of the file to which object OBJ_ID belongs.
|
||||
- * If 'name' is non-NULL then write up to 'size' bytes into that
|
||||
- * buffer and always return the length of the entry name.
|
||||
- * Otherwise `size' is ignored and the function does not store
|
||||
- * the name, just returning the number of characters required to
|
||||
- * store the name. If an error occurs then the buffer pointed to
|
||||
- * by 'name' (NULL or non-NULL) is unchanged and the function
|
||||
- * returns a negative value.
|
||||
+ *
|
||||
+ * Description:
|
||||
+ * When 'name' is non-NULL:
|
||||
+ * - if 'size' > 0: writes up to 'size' bytes into the buffer
|
||||
+ * (including null terminator) and returns the actual length
|
||||
+ * of the name (excluding null terminator).
|
||||
+ * - if 'size' == 0: treats the call as length query, does not
|
||||
+ * write anything to the buffer (not even a null terminator), and
|
||||
+ * returns the actual length of the name (excluding null terminator).
|
||||
+ *
|
||||
+ * When 'name' is NULL: does not write anything regardless of 'size'
|
||||
+ * and returns the actual length of the name (excluding null terminator).
|
||||
+ *
|
||||
+ * On error, the buffer is unchanged and the function returns
|
||||
+ * a negative value.
|
||||
+ *
|
||||
+ * Return: Success: Length of the name (excluding null terminator)
|
||||
+ * Failure: Negative
|
||||
*
|
||||
* Note: This routine returns the name that was used to open the file,
|
||||
* not the actual name after resolving symlinks, etc.
|
||||
- *
|
||||
- * Return: Success: The length of the file name
|
||||
- * Failure: -1
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
ssize_t
|
||||
@@ -1998,6 +2006,10 @@ H5Fget_name(hid_t obj_id, char *name /*out*/, size_t size)
|
||||
|
||||
FUNC_ENTER_API((-1))
|
||||
|
||||
+ /* If name size is zero, treat as length query and do not write, even a '\0' */
|
||||
+ if (name && size == 0)
|
||||
+ name = NULL;
|
||||
+
|
||||
/* Check the type */
|
||||
type = H5I_get_type(obj_id);
|
||||
if (H5I_FILE != type && H5I_GROUP != type && H5I_DATATYPE != type && H5I_DATASET != type &&
|
||||
diff --git a/src/H5Gdeprec.c b/src/H5Gdeprec.c
|
||||
index b6364db46..b610ad473 100644
|
||||
--- a/src/H5Gdeprec.c
|
||||
+++ b/src/H5Gdeprec.c
|
||||
@@ -1145,20 +1145,26 @@ done:
|
||||
* Function: H5Gget_objname_by_idx
|
||||
*
|
||||
* Purpose: Returns the name of objects in the group by giving index.
|
||||
- * If `name' is non-NULL then write up to `size' bytes into that
|
||||
- * buffer and always return the length of the entry name.
|
||||
- * Otherwise `size' is ignored and the function does not store the name,
|
||||
- * just returning the number of characters required to store the name.
|
||||
- * If an error occurs then the buffer pointed to by `name' (NULL or non-NULL)
|
||||
- * is unchanged and the function returns a negative value.
|
||||
- * If a zero is returned for the name's length, then there is no name
|
||||
- * associated with the ID.
|
||||
*
|
||||
- * Note: Deprecated in favor of H5Lget_name_by_idx
|
||||
+ * Description:
|
||||
+ * When 'name' is non-NULL:
|
||||
+ * - if 'size' > 0: writes up to 'size' bytes into the buffer
|
||||
+ * (including null terminator) and returns the actual length
|
||||
+ * of the name (excluding null terminator).
|
||||
+ * - if 'size' == 0: treats the call as length query, does not
|
||||
+ * write anything to the buffer (not even a null terminator), and
|
||||
+ * returns the actual length of the name (excluding null terminator).
|
||||
*
|
||||
- * Return: Success: Non-negative
|
||||
- * Failure: Negative
|
||||
+ * When 'name' is NULL: does not write anything regardless of 'size'
|
||||
+ * and returns the actual length of the name (excluding null terminator).
|
||||
+ *
|
||||
+ * On error, the buffer is unchanged and the function returns
|
||||
+ * a negative value.
|
||||
*
|
||||
+ * Return: Success: Length of the name (excluding null terminator)
|
||||
+ * Failure: Negative
|
||||
+ *
|
||||
+ * Note: Deprecated in favor of H5Lget_name_by_idx
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
ssize_t
|
||||
@@ -1172,6 +1178,10 @@ H5Gget_objname_by_idx(hid_t loc_id, hsize_t idx, char *name /*out*/, size_t size
|
||||
|
||||
FUNC_ENTER_API(-1)
|
||||
|
||||
+ /* If name size is zero, treat as length query and do not write, even a '\0' */
|
||||
+ if (name && size == 0)
|
||||
+ name = NULL;
|
||||
+
|
||||
/* Set up collective metadata if appropriate */
|
||||
if (H5CX_set_loc(loc_id) < 0)
|
||||
HGOTO_ERROR(H5E_SYM, H5E_CANTSET, (-1), "can't set collective metadata read info");
|
||||
diff --git a/src/H5I.c b/src/H5I.c
|
||||
index b71a9772b..4b8fc4f02 100644
|
||||
--- a/src/H5I.c
|
||||
+++ b/src/H5I.c
|
||||
@@ -824,19 +824,27 @@ done:
|
||||
*
|
||||
* Purpose: Gets a name of an object from its ID.
|
||||
*
|
||||
- * Return: Success: The length of the name
|
||||
+ * Description:
|
||||
+ * When 'name' is non-NULL:
|
||||
+ * - if 'size' > 0: writes up to 'size' bytes into the buffer
|
||||
+ * (including null terminator) and returns the actual length
|
||||
+ * of the name (excluding null terminator).
|
||||
+ * - if 'size' == 0: treats the call as length query, does not
|
||||
+ * write anything to the buffer (not even a null terminator), and
|
||||
+ * returns the actual length of the name (excluding null terminator).
|
||||
*
|
||||
- * Failure: -1
|
||||
+ * When 'name' is NULL: does not write anything regardless of 'size'
|
||||
+ * and returns the actual length of the name (excluding null terminator).
|
||||
+ *
|
||||
+ * On error, the buffer is unchanged and the function returns
|
||||
+ * a negative value.
|
||||
+ *
|
||||
+ * Return: Success: The length of the name (excluding null terminator)
|
||||
+ * Failure: Negative
|
||||
*
|
||||
* Notes:
|
||||
- * If 'name' is non-NULL then write up to 'size' bytes into that
|
||||
- * buffer and always return the length of the entry name.
|
||||
- * Otherwise 'size' is ignored and the function does not store the name,
|
||||
- * just returning the number of characters required to store the name.
|
||||
- * If an error occurs then the buffer pointed to by 'name' (NULL or non-NULL)
|
||||
- * is unchanged and the function returns a negative value.
|
||||
- * If a zero is returned for the name's length, then there is no name
|
||||
- * associated with the ID.
|
||||
+ * If a zero is returned for the name's length, then there is no name
|
||||
+ * associated with the ID.
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -851,6 +859,10 @@ H5Iget_name(hid_t id, char *name /*out*/, size_t size)
|
||||
|
||||
FUNC_ENTER_API((-1))
|
||||
|
||||
+ /* If name size is zero, treat as length query and do not write, even a '\0' */
|
||||
+ if (name && size == 0)
|
||||
+ name = NULL;
|
||||
+
|
||||
/* Get the object pointer */
|
||||
if (NULL == (vol_obj = H5VL_vol_object(id)))
|
||||
HGOTO_ERROR(H5E_ID, H5E_BADTYPE, (-1), "invalid identifier");
|
||||
diff --git a/src/H5L.c b/src/H5L.c
|
||||
index a818445c5..ee603bfa8 100644
|
||||
--- a/src/H5L.c
|
||||
+++ b/src/H5L.c
|
||||
@@ -1478,6 +1478,10 @@ H5Lget_name_by_idx(hid_t loc_id, const char *group_name, H5_index_t idx_type, H5
|
||||
|
||||
FUNC_ENTER_API((-1))
|
||||
|
||||
+ /* If name size is zero, treat as length query and do not write, even a '\0' */
|
||||
+ if (name && size == 0)
|
||||
+ name = NULL;
|
||||
+
|
||||
/* Check arguments */
|
||||
if (!group_name || !*group_name)
|
||||
HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, (-1), "no name specified");
|
||||
diff --git a/src/H5R.c b/src/H5R.c
|
||||
index 2b8dcdbf2..8851cb33f 100644
|
||||
--- a/src/H5R.c
|
||||
+++ b/src/H5R.c
|
||||
@@ -1013,8 +1013,23 @@ done:
|
||||
* Purpose: Given a reference to some object, determine a file name of the
|
||||
* object located into.
|
||||
*
|
||||
- * Return: Non-negative length of the path on success / -1 on failure
|
||||
+ * Description:
|
||||
+ * When 'buf' is non-NULL:
|
||||
+ * - if 'size' > 0: writes up to 'size' bytes into the buffer
|
||||
+ * (including null terminator) and returns the actual length
|
||||
+ * of the name (excluding null terminator).
|
||||
+ * - if 'size' == 0: treats the call as length query, does not
|
||||
+ * write anything to the buffer (not even a null terminator), and
|
||||
+ * returns the actual length of the name (excluding null terminator).
|
||||
+ *
|
||||
+ * When 'buf' is NULL: does not write anything regardless of 'size'
|
||||
+ * and returns the actual length of the name (excluding null terminator).
|
||||
+ *
|
||||
+ * On error, the buffer is unchanged and the function returns
|
||||
+ * a negative value.
|
||||
*
|
||||
+ * Return: Success: The length of the name (excluding null terminator)
|
||||
+ * Failure: Negative
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
ssize_t
|
||||
@@ -1032,6 +1047,10 @@ H5Rget_file_name(const H5R_ref_t *ref_ptr, char *buf /*out*/, size_t size)
|
||||
H5R__get_type((const H5R_ref_priv_t *)ref_ptr) >= H5R_MAXTYPE)
|
||||
HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, (-1), "invalid reference type");
|
||||
|
||||
+ /* If buffer size is zero, treat as length query and do not write, even a '\0' */
|
||||
+ if (buf && size == 0)
|
||||
+ buf = NULL;
|
||||
+
|
||||
/* Get name */
|
||||
if (H5I_INVALID_HID == (loc_id = H5R__get_loc_id((const H5R_ref_priv_t *)ref_ptr))) {
|
||||
/* Un-opened external references do not have loc_id set but hold a
|
||||
@@ -1073,6 +1092,21 @@ done:
|
||||
* Purpose: Given a reference to some object, determine a path to the
|
||||
* object referenced in the file.
|
||||
*
|
||||
+ * Description:
|
||||
+ * When 'buf' is non-NULL:
|
||||
+ * - if 'size' > 0: writes up to 'size' bytes into the buffer
|
||||
+ * (including null terminator) and returns the actual length
|
||||
+ * of the name (excluding null terminator).
|
||||
+ * - if 'size' == 0: treats the call as length query, does not
|
||||
+ * write anything to the buffer (not even a null terminator), and
|
||||
+ * returns the actual length of the name (excluding null terminator).
|
||||
+ *
|
||||
+ * When 'buf' is NULL: does not write anything regardless of 'size'
|
||||
+ * and returns the actual length of the name (excluding null terminator).
|
||||
+ *
|
||||
+ * On error, the buffer is unchanged and the function returns
|
||||
+ * a negative value.
|
||||
+ *
|
||||
* Return: Non-negative length of the path on success / -1 on failure
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
@@ -1099,6 +1133,10 @@ H5Rget_obj_name(H5R_ref_t *ref_ptr, hid_t rapl_id, char *buf /*out*/, size_t siz
|
||||
if (rapl_id < 0)
|
||||
HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, (-1), "not a property list");
|
||||
|
||||
+ /* If buffer size is zero, treat as length query and do not write, even a '\0' */
|
||||
+ if (buf && size == 0)
|
||||
+ buf = NULL;
|
||||
+
|
||||
/* Retrieve loc_id from reference */
|
||||
if (H5I_INVALID_HID == (loc_id = H5R__get_loc_id((const H5R_ref_priv_t *)ref_ptr)))
|
||||
/* Attempt to re-open file and pass rapl_id as a fapl_id */
|
||||
@@ -1140,6 +1178,21 @@ done:
|
||||
*
|
||||
* Purpose: Given a reference to some attribute, determine its name.
|
||||
*
|
||||
+ * Description:
|
||||
+ * When 'buf' is non-NULL:
|
||||
+ * - if 'size' > 0: writes up to 'size' bytes into the buffer
|
||||
+ * (including null terminator) and returns the actual length
|
||||
+ * of the name (excluding null terminator).
|
||||
+ * - if 'size' == 0: treats the call as length query, does not
|
||||
+ * write anything to the buffer (not even a null terminator), and
|
||||
+ * returns the actual length of the name (excluding null terminator).
|
||||
+ *
|
||||
+ * When 'buf' is NULL: does not write anything regardless of 'size'
|
||||
+ * and returns the actual length of the name (excluding null terminator).
|
||||
+ *
|
||||
+ * On error, the buffer is unchanged and the function returns
|
||||
+ * a negative value.
|
||||
+ *
|
||||
* Return: Non-negative length of the path on success / -1 on failure
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
@@ -1157,6 +1210,10 @@ H5Rget_attr_name(const H5R_ref_t *ref_ptr, char *buf /*out*/, size_t size)
|
||||
if (H5R__get_type((const H5R_ref_priv_t *)ref_ptr) != H5R_ATTR)
|
||||
HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, (-1), "invalid reference type");
|
||||
|
||||
+ /* If buffer size is zero, treat as length query and do not write, even a '\0' */
|
||||
+ if (buf && size == 0)
|
||||
+ buf = NULL;
|
||||
+
|
||||
/* Get attribute name */
|
||||
if ((ret_value = H5R__get_attr_name((const H5R_ref_priv_t *)ref_ptr, buf, size)) < 0)
|
||||
HGOTO_ERROR(H5E_REFERENCE, H5E_CANTGET, (-1), "unable to determine attribute name");
|
||||
diff --git a/src/H5Rdeprec.c b/src/H5Rdeprec.c
|
||||
index 6ca014e16..4b5437d4f 100644
|
||||
--- a/src/H5Rdeprec.c
|
||||
+++ b/src/H5Rdeprec.c
|
||||
@@ -741,9 +741,23 @@ done:
|
||||
* Purpose: Given a reference to some object, determine a path to the
|
||||
* object referenced in the file.
|
||||
*
|
||||
- * Return: Success: Non-negative length of the path
|
||||
- * Failure: -1
|
||||
+ * Description:
|
||||
+ * When 'name' is non-NULL:
|
||||
+ * - if 'size' > 0: writes up to 'size' bytes into the buffer
|
||||
+ * (including null terminator) and returns the actual length
|
||||
+ * of the name (excluding null terminator).
|
||||
+ * - if 'size' == 0: treats the call as length query, does not
|
||||
+ * write anything to the buffer (not even a null terminator), and
|
||||
+ * returns the actual length of the name (excluding null terminator).
|
||||
*
|
||||
+ * When 'name' is NULL: does not write anything regardless of 'size'
|
||||
+ * and returns the actual length of the path (excluding null terminator).
|
||||
+ *
|
||||
+ * On error, the buffer is unchanged and the function returns
|
||||
+ * a negative value.
|
||||
+ *
|
||||
+ * Return: Success: The length of the path (excluding null terminator)
|
||||
+ * Failure: Negative
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
ssize_t
|
||||
@@ -766,6 +780,10 @@ H5Rget_name(hid_t id, H5R_type_t ref_type, const void *ref, char *name /*out*/,
|
||||
if (ref_type != H5R_OBJECT1 && ref_type != H5R_DATASET_REGION1)
|
||||
HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, (-1), "invalid reference type");
|
||||
|
||||
+ /* If buffer size is zero, treat as length query and do not write, even a '\0' */
|
||||
+ if (name && size == 0)
|
||||
+ name = NULL;
|
||||
+
|
||||
/* Get the VOL object */
|
||||
if (NULL == (vol_obj = H5VL_vol_object(id)))
|
||||
HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, (-1), "invalid file identifier");
|
||||
diff --git a/test/links.c b/test/links.c
|
||||
index 262cd0f2e..091cdaf84 100644
|
||||
--- a/test/links.c
|
||||
+++ b/test/links.c
|
||||
@@ -154,6 +154,9 @@ static const char *FILENAME[] = {"links0",
|
||||
#define TIMESTAMP_GROUP_1 "timestamp1"
|
||||
#define TIMESTAMP_GROUP_2 "timestamp2"
|
||||
|
||||
+/* Used by test_deprec() */
|
||||
+#define NON_NULL_BUF "NON_NULL_BUF"
|
||||
+
|
||||
/* Link iteration struct */
|
||||
typedef struct {
|
||||
H5_iter_order_t order; /* Direction of iteration */
|
||||
@@ -1990,8 +1993,11 @@ test_deprec(hid_t fapl, bool new_format)
|
||||
hsize_t num_objs; /* Number of objects in a group */
|
||||
char filename[1024];
|
||||
char tmpstr[1024];
|
||||
- int len = 0; /* Length of comment */
|
||||
- herr_t status; /* Generic return value */
|
||||
+ int len = 0; /* Length of comment */
|
||||
+ char non_null_buf[80]; /* Buffer to test non-null buffer calls */
|
||||
+ char *buf_ptr; /* To pass mid-string */
|
||||
+ ssize_t name_len; /* Length of name */
|
||||
+ herr_t status; /* Generic return value */
|
||||
|
||||
if (new_format)
|
||||
TESTING("backwards compatibility (w/new group format)");
|
||||
@@ -2052,6 +2058,17 @@ test_deprec(hid_t fapl, bool new_format)
|
||||
if (len >= 0)
|
||||
TEST_ERROR;
|
||||
|
||||
+ /* Verify that passing a non-null buffer with size 0 still returns the correct name
|
||||
+ size and the buffer is not modified */
|
||||
+ strcpy(non_null_buf, NON_NULL_BUF);
|
||||
+ buf_ptr = &non_null_buf[4];
|
||||
+ if ((name_len = H5Gget_objname_by_idx(group1_id, (hsize_t)0, buf_ptr, 0)) < 0)
|
||||
+ FAIL_STACK_ERROR;
|
||||
+ if ((size_t)name_len != strlen(tmpstr))
|
||||
+ TEST_ERROR;
|
||||
+ if ((strcmp(non_null_buf, NON_NULL_BUF) != 0))
|
||||
+ TEST_ERROR;
|
||||
+
|
||||
/* Test getting the type for objects */
|
||||
if ((obj_type = H5Gget_objtype_by_idx(group1_id, (hsize_t)0)) < 0)
|
||||
FAIL_STACK_ERROR;
|
||||
diff --git a/test/tattr.c b/test/tattr.c
|
||||
index 780f11591..af08d2db0 100644
|
||||
--- a/test/tattr.c
|
||||
+++ b/test/tattr.c
|
||||
@@ -148,6 +148,7 @@ static float attr_data5 = -5.123F; /* Test data for 5th attribute */
|
||||
|
||||
/* Used by test_attr_info_null_info_pointer() */
|
||||
#define GET_INFO_NULL_POINTER_ATTR_NAME "NullInfoPointerAttr"
|
||||
+#define NON_NULL_BUF "NON_NULL_BUF"
|
||||
|
||||
/* Used by test_attr_rename_invalid_name() */
|
||||
#define INVALID_RENAME_TEST_ATTR_NAME "InvalidRenameTestAttr"
|
||||
@@ -6526,10 +6527,13 @@ test_attr_rename_invalid_name(hid_t fcpl, hid_t fapl)
|
||||
|
||||
/***************************************************************
|
||||
**
|
||||
-** test_attr_get_name_invalid_buf(): A test to ensure that
|
||||
-** passing a NULL buffer to H5Aget_name(_by_idx) when
|
||||
+** test_attr_get_name_invalid_buf(): A test to ensure that:
|
||||
+** - passing a NULL buffer to H5Aget_name(_by_idx) when
|
||||
** the 'size' parameter is non-zero doesn't cause bad
|
||||
** behavior.
|
||||
+** - passing a non-NULL buffer to H5Aget_name(_by_idx)
|
||||
+** when the 'size' parameter is zero treats as a length
|
||||
+** query call.
|
||||
**
|
||||
****************************************************************/
|
||||
static void
|
||||
@@ -6539,6 +6543,9 @@ test_attr_get_name_invalid_buf(hid_t fcpl, hid_t fapl)
|
||||
hid_t fid;
|
||||
hid_t attr;
|
||||
hid_t sid;
|
||||
+ char non_null_buf[80]; /* Buffer to test non-null buffer calls */
|
||||
+ char *buf_ptr; /* To pass mid-string */
|
||||
+ ssize_t namelen; /* Length of attribute name */
|
||||
|
||||
/* Create dataspace for attribute */
|
||||
sid = H5Screate(H5S_SCALAR);
|
||||
@@ -6569,6 +6576,20 @@ test_attr_get_name_invalid_buf(hid_t fcpl, hid_t fapl)
|
||||
|
||||
VERIFY(err_ret, FAIL, "H5Aget_name_by_idx");
|
||||
|
||||
+ /* Verify that passing a non-null buffer with size 0 still returns the correct name
|
||||
+ size and the buffer is not modified */
|
||||
+ strcpy(non_null_buf, NON_NULL_BUF);
|
||||
+ buf_ptr = &non_null_buf[4];
|
||||
+ namelen = H5Aget_name(attr, (size_t)0, buf_ptr);
|
||||
+ CHECK(namelen, FAIL, "H5Aget_name");
|
||||
+ VERIFY(namelen, (ssize_t)strlen(GET_NAME_INVALID_BUF_TEST_ATTR_NAME), "H5Aget_name");
|
||||
+ VERIFY(strcmp(non_null_buf, NON_NULL_BUF), 0, "H5Aget_name");
|
||||
+
|
||||
+ namelen = H5Aget_name_by_idx(fid, ".", H5_INDEX_CRT_ORDER, H5_ITER_INC, 0, buf_ptr, 0, H5P_DEFAULT);
|
||||
+ CHECK(namelen, FAIL, "H5Aget_name_by_idx");
|
||||
+ VERIFY(namelen, (ssize_t)strlen(GET_NAME_INVALID_BUF_TEST_ATTR_NAME), "H5Aget_name_by_idx");
|
||||
+ VERIFY(strcmp(non_null_buf, NON_NULL_BUF), 0, "H5Aget_name_by_idx");
|
||||
+
|
||||
/* Close dataspace */
|
||||
err_ret = H5Sclose(sid);
|
||||
CHECK(err_ret, FAIL, "H5Sclose");
|
||||
diff --git a/test/tfile.c b/test/tfile.c
|
||||
index 7f7e293b9..32ea586cd 100644
|
||||
--- a/test/tfile.c
|
||||
+++ b/test/tfile.c
|
||||
@@ -147,6 +147,9 @@
|
||||
/* Declaration for test_incr_filesize() */
|
||||
#define FILE_INCR_FILESIZE "tfile_incr_filesize"
|
||||
|
||||
+/* Used by test_file_getname() */
|
||||
+#define NON_NULL_BUF "NON_NULL_BUF"
|
||||
+
|
||||
/* Files created under 1.6 branch and 1.8 branch--used in test_filespace_compatible() */
|
||||
static const char *OLD_FILENAME[] = {
|
||||
"filespace_1_6.h5", /* 1.6 HDF5 file */
|
||||
@@ -2411,7 +2414,9 @@ test_file_getname(void)
|
||||
hsize_t dims[TESTA_RANK] = {TESTA_NX, TESTA_NY};
|
||||
char name[TESTA_NAME_BUF_SIZE];
|
||||
ssize_t name_len;
|
||||
- herr_t ret; /* Generic return value */
|
||||
+ char non_null_buf[80]; /* Buffer to test non-null buffer calls */
|
||||
+ char *buf_ptr; /* To pass mid-string */
|
||||
+ herr_t ret; /* Generic return value */
|
||||
|
||||
/* Output message about test being performed */
|
||||
MESSAGE(5, ("Testing H5Fget_name() functionality\n"));
|
||||
@@ -2426,6 +2431,15 @@ test_file_getname(void)
|
||||
VERIFY_STR(name, FILE1, "H5Fget_name");
|
||||
VERIFY(name_len, strlen(FILE1), "H5Fget_name");
|
||||
|
||||
+ /* Verify that passing a non-null buffer with size 0 still returns the correct name
|
||||
+ size and the buffer is not modified */
|
||||
+ strcpy(non_null_buf, NON_NULL_BUF);
|
||||
+ buf_ptr = &non_null_buf[4];
|
||||
+ name_len = H5Fget_name(file_id, buf_ptr, 0);
|
||||
+ CHECK(name_len, FAIL, "H5Fget_name");
|
||||
+ VERIFY(name_len, strlen(FILE1), "H5Fget_name");
|
||||
+ VERIFY(strcmp(non_null_buf, NON_NULL_BUF), 0, "H5Fget_name");
|
||||
+
|
||||
/* Create a group in the root group */
|
||||
group_id = H5Gcreate2(file_id, TESTA_GROUPNAME, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
|
||||
CHECK(group_id, FAIL, "H5Gcreate2");
|
||||
diff --git a/test/titerate.c b/test/titerate.c
|
||||
index 7efae3472..595a577d8 100644
|
||||
--- a/test/titerate.c
|
||||
+++ b/test/titerate.c
|
||||
@@ -39,6 +39,9 @@
|
||||
#define SPACE1_RANK 1
|
||||
#define SPACE1_DIM1 4
|
||||
|
||||
+/* Used by test_reference_obj() and test_reference_attr() */
|
||||
+#define NON_NULL_BUF "NON_NULL_BUF"
|
||||
+
|
||||
typedef enum { RET_ZERO, RET_TWO, RET_CHANGE, RET_CHANGE2 } iter_enum;
|
||||
|
||||
/* Custom group iteration callback data */
|
||||
@@ -894,7 +897,9 @@ test_grp_memb_funcs(hid_t fapl)
|
||||
VERIFY(ginfo.nlinks, (NDATASETS + 2), "H5Gget_info");
|
||||
|
||||
for (i = 0; i < (int)ginfo.nlinks; i++) {
|
||||
- H5O_info2_t oinfo; /* Object info */
|
||||
+ H5O_info2_t oinfo; /* Object info */
|
||||
+ char non_null_buf[80]; /* Buffer to test non-null buffer calls */
|
||||
+ char *buf_ptr; /* To pass mid-string */
|
||||
|
||||
/* Test with NULL for name, to query length */
|
||||
name_len = H5Lget_name_by_idx(root_group, ".", H5_INDEX_NAME, H5_ITER_INC, (hsize_t)i, NULL,
|
||||
@@ -908,6 +913,15 @@ test_grp_memb_funcs(hid_t fapl)
|
||||
/* Double-check that the length is the same */
|
||||
VERIFY(ret, name_len, "H5Lget_name_by_idx");
|
||||
|
||||
+ /* Test with non-null buffer for name and 0 for size */
|
||||
+ strcpy(non_null_buf, NON_NULL_BUF);
|
||||
+ buf_ptr = &non_null_buf[4];
|
||||
+ ret = (herr_t)H5Lget_name_by_idx(root_group, ".", H5_INDEX_NAME, H5_ITER_INC, (hsize_t)i, buf_ptr, 0,
|
||||
+ H5P_DEFAULT);
|
||||
+ CHECK(ret, FAIL, "H5Lget_name_by_idx");
|
||||
+ VERIFY(ret, name_len, "H5Lget_name_by_idx");
|
||||
+ VERIFY(strcmp(non_null_buf, NON_NULL_BUF), 0, "H5Lget_name_by_idx");
|
||||
+
|
||||
/* Keep a copy of the dataset names around for later */
|
||||
obj_names[i] = strdup(dataset_name);
|
||||
CHECK_PTR(obj_names[i], "strdup");
|
||||
diff --git a/test/trefer.c b/test/trefer.c
|
||||
index cd6bf2ca1..4df923fd8 100644
|
||||
--- a/test/trefer.c
|
||||
+++ b/test/trefer.c
|
||||
@@ -88,6 +88,9 @@ typedef struct s2_t {
|
||||
#define MAX_ITER_WRITE MAX_ITER_CREATE
|
||||
#define MAX_ITER_READ MAX_ITER_CREATE
|
||||
|
||||
+/* Used by test_reference_obj() and test_reference_attr() */
|
||||
+#define NON_NULL_BUF "NON_NULL_BUF"
|
||||
+
|
||||
/****************************************************************
|
||||
**
|
||||
** test_reference_params(): Test basic H5R (reference) parameters
|
||||
@@ -458,11 +461,13 @@ test_reference_obj(void)
|
||||
*rbuf; /* buffer read from disk */
|
||||
H5R_ref_t *wbuf_cp; /* copy buffer */
|
||||
unsigned *ibuf, *obuf;
|
||||
- unsigned i, j; /* Counters */
|
||||
- ssize_t namelen; /* String buffer size return value */
|
||||
- char *namebuf; /* Buffer for attribute's or dataset's name */
|
||||
- H5O_type_t obj_type; /* Object type */
|
||||
- herr_t ret; /* Generic return value */
|
||||
+ unsigned i, j; /* Counters */
|
||||
+ ssize_t namelen; /* String buffer size return value */
|
||||
+ char *namebuf; /* Buffer for attribute's or dataset's name */
|
||||
+ H5O_type_t obj_type; /* Object type */
|
||||
+ char non_null_buf[80]; /* Buffer to test non-null buffer calls */
|
||||
+ char *buf_ptr; /* To pass mid-string */
|
||||
+ herr_t ret; /* Generic return value */
|
||||
|
||||
/* Output message about test being performed */
|
||||
MESSAGE(5, ("Testing Object Reference Functions\n"));
|
||||
@@ -626,17 +631,31 @@ test_reference_obj(void)
|
||||
CHECK(namelen, FAIL, "H5Rget_file_name");
|
||||
VERIFY(namelen, strlen(FILE_REF_OBJ), "H5Rget_file_name");
|
||||
|
||||
+ /* Test passing in non-null buffer with buffer size is zero */
|
||||
+ strcpy(non_null_buf, NON_NULL_BUF);
|
||||
+ buf_ptr = &non_null_buf[4];
|
||||
+ namelen = H5Rget_file_name(&rbuf[0], buf_ptr, 0);
|
||||
+ CHECK(namelen, FAIL, "H5Rget_file_name");
|
||||
+ VERIFY(namelen, strlen(FILE_REF_OBJ), "H5Rget_file_name");
|
||||
+ VERIFY(strcmp(non_null_buf, NON_NULL_BUF), 0, "H5Rget_file_name");
|
||||
+
|
||||
/* Get the file name for the reference */
|
||||
namebuf = (char *)malloc((size_t)namelen + 1);
|
||||
namelen = H5Rget_file_name(&rbuf[0], namebuf, (size_t)namelen + 1);
|
||||
CHECK(namelen, FAIL, "H5Rget_file_name");
|
||||
VERIFY(strcmp(namebuf, FILE_REF_OBJ), 0, "namebuf vs FILE_REF_OBJ");
|
||||
VERIFY(namelen, strlen(FILE_REF_OBJ), "H5Rget_file_name");
|
||||
-
|
||||
free(namebuf);
|
||||
|
||||
/* Testing Dataset1 */
|
||||
|
||||
+ /* Test passing in non-null buffer with buffer size is zero */
|
||||
+ buf_ptr = &non_null_buf[8];
|
||||
+ namelen = H5Rget_obj_name(&rbuf[0], H5P_DEFAULT, buf_ptr, 0);
|
||||
+ CHECK(namelen, FAIL, "H5Rget_obj_name");
|
||||
+ VERIFY(namelen, strlen(DS1_REF_OBJ), "H5Rget_obj_name");
|
||||
+ VERIFY(strcmp(non_null_buf, NON_NULL_BUF), 0, "H5Rget_obj_name");
|
||||
+
|
||||
/* Getting the name of the referenced object and verify it */
|
||||
namelen = H5Rget_obj_name(&rbuf[0], H5P_DEFAULT, NULL, 0);
|
||||
CHECK(namelen, FAIL, "H5Rget_obj_name");
|
||||
@@ -2479,6 +2498,8 @@ test_reference_attr(void)
|
||||
char *attr_name = NULL; /* name of attribute, from H5A */
|
||||
ssize_t attr_name_size; /* size of attribute name */
|
||||
H5O_type_t obj_type; /* Object type */
|
||||
+ char non_null_buf[80]; /* Buffer to test non-null buffer calls */
|
||||
+ char *buf_ptr; /* To pass mid-string */
|
||||
herr_t ret; /* Generic return value */
|
||||
|
||||
/* Output message about test being performed */
|
||||
@@ -2649,10 +2670,18 @@ test_reference_attr(void)
|
||||
|
||||
/* Testing "Attr1" */
|
||||
|
||||
+ /* Test passing in non-null buffer with buffer size is zero */
|
||||
+ strcpy(non_null_buf, NON_NULL_BUF);
|
||||
+ buf_ptr = &non_null_buf[4];
|
||||
+ namelen = H5Rget_attr_name(&ref_rbuf[0], buf_ptr, 0);
|
||||
+ CHECK(namelen, FAIL, "H5Rget_attr_name");
|
||||
+ VERIFY(namelen, strlen(ATTR1_REF_OBJ), "H5Rget_attr_name");
|
||||
+ VERIFY(strcmp(non_null_buf, NON_NULL_BUF), 0, "H5Rget_attr_name");
|
||||
+
|
||||
/* Getting the name of the referenced attribute and verify it */
|
||||
namelen = H5Rget_attr_name(&ref_rbuf[0], NULL, 0);
|
||||
CHECK(namelen, FAIL, "H5Rget_attr_name");
|
||||
- VERIFY(namelen, strlen(ATTR1_REF_OBJ), "H5Rget_obj_name");
|
||||
+ VERIFY(namelen, strlen(ATTR1_REF_OBJ), "H5Rget_attr_name");
|
||||
|
||||
namebuf = (char *)malloc((size_t)namelen + 1);
|
||||
namelen = H5Rget_attr_name(&ref_rbuf[0], namebuf, (size_t)namelen + 1);
|
||||
+2
-9
@@ -11,16 +11,9 @@ inherit cmake pkgconfig siteinfo qemu multilib_header multilib_script
|
||||
|
||||
DEPENDS += "qemu-native zlib"
|
||||
|
||||
# set downloadfilename to workaround mirroring test issues. When hdf5 is
|
||||
# upgraded beyond 2.0.0 this can likely be removed
|
||||
SRC_URI = "https://support.hdfgroup.org/releases/hdf5/v2_0/v2_0_0/downloads/${BPN}-${PV}.tar.gz;downloadfilename=${BPN}-${PV}-1.tar.gz \
|
||||
SRC_URI = "https://github.com/HDFGroup/hdf5/releases/download/${PV}/${BPN}-${PV}.tar.gz \
|
||||
file://0002-Remove-suffix-shared-from-shared-library-name.patch \
|
||||
file://0001-cmake-remove-build-flags.patch \
|
||||
file://CVE-2026-26199.patch \
|
||||
file://CVE-2026-26197.patch \
|
||||
file://CVE-2026-17572.patch \
|
||||
file://CVE-2026-17573.patch \
|
||||
file://CVE-2026-17574.patch \
|
||||
file://CVE-2026-19025.patch \
|
||||
file://CVE-2026-19026-CVE-2026-19027-CVE-2026-19028.patch \
|
||||
file://CVE-2026-19023-CVE-2026-19024.patch \
|
||||
@@ -30,7 +23,7 @@ SRC_URI = "https://support.hdfgroup.org/releases/hdf5/v2_0/v2_0_0/downloads/${BP
|
||||
file://CVE-2026-120757.patch \
|
||||
file://CVE-2026-120758.patch \
|
||||
"
|
||||
SRC_URI[sha256sum] = "f4c2edc5668fb846627182708dbe1e16c60c467e63177a75b0b9f12c19d7efed"
|
||||
SRC_URI[sha256sum] = "1a1ab8209b35586fbc1aa279ba76d102130b95badcb20ca329587219112d8c16"
|
||||
|
||||
UPSTREAM_CHECK_URI = "https://support.hdfgroup.org/releases/hdf5/"
|
||||
UPSTREAM_CHECK_REGEX = "\./(?P<pver>\d+(\.\d+)+)/index\.html"
|
||||
Reference in new issue
Block a user