new file mode 100644
@@ -0,0 +1,579 @@
+From 8623863e172662af94d30842e1f735219b682852 Mon Sep 17 00:00:00 2001
+From: Matt L <124107509+mattjala@users.noreply.github.com>
+Date: Fri, 25 Sep 2026 17:15:06 -0500
+Subject: [PATCH] Fix CVE issues related to Nbit/Fletcher32 decode paths
+ (#6497)
+
+* Fix h5ls SIGSEGVs in Nbit and Fletcher32 filter decode paths
+
+This PR fixes three related issues which could cause crashes when
+crafted files were provided to h5ls. As it happens, all three are reachable from
+any reader via H5Z_pipeline() during a chunked H5Dread(), so the root issues
+affect the library itself.
+
+1. Nbit NULL/short parameter array (#6489, "Null_Pointer")
+
+ H5Z__filter_nbit() dereferenced cd_values[0] before validating the
+ parameter array. A file storing the filter with zero client-data
+ values produced cd_values=NULL / cd_nelmts=0 and a NULL dereference.
+
+ Fix is to reject a NULL cd_values or a cd_nelmts < 5 (the header at indices
+ 0..4 is always read) before any access.
+
+2. Nbit compressed-input buffer over-read (#6489, "Heap_Corruption_1")
+
+ The H5Z__nbit_decompress* family walked the compressed input via
+ index *j with no bound against the input size, and nbytes was never
+ even passed in. Malformed parameters (e.g. d_nelmts=67108876 over a
+ 31-byte chunk) drove *j past the end, reading out of bounds in
+ H5Z__nbit_decompress_one_byte().
+
+ Fix is thread the input size through the whole decompress call chain,
+ convert the void helpers (_one_byte, _one_nooptype, _one_atomic)
+ to return herr_t, and bounds-check *j against buffer_size before every
+ buffer[*j] read, propagating a filter error up the stack.
+
+3. Fletcher32 checksum length underflow (#6490, "Heap_Corruption_2")
+
+ The read path computed `src_nbytes = nbytes - FLETCHER_LEN` with no
+ lower-bound check. A corrupt 0-byte chunk underflowed src_nbytes to
+ SIZE_MAX-3, which was passed straight to H5_checksum_fletcher32(),
+ causing an out-of-bounds read.
+
+ Fix is to reject nbytes<FLETCHER_LEN up
+ front, since a valid Fletcher32 buffer must contain at least the
+ trailing 4-byte checksum.
+
+All three now fail gracefully with an error instead of crashing.
+
+Fixes #6489
+Fixes #6490
+
+* Add regression tests for Nbit/Fletcher32 filter decode crashes
+
+Added regression tests for the core library to guard against
+the patched issues.
+
+These files were produced with the new generator test/gen_bad_filters.c,
+which writes each dataset via the public API (using earliest library
+version bounds so the pipeline message lands in a version-1,
+un-checksummed object header) and then patches the specific bytes.
+
+* Committing clang-format changes
+
+* Address PR #6497 review: nbit size guard, comment, CHANGELOG
+
+* Bound the nbit filter's walk through its own parameters
+
+H5Z__nbit_decompress() and the array and compound helpers previously read the
+parameter list at offsets taken from the datatype description held in
+that same list, advancing a running index as they recursed, and never
+compared the index against the number of parameters they were given. A
+list that stopped short of the datatype it described left the walk
+reading past the end of it. H5O__pline_decode() allocates the list at
+exactly the stored count once it exceeds H5Z_COMMON_CD_VALUES, so past
+the end is past the allocation.
+
+This commit threads the parameter count through decompression and checks it before
+each step of the walk. The check has to sit at each step rather than
+being measured once up front, because how far the walk runs is itself
+read out of the parameters.
+
+Only the read path is bounded. The write path walks the same
+parameters, but they are built by H5Z__set_local_nbit() rather than read
+from a file.
+
+* Update CHANGELOG
+
+* Correct bad CHANGELOG merge
+
+---------
+
+Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com>
+Co-authored-by: H. Joe Lee <hyoklee@hdfgroup.org>
+
+CVE: CVE-2026-19026 CVE-2026-19027 CVE-2026-19028
+Upstream-Status: Backport [https://github.com/HDFGroup/hdf5/commit/a3cf1ea82cc7a66e50029a688121e1b105a7ce88]
+
+Dropped changes to the test and CHANGELOG file.
+
+Signed-off-by: Ankur Tyagi <ankur.tyagi85@gmail.com>
+---
+ src/H5Zfletcher32.c | 8 ++
+ src/H5Znbit.c | 211 +++++++++++++++++++++++++++++++++-----------
+ 2 files changed, 166 insertions(+), 53 deletions(-)
+
+diff --git a/src/H5Zfletcher32.c b/src/H5Zfletcher32.c
+index c3ec5f7ccb0..b89724ad0a3 100644
+--- a/src/H5Zfletcher32.c
++++ b/src/H5Zfletcher32.c
+@@ -62,6 +62,14 @@ H5Z__filter_fletcher32(unsigned flags, size_t H5_ATTR_UNUSED cd_nelmts,
+ assert(sizeof(uint32_t) >= 4);
+
+ if (flags & H5Z_FLAG_REVERSE) { /* Read */
++ /* A Fletcher32-filtered buffer must contain at least the trailing
++ * checksum. Reject anything smaller to avoid a size_t underflow
++ * when computing the data length.
++ */
++ if (nbytes < FLETCHER_LEN)
++ HGOTO_ERROR(H5E_STORAGE, H5E_OVERFLOW, 0,
++ "fletcher32 filter input buffer too small to contain checksum");
++
+ /* Do checksum if it's enabled for read; otherwise skip it
+ * to save performance. */
+ if (!(flags & H5Z_FLAG_SKIP_EDC)) {
+diff --git a/src/H5Znbit.c b/src/H5Znbit.c
+index fed86a1a3bd..ce8c726370a 100644
+--- a/src/H5Znbit.c
++++ b/src/H5Znbit.c
+@@ -51,26 +51,29 @@ static herr_t H5Z__set_parms_compound(const H5T_t *type, unsigned *cd_values_ind
+ bool *need_not_compress);
+
+ static void H5Z__nbit_next_byte(size_t *j, size_t *buf_len);
+-static void H5Z__nbit_decompress_one_byte(unsigned char *data, size_t data_offset, unsigned k,
++static herr_t H5Z__nbit_decompress_one_byte(unsigned char *data, size_t data_offset, unsigned k,
+ unsigned begin_i, unsigned end_i, const unsigned char *buffer,
+- size_t *j, size_t *buf_len, const parms_atomic *p,
+- size_t datatype_len);
++ size_t buffer_size, size_t *j, size_t *buf_len,
++ const parms_atomic *p, size_t datatype_len);
+ static void H5Z__nbit_compress_one_byte(const unsigned char *data, size_t data_offset, unsigned k,
+ unsigned begin_i, unsigned end_i, unsigned char *buffer, size_t *j,
+ size_t *buf_len, const parms_atomic *p, size_t datatype_len);
+-static void H5Z__nbit_decompress_one_nooptype(unsigned char *data, size_t data_offset,
+- const unsigned char *buffer, size_t *j, size_t *buf_len,
+- unsigned size);
+-static void H5Z__nbit_decompress_one_atomic(unsigned char *data, size_t data_offset, unsigned char *buffer,
+- size_t *j, size_t *buf_len, const parms_atomic *p);
++static herr_t H5Z__nbit_decompress_one_nooptype(unsigned char *data, size_t data_offset,
++ const unsigned char *buffer, size_t buffer_size, size_t *j,
++ size_t *buf_len, unsigned size);
++static herr_t H5Z__nbit_decompress_one_atomic(unsigned char *data, size_t data_offset, unsigned char *buffer,
++ size_t buffer_size, size_t *j, size_t *buf_len,
++ const parms_atomic *p);
+ static herr_t H5Z__nbit_decompress_one_array(unsigned char *data, size_t data_offset, unsigned char *buffer,
+- size_t *j, size_t *buf_len, const unsigned parms[],
++ size_t buffer_size, size_t *j, size_t *buf_len,
++ const unsigned parms[], size_t parms_nelmts,
+ unsigned *parms_index);
+ static herr_t H5Z__nbit_decompress_one_compound(unsigned char *data, size_t data_offset,
+- unsigned char *buffer, size_t *j, size_t *buf_len,
+- const unsigned parms[], unsigned *parms_index);
++ unsigned char *buffer, size_t buffer_size, size_t *j,
++ size_t *buf_len, const unsigned parms[], size_t parms_nelmts,
++ unsigned *parms_index);
+ static herr_t H5Z__nbit_decompress(unsigned char *data, unsigned d_nelmts, unsigned char *buffer,
+- const unsigned parms[]);
++ size_t buffer_size, const unsigned parms[], size_t parms_nelmts);
+ static void H5Z__nbit_compress_one_nooptype(const unsigned char *data, size_t data_offset,
+ unsigned char *buffer, size_t *j, size_t *buf_len, unsigned size);
+ static void H5Z__nbit_compress_one_array(unsigned char *data, size_t data_offset, unsigned char *buffer,
+@@ -100,8 +103,15 @@ H5Z_class2_t H5Z_NBIT[1] = {{
+ #define H5Z_NBIT_COMPOUND 3 /* Compound datatype class */
+ #define H5Z_NBIT_NOOPTYPE 4 /* Other datatype class: nbit does no compression */
+ #define H5Z_NBIT_MAX_NPARMS 4096 /* Max number of parameters for filter */
+-#define H5Z_NBIT_ORDER_LE 0 /* Little endian for datatype byte order */
+-#define H5Z_NBIT_ORDER_BE 1 /* Big endian for datatype byte order */
++
++/* Whether the parameter list holds N more values starting at IDX. The
++ * datatype description that drives the walk through the parameters is held in
++ * those same parameters, so a list that stops short of the datatype it
++ * describes has to be caught at each step rather than measured up front.
++ */
++#define H5Z_NBIT_PARMS_AVAIL(idx, n, nelmts) (((nelmts) >= (n)) && ((size_t)(idx) <= (nelmts) - (n)))
++#define H5Z_NBIT_ORDER_LE 0 /* Little endian for datatype byte order */
++#define H5Z_NBIT_ORDER_BE 1 /* Big endian for datatype byte order */
+
+ /* Local variables */
+
+@@ -931,7 +941,16 @@ H5Z__filter_nbit(unsigned flags, size_t cd_nelmts, const unsigned cd_values[], s
+
+ /* check arguments
+ * cd_values[0] stores actual number of parameters in cd_values[]
++ *
++ * The filter header always occupies cd_values[0..4] (number of
++ * parameters, no-compression flag, number of elements, datatype class
++ * and datatype size), all of which are read unconditionally below.
++ * Reject a NULL array or one shorter than that to avoid a bad
++ * dereference.
+ */
++ if (cd_values == NULL || cd_nelmts < 5)
++ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, 0, "invalid nbit parameters");
++
+ if (cd_nelmts != cd_values[0])
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, 0, "invalid nbit aggression level");
+
+@@ -944,6 +963,18 @@ H5Z__filter_nbit(unsigned flags, size_t cd_nelmts, const unsigned cd_values[], s
+ /* copy a filter parameter to d_nelmts */
+ d_nelmts = cd_values[2];
+
++ /* cd_values[4] stores the datatype size, which is used together with
++ * d_nelmts to size the (de)compression buffer. A zero size is invalid,
++ * and a d_nelmts * size product that overflows size_t would produce an
++ * undersized allocation and out-of-bounds accesses (this matters on
++ * platforms with a 32-bit size_t). Reject both, as they can only arise
++ * from a corrupted or crafted file.
++ */
++ if (cd_values[4] == 0)
++ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, 0, "invalid nbit datatype size");
++ if (d_nelmts != 0 && (size_t)cd_values[4] > SIZE_MAX / d_nelmts)
++ HGOTO_ERROR(H5E_ARGS, H5E_OVERFLOW, 0, "nbit (de)compression buffer size overflow");
++
+ /* input; decompress */
+ if (flags & H5Z_FLAG_REVERSE) {
+ size_out = d_nelmts * (size_t)cd_values[4]; /* cd_values[4] stores datatype size */
+@@ -953,7 +984,7 @@ H5Z__filter_nbit(unsigned flags, size_t cd_nelmts, const unsigned cd_values[], s
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, 0, "memory allocation failed for nbit decompression");
+
+ /* decompress the buffer */
+- if (H5Z__nbit_decompress(outbuf, d_nelmts, (unsigned char *)*buf, cd_values) < 0) {
++ if (H5Z__nbit_decompress(outbuf, d_nelmts, (unsigned char *)*buf, nbytes, cd_values, cd_nelmts) < 0) {
+ H5MM_xfree(outbuf);
+ HGOTO_ERROR(H5E_PLINE, H5E_CANTFILTER, 0, "can't decompress buffer");
+ }
+@@ -999,15 +1030,19 @@ H5Z__nbit_next_byte(size_t *j, size_t *buf_len)
+ *buf_len = 8 * sizeof(unsigned char);
+ }
+
+-static void
++static herr_t
+ H5Z__nbit_decompress_one_byte(unsigned char *data, size_t data_offset, unsigned k, unsigned begin_i,
+- unsigned end_i, const unsigned char *buffer, size_t *j, size_t *buf_len,
+- const parms_atomic *p, size_t datatype_len)
++ unsigned end_i, const unsigned char *buffer, size_t buffer_size, size_t *j,
++ size_t *buf_len, const parms_atomic *p, size_t datatype_len)
+ {
+ size_t dat_len; /* dat_len is the number of bits to be copied in each data byte */
+ size_t dat_offset;
+ unsigned char val; /* value to be copied in each data byte */
+
++ /* Ensure the byte to be read is within the bounds of the compressed buffer */
++ if (*j >= buffer_size)
++ return FAIL;
++
+ /* initialize value and bits of unsigned char to be copied */
+ val = buffer[*j];
+ dat_offset = 0;
+@@ -1039,25 +1074,33 @@ H5Z__nbit_decompress_one_byte(unsigned char *data, size_t data_offset, unsigned
+ dat_len -= *buf_len;
+ H5Z__nbit_next_byte(j, buf_len);
+ if (dat_len == 0)
+- return;
++ return SUCCEED;
+
++ if (*j >= buffer_size)
++ return FAIL;
+ val = buffer[*j];
+ data[data_offset + k] |= (unsigned char)(((unsigned)(val >> (*buf_len - dat_len)) &
+ (unsigned)(~((unsigned)(~0) << dat_len)))
+ << dat_offset);
+ *buf_len -= dat_len;
+ }
++
++ return SUCCEED;
+ }
+
+-static void
++static herr_t
+ H5Z__nbit_decompress_one_nooptype(unsigned char *data, size_t data_offset, const unsigned char *buffer,
+- size_t *j, size_t *buf_len, unsigned size)
++ size_t buffer_size, size_t *j, size_t *buf_len, unsigned size)
+ {
+ unsigned i; /* index */
+ size_t dat_len; /* dat_len is the number of bits to be copied in each data byte */
+ unsigned char val; /* value to be copied in each data byte */
+
+ for (i = 0; i < size; i++) {
++ /* Ensure the byte to be read is within the bounds of the compressed buffer */
++ if (*j >= buffer_size)
++ return FAIL;
++
+ /* initialize value and bits of unsigned char to be copied */
+ val = buffer[*j];
+ dat_len = sizeof(unsigned char) * 8;
+@@ -1069,16 +1112,20 @@ H5Z__nbit_decompress_one_nooptype(unsigned char *data, size_t data_offset, const
+ if (dat_len == 0)
+ continue;
+
++ if (*j >= buffer_size)
++ return FAIL;
+ val = buffer[*j];
+ data[data_offset + i] |= (unsigned char)((unsigned)(val >> (*buf_len - dat_len)) &
+ (unsigned)(~((unsigned)(~0) << dat_len)));
+ *buf_len -= dat_len;
+ }
++
++ return SUCCEED;
+ }
+
+-static void
+-H5Z__nbit_decompress_one_atomic(unsigned char *data, size_t data_offset, unsigned char *buffer, size_t *j,
+- size_t *buf_len, const parms_atomic *p)
++static herr_t
++H5Z__nbit_decompress_one_atomic(unsigned char *data, size_t data_offset, unsigned char *buffer,
++ size_t buffer_size, size_t *j, size_t *buf_len, const parms_atomic *p)
+ {
+ /* begin_i: the index of byte having first significant bit
+ end_i: the index of byte having last significant bit */
+@@ -1097,8 +1144,9 @@ H5Z__nbit_decompress_one_atomic(unsigned char *data, size_t data_offset, unsigne
+ end_i = p->offset / 8;
+
+ for (k = (int)begin_i; k >= (int)end_i; k--)
+- H5Z__nbit_decompress_one_byte(data, data_offset, (unsigned)k, begin_i, end_i, buffer, j, buf_len,
+- p, datatype_len);
++ if (H5Z__nbit_decompress_one_byte(data, data_offset, (unsigned)k, begin_i, end_i, buffer,
++ buffer_size, j, buf_len, p, datatype_len) < 0)
++ return FAIL;
+ }
+ else { /* big endian */
+ /* Sanity check */
+@@ -1112,14 +1160,18 @@ H5Z__nbit_decompress_one_atomic(unsigned char *data, size_t data_offset, unsigne
+ end_i = ((unsigned)datatype_len - p->offset) / 8 - 1;
+
+ for (k = (int)begin_i; k <= (int)end_i; k++)
+- H5Z__nbit_decompress_one_byte(data, data_offset, (unsigned)k, begin_i, end_i, buffer, j, buf_len,
+- p, datatype_len);
++ if (H5Z__nbit_decompress_one_byte(data, data_offset, (unsigned)k, begin_i, end_i, buffer,
++ buffer_size, j, buf_len, p, datatype_len) < 0)
++ return FAIL;
+ }
++
++ return SUCCEED;
+ }
+
+ static herr_t
+-H5Z__nbit_decompress_one_array(unsigned char *data, size_t data_offset, unsigned char *buffer, size_t *j,
+- size_t *buf_len, const unsigned parms[], unsigned *parms_index)
++H5Z__nbit_decompress_one_array(unsigned char *data, size_t data_offset, unsigned char *buffer,
++ size_t buffer_size, size_t *j, size_t *buf_len, const unsigned parms[],
++ size_t parms_nelmts, unsigned *parms_index)
+ {
+ unsigned i, total_size, base_class, base_size, n, begin_index;
+ parms_atomic p;
+@@ -1127,11 +1179,19 @@ H5Z__nbit_decompress_one_array(unsigned char *data, size_t data_offset, unsigned
+
+ FUNC_ENTER_PACKAGE
+
++ if (!H5Z_NBIT_PARMS_AVAIL(*parms_index, 2, parms_nelmts))
++ HGOTO_ERROR(H5E_PLINE, H5E_OVERFLOW, FAIL,
++ "parameter list is shorter than the datatype it describes");
++
+ total_size = parms[(*parms_index)++];
+ base_class = parms[(*parms_index)++];
+
+ switch (base_class) {
+ case H5Z_NBIT_ATOMIC:
++ if (!H5Z_NBIT_PARMS_AVAIL(*parms_index, 4, parms_nelmts))
++ HGOTO_ERROR(H5E_PLINE, H5E_OVERFLOW, FAIL,
++ "parameter list is shorter than the datatype it describes");
++
+ p.size = parms[(*parms_index)++];
+ p.order = parms[(*parms_index)++];
+ p.precision = parms[(*parms_index)++];
+@@ -1143,37 +1203,54 @@ H5Z__nbit_decompress_one_array(unsigned char *data, size_t data_offset, unsigned
+
+ n = total_size / p.size;
+ for (i = 0; i < n; i++)
+- H5Z__nbit_decompress_one_atomic(data, data_offset + i * (size_t)p.size, buffer, j, buf_len,
+- &p);
++ if (H5Z__nbit_decompress_one_atomic(data, data_offset + i * (size_t)p.size, buffer,
++ buffer_size, j, buf_len, &p) < 0)
++ HGOTO_ERROR(H5E_PLINE, H5E_CANTFILTER, FAIL, "can't decompress atomic");
+ break;
+
+ case H5Z_NBIT_ARRAY:
++ if (!H5Z_NBIT_PARMS_AVAIL(*parms_index, 1, parms_nelmts))
++ HGOTO_ERROR(H5E_PLINE, H5E_OVERFLOW, FAIL,
++ "parameter list is shorter than the datatype it describes");
++
+ base_size = parms[*parms_index]; /* read in advance */
+ n = total_size / base_size; /* number of base_type elements inside the array datatype */
+ begin_index = *parms_index;
+ for (i = 0; i < n; i++) {
+- if (H5Z__nbit_decompress_one_array(data, data_offset + i * (size_t)base_size, buffer, j,
+- buf_len, parms, parms_index) < 0)
++ if (H5Z__nbit_decompress_one_array(data, data_offset + i * (size_t)base_size, buffer,
++ buffer_size, j, buf_len, parms, parms_nelmts,
++ parms_index) < 0)
+ HGOTO_ERROR(H5E_PLINE, H5E_CANTFILTER, FAIL, "can't decompress array");
+ *parms_index = begin_index;
+ }
+ break;
+
+ case H5Z_NBIT_COMPOUND:
++ if (!H5Z_NBIT_PARMS_AVAIL(*parms_index, 1, parms_nelmts))
++ HGOTO_ERROR(H5E_PLINE, H5E_OVERFLOW, FAIL,
++ "parameter list is shorter than the datatype it describes");
++
+ base_size = parms[*parms_index]; /* read in advance */
+ n = total_size / base_size; /* number of base_type elements inside the array datatype */
+ begin_index = *parms_index;
+ for (i = 0; i < n; i++) {
+- if (H5Z__nbit_decompress_one_compound(data, data_offset + i * (size_t)base_size, buffer, j,
+- buf_len, parms, parms_index) < 0)
++ if (H5Z__nbit_decompress_one_compound(data, data_offset + i * (size_t)base_size, buffer,
++ buffer_size, j, buf_len, parms, parms_nelmts,
++ parms_index) < 0)
+ HGOTO_ERROR(H5E_PLINE, H5E_CANTFILTER, FAIL, "can't decompress compound");
+ *parms_index = begin_index;
+ }
+ break;
+
+ case H5Z_NBIT_NOOPTYPE:
++ if (!H5Z_NBIT_PARMS_AVAIL(*parms_index, 1, parms_nelmts))
++ HGOTO_ERROR(H5E_PLINE, H5E_OVERFLOW, FAIL,
++ "parameter list is shorter than the datatype it describes");
++
+ (*parms_index)++; /* skip size of no-op type */
+- H5Z__nbit_decompress_one_nooptype(data, data_offset, buffer, j, buf_len, total_size);
++ if (H5Z__nbit_decompress_one_nooptype(data, data_offset, buffer, buffer_size, j, buf_len,
++ total_size) < 0)
++ HGOTO_ERROR(H5E_PLINE, H5E_CANTFILTER, FAIL, "can't decompress no-op type");
+ break;
+
+ default:
+@@ -1185,8 +1262,9 @@ done:
+ }
+
+ static herr_t
+-H5Z__nbit_decompress_one_compound(unsigned char *data, size_t data_offset, unsigned char *buffer, size_t *j,
+- size_t *buf_len, const unsigned parms[], unsigned *parms_index)
++H5Z__nbit_decompress_one_compound(unsigned char *data, size_t data_offset, unsigned char *buffer,
++ size_t buffer_size, size_t *j, size_t *buf_len, const unsigned parms[],
++ size_t parms_nelmts, unsigned *parms_index)
+ {
+ unsigned i, nmembers, member_offset, member_class, member_size, used_size = 0, prev_used_size, size;
+ parms_atomic p;
+@@ -1194,10 +1272,18 @@ H5Z__nbit_decompress_one_compound(unsigned char *data, size_t data_offset, unsig
+
+ FUNC_ENTER_PACKAGE
+
++ if (!H5Z_NBIT_PARMS_AVAIL(*parms_index, 2, parms_nelmts))
++ HGOTO_ERROR(H5E_PLINE, H5E_OVERFLOW, FAIL,
++ "parameter list is shorter than the datatype it describes");
++
+ size = parms[(*parms_index)++];
+ nmembers = parms[(*parms_index)++];
+
+ for (i = 0; i < nmembers; i++) {
++ if (!H5Z_NBIT_PARMS_AVAIL(*parms_index, 3, parms_nelmts))
++ HGOTO_ERROR(H5E_PLINE, H5E_OVERFLOW, FAIL,
++ "parameter list is shorter than the datatype it describes");
++
+ member_offset = parms[(*parms_index)++];
+ member_class = parms[(*parms_index)++];
+
+@@ -1213,6 +1299,10 @@ H5Z__nbit_decompress_one_compound(unsigned char *data, size_t data_offset, unsig
+ HGOTO_ERROR(H5E_PLINE, H5E_BADRANGE, FAIL, "compound member offset overflowed compound size");
+ switch (member_class) {
+ case H5Z_NBIT_ATOMIC:
++ if (!H5Z_NBIT_PARMS_AVAIL(*parms_index, 4, parms_nelmts))
++ HGOTO_ERROR(H5E_PLINE, H5E_OVERFLOW, FAIL,
++ "parameter list is shorter than the datatype it describes");
++
+ p.size = member_size;
+ /* Advance past member size */
+ (*parms_index)++;
+@@ -1224,26 +1314,29 @@ H5Z__nbit_decompress_one_compound(unsigned char *data, size_t data_offset, unsig
+ if (p.precision > p.size * 8 || (p.precision + p.offset) > p.size * 8)
+ HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, FAIL, "invalid datatype precision/offset");
+
+- H5Z__nbit_decompress_one_atomic(data, data_offset + member_offset, buffer, j, buf_len, &p);
++ if (H5Z__nbit_decompress_one_atomic(data, data_offset + member_offset, buffer, buffer_size, j,
++ buf_len, &p) < 0)
++ HGOTO_ERROR(H5E_PLINE, H5E_CANTFILTER, FAIL, "can't decompress atomic");
+ break;
+
+ case H5Z_NBIT_ARRAY:
+- if (H5Z__nbit_decompress_one_array(data, data_offset + member_offset, buffer, j, buf_len,
+- parms, parms_index) < 0)
++ if (H5Z__nbit_decompress_one_array(data, data_offset + member_offset, buffer, buffer_size, j,
++ buf_len, parms, parms_nelmts, parms_index) < 0)
+ HGOTO_ERROR(H5E_PLINE, H5E_CANTFILTER, FAIL, "can't decompress array");
+ break;
+
+ case H5Z_NBIT_COMPOUND:
+- if (H5Z__nbit_decompress_one_compound(data, data_offset + member_offset, buffer, j, buf_len,
+- parms, parms_index) < 0)
++ if (H5Z__nbit_decompress_one_compound(data, data_offset + member_offset, buffer, buffer_size,
++ j, buf_len, parms, parms_nelmts, parms_index) < 0)
+ HGOTO_ERROR(H5E_PLINE, H5E_CANTFILTER, FAIL, "can't decompress compound");
+ break;
+
+ case H5Z_NBIT_NOOPTYPE:
+- /* Advance past member size */
++ /* Advance past member size (already checked above) */
+ (*parms_index)++;
+- H5Z__nbit_decompress_one_nooptype(data, data_offset + member_offset, buffer, j, buf_len,
+- member_size);
++ if (H5Z__nbit_decompress_one_nooptype(data, data_offset + member_offset, buffer, buffer_size,
++ j, buf_len, member_size) < 0)
++ HGOTO_ERROR(H5E_PLINE, H5E_CANTFILTER, FAIL, "can't decompress no-op type");
+ break;
+
+ default:
+@@ -1256,7 +1349,8 @@ done:
+ }
+
+ static herr_t
+-H5Z__nbit_decompress(unsigned char *data, unsigned d_nelmts, unsigned char *buffer, const unsigned parms[])
++H5Z__nbit_decompress(unsigned char *data, unsigned d_nelmts, unsigned char *buffer, size_t buffer_size,
++ const unsigned parms[], size_t parms_nelmts)
+ {
+ /* i: index of data, j: index of buffer,
+ buf_len: number of bits to be filled in current byte */
+@@ -1269,6 +1363,11 @@ H5Z__nbit_decompress(unsigned char *data, unsigned d_nelmts, unsigned char *buff
+
+ FUNC_ENTER_PACKAGE
+
++ /* The datatype class and its size are read before the walk begins */
++ if (!H5Z_NBIT_PARMS_AVAIL(0, 5, parms_nelmts))
++ HGOTO_ERROR(H5E_PLINE, H5E_OVERFLOW, FAIL,
++ "parameter list is shorter than the datatype it describes");
++
+ /* may not have to initialize to zeros */
+ memset(data, 0, d_nelmts * (size_t)parms[4]);
+
+@@ -1278,6 +1377,10 @@ H5Z__nbit_decompress(unsigned char *data, unsigned d_nelmts, unsigned char *buff
+
+ switch (parms[3]) {
+ case H5Z_NBIT_ATOMIC:
++ if (!H5Z_NBIT_PARMS_AVAIL(0, 8, parms_nelmts))
++ HGOTO_ERROR(H5E_PLINE, H5E_OVERFLOW, FAIL,
++ "parameter list is shorter than the datatype it describes");
++
+ p.size = parms[4];
+ p.order = parms[5];
+ p.precision = parms[6];
+@@ -1288,15 +1391,17 @@ H5Z__nbit_decompress(unsigned char *data, unsigned d_nelmts, unsigned char *buff
+ HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, FAIL, "invalid datatype precision/offset");
+
+ for (i = 0; i < d_nelmts; i++)
+- H5Z__nbit_decompress_one_atomic(data, i * (size_t)p.size, buffer, &j, &buf_len, &p);
++ if (H5Z__nbit_decompress_one_atomic(data, i * (size_t)p.size, buffer, buffer_size, &j,
++ &buf_len, &p) < 0)
++ HGOTO_ERROR(H5E_PLINE, H5E_CANTFILTER, FAIL, "can't decompress atomic");
+ break;
+
+ case H5Z_NBIT_ARRAY:
+ size = parms[4];
+ parms_index = 4; /* set the index before goto function call */
+ for (i = 0; i < d_nelmts; i++) {
+- if (H5Z__nbit_decompress_one_array(data, i * size, buffer, &j, &buf_len, parms,
+- &parms_index) < 0)
++ if (H5Z__nbit_decompress_one_array(data, i * size, buffer, buffer_size, &j, &buf_len, parms,
++ parms_nelmts, &parms_index) < 0)
+ HGOTO_ERROR(H5E_PLINE, H5E_CANTFILTER, FAIL, "can't decompress array");
+ parms_index = 4;
+ }
+@@ -1306,8 +1411,8 @@ H5Z__nbit_decompress(unsigned char *data, unsigned d_nelmts, unsigned char *buff
+ size = parms[4];
+ parms_index = 4; /* set the index before goto function call */
+ for (i = 0; i < d_nelmts; i++) {
+- if (H5Z__nbit_decompress_one_compound(data, i * size, buffer, &j, &buf_len, parms,
+- &parms_index) < 0)
++ if (H5Z__nbit_decompress_one_compound(data, i * size, buffer, buffer_size, &j, &buf_len,
++ parms, parms_nelmts, &parms_index) < 0)
+ HGOTO_ERROR(H5E_PLINE, H5E_CANTFILTER, FAIL, "can't decompress compound");
+ parms_index = 4;
+ }
@@ -22,6 +22,7 @@ SRC_URI = "https://support.hdfgroup.org/releases/hdf5/v2_0/v2_0_0/downloads/${BP
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 \
"
SRC_URI[sha256sum] = "f4c2edc5668fb846627182708dbe1e16c60c467e63177a75b0b9f12c19d7efed"