hdf5: patch CVE-2026-19026, CVE-2026-19027 and CVE-2026-19028

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>
Signed-off-by: Anuj Mittal <anuj.mittal@oss.qualcomm.com>
This commit is contained in:
Ankur Tyagi authored and Anuj Mittal committed 2026-11-09 09:10:40 +05:30
1 parent 9bcdd198a9
commit 35efa73ce4
2 files changed
+580

No files matched your search

@@ -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"