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

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