Skip to content

Commit a8ceb1d

Browse files
Add additional checks for v1 B-tree corruption
1 parent fe8de45 commit a8ceb1d

File tree

2 files changed

+74
-15
lines changed

2 files changed

+74
-15
lines changed

release_docs/CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -454,6 +454,12 @@ HDF5 release, platforms tested, and known problems in this release.
454454
# 🪲 Bug Fixes
455455
456456
## Library
457+
- Fixed security issue CVE-2025-6857
458+
459+
An HDF5 file had a corrupted v1 B-tree that would result in a stack overflow when performing a lookup on it. This has been fixed with additional integrity checks.
460+
461+
Fixes GitHub issue #5575
462+
457463
- Check for overflow in decoded heap block addresses
458464
459465
Currently, we do not check for overflow when decoding addresses from the heap, which can cause overflow problems. We've added a check in H5HL__fl_deserialize to ensure no overflow can occur.

src/H5B.c

Lines changed: 68 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,8 @@ typedef struct H5B_ins_ud_t {
140140
/********************/
141141
/* Local Prototypes */
142142
/********************/
143+
static herr_t H5B_find_helper(H5F_t *f, const H5B_class_t *type, haddr_t addr, int exp_level, bool *found,
144+
void *udata);
143145
static H5B_ins_t H5B__insert_helper(H5F_t *f, H5B_ins_ud_t *bt_ud, const H5B_class_t *type, uint8_t *lt_key,
144146
bool *lt_key_changed, uint8_t *md_key, void *udata, uint8_t *rt_key,
145147
bool *rt_key_changed, H5B_ins_ud_t *split_bt_ud /*out*/);
@@ -255,26 +257,67 @@ H5B_create(H5F_t *f, const H5B_class_t *type, void *udata, haddr_t *addr_p /*out
255257
} /* end H5B_create() */
256258

257259
/*-------------------------------------------------------------------------
258-
* Function: H5B_find
260+
* Function: H5B_find
259261
*
260-
* Purpose: Locate the specified information in a B-tree and return
261-
* that information by filling in fields of the caller-supplied
262-
* UDATA pointer depending on the type of leaf node
263-
* requested. The UDATA can point to additional data passed
264-
* to the key comparison function.
262+
* Purpose: Locate the specified information in a B-tree and return
263+
* that information by filling in fields of the
264+
* caller-supplied UDATA pointer depending on the type of leaf
265+
* node requested. The UDATA can point to additional data
266+
* passed to the key comparison function.
265267
*
266-
* Note: This function does not follow the left/right sibling
267-
* pointers since it assumes that all nodes can be reached
268-
* from the parent node.
268+
* Note: This function does not follow the left/right sibling
269+
* pointers since it assumes that all nodes can be reached
270+
* from the parent node.
269271
*
270-
* Return: Non-negative (true/false) on success (if found, values returned
271-
* through the UDATA argument). Negative on failure (if not found,
272-
* UDATA is undefined).
272+
* Return: Non-negative (true/false) on success (if found, values
273+
* returned through the UDATA argument). Negative on failure
274+
* (if not found, UDATA is undefined).
273275
*
274276
*-------------------------------------------------------------------------
275277
*/
276278
herr_t
277279
H5B_find(H5F_t *f, const H5B_class_t *type, haddr_t addr, bool *found, void *udata)
280+
{
281+
herr_t ret_value = SUCCEED;
282+
283+
FUNC_ENTER_NOAPI(FAIL)
284+
285+
/*
286+
* Check arguments.
287+
*/
288+
assert(f);
289+
assert(type);
290+
assert(type->decode);
291+
assert(type->cmp3);
292+
assert(type->found);
293+
assert(H5_addr_defined(addr));
294+
295+
if ((ret_value = H5B_find_helper(f, type, addr, H5B_UNKNOWN_NODELEVEL, found, udata)) < 0)
296+
HGOTO_ERROR(H5E_BTREE, H5E_NOTFOUND, FAIL, "can't lookup key");
297+
298+
done:
299+
FUNC_LEAVE_NOAPI(ret_value)
300+
} /* end H5B_find() */
301+
302+
/*-------------------------------------------------------------------------
303+
* Function: H5B_find_helper
304+
*
305+
* Purpose: Recursive helper routine for H5B_find used to track node
306+
* levels and attempt to detect B-tree corruption during
307+
* lookups.
308+
*
309+
* Note: This function does not follow the left/right sibling
310+
* pointers since it assumes that all nodes can be reached
311+
* from the parent node.
312+
*
313+
* Return: Non-negative on success (if found, values returned through
314+
* the UDATA argument). Negative on failure (if not found,
315+
* UDATA is undefined).
316+
*
317+
*-------------------------------------------------------------------------
318+
*/
319+
static herr_t
320+
H5B_find_helper(H5F_t *f, const H5B_class_t *type, haddr_t addr, int exp_level, bool *found, void *udata)
278321
{
279322
H5B_t *bt = NULL;
280323
H5UC_t *rc_shared; /* Ref-counted shared info */
@@ -309,7 +352,7 @@ H5B_find(H5F_t *f, const H5B_class_t *type, haddr_t addr, bool *found, void *uda
309352
cache_udata.f = f;
310353
cache_udata.type = type;
311354
cache_udata.rc_shared = rc_shared;
312-
cache_udata.exp_level = H5B_UNKNOWN_NODELEVEL;
355+
cache_udata.exp_level = exp_level;
313356
if (NULL == (bt = (H5B_t *)H5AC_protect(f, H5AC_BT, addr, &cache_udata, H5AC__READ_ONLY_FLAG)))
314357
HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to load B-tree node");
315358

@@ -333,7 +376,17 @@ H5B_find(H5F_t *f, const H5B_class_t *type, haddr_t addr, bool *found, void *uda
333376
assert(idx < bt->nchildren);
334377

335378
if (bt->level > 0) {
336-
if ((ret_value = H5B_find(f, type, bt->child[idx], found, udata)) < 0)
379+
/* Sanity check to catch the case where the current node points to
380+
* itself and the current node was loaded with an expected node level
381+
* of H5B_UNKNOWN_NODELEVEL, thus bypassing the expected node level
382+
* check during deserialization and in the future if the node was
383+
* cached.
384+
*/
385+
if (bt->child[idx] == addr)
386+
HGOTO_ERROR(H5E_BTREE, H5E_BADVALUE, FAIL, "cyclic B-tree detected");
387+
388+
if ((ret_value = H5B_find_helper(f, type, bt->child[idx], (int)(bt->level - 1), found, udata)) <
389+
0)
337390
HGOTO_ERROR(H5E_BTREE, H5E_NOTFOUND, FAIL, "can't lookup key in subtree");
338391
} /* end if */
339392
else {
@@ -347,7 +400,7 @@ H5B_find(H5F_t *f, const H5B_class_t *type, haddr_t addr, bool *found, void *uda
347400
HDONE_ERROR(H5E_BTREE, H5E_CANTUNPROTECT, FAIL, "unable to release node");
348401

349402
FUNC_LEAVE_NOAPI(ret_value)
350-
} /* end H5B_find() */
403+
} /* end H5B_find_helper() */
351404

352405
/*-------------------------------------------------------------------------
353406
* Function: H5B__split

0 commit comments

Comments
 (0)