Blame SOURCES/0010-lib-allow-to-walk-registry-with-corrupted-blocks.patch

c1e277
From 8e187357f466c31a9e75ac4924b32bbf4823e73f Mon Sep 17 00:00:00 2001
c1e277
From: Dawid Zamirski <dzamirski@datto.com>
c1e277
Date: Thu, 16 Feb 2017 18:17:24 -0500
c1e277
Subject: [PATCH 10/12] lib: allow to walk registry with corrupted blocks
c1e277
c1e277
Only when HIVEX_OPEN_UNSAFE flag is set.
c1e277
c1e277
There are some corrupted registry files that have invalid hbin cells
c1e277
but are still readable. This patch makes the following changes:
c1e277
c1e277
* hivex_open - do not abort with complete failure if we run across a
c1e277
  block with invalid size (unless it's the root block). Instead just
c1e277
  log the event, and move on. This will allow open hives that have
c1e277
  apparent invalid blocks but the ones of potential interest might be
c1e277
  perfectly accessible.
c1e277
* _hivex_get_children - similiarly, if the's invalid subkey, just skip
c1e277
  it instead of failing so one can continue to browse other valid
c1e277
  subkeys.
c1e277
c1e277
The above is similar to the behavior to Windows regedit where one can
c1e277
load such corrupted hives with e.g. "reg load HKU\Corrupted" and
c1e277
browse/change it despite some keys might be missing.
c1e277
c1e277
(cherry picked from commit 5345ec8f1df304dc93a6b1e4cbb40e7c1cf6f88d)
c1e277
---
c1e277
 lib/handle.c | 16 ++++++++++++----
c1e277
 lib/node.c   | 46 +++++++++++++++++++++++++++++++++++-----------
c1e277
 2 files changed, 47 insertions(+), 15 deletions(-)
c1e277
c1e277
diff --git a/lib/handle.c b/lib/handle.c
c1e277
index 8c64b6d..0d2b24b 100644
c1e277
--- a/lib/handle.c
c1e277
+++ b/lib/handle.c
c1e277
@@ -313,10 +313,18 @@ hivex_open (const char *filename, int flags)
c1e277
       int used;
c1e277
       seg_len = block_len (h, blkoff, &used);
c1e277
       if (seg_len <= 4 || (seg_len & 3) != 0) {
c1e277
-        SET_ERRNO (ENOTSUP,
c1e277
-                   "%s: block size %" PRIu32 " at 0x%zx, bad registry",
c1e277
-                   filename, le32toh (block->seg_len), blkoff);
c1e277
-        goto error;
c1e277
+        if (is_root || !h->unsafe) {
c1e277
+          SET_ERRNO (ENOTSUP,
c1e277
+                     "%s, the block at 0x%zx has invalid size %" PRIi32
c1e277
+                     ", bad registry",
c1e277
+                     filename, blkoff, le32toh (block->seg_len));
c1e277
+          goto error;
c1e277
+        } else {
c1e277
+          DEBUG (2,
c1e277
+                 "%s: block at 0x%zx has invalid size %" PRIi32 ", skipping",
c1e277
+                 filename, blkoff, le32toh (block->seg_len));
c1e277
+          break;
c1e277
+        }
c1e277
       }
c1e277
 
c1e277
       if (h->msglvl >= 2) {
c1e277
diff --git a/lib/node.c b/lib/node.c
c1e277
index 22d1861..a90c964 100644
c1e277
--- a/lib/node.c
c1e277
+++ b/lib/node.c
c1e277
@@ -343,11 +343,18 @@ _hivex_get_children (hive_h *h, hive_node_h node,
c1e277
    */
c1e277
   size_t nr_children = _hivex_get_offset_list_length (&children);
c1e277
   if (nr_subkeys_in_nk != nr_children) {
c1e277
-    SET_ERRNO (ENOTSUP,
c1e277
-               "nr_subkeys_in_nk = %zu "
c1e277
-               "is not equal to number of children read %zu",
c1e277
-               nr_subkeys_in_nk, nr_children);
c1e277
-    goto error;
c1e277
+    if (!h->unsafe) {
c1e277
+      SET_ERRNO (ENOTSUP,
c1e277
+                 "nr_subkeys_in_nk = %zu "
c1e277
+                 "is not equal to number of childred read %zu",
c1e277
+                 nr_subkeys_in_nk, nr_children);
c1e277
+      goto error;
c1e277
+    } else {
c1e277
+      DEBUG (2,
c1e277
+             "nr_subkeys_in_nk = %zu "
c1e277
+             "is not equal to number of children read %zu",
c1e277
+             nr_subkeys_in_nk, nr_children);
c1e277
+    }
c1e277
   }
c1e277
 
c1e277
  out:
c1e277
@@ -407,8 +414,14 @@ _get_children (hive_h *h, hive_node_h blkoff,
c1e277
     for (i = 0; i < nr_subkeys_in_lf; ++i) {
c1e277
       hive_node_h subkey = le32toh (lf->keys[i].offset);
c1e277
       subkey += 0x1000;
c1e277
-      if (check_child_is_nk_block (h, subkey, flags) == -1)
c1e277
-        return -1;
c1e277
+      if (check_child_is_nk_block (h, subkey, flags) == -1) {
c1e277
+        if (h->unsafe) {
c1e277
+          DEBUG (2, "subkey at 0x%zx is not an NK block, skipping", subkey);
c1e277
+          continue;
c1e277
+        } else {
c1e277
+          return -1;
c1e277
+        }
c1e277
+      }
c1e277
       if (_hivex_add_to_offset_list (children, subkey) == -1)
c1e277
         return -1;
c1e277
     }
c1e277
@@ -435,8 +448,14 @@ _get_children (hive_h *h, hive_node_h blkoff,
c1e277
     for (i = 0; i < nr_offsets; ++i) {
c1e277
       hive_node_h subkey = le32toh (ri->offset[i]);
c1e277
       subkey += 0x1000;
c1e277
-      if (check_child_is_nk_block (h, subkey, flags) == -1)
c1e277
-        return -1;
c1e277
+      if (check_child_is_nk_block (h, subkey, flags) == -1) {
c1e277
+        if (h->unsafe) {
c1e277
+          DEBUG (2, "subkey at 0x%zx is not an NK block, skipping", subkey);
c1e277
+          continue;
c1e277
+        } else {
c1e277
+          return -1;
c1e277
+        }
c1e277
+      }
c1e277
       if (_hivex_add_to_offset_list (children, subkey) == -1)
c1e277
         return -1;
c1e277
     }
c1e277
@@ -458,8 +477,13 @@ _get_children (hive_h *h, hive_node_h blkoff,
c1e277
       hive_node_h offset = le32toh (ri->offset[i]);
c1e277
       offset += 0x1000;
c1e277
       if (!IS_VALID_BLOCK (h, offset)) {
c1e277
-        SET_ERRNO (EFAULT, "ri-offset is not a valid block (0x%zx)", offset);
c1e277
-        return -1;
c1e277
+        if (h->unsafe) {
c1e277
+          DEBUG (2, "ri-offset is not a valid block (0x%zx), skipping", offset);
c1e277
+          continue;
c1e277
+        } else {
c1e277
+          SET_ERRNO (EFAULT, "ri-offset is not a valid block (0x%zx)", offset);
c1e277
+          return -1;
c1e277
+        }
c1e277
       }
c1e277
 
c1e277
       if (_get_children (h, offset, children, blocks, flags) == -1)
c1e277
-- 
c1e277
1.8.3.1
c1e277