diff mbox series

[meta-oe,1/9] hdf5: patch CVE-2026-19026, CVE-2026-19027 and CVE-2026-19028

Message ID 20261105200552.81303-1-ankur.tyagi85@gmail.com
State New
Headers show
Series [meta-oe,1/9] hdf5: patch CVE-2026-19026, CVE-2026-19027 and CVE-2026-19028 | expand

Commit Message

Ankur Tyagi Nov. 5, 2026, 8:05 p.m. UTC
From: Ankur Tyagi <ankur.tyagi85@gmail.com>

Details:
https://nvd.nist.gov/vuln/detail/cve-2026-19026
https://nvd.nist.gov/vuln/detail/cve-2026-19027
https://nvd.nist.gov/vuln/detail/cve-2026-19028

Signed-off-by: Ankur Tyagi <ankur.tyagi85@gmail.com>
---
 ...-19026-CVE-2026-19027-CVE-2026-19028.patch | 579 ++++++++++++++++++
 meta-oe/recipes-support/hdf5/hdf5_2.0.0.bb    |   1 +
 2 files changed, 580 insertions(+)
 create mode 100644 meta-oe/recipes-support/hdf5/files/CVE-2026-19026-CVE-2026-19027-CVE-2026-19028.patch
diff mbox series

Patch

diff --git a/meta-oe/recipes-support/hdf5/files/CVE-2026-19026-CVE-2026-19027-CVE-2026-19028.patch b/meta-oe/recipes-support/hdf5/files/CVE-2026-19026-CVE-2026-19027-CVE-2026-19028.patch
new file mode 100644
index 0000000000..8187612342
--- /dev/null
+++ b/meta-oe/recipes-support/hdf5/files/CVE-2026-19026-CVE-2026-19027-CVE-2026-19028.patch
@@ -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;
+             }
diff --git a/meta-oe/recipes-support/hdf5/hdf5_2.0.0.bb b/meta-oe/recipes-support/hdf5/hdf5_2.0.0.bb
index 4e493f0aa7..90a0e5c066 100644
--- a/meta-oe/recipes-support/hdf5/hdf5_2.0.0.bb
+++ b/meta-oe/recipes-support/hdf5/hdf5_2.0.0.bb
@@ -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"