Skip to content
Permalink
Browse files Browse the repository at this point in the history
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 <rjones@redhat.com>
Fixes: CVE-2021-3622
Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1975489
(cherry picked from commit 781a12c4a49dd81365c9c567c5aa5e19e894ba0e)
  • Loading branch information
rwmjones committed Aug 2, 2021
1 parent bb92eed commit 7717282
Showing 1 changed file with 14 additions and 4 deletions.
18 changes: 14 additions & 4 deletions lib/node.c
Expand Up @@ -203,7 +203,7 @@ hivex_node_classname (hive_h *h, hive_node_h node)

static int _get_children (hive_h *h, hive_node_h blkoff,
offset_list *children, offset_list *blocks,
int flags);
int flags, unsigned depth);
static int check_child_is_nk_block (hive_h *h, hive_node_h child, int flags);

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

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

/* Check the number of children we ended up reading matches
Expand Down Expand Up @@ -383,7 +383,7 @@ _hivex_get_children (hive_h *h, hive_node_h node,
static int
_get_children (hive_h *h, hive_node_h blkoff,
offset_list *children, offset_list *blocks,
int flags)
int flags, unsigned depth)
{
/* Add this intermediate block. */
if (_hivex_add_to_offset_list (blocks, blkoff) == -1)
Expand Down Expand Up @@ -486,7 +486,17 @@ _get_children (hive_h *h, hive_node_h blkoff,
}
}

if (_get_children (h, offset, children, blocks, flags) == -1)
/* Although in theory hive ri records might be nested to any
* depth, in practice this is unlikely. Recursing here caused
* CVE-2021-3622. Thus limit the depth we will recurse to
* something small.
*/
if (depth >= 32) {
SET_ERRNO (EINVAL, "ri-record nested to depth >= %u", depth);
return -1;
}

if (_get_children (h, offset, children, blocks, flags, depth+1) == -1)
return -1;
}
}
Expand Down

0 comments on commit 7717282

Please sign in to comment.