diff --git a/src/H5B.c b/src/H5B.c index 9969e08b0c9..d87f8828074 100644 --- a/src/H5B.c +++ b/src/H5B.c @@ -309,6 +309,7 @@ H5B_find(H5F_t *f, const H5B_class_t *type, haddr_t addr, bool *found, void *uda cache_udata.f = f; cache_udata.type = type; cache_udata.rc_shared = rc_shared; + cache_udata.exp_level = H5B_UNKNOWN_NODELEVEL; if (NULL == (bt = (H5B_t *)H5AC_protect(f, H5AC_BT, addr, &cache_udata, H5AC__READ_ONLY_FLAG))) HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to load B-tree node"); @@ -428,6 +429,7 @@ H5B__split(H5F_t *f, H5B_ins_ud_t *bt_ud, unsigned idx, void *udata, H5B_ins_ud_ cache_udata.f = f; cache_udata.type = shared->type; cache_udata.rc_shared = bt_ud->bt->rc_shared; + cache_udata.exp_level = H5B_UNKNOWN_NODELEVEL; if (NULL == (split_bt_ud->bt = (H5B_t *)H5AC_protect(f, H5AC_BT, split_bt_ud->addr, &cache_udata, H5AC__NO_FLAGS_SET))) HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree"); @@ -535,6 +537,7 @@ H5B_insert(H5F_t *f, const H5B_class_t *type, haddr_t addr, void *udata) cache_udata.f = f; cache_udata.type = type; cache_udata.rc_shared = rc_shared; + cache_udata.exp_level = H5B_UNKNOWN_NODELEVEL; bt_ud.addr = addr; if (NULL == (bt_ud.bt = (H5B_t *)H5AC_protect(f, H5AC_BT, addr, &cache_udata, H5AC__NO_FLAGS_SET))) HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to locate root of B-tree"); @@ -792,6 +795,7 @@ H5B__insert_helper(H5F_t *f, H5B_ins_ud_t *bt_ud, const H5B_class_t *type, uint8 cache_udata.f = f; cache_udata.type = type; cache_udata.rc_shared = rc_shared; + cache_udata.exp_level = H5B_UNKNOWN_NODELEVEL; if (0 == bt->nchildren) { /* @@ -1048,7 +1052,8 @@ H5B__insert_helper(H5F_t *f, H5B_ins_ud_t *bt_ud, const H5B_class_t *type, uint8 *------------------------------------------------------------------------- */ static herr_t -H5B__iterate_helper(H5F_t *f, const H5B_class_t *type, haddr_t addr, H5B_operator_t op, void *udata) +H5B__iterate_helper(H5F_t *f, const H5B_class_t *type, haddr_t addr, int exp_level, H5B_operator_t op, + void *udata) { H5B_t *bt = NULL; /* Pointer to current B-tree node */ H5UC_t *rc_shared; /* Ref-counted shared info */ @@ -1078,13 +1083,14 @@ H5B__iterate_helper(H5F_t *f, const H5B_class_t *type, haddr_t addr, H5B_operato cache_udata.f = f; cache_udata.type = type; cache_udata.rc_shared = rc_shared; + cache_udata.exp_level = exp_level; if (NULL == (bt = (H5B_t *)H5AC_protect(f, H5AC_BT, addr, &cache_udata, H5AC__READ_ONLY_FLAG))) HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, H5_ITER_ERROR, "unable to load B-tree node"); /* Iterate over node's children */ for (u = 0; u < bt->nchildren && ret_value == H5_ITER_CONT; u++) { if (bt->level > 0) - ret_value = H5B__iterate_helper(f, type, bt->child[u], op, udata); + ret_value = H5B__iterate_helper(f, type, bt->child[u], (int)(bt->level - 1), op, udata); else ret_value = (*op)(f, H5B_NKEY(bt, shared, u), bt->child[u], H5B_NKEY(bt, shared, u + 1), udata); if (ret_value < 0) @@ -1125,7 +1131,7 @@ H5B_iterate(H5F_t *f, const H5B_class_t *type, haddr_t addr, H5B_operator_t op, assert(udata); /* Iterate over the B-tree records */ - if ((ret_value = H5B__iterate_helper(f, type, addr, op, udata)) < 0) + if ((ret_value = H5B__iterate_helper(f, type, addr, H5B_UNKNOWN_NODELEVEL, op, udata)) < 0) HERROR(H5E_BTREE, H5E_BADITER, "B-tree iteration failed"); FUNC_LEAVE_NOAPI(ret_value) @@ -1191,6 +1197,7 @@ H5B__remove_helper(H5F_t *f, haddr_t addr, const H5B_class_t *type, int level, u cache_udata.f = f; cache_udata.type = type; cache_udata.rc_shared = rc_shared; + cache_udata.exp_level = H5B_UNKNOWN_NODELEVEL; if (NULL == (bt = (H5B_t *)H5AC_protect(f, H5AC_BT, addr, &cache_udata, H5AC__NO_FLAGS_SET))) HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, H5B_INS_ERROR, "unable to load B-tree node"); @@ -1543,6 +1550,7 @@ H5B_delete(H5F_t *f, const H5B_class_t *type, haddr_t addr, void *udata) cache_udata.f = f; cache_udata.type = type; cache_udata.rc_shared = rc_shared; + cache_udata.exp_level = H5B_UNKNOWN_NODELEVEL; if (NULL == (bt = (H5B_t *)H5AC_protect(f, H5AC_BT, addr, &cache_udata, H5AC__NO_FLAGS_SET))) HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to load B-tree node"); @@ -1783,6 +1791,7 @@ H5B__get_info_helper(H5F_t *f, const H5B_class_t *type, haddr_t addr, const H5B_ cache_udata.f = f; cache_udata.type = type; cache_udata.rc_shared = rc_shared; + cache_udata.exp_level = H5B_UNKNOWN_NODELEVEL; if (NULL == (bt = (H5B_t *)H5AC_protect(f, H5AC_BT, addr, &cache_udata, H5AC__READ_ONLY_FLAG))) HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to load B-tree node"); @@ -1878,7 +1887,7 @@ H5B_get_info(H5F_t *f, const H5B_class_t *type, haddr_t addr, H5B_info_t *bt_inf /* Iterate over the B-tree records, making any "leaf" callbacks */ /* (Only if operator defined) */ if (op) - if ((ret_value = H5B__iterate_helper(f, type, addr, op, udata)) < 0) + if ((ret_value = H5B__iterate_helper(f, type, addr, H5B_UNKNOWN_NODELEVEL, op, udata)) < 0) HERROR(H5E_BTREE, H5E_BADITER, "B-tree iteration failed"); done: @@ -1924,6 +1933,7 @@ H5B_valid(H5F_t *f, const H5B_class_t *type, haddr_t addr) cache_udata.f = f; cache_udata.type = type; cache_udata.rc_shared = rc_shared; + cache_udata.exp_level = H5B_UNKNOWN_NODELEVEL; if (NULL == (bt = (H5B_t *)H5AC_protect(f, H5AC_BT, addr, &cache_udata, H5AC__READ_ONLY_FLAG))) HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree node"); diff --git a/src/H5Bcache.c b/src/H5Bcache.c index 8d3655dadff..a832425c78b 100644 --- a/src/H5Bcache.c +++ b/src/H5Bcache.c @@ -170,6 +170,11 @@ H5B__cache_deserialize(const void *_image, size_t len, void *_udata, bool H5_ATT HGOTO_ERROR(H5E_BTREE, H5E_CANTLOAD, NULL, "incorrect B-tree node type"); bt->level = *image++; + /* Check in case of level is corrupted, if expected level is known */ + if (udata->exp_level != H5B_UNKNOWN_NODELEVEL) + if (bt->level != (unsigned)udata->exp_level) + HGOTO_ERROR(H5E_BTREE, H5E_BADVALUE, NULL, "level is not as expected, possibly corrupted"); + /* Entries used */ if (H5_IS_BUFFER_OVERFLOW(image, 2, p_end)) HGOTO_ERROR(H5E_BTREE, H5E_OVERFLOW, NULL, "ran off end of input buffer while decoding"); @@ -179,12 +184,6 @@ H5B__cache_deserialize(const void *_image, size_t len, void *_udata, bool H5_ATT if (bt->nchildren > shared->two_k) HGOTO_ERROR(H5E_BTREE, H5E_BADVALUE, NULL, "number of children is greater than maximum"); - /* Check in case of level is corrupted, it is unreasonable for level to be - larger than the number of entries */ - if (bt->level > bt->nchildren) - HGOTO_ERROR(H5E_BTREE, H5E_BADVALUE, NULL, - "level cannot be greater than the number of children, possibly corrupted"); - /* Sibling pointers */ if (H5_IS_BUFFER_OVERFLOW(image, H5F_sizeof_addr(udata->f), p_end)) HGOTO_ERROR(H5E_BTREE, H5E_OVERFLOW, NULL, "ran off end of input buffer while decoding"); diff --git a/src/H5Bpkg.h b/src/H5Bpkg.h index 4f61614a9e0..b56a6f3a7e9 100644 --- a/src/H5Bpkg.h +++ b/src/H5Bpkg.h @@ -39,6 +39,11 @@ /* # of bits for node level: 1 byte */ #define LEVEL_BITS 8 +/* Indicates that the level of the current node is unknown. When the level + * is known, it can be used to detect corrupted level during decoding + */ +#define H5B_UNKNOWN_NODELEVEL -1 + /****************************/ /* Package Private Typedefs */ /****************************/ @@ -60,6 +65,7 @@ typedef struct H5B_t { typedef struct H5B_cache_ud_t { H5F_t *f; /* File that B-tree node is within */ const struct H5B_class_t *type; /* Type of tree */ + int exp_level; /* Expected level of the current node */ H5UC_t *rc_shared; /* Ref-counted shared info */ } H5B_cache_ud_t;