mrc0mmand / rpms / hivex

Forked from rpms/hivex 3 years ago
Clone

Blame SOURCES/0001-lib-handle.c-Bounds-check-for-block-exceeding-page-l.patch

7483d8
From 61f4928dcc31b91aaf3bcbcf2898f8f09586a213 Mon Sep 17 00:00:00 2001
7483d8
From: "Richard W.M. Jones" <rjones@redhat.com>
7483d8
Date: Thu, 15 Apr 2021 15:50:13 +0100
7483d8
Subject: [PATCH] lib/handle.c: Bounds check for block exceeding page length
7483d8
 (CVE-2021-3504)
7483d8
7483d8
Hives are encoded as fixed-sized pages containing smaller variable-
7483d8
length blocks:
7483d8
7483d8
  +-------------------+-------------------+-------------------+--
7483d8
  | header            |[ blk ][blk][ blk ]|[blk][blk][blk]    |
7483d8
  +-------------------+-------------------+-------------------+--
7483d8
7483d8
Blocks should not straddle a page boundary.  However because blocks
7483d8
contain a 32 bit length field it is possible to construct an invalid
7483d8
hive where the last block in a page overlaps either the next page or
7483d8
the end of the file:
7483d8
7483d8
  +-------------------+-------------------+
7483d8
  | header            |[ blk ][blk][ blk ..... ]
7483d8
  +-------------------+-------------------+
7483d8
7483d8
Hivex lacked a bounds check and would process the registry.  Because
7483d8
the rest of the code assumes this situation can never happen it was
7483d8
possible to have a block containing some field (eg. a registry key
7483d8
name) which would extend beyond the end of the file.  Hivex mmaps or
7483d8
mallocs the file, causing hivex to read memory beyond the end of the
7483d8
mapped region, resulting in reading other memory structures or a
7483d8
crash.  (Writing beyond the end of the mapped region seems to be
7483d8
impossible because we always allocate a new page before writing.)
7483d8
7483d8
This commit adds a check which rejects the malformed registry on
7483d8
hivex_open.
7483d8
7483d8
Credit: Jeremy Galindo, Sr Security Engineer, Datto.com
7483d8
Signed-off-by: Richard W.M. Jones <rjones@redhat.com>
7483d8
Fixes: CVE-2021-3504
7483d8
Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1949687
7483d8
---
7483d8
 lib/handle.c | 12 ++++++++++--
7483d8
 1 file changed, 10 insertions(+), 2 deletions(-)
7483d8
7483d8
diff --git a/lib/handle.c b/lib/handle.c
7483d8
index 88b1563f..2e4231a5 100644
7483d8
--- a/lib/handle.c
7483d8
+++ b/lib/handle.c
7483d8
@@ -353,8 +353,8 @@ hivex_open (const char *filename, int flags)
7483d8
 #pragma GCC diagnostic pop
7483d8
         if (is_root || !h->unsafe) {
7483d8
           SET_ERRNO (ENOTSUP,
7483d8
-                     "%s, the block at 0x%zx has invalid size %" PRIu32
7483d8
-                     ", bad registry",
7483d8
+                     "%s, the block at 0x%zx size %" PRIu32
7483d8
+                     " <= 4 or not a multiple of 4, bad registry",
7483d8
                      filename, blkoff, le32toh (block->seg_len));
7483d8
           goto error;
7483d8
         } else {
7483d8
@@ -365,6 +365,14 @@ hivex_open (const char *filename, int flags)
7483d8
         }
7483d8
       }
7483d8
 
7483d8
+      if (blkoff + seg_len > off + page_size) {
7483d8
+        SET_ERRNO (ENOTSUP,
7483d8
+                   "%s, the block at 0x%zx size %" PRIu32
7483d8
+                   " extends beyond the current page, bad registry",
7483d8
+                   filename, blkoff, le32toh (block->seg_len));
7483d8
+        goto error;
7483d8
+      }
7483d8
+
7483d8
       if (h->msglvl >= 2) {
7483d8
         unsigned char *id = (unsigned char *) block->id;
7483d8
         int id0 = id[0], id1 = id[1];
7483d8
-- 
7483d8
2.29.2
7483d8