Skip to content

Commit 7717282

Browse files
committed
lib/node.c: Limit recursion in ri-records (CVE-2021-3622)
Windows Registry hive "ri"-records are arbitrarily nested B-tree-like structures: +-------------+ | ri | |-------------| | nr_offsets | | offset[0] ------> points to another lf/lh/li/ri block | offset[1] ------> | offset[2] ------> +-------------+ It is possible to construct a hive with a very deeply nested tree of ri-records, causing the internal _get_children function to recurse to any depth which can cause programs linked to hivex to crash with a stack overflow. Since it is not thought that deeply nested ri-records occur in real hives, limit recursion depth. If you hit this limit you will see the following error and the operation will return an error instead of crashing: \> ls hivex: _get_children: returning EINVAL because: ri-record nested to depth >= 32 ls: Invalid argument Thanks to Jeremy Galindo for finding and reporting this bug. Reported-by: Jeremy Galindo, Sr Security Engineer, Datto.com Signed-off-by: Richard W.M. Jones <[email protected]> Fixes: CVE-2021-3622 Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1975489 (cherry picked from commit 781a12c4a49dd81365c9c567c5aa5e19e894ba0e)
1 parent bb92eed commit 7717282

File tree

1 file changed

+14
-4
lines changed

1 file changed

+14
-4
lines changed

lib/node.c

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,7 @@ hivex_node_classname (hive_h *h, hive_node_h node)
203203

204204
static int _get_children (hive_h *h, hive_node_h blkoff,
205205
offset_list *children, offset_list *blocks,
206-
int flags);
206+
int flags, unsigned depth);
207207
static int check_child_is_nk_block (hive_h *h, hive_node_h child, int flags);
208208

209209
/* Iterate over children (ie. subkeys of a node), returning child
@@ -335,7 +335,7 @@ _hivex_get_children (hive_h *h, hive_node_h node,
335335
goto error;
336336
}
337337

338-
if (_get_children (h, subkey_lf, &children, &blocks, flags) == -1)
338+
if (_get_children (h, subkey_lf, &children, &blocks, flags, 0) == -1)
339339
goto error;
340340

341341
/* Check the number of children we ended up reading matches
@@ -383,7 +383,7 @@ _hivex_get_children (hive_h *h, hive_node_h node,
383383
static int
384384
_get_children (hive_h *h, hive_node_h blkoff,
385385
offset_list *children, offset_list *blocks,
386-
int flags)
386+
int flags, unsigned depth)
387387
{
388388
/* Add this intermediate block. */
389389
if (_hivex_add_to_offset_list (blocks, blkoff) == -1)
@@ -486,7 +486,17 @@ _get_children (hive_h *h, hive_node_h blkoff,
486486
}
487487
}
488488

489-
if (_get_children (h, offset, children, blocks, flags) == -1)
489+
/* Although in theory hive ri records might be nested to any
490+
* depth, in practice this is unlikely. Recursing here caused
491+
* CVE-2021-3622. Thus limit the depth we will recurse to
492+
* something small.
493+
*/
494+
if (depth >= 32) {
495+
SET_ERRNO (EINVAL, "ri-record nested to depth >= %u", depth);
496+
return -1;
497+
}
498+
499+
if (_get_children (h, offset, children, blocks, flags, depth+1) == -1)
490500
return -1;
491501
}
492502
}

0 commit comments

Comments
 (0)