diff --git a/java/jtest/TestH5Affm.java b/java/jtest/TestH5Affm.java index 96db05ec7e0..6afa6b33071 100644 --- a/java/jtest/TestH5Affm.java +++ b/java/jtest/TestH5Affm.java @@ -1027,7 +1027,7 @@ public class TestH5Affm { } @Test - public void testH5Aiterate() + public void testH5Aiterate_nullCallback() { System.out.print(testname.getMethodName()); @@ -1035,10 +1035,10 @@ public class TestH5Affm { MemorySegment idx = allocateLongArray(arena, 1); copyToSegment(idx, new long[] {0}); - // Just verify the API works, iteration callback complex for FFM + // NULL callback must be rejected gracefully (H5E_BADVALUE), not crash long result = hdf5_h.H5Aiterate2(H5did, hdf5_h.H5_INDEX_NAME(), hdf5_h.H5_ITER_INC(), idx, MemorySegment.NULL, MemorySegment.NULL); - assertTrue("H5Aiterate2 should complete", result >= 0); + assertTrue("H5Aiterate2 should fail when callback is NULL", result < 0); } } } diff --git a/release_docs/CHANGELOG.md b/release_docs/CHANGELOG.md index ac8ce4e95c0..30113c2ddee 100644 --- a/release_docs/CHANGELOG.md +++ b/release_docs/CHANGELOG.md @@ -155,6 +155,12 @@ The `h5repack` tool now obtains its default low and high library version bounds Previously the error stack would be cleared when exiting a data filter, even an internal library filter, so the user could not see what caused the filter to fail. This has been fixed by not treating internal data filters like a user callback. Note that user-defined or third-party filters that use the default error stack will need to print that stack before returning from their callbacks. +### Fixed error when reading variable-length chunked datasets in read-only mode + + Passing NULL for the callback function pointer to H5Aiterate2 and H5Aiterate_by_name was not detected, leading to a subsequent access of an uninitialized pointer. This is now fixed. + + Fixes CVE-2025-9274 + ### Fixed error when reading variable-length chunked datasets in read-only mode When reading from a chunked dataset with a variable-length type, a non-default fill value, and unwritten chunks, the library would internally try to write data to the file and fail due to writing to a read-only file. Reworked the I/O code to avoid these writes in this case. This may also improve performance and file space usage in similar cases with files open with write access. diff --git a/src/H5A.c b/src/H5A.c index 9d4862d327b..028e473f107 100644 --- a/src/H5A.c +++ b/src/H5A.c @@ -1869,6 +1869,8 @@ H5Aiterate2(hid_t loc_id, H5_index_t idx_type, H5_iter_order_t order, hsize_t *i HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid index type specified"); if (order <= H5_ITER_UNKNOWN || order >= H5_ITER_N) HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid iteration order specified"); + if (op == NULL) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no operator specified"); /* Get the loc object */ if (NULL == (vol_obj = H5VL_vol_object(loc_id))) @@ -1958,6 +1960,8 @@ H5Aiterate_by_name(hid_t loc_id, const char *obj_name, H5_index_t idx_type, H5_i HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid index type specified"); if (order <= H5_ITER_UNKNOWN || order >= H5_ITER_N) HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid iteration order specified"); + if (op == NULL) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no operator specified"); /* Verify access property list and set up collective metadata if appropriate */ if (H5CX_set_apl(&lapl_id, H5P_CLS_LACC, loc_id, false) < 0) diff --git a/test/tattr.c b/test/tattr.c index af08d2db0a2..126d61e0e0d 100644 --- a/test/tattr.c +++ b/test/tattr.c @@ -7608,6 +7608,14 @@ attr_iterate_check(hid_t fid, const char *dsetname, hid_t obj_id, H5_index_t idx H5E_END_TRY VERIFY(ret, FAIL, "H5Aiterate_by_name"); + /* Test passing null pointer for callback */ + H5E_BEGIN_TRY + { + ret = H5Aiterate_by_name(obj_id, ".", idx_type, order, &skip, NULL, NULL, H5P_DEFAULT); + } + H5E_END_TRY + VERIFY(ret, FAIL, "H5Aiterate_by_name"); + /* Retrieve current # of errors */ if (old_nerrs == GetTestNumErrs()) return (0); diff --git a/test/titerate.c b/test/titerate.c index 595a577d8f6..ab448cc7b87 100644 --- a/test/titerate.c +++ b/test/titerate.c @@ -539,6 +539,14 @@ test_iter_attr(hid_t fapl, bool new_format) H5E_END_TRY VERIFY(ret, FAIL, "H5Aiterate2"); + /* Test passing null pointer for callback */ + H5E_BEGIN_TRY + { + ret = H5Aiterate2(dataset, H5_INDEX_NAME, H5_ITER_INC, &idx, NULL, &info); + } + H5E_END_TRY + VERIFY(ret, FAIL, "H5Aiterate2"); + /* Test all attributes on dataset, when callback always returns 0 */ info.command = RET_ZERO; idx = 0;