diff --git a/meta-oe/recipes-support/hdf5/files/CVE-2025-2308.patch b/meta-oe/recipes-support/hdf5/files/CVE-2025-2308.patch new file mode 100644 index 0000000000..336a0d2697 --- /dev/null +++ b/meta-oe/recipes-support/hdf5/files/CVE-2025-2308.patch @@ -0,0 +1,333 @@ +From cbce4c2ecf6f5557605890eec125ecfaa4371131 Mon Sep 17 00:00:00 2001 +From: Libo Chen +Date: Fri, 30 Jan 2026 16:43:04 +0800 +Subject: [PATCH] Fix CVE-2025-2308 (#5960) + +A malformed file can cause the scale-offset filter to have too little input data causing a heap buffer overflow. Additional checks on the maximum buffer length are required during the decompression. + +This PR fixes CVE-2025-2308. + +CVE: CVE-2025-2308 + +Upstream-Status: Backport [https://github.com/HDFGroup/hdf5/commit/2ce7fdc4cf147d280aa6d49686297faacc250e40] + +Signed-off-by: Libo Chen +--- + src/H5Zscaleoffset.c | 177 ++-- + src/H5Zscaleoffset.c.orig | 1781 +++++++++++++++++++++++++++++++++++++ + 1 files changed, 105 insertions(+), 72 deletions(-) + create mode 100644 src/H5Zscaleoffset.c.orig + +diff --git a/src/H5Zscaleoffset.c b/src/H5Zscaleoffset.c +index fbf12d6..8355b13 100644 +--- a/src/H5Zscaleoffset.c ++++ b/src/H5Zscaleoffset.c +@@ -69,21 +69,22 @@ static herr_t H5Z__scaleoffset_precompress_fd(void *data, unsigned d_nelmts, enu + static herr_t H5Z__scaleoffset_postdecompress_fd(void *data, unsigned d_nelmts, enum H5Z_scaleoffset_t type, + unsigned filavail, const unsigned cd_values[], + uint32_t minbits, unsigned long long minval, double D_val); +-static void H5Z__scaleoffset_next_byte(size_t *j, unsigned *buf_len); +-static void H5Z__scaleoffset_decompress_one_byte(unsigned char *data, size_t data_offset, unsigned k, +- unsigned begin_i, const unsigned char *buffer, size_t *j, +- unsigned *buf_len, parms_atomic p, unsigned dtype_len); ++static void H5Z__scaleoffset_next_byte(size_t *j, unsigned *bits_to_fill); ++static herr_t H5Z__scaleoffset_decompress_one_byte(unsigned char *data, size_t data_offset, unsigned k, ++ unsigned begin_i, const unsigned char *buffer, ++ size_t buf_size, size_t *j, unsigned *bits_to_fill, ++ parms_atomic p, unsigned dtype_len); + static void H5Z__scaleoffset_compress_one_byte(const unsigned char *data, size_t data_offset, unsigned k, + unsigned begin_i, unsigned char *buffer, size_t *j, +- unsigned *buf_len, parms_atomic p, unsigned dtype_len); +-static void H5Z__scaleoffset_decompress_one_atomic(unsigned char *data, size_t data_offset, +- unsigned char *buffer, size_t *j, unsigned *buf_len, +- parms_atomic p); ++ unsigned *bits_to_fill, parms_atomic p, unsigned dtype_len); ++static herr_t H5Z__scaleoffset_decompress_one_atomic(unsigned char *data, size_t data_offset, ++ unsigned char *buffer, size_t buf_size, size_t *j, ++ unsigned *bits_to_fill, parms_atomic p); + static void H5Z__scaleoffset_compress_one_atomic(unsigned char *data, size_t data_offset, +- unsigned char *buffer, size_t *j, unsigned *buf_len, ++ unsigned char *buffer, size_t *j, unsigned *bits_to_fill, + parms_atomic p); +-static void H5Z__scaleoffset_decompress(unsigned char *data, unsigned d_nelmts, unsigned char *buffer, +- parms_atomic p); ++static herr_t H5Z__scaleoffset_decompress(unsigned char *data, unsigned d_nelmts, unsigned char *buffer, ++ size_t buf_size, parms_atomic p); + static void H5Z__scaleoffset_compress(unsigned char *data, unsigned d_nelmts, unsigned char *buffer, + size_t buffer_size, parms_atomic p); + +@@ -1261,8 +1262,11 @@ H5Z__filter_scaleoffset(unsigned flags, size_t cd_nelmts, const unsigned cd_valu + } + + /* decompress the buffer if minbits not equal to zero */ +- if (minbits != 0) +- H5Z__scaleoffset_decompress(outbuf, d_nelmts, (unsigned char *)(*buf) + buf_offset, p); ++ if (minbits != 0) { ++ if (H5Z__scaleoffset_decompress(outbuf, d_nelmts, (unsigned char *)(*buf) + buf_offset, ++ *buf_size - buf_offset, p)) ++ HGOTO_ERROR(H5E_PLINE, H5E_BADVALUE, 0, "Scaleoffset decompression failed"); ++ } + else { + /* fill value is not defined and all data elements have the same value */ + for (i = 0; i < size_out; i++) +@@ -1603,55 +1607,69 @@ done: + } + + static void +-H5Z__scaleoffset_next_byte(size_t *j, unsigned *buf_len) ++H5Z__scaleoffset_next_byte(size_t *j, unsigned *bits_to_fill) + { + ++(*j); +- *buf_len = 8 * sizeof(unsigned char); ++ *bits_to_fill = 8 * sizeof(unsigned char); + } + +-static void ++static herr_t + H5Z__scaleoffset_decompress_one_byte(unsigned char *data, size_t data_offset, unsigned k, unsigned begin_i, +- const unsigned char *buffer, size_t *j, unsigned *buf_len, +- parms_atomic p, unsigned dtype_len) ++ const unsigned char *buffer, size_t buf_size, size_t *j, ++ unsigned *bits_to_fill, parms_atomic p, unsigned dtype_len) + { +- unsigned 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 */ ++ unsigned bits_to_copy; /* bits_to_copy is the number of bits to be copied in each data byte */ ++ unsigned char val; /* value to be copied in each data byte */ ++ herr_t ret_value = SUCCEED; /* Return value */ ++ ++ FUNC_ENTER_PACKAGE ++ ++ if (*j >= buf_size) ++ HGOTO_ERROR(H5E_PLINE, H5E_BADVALUE, 0, "Buffer too short"); + + /* initialize value and bits of unsigned char to be copied */ + val = buffer[*j]; + if (k == begin_i) +- dat_len = 8 - (dtype_len - p.minbits) % 8; ++ bits_to_copy = 8 - (dtype_len - p.minbits) % 8; + else +- dat_len = 8; ++ bits_to_copy = 8; + +- if (*buf_len > dat_len) { +- data[data_offset + k] = +- (unsigned char)((unsigned)(val >> (*buf_len - dat_len)) & (unsigned)(~((unsigned)~0 << dat_len))); +- *buf_len -= dat_len; ++ if (*bits_to_fill > bits_to_copy) { ++ data[data_offset + k] = (unsigned char)((unsigned)(val >> (*bits_to_fill - bits_to_copy)) & ++ (unsigned)(~((unsigned)~0 << bits_to_copy))); ++ *bits_to_fill -= bits_to_copy; + } /* end if */ + else { + data[data_offset + k] = +- (unsigned char)((val & ~((unsigned)(~0) << *buf_len)) << (dat_len - *buf_len)); +- dat_len -= *buf_len; +- H5Z__scaleoffset_next_byte(j, buf_len); +- if (dat_len == 0) +- return; ++ (unsigned char)((val & ~((unsigned)(~0) << *bits_to_fill)) << (bits_to_copy - *bits_to_fill)); ++ bits_to_copy -= *bits_to_fill; ++ H5Z__scaleoffset_next_byte(j, bits_to_fill); ++ if (bits_to_copy == 0) ++ goto done; ++ else if (*j >= buf_size) ++ HGOTO_ERROR(H5E_PLINE, H5E_BADVALUE, 0, "Buffer too short"); + + val = buffer[*j]; +- data[data_offset + k] |= +- (unsigned char)((unsigned)(val >> (*buf_len - dat_len)) & ~((unsigned)(~0) << dat_len)); +- *buf_len -= dat_len; ++ data[data_offset + k] |= (unsigned char)((unsigned)(val >> (*bits_to_fill - bits_to_copy)) & ++ ~((unsigned)(~0) << bits_to_copy)); ++ *bits_to_fill -= bits_to_copy; + } /* end else */ ++ ++done: ++ FUNC_LEAVE_NOAPI(ret_value) + } + +-static void ++static herr_t + H5Z__scaleoffset_decompress_one_atomic(unsigned char *data, size_t data_offset, unsigned char *buffer, +- size_t *j, unsigned *buf_len, parms_atomic p) ++ size_t buf_size, size_t *j, unsigned *bits_to_fill, parms_atomic p) + { + /* begin_i: the index of byte having first significant bit */ + unsigned begin_i; + unsigned dtype_len; + int k; ++ herr_t ret_value = SUCCEED; /* Return value */ ++ ++ FUNC_ENTER_PACKAGE + + assert(p.minbits > 0); + +@@ -1661,8 +1679,9 @@ H5Z__scaleoffset_decompress_one_atomic(unsigned char *data, size_t data_offset, + begin_i = p.size - 1 - (dtype_len - p.minbits) / 8; + + for (k = (int)begin_i; k >= 0; k--) +- H5Z__scaleoffset_decompress_one_byte(data, data_offset, (unsigned)k, begin_i, buffer, j, buf_len, +- p, dtype_len); ++ if (H5Z__scaleoffset_decompress_one_byte(data, data_offset, (unsigned)k, begin_i, buffer, ++ buf_size, j, bits_to_fill, p, dtype_len)) ++ HGOTO_ERROR(H5E_PLINE, H5E_BADVALUE, 0, "Atomic decompression failed"); + } + else { /* big endian */ + assert(p.mem_order == H5Z_SCALEOFFSET_ORDER_BE); +@@ -1670,67 +1689,81 @@ H5Z__scaleoffset_decompress_one_atomic(unsigned char *data, size_t data_offset, + begin_i = (dtype_len - p.minbits) / 8; + + for (k = (int)begin_i; k <= (int)(p.size - 1); k++) +- H5Z__scaleoffset_decompress_one_byte(data, data_offset, (unsigned)k, begin_i, buffer, j, buf_len, +- p, dtype_len); ++ if (H5Z__scaleoffset_decompress_one_byte(data, data_offset, (unsigned)k, begin_i, buffer, ++ buf_size, j, bits_to_fill, p, dtype_len)) ++ HGOTO_ERROR(H5E_PLINE, H5E_BADVALUE, 0, "Atomic decompression failed"); + } ++ ++done: ++ FUNC_LEAVE_NOAPI(ret_value) + } + +-static void +-H5Z__scaleoffset_decompress(unsigned char *data, unsigned d_nelmts, unsigned char *buffer, parms_atomic p) ++static herr_t ++H5Z__scaleoffset_decompress(unsigned char *data, unsigned d_nelmts, unsigned char *buffer, size_t buf_size, ++ parms_atomic p) + { + /* i: index of data, j: index of buffer, +- buf_len: number of bits to be filled in current byte */ ++ bits_to_fill: number of bits to be filled in current byte */ + size_t i, j; +- unsigned buf_len; ++ unsigned bits_to_fill; ++ herr_t ret_value = SUCCEED; /* Return value */ ++ ++ FUNC_ENTER_PACKAGE + + /* must initialize to zeros */ + for (i = 0; i < d_nelmts * (size_t)p.size; i++) + data[i] = 0; + + /* initialization before the loop */ +- j = 0; +- buf_len = sizeof(unsigned char) * 8; ++ j = 0; ++ bits_to_fill = sizeof(unsigned char) * 8; + + /* decompress */ + for (i = 0; i < d_nelmts; i++) +- H5Z__scaleoffset_decompress_one_atomic(data, i * p.size, buffer, &j, &buf_len, p); ++ if (H5Z__scaleoffset_decompress_one_atomic(data, i * p.size, buffer, buf_size, &j, &bits_to_fill, p)) ++ HGOTO_ERROR(H5E_PLINE, H5E_BADVALUE, 0, "Scaleoffset decompression failed"); ++ ++done: ++ FUNC_LEAVE_NOAPI(ret_value) + } + + static void + H5Z__scaleoffset_compress_one_byte(const unsigned char *data, size_t data_offset, unsigned k, +- unsigned begin_i, unsigned char *buffer, size_t *j, unsigned *buf_len, ++ unsigned begin_i, unsigned char *buffer, size_t *j, unsigned *bits_to_fill, + parms_atomic p, unsigned dtype_len) + { +- unsigned 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 */ ++ unsigned bits_to_copy; /* bits_to_copy is the number of bits to be copied in each data byte */ ++ unsigned char val; /* value to be copied in each data byte */ + + /* initialize value and bits of unsigned char to be copied */ + val = data[data_offset + k]; + if (k == begin_i) +- dat_len = 8 - (dtype_len - p.minbits) % 8; ++ bits_to_copy = 8 - (dtype_len - p.minbits) % 8; + else +- dat_len = 8; ++ bits_to_copy = 8; + +- if (*buf_len > dat_len) { +- buffer[*j] |= (unsigned char)((val & ~((unsigned)(~0) << dat_len)) << (*buf_len - dat_len)); +- *buf_len -= dat_len; ++ if (*bits_to_fill > bits_to_copy) { ++ buffer[*j] |= ++ (unsigned char)((val & ~((unsigned)(~0) << bits_to_copy)) << (*bits_to_fill - bits_to_copy)); ++ *bits_to_fill -= bits_to_copy; + } + else { +- buffer[*j] |= +- (unsigned char)((unsigned)(val >> (dat_len - *buf_len)) & ~((unsigned)(~0) << *buf_len)); +- dat_len -= *buf_len; +- H5Z__scaleoffset_next_byte(j, buf_len); +- if (dat_len == 0) ++ buffer[*j] |= (unsigned char)((unsigned)(val >> (bits_to_copy - *bits_to_fill)) & ++ ~((unsigned)(~0) << *bits_to_fill)); ++ bits_to_copy -= *bits_to_fill; ++ H5Z__scaleoffset_next_byte(j, bits_to_fill); ++ if (bits_to_copy == 0) + return; + +- buffer[*j] = (unsigned char)((val & ~((unsigned)(~0) << dat_len)) << (*buf_len - dat_len)); +- *buf_len -= dat_len; ++ buffer[*j] = ++ (unsigned char)((val & ~((unsigned)(~0) << bits_to_copy)) << (*bits_to_fill - bits_to_copy)); ++ *bits_to_fill -= bits_to_copy; + } /* end else */ + } + + static void + H5Z__scaleoffset_compress_one_atomic(unsigned char *data, size_t data_offset, unsigned char *buffer, +- size_t *j, unsigned *buf_len, parms_atomic p) ++ size_t *j, unsigned *bits_to_fill, parms_atomic p) + { + /* begin_i: the index of byte having first significant bit */ + unsigned begin_i; +@@ -1745,16 +1778,16 @@ H5Z__scaleoffset_compress_one_atomic(unsigned char *data, size_t data_offset, un + begin_i = p.size - 1 - (dtype_len - p.minbits) / 8; + + for (k = (int)begin_i; k >= 0; k--) +- H5Z__scaleoffset_compress_one_byte(data, data_offset, (unsigned)k, begin_i, buffer, j, buf_len, p, +- dtype_len); ++ H5Z__scaleoffset_compress_one_byte(data, data_offset, (unsigned)k, begin_i, buffer, j, ++ bits_to_fill, p, dtype_len); + } + else { /* big endian */ + assert(p.mem_order == H5Z_SCALEOFFSET_ORDER_BE); + begin_i = (dtype_len - p.minbits) / 8; + + for (k = (int)begin_i; k <= (int)(p.size - 1); k++) +- H5Z__scaleoffset_compress_one_byte(data, data_offset, (unsigned)k, begin_i, buffer, j, buf_len, p, +- dtype_len); ++ H5Z__scaleoffset_compress_one_byte(data, data_offset, (unsigned)k, begin_i, buffer, j, ++ bits_to_fill, p, dtype_len); + } + } + +@@ -1763,19 +1796,19 @@ H5Z__scaleoffset_compress(unsigned char *data, unsigned d_nelmts, unsigned char + parms_atomic p) + { + /* i: index of data, j: index of buffer, +- buf_len: number of bits to be filled in current byte */ ++ bits_to_fill: number of bits to be filled in current byte */ + size_t i, j; +- unsigned buf_len; ++ unsigned bits_to_fill; + + /* must initialize buffer to be zeros */ + for (j = 0; j < buffer_size; j++) + buffer[j] = 0; + + /* initialization before the loop */ +- j = 0; +- buf_len = sizeof(unsigned char) * 8; ++ j = 0; ++ bits_to_fill = sizeof(unsigned char) * 8; + + /* compress */ + for (i = 0; i < d_nelmts; i++) +- H5Z__scaleoffset_compress_one_atomic(data, i * p.size, buffer, &j, &buf_len, p); ++ H5Z__scaleoffset_compress_one_atomic(data, i * p.size, buffer, &j, &bits_to_fill, p); + } +-- +2.34.1 + 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 ca1e8d7076..b31a8d8cfa 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 @@ -28,6 +28,7 @@ SRC_URI = " \ file://CVE-2025-2310.patch \ file://CVE-2025-44905.patch \ file://CVE-2025-2309.patch \ + file://CVE-2025-2308.patch \ " SRC_URI[sha256sum] = "019ac451d9e1cf89c0482ba2a06f07a46166caf23f60fea5ef3c37724a318e03"