Blame SOURCES/0001-lib-node.c-Limit-recursion-in-ri-records-CVE-2021-36.patch

d05035
From 771728218dac2fbf6997a7e53225e75a4c6b7255 Mon Sep 17 00:00:00 2001
d05035
From: "Richard W.M. Jones" <rjones@redhat.com>
d05035
Date: Thu, 8 Jul 2021 19:00:45 +0100
d05035
Subject: [PATCH] lib/node.c: Limit recursion in ri-records (CVE-2021-3622)
d05035
d05035
Windows Registry hive "ri"-records are arbitrarily nested B-tree-like
d05035
structures:
d05035
d05035
  +-------------+
d05035
  | ri          |
d05035
  |-------------|
d05035
  | nr_offsets  |
d05035
  |   offset[0] ------>  points to another lf/lh/li/ri block
d05035
  |   offset[1] ------>
d05035
  |   offset[2] ------>
d05035
  +-------------+
d05035
d05035
It is possible to construct a hive with a very deeply nested tree of
d05035
ri-records, causing the internal _get_children function to recurse to
d05035
any depth which can cause programs linked to hivex to crash with a
d05035
stack overflow.
d05035
d05035
Since it is not thought that deeply nested ri-records occur in real
d05035
hives, limit recursion depth.  If you hit this limit you will see the
d05035
following error and the operation will return an error instead of
d05035
crashing:
d05035
d05035
  \> ls
d05035
  hivex: _get_children: returning EINVAL because: ri-record nested to depth >= 32
d05035
  ls: Invalid argument
d05035
d05035
Thanks to Jeremy Galindo for finding and reporting this bug.
d05035
d05035
Reported-by: Jeremy Galindo, Sr Security Engineer, Datto.com
d05035
Signed-off-by: Richard W.M. Jones <rjones@redhat.com>
d05035
Fixes: CVE-2021-3622
d05035
Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1975489
d05035
(cherry picked from commit 781a12c4a49dd81365c9c567c5aa5e19e894ba0e)
d05035
---
d05035
 lib/node.c | 18 ++++++++++++++----
d05035
 1 file changed, 14 insertions(+), 4 deletions(-)
d05035
d05035
diff --git a/lib/node.c b/lib/node.c
d05035
index 7b002a46..eb7fe93c 100644
d05035
--- a/lib/node.c
d05035
+++ b/lib/node.c
d05035
@@ -203,7 +203,7 @@ hivex_node_classname (hive_h *h, hive_node_h node)
d05035
 
d05035
 static int _get_children (hive_h *h, hive_node_h blkoff,
d05035
                           offset_list *children, offset_list *blocks,
d05035
-                          int flags);
d05035
+                          int flags, unsigned depth);
d05035
 static int check_child_is_nk_block (hive_h *h, hive_node_h child, int flags);
d05035
 
d05035
 /* Iterate over children (ie. subkeys of a node), returning child
d05035
@@ -335,7 +335,7 @@ _hivex_get_children (hive_h *h, hive_node_h node,
d05035
     goto error;
d05035
   }
d05035
 
d05035
-  if (_get_children (h, subkey_lf, &children, &blocks, flags) == -1)
d05035
+  if (_get_children (h, subkey_lf, &children, &blocks, flags, 0) == -1)
d05035
     goto error;
d05035
 
d05035
   /* Check the number of children we ended up reading matches
d05035
@@ -383,7 +383,7 @@ _hivex_get_children (hive_h *h, hive_node_h node,
d05035
 static int
d05035
 _get_children (hive_h *h, hive_node_h blkoff,
d05035
                offset_list *children, offset_list *blocks,
d05035
-               int flags)
d05035
+               int flags, unsigned depth)
d05035
 {
d05035
   /* Add this intermediate block. */
d05035
   if (_hivex_add_to_offset_list (blocks, blkoff) == -1)
d05035
@@ -486,7 +486,17 @@ _get_children (hive_h *h, hive_node_h blkoff,
d05035
         }
d05035
       }
d05035
 
d05035
-      if (_get_children (h, offset, children, blocks, flags) == -1)
d05035
+      /* Although in theory hive ri records might be nested to any
d05035
+       * depth, in practice this is unlikely.  Recursing here caused
d05035
+       * CVE-2021-3622.  Thus limit the depth we will recurse to
d05035
+       * something small.
d05035
+       */
d05035
+      if (depth >= 32) {
d05035
+        SET_ERRNO (EINVAL, "ri-record nested to depth >= %u", depth);
d05035
+        return -1;
d05035
+      }
d05035
+
d05035
+      if (_get_children (h, offset, children, blocks, flags, depth+1) == -1)
d05035
         return -1;
d05035
     }
d05035
   }
d05035
-- 
d05035
2.32.0
d05035