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

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