Skip to content

Commit 5bdd379

Browse files
authored
Fix segfault in h5dump caused by corrupted btree node level (#5002)
Added another argument, expected node level, to H5B__iterate_helper to pass down to H5B__cache_deserialize for checking the decoded node level. When this expected level is not known, the new macro H5_UNKNOWN_NODELEVEL (-1) will be used for not checking the level. Fixes GH-4432
1 parent f4dbb81 commit 5bdd379

File tree

3 files changed

+25
-10
lines changed

3 files changed

+25
-10
lines changed

src/H5B.c

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -309,6 +309,7 @@ H5B_find(H5F_t *f, const H5B_class_t *type, haddr_t addr, bool *found, void *uda
309309
cache_udata.f = f;
310310
cache_udata.type = type;
311311
cache_udata.rc_shared = rc_shared;
312+
cache_udata.exp_level = H5B_UNKNOWN_NODELEVEL;
312313
if (NULL == (bt = (H5B_t *)H5AC_protect(f, H5AC_BT, addr, &cache_udata, H5AC__READ_ONLY_FLAG)))
313314
HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to load B-tree node");
314315

@@ -428,6 +429,7 @@ H5B__split(H5F_t *f, H5B_ins_ud_t *bt_ud, unsigned idx, void *udata, H5B_ins_ud_
428429
cache_udata.f = f;
429430
cache_udata.type = shared->type;
430431
cache_udata.rc_shared = bt_ud->bt->rc_shared;
432+
cache_udata.exp_level = H5B_UNKNOWN_NODELEVEL;
431433
if (NULL == (split_bt_ud->bt =
432434
(H5B_t *)H5AC_protect(f, H5AC_BT, split_bt_ud->addr, &cache_udata, H5AC__NO_FLAGS_SET)))
433435
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)
535537
cache_udata.f = f;
536538
cache_udata.type = type;
537539
cache_udata.rc_shared = rc_shared;
540+
cache_udata.exp_level = H5B_UNKNOWN_NODELEVEL;
538541
bt_ud.addr = addr;
539542
if (NULL == (bt_ud.bt = (H5B_t *)H5AC_protect(f, H5AC_BT, addr, &cache_udata, H5AC__NO_FLAGS_SET)))
540543
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
792795
cache_udata.f = f;
793796
cache_udata.type = type;
794797
cache_udata.rc_shared = rc_shared;
798+
cache_udata.exp_level = H5B_UNKNOWN_NODELEVEL;
795799

796800
if (0 == bt->nchildren) {
797801
/*
@@ -1048,7 +1052,8 @@ H5B__insert_helper(H5F_t *f, H5B_ins_ud_t *bt_ud, const H5B_class_t *type, uint8
10481052
*-------------------------------------------------------------------------
10491053
*/
10501054
static herr_t
1051-
H5B__iterate_helper(H5F_t *f, const H5B_class_t *type, haddr_t addr, H5B_operator_t op, void *udata)
1055+
H5B__iterate_helper(H5F_t *f, const H5B_class_t *type, haddr_t addr, int exp_level, H5B_operator_t op,
1056+
void *udata)
10521057
{
10531058
H5B_t *bt = NULL; /* Pointer to current B-tree node */
10541059
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
10781083
cache_udata.f = f;
10791084
cache_udata.type = type;
10801085
cache_udata.rc_shared = rc_shared;
1086+
cache_udata.exp_level = exp_level;
10811087
if (NULL == (bt = (H5B_t *)H5AC_protect(f, H5AC_BT, addr, &cache_udata, H5AC__READ_ONLY_FLAG)))
10821088
HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, H5_ITER_ERROR, "unable to load B-tree node");
10831089

10841090
/* Iterate over node's children */
10851091
for (u = 0; u < bt->nchildren && ret_value == H5_ITER_CONT; u++) {
10861092
if (bt->level > 0)
1087-
ret_value = H5B__iterate_helper(f, type, bt->child[u], op, udata);
1093+
ret_value = H5B__iterate_helper(f, type, bt->child[u], (int)(bt->level - 1), op, udata);
10881094
else
10891095
ret_value = (*op)(f, H5B_NKEY(bt, shared, u), bt->child[u], H5B_NKEY(bt, shared, u + 1), udata);
10901096
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,
11251131
assert(udata);
11261132

11271133
/* Iterate over the B-tree records */
1128-
if ((ret_value = H5B__iterate_helper(f, type, addr, op, udata)) < 0)
1134+
if ((ret_value = H5B__iterate_helper(f, type, addr, H5B_UNKNOWN_NODELEVEL, op, udata)) < 0)
11291135
HERROR(H5E_BTREE, H5E_BADITER, "B-tree iteration failed");
11301136

11311137
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
11911197
cache_udata.f = f;
11921198
cache_udata.type = type;
11931199
cache_udata.rc_shared = rc_shared;
1200+
cache_udata.exp_level = H5B_UNKNOWN_NODELEVEL;
11941201
if (NULL == (bt = (H5B_t *)H5AC_protect(f, H5AC_BT, addr, &cache_udata, H5AC__NO_FLAGS_SET)))
11951202
HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, H5B_INS_ERROR, "unable to load B-tree node");
11961203

@@ -1543,6 +1550,7 @@ H5B_delete(H5F_t *f, const H5B_class_t *type, haddr_t addr, void *udata)
15431550
cache_udata.f = f;
15441551
cache_udata.type = type;
15451552
cache_udata.rc_shared = rc_shared;
1553+
cache_udata.exp_level = H5B_UNKNOWN_NODELEVEL;
15461554
if (NULL == (bt = (H5B_t *)H5AC_protect(f, H5AC_BT, addr, &cache_udata, H5AC__NO_FLAGS_SET)))
15471555
HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to load B-tree node");
15481556

@@ -1783,6 +1791,7 @@ H5B__get_info_helper(H5F_t *f, const H5B_class_t *type, haddr_t addr, const H5B_
17831791
cache_udata.f = f;
17841792
cache_udata.type = type;
17851793
cache_udata.rc_shared = rc_shared;
1794+
cache_udata.exp_level = H5B_UNKNOWN_NODELEVEL;
17861795
if (NULL == (bt = (H5B_t *)H5AC_protect(f, H5AC_BT, addr, &cache_udata, H5AC__READ_ONLY_FLAG)))
17871796
HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to load B-tree node");
17881797

@@ -1878,7 +1887,7 @@ H5B_get_info(H5F_t *f, const H5B_class_t *type, haddr_t addr, H5B_info_t *bt_inf
18781887
/* Iterate over the B-tree records, making any "leaf" callbacks */
18791888
/* (Only if operator defined) */
18801889
if (op)
1881-
if ((ret_value = H5B__iterate_helper(f, type, addr, op, udata)) < 0)
1890+
if ((ret_value = H5B__iterate_helper(f, type, addr, H5B_UNKNOWN_NODELEVEL, op, udata)) < 0)
18821891
HERROR(H5E_BTREE, H5E_BADITER, "B-tree iteration failed");
18831892

18841893
done:
@@ -1924,6 +1933,7 @@ H5B_valid(H5F_t *f, const H5B_class_t *type, haddr_t addr)
19241933
cache_udata.f = f;
19251934
cache_udata.type = type;
19261935
cache_udata.rc_shared = rc_shared;
1936+
cache_udata.exp_level = H5B_UNKNOWN_NODELEVEL;
19271937
if (NULL == (bt = (H5B_t *)H5AC_protect(f, H5AC_BT, addr, &cache_udata, H5AC__READ_ONLY_FLAG)))
19281938
HGOTO_ERROR(H5E_BTREE, H5E_CANTPROTECT, FAIL, "unable to protect B-tree node");
19291939

src/H5Bcache.c

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,11 @@ H5B__cache_deserialize(const void *_image, size_t len, void *_udata, bool H5_ATT
170170
HGOTO_ERROR(H5E_BTREE, H5E_CANTLOAD, NULL, "incorrect B-tree node type");
171171
bt->level = *image++;
172172

173+
/* Check in case of level is corrupted, if expected level is known */
174+
if (udata->exp_level != H5B_UNKNOWN_NODELEVEL)
175+
if (bt->level != (unsigned)udata->exp_level)
176+
HGOTO_ERROR(H5E_BTREE, H5E_BADVALUE, NULL, "level is not as expected, possibly corrupted");
177+
173178
/* Entries used */
174179
if (H5_IS_BUFFER_OVERFLOW(image, 2, p_end))
175180
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
179184
if (bt->nchildren > shared->two_k)
180185
HGOTO_ERROR(H5E_BTREE, H5E_BADVALUE, NULL, "number of children is greater than maximum");
181186

182-
/* Check in case of level is corrupted, it is unreasonable for level to be
183-
larger than the number of entries */
184-
if (bt->level > bt->nchildren)
185-
HGOTO_ERROR(H5E_BTREE, H5E_BADVALUE, NULL,
186-
"level cannot be greater than the number of children, possibly corrupted");
187-
188187
/* Sibling pointers */
189188
if (H5_IS_BUFFER_OVERFLOW(image, H5F_sizeof_addr(udata->f), p_end))
190189
HGOTO_ERROR(H5E_BTREE, H5E_OVERFLOW, NULL, "ran off end of input buffer while decoding");

src/H5Bpkg.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,11 @@
3939
/* # of bits for node level: 1 byte */
4040
#define LEVEL_BITS 8
4141

42+
/* Indicates that the level of the current node is unknown. When the level
43+
* is known, it can be used to detect corrupted level during decoding
44+
*/
45+
#define H5B_UNKNOWN_NODELEVEL -1
46+
4247
/****************************/
4348
/* Package Private Typedefs */
4449
/****************************/
@@ -60,6 +65,7 @@ typedef struct H5B_t {
6065
typedef struct H5B_cache_ud_t {
6166
H5F_t *f; /* File that B-tree node is within */
6267
const struct H5B_class_t *type; /* Type of tree */
68+
int exp_level; /* Expected level of the current node */
6369
H5UC_t *rc_shared; /* Ref-counted shared info */
6470
} H5B_cache_ud_t;
6571

0 commit comments

Comments
 (0)