* [meta-oe][scarthgap][PATCH 1/2] hdf5: Fix CVE-2026-26199
@ 2026-08-14 15:21 Devansh Patel -X (devanshp - E INFOCHIPS PRIVATE LIMITED at Cisco)
2026-08-14 15:21 ` [meta-oe][scarthgap][PATCH 2/2] hdf5: Fix CVE-2026-26197 Devansh Patel -X (devanshp - E INFOCHIPS PRIVATE LIMITED at Cisco)
0 siblings, 1 reply; 2+ messages in thread
From: Devansh Patel -X (devanshp - E INFOCHIPS PRIVATE LIMITED at Cisco) @ 2026-08-14 15:21 UTC (permalink / raw)
To: openembedded-devel; +Cc: xe-linux-external
From: Devansh Patel <devanshp@cisco.com>
This patch backports the upstream fix first released in HDF5 2.1.0.
The upstream fix commit is referenced in [1], and the public advisory
is referenced in [2].
[1] https://github.com/HDFGroup/hdf5/commit/9268b803b742f99c1f8793cae74f19e74976b065
[2] https://github.com/HDFGroup/hdf5/security/advisories/GHSA-5c6x-jmgf-f5vc
Signed-off-by: Devansh Patel <devanshp@cisco.com>
---
.../hdf5/files/CVE-2026-26199.patch | 675 ++++++++++++++++++
meta-oe/recipes-support/hdf5/hdf5_1.14.4-3.bb | 1 +
2 files changed, 676 insertions(+)
create mode 100644 meta-oe/recipes-support/hdf5/files/CVE-2026-26199.patch
diff --git a/meta-oe/recipes-support/hdf5/files/CVE-2026-26199.patch b/meta-oe/recipes-support/hdf5/files/CVE-2026-26199.patch
new file mode 100644
index 000000000..dea76a4de
--- /dev/null
+++ b/meta-oe/recipes-support/hdf5/files/CVE-2026-26199.patch
@@ -0,0 +1,675 @@
+From e501750498ab0d5d119f63f34b28e396c70ea1c1 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 the file does not exist in
+ HDF5 1.14.4-3 and its HDF5 2.1.0 release context is not applicable.
+- Adapted test/links.c to the HDF5 1.14.4-3 test_deprec() layout,
+ where the later len and status declarations reformatted upstream are
+ absent; the zero-size regression case is retained.
+- Adapted test/trefer.c to the HDF5 1.14.4-3 test layout. The zero-size
+ regression cases are retained with the existing literal object and
+ attribute names because the later DS1_REF_OBJ and ATTR1_REF_OBJ test
+ constants are absent.
+- Preserved the HDF5 1.14.4-3 H5Rget_attr_name convention of returning
+ the required buffer size, including the null terminator. The upstream
+ base includes a separate, later API behavior change that is not needed
+ to prevent this underflow.
+
+(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 | 61 +++++++++++++++++++++++++++++++++++++++++++++++--
+ src/H5Rdeprec.c | 22 ++++++++++++++++--
+ test/links.c | 17 ++++++++++++++
+ test/tattr.c | 25 ++++++++++++++++++--
+ test/tfile.c | 16 ++++++++++++-
+ test/titerate.c | 16 ++++++++++++-
+ test/trefer.c | 44 ++++++++++++++++++++++++++++++-----
+ 12 files changed, 266 insertions(+), 46 deletions(-)
+
+diff --git a/src/H5A.c b/src/H5A.c
+index 6728596ab..7e2ee2b6e 100644
+--- a/src/H5A.c
++++ b/src/H5A.c
+@@ -1242,7 +1242,8 @@ done:
+ Up to 'buf_size' 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*/)
+@@ -1255,6 +1256,10 @@ H5Aget_name(hid_t attr_id, size_t buf_size, char *buf /*out*/)
+ FUNC_ENTER_API((-1))
+ H5TRACE3("Zs", "iz*s", attr_id, buf_size, buf);
+
++ /* 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_object_t *)H5I_object_verify(attr_id, H5I_ATTR)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, (-1), "not an attribute");
+@@ -1306,6 +1311,10 @@ H5Aget_name_by_idx(hid_t loc_id, const char *obj_name, H5_index_t idx_type, H5_i
+ FUNC_ENTER_API(FAIL)
+ H5TRACE8("Zs", "i*sIiIoh*szi", loc_id, obj_name, idx_type, order, n, name, size, lapl_id);
+
++ /* 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 ee4fd71af..e58cc086c 100644
+--- a/src/H5F.c
++++ b/src/H5F.c
+@@ -2007,19 +2007,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
+@@ -2034,6 +2042,10 @@ H5Fget_name(hid_t obj_id, char *name /*out*/, size_t size)
+ FUNC_ENTER_API((-1))
+ H5TRACE3("Zs", "i*sz", obj_id, name, size);
+
++ /* 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 19493ace0..3d42a9508 100644
+--- a/src/H5Gdeprec.c
++++ b/src/H5Gdeprec.c
+@@ -1121,20 +1121,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
+@@ -1149,6 +1155,10 @@ H5Gget_objname_by_idx(hid_t loc_id, hsize_t idx, char *name /*out*/, size_t size
+ FUNC_ENTER_API(FAIL)
+ H5TRACE4("Zs", "ih*sz", loc_id, idx, name, size);
+
++ /* 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 a5d3b39f1..30bb9bb73 100644
+--- a/src/H5I.c
++++ b/src/H5I.c
+@@ -882,19 +882,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.
+ *
+ *-------------------------------------------------------------------------
+ */
+@@ -910,6 +918,10 @@ H5Iget_name(hid_t id, char *name /*out*/, size_t size)
+ FUNC_ENTER_API((-1))
+ H5TRACE3("Zs", "i*sz", id, name, size);
+
++ /* 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 49fe1ac4f..7371da213 100644
+--- a/src/H5L.c
++++ b/src/H5L.c
+@@ -1517,6 +1517,10 @@ H5Lget_name_by_idx(hid_t loc_id, const char *group_name, H5_index_t idx_type, H5
+ FUNC_ENTER_API((-1))
+ H5TRACE8("Zs", "i*sIiIoh*szi", loc_id, group_name, idx_type, order, n, name, size, lapl_id);
+
++ /* 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 3a91b926a..5d361e91f 100644
+--- a/src/H5R.c
++++ b/src/H5R.c
+@@ -1027,8 +1027,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
+@@ -1047,6 +1062,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
+@@ -1088,6 +1107,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
+ *
+ *-------------------------------------------------------------------------
+@@ -1115,6 +1149,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 */
+@@ -1156,7 +1194,22 @@ done:
+ *
+ * Purpose: Given a reference to some attribute, determine its name.
+ *
+- * 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 required buffer
++ * size (including 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 required buffer size (including null terminator).
++ *
++ * When 'buf' is NULL: does not write anything regardless of 'size'
++ * and returns the required buffer size (including null terminator).
++ *
++ * On error, the buffer is unchanged and the function returns
++ * a negative value.
++ *
++ * Return: Required buffer size on success / -1 on failure
+ *
+ *-------------------------------------------------------------------------
+ */
+@@ -1174,6 +1227,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 90869cf3a..41cecdcad 100644
+--- a/src/H5Rdeprec.c
++++ b/src/H5Rdeprec.c
+@@ -747,9 +747,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
+@@ -773,6 +787,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 4ea612ebd..85e9225ac 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 */
+@@ -1949,6 +1952,9 @@ test_deprec(hid_t fapl, bool new_format)
+ hsize_t num_objs; /* Number of objects in a group */
+ char filename[1024];
+ char tmpstr[1024];
++ 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 */
+
+ if (new_format)
+ TESTING("backwards compatibility (w/new group format)");
+@@ -1997,6 +2003,17 @@ test_deprec(hid_t fapl, bool new_format)
+ }
+ H5E_END_TRY
+
++ /* 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 d38fdaabc..30a436465 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"
+@@ -6512,10 +6513,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
+@@ -6525,6 +6529,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);
+@@ -6555,6 +6562,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 028de9a3e..f4abe35b8 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"));
+@@ -2425,6 +2430,15 @@ test_file_getname(void)
+ CHECK(name_len, FAIL, "H5Fget_name");
+ VERIFY_STR(name, 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 3c0b82e68..fd3b55783 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 */
+@@ -872,7 +875,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,
+@@ -886,6 +891,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 fc0d89420..f5503b9a1 100644
+--- a/test/trefer.c
++++ b/test/trefer.c
+@@ -76,6 +76,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
+@@ -441,9 +444,12 @@ test_reference_obj(void)
+ H5R_ref_t *wbuf, /* buffer to write to disk */
+ *rbuf; /* buffer read from disk */
+ unsigned *ibuf, *obuf;
+- unsigned i, j; /* Counters */
+- 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 */
++ 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"));
+@@ -579,6 +585,21 @@ test_reference_obj(void)
+ ret = H5Dread(dataset, H5T_STD_REF, H5S_ALL, H5S_ALL, H5P_DEFAULT, rbuf);
+ CHECK(ret, FAIL, "H5Dread");
+
++ /* 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");
++
++ /* 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("/Group1/Dataset1"), "H5Rget_obj_name");
++ VERIFY(strcmp(non_null_buf, NON_NULL_BUF), 0, "H5Rget_obj_name");
++
+ /* Open dataset object */
+ dset2 = H5Ropen_object(&rbuf[0], H5P_DEFAULT, dapl_id);
+ CHECK(dset2, H5I_INVALID_HID, "H5Ropen_object");
+@@ -2312,9 +2333,12 @@ test_reference_attr(void)
+ H5R_ref_t ref_wbuf[SPACE1_DIM1], /* Buffer to write to disk */
+ ref_rbuf[SPACE1_DIM1]; /* Buffer read from disk */
+ unsigned wbuf[SPACE1_DIM1], rbuf[SPACE1_DIM1];
+- unsigned i; /* Local index variables */
+- H5O_type_t obj_type; /* Object type */
+- herr_t ret; /* Generic return value */
++ unsigned i; /* Local index variables */
++ ssize_t namelen; /* String buffer size return value */
++ 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 Attribute Reference Functions\n"));
+@@ -2482,6 +2506,14 @@ test_reference_attr(void)
+ ret = H5Dread(dataset, H5T_STD_REF, H5S_ALL, H5S_ALL, H5P_DEFAULT, ref_rbuf);
+ CHECK(ret, FAIL, "H5Dread");
+
++ /* 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") + 1, "H5Rget_attr_name");
++ VERIFY(strcmp(non_null_buf, NON_NULL_BUF), 0, "H5Rget_attr_name");
++
+ /* Open attribute on dataset object */
+ attr = H5Ropen_attr(&ref_rbuf[0], H5P_DEFAULT, H5P_DEFAULT);
+ CHECK(attr, H5I_INVALID_HID, "H5Ropen_attr");
diff --git a/meta-oe/recipes-support/hdf5/hdf5_1.14.4-3.bb b/meta-oe/recipes-support/hdf5/hdf5_1.14.4-3.bb
index 816bd752a..80ab17dd2 100644
--- a/meta-oe/recipes-support/hdf5/hdf5_1.14.4-3.bb
+++ b/meta-oe/recipes-support/hdf5/hdf5_1.14.4-3.bb
@@ -30,6 +30,7 @@ SRC_URI = " \
file://CVE-2025-2309.patch \
file://CVE-2025-2308.patch \
file://CVE-2025-6857.patch \
+ file://CVE-2026-26199.patch \
"
SRC_URI[sha256sum] = "019ac451d9e1cf89c0482ba2a06f07a46166caf23f60fea5ef3c37724a318e03"
--
2.35.6
^ permalink raw reply related [flat|nested] 2+ messages in thread
* [meta-oe][scarthgap][PATCH 2/2] hdf5: Fix CVE-2026-26197
2026-08-14 15:21 [meta-oe][scarthgap][PATCH 1/2] hdf5: Fix CVE-2026-26199 Devansh Patel -X (devanshp - E INFOCHIPS PRIVATE LIMITED at Cisco)
@ 2026-08-14 15:21 ` Devansh Patel -X (devanshp - E INFOCHIPS PRIVATE LIMITED at Cisco)
0 siblings, 0 replies; 2+ messages in thread
From: Devansh Patel -X (devanshp - E INFOCHIPS PRIVATE LIMITED at Cisco) @ 2026-08-14 15:21 UTC (permalink / raw)
To: openembedded-devel; +Cc: xe-linux-external
From: Devansh Patel <devanshp@cisco.com>
This patch backports the upstream fix first released in HDF5 2.1.0.
The upstream fix commit is referenced in [1], and the public advisory
is referenced in [2].
Although the advisory [2] lists HDF5 2.0.0 as affected, NVD [3]
also marks versions before 2.0.0 as affected, and its CPE
configuration marks versions before 2.1.0 as vulnerable. Scarthgap's
HDF5 1.14.4-3 H5T_ARRAY decoder in src/H5Odtype.c computes the array
element count and decodes the parent datatype without checking for
multiplication overflow or verifying that the stored datatype size
matches the element size multiplied by the element count. The
vulnerable code path is therefore present in 1.14.4-3, so this
backport is applicable.
[1] https://github.com/HDFGroup/hdf5/commit/8cd9f7a7ba6757fbb72e36bbe23e127f8507c8a6
[2] https://github.com/HDFGroup/hdf5/security/advisories/GHSA-gh44-7wpq-622f
[3] https://nvd.nist.gov/vuln/detail/CVE-2026-26197
Signed-off-by: Devansh Patel <devanshp@cisco.com>
---
.../hdf5/files/CVE-2026-26197.patch | 69 +++++++++++++++++++
meta-oe/recipes-support/hdf5/hdf5_1.14.4-3.bb | 1 +
2 files changed, 70 insertions(+)
create mode 100644 meta-oe/recipes-support/hdf5/files/CVE-2026-26197.patch
diff --git a/meta-oe/recipes-support/hdf5/files/CVE-2026-26197.patch b/meta-oe/recipes-support/hdf5/files/CVE-2026-26197.patch
new file mode 100644
index 000000000..4df770e93
--- /dev/null
+++ b/meta-oe/recipes-support/hdf5/files/CVE-2026-26197.patch
@@ -0,0 +1,69 @@
+From 8a69764e016009a0ac949707d84161550dde8af4 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 the file does not exist in
+ HDF5 1.14.4-3 and its HDF5 2.1.0 release context is not applicable.
+
+(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 085ce24cd..2541b001f 100644
+--- a/src/H5Odtype.c
++++ b/src/H5Odtype.c
+@@ -783,7 +783,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...
+ */
+@@ -825,6 +826,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)
+@@ -838,6 +855,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_NO_CLASS:
+ case H5T_NCLASSES:
diff --git a/meta-oe/recipes-support/hdf5/hdf5_1.14.4-3.bb b/meta-oe/recipes-support/hdf5/hdf5_1.14.4-3.bb
index 80ab17dd2..7769a3034 100644
--- a/meta-oe/recipes-support/hdf5/hdf5_1.14.4-3.bb
+++ b/meta-oe/recipes-support/hdf5/hdf5_1.14.4-3.bb
@@ -31,6 +31,7 @@ SRC_URI = " \
file://CVE-2025-2308.patch \
file://CVE-2025-6857.patch \
file://CVE-2026-26199.patch \
+ file://CVE-2026-26197.patch \
"
SRC_URI[sha256sum] = "019ac451d9e1cf89c0482ba2a06f07a46166caf23f60fea5ef3c37724a318e03"
--
2.35.6
^ permalink raw reply related [flat|nested] 2+ messages in thread
end of thread, other threads:[~2026-08-14 15:21 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-14 15:21 [meta-oe][scarthgap][PATCH 1/2] hdf5: Fix CVE-2026-26199 Devansh Patel -X (devanshp - E INFOCHIPS PRIVATE LIMITED at Cisco)
2026-08-14 15:21 ` [meta-oe][scarthgap][PATCH 2/2] hdf5: Fix CVE-2026-26197 Devansh Patel -X (devanshp - E INFOCHIPS PRIVATE LIMITED at Cisco)
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.