zbyszek / rpms / grub2

Forked from rpms/grub2 5 years ago
Clone
3d407d2
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
3d407d2
From: Darren Kenny <darren.kenny@oracle.com>
3d407d2
Date: Thu, 7 Apr 2022 15:18:12 +0000
3d407d2
Subject: [PATCH] fs/btrfs: Fix more fuzz issues related to chunks
3d407d2
3d407d2
The corpus we generating issues in grub_btrfs_read_logical() when
3d407d2
attempting to iterate over nstripes entries in the boot mapping.
3d407d2
3d407d2
In most cases the reason for the failure was that the number of strips
3d407d2
exceeded the possible space statically allocated in superblock bootmapping
3d407d2
space. Each stripe entry in the bootmapping block consists of
3d407d2
a grub_btrfs_key followed by a grub_btrfs_chunk_stripe.
3d407d2
3d407d2
Another issue that came up was that while calculating the chunk size,
3d407d2
in an earlier piece of code in that function, depending on the data
3d407d2
provided in the btrfs file system, it would end up calculating a size
3d407d2
that was too small to contain even 1 grub_btrfs_chunk_item, which is
3d407d2
obviously invalid too.
3d407d2
3d407d2
Signed-off-by: Darren Kenny <darren.kenny@oracle.com>
3d407d2
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
3d407d2
(cherry picked from commit e00cd76cbadcc897a9cc4087cb2fcb5dbe15e596)
3d407d2
---
3d407d2
 grub-core/fs/btrfs.c | 24 ++++++++++++++++++++++++
3d407d2
 1 file changed, 24 insertions(+)
3d407d2
3d407d2
diff --git a/grub-core/fs/btrfs.c b/grub-core/fs/btrfs.c
3d407d2
index 0e9b450413..47325f6ad7 100644
3d407d2
--- a/grub-core/fs/btrfs.c
3d407d2
+++ b/grub-core/fs/btrfs.c
3d407d2
@@ -947,6 +947,17 @@ grub_btrfs_read_logical (struct grub_btrfs_data *data, grub_disk_addr_t addr,
3d407d2
 	  return grub_error (GRUB_ERR_BAD_FS,
3d407d2
 			     "got an invalid zero-size chunk");
3d407d2
 	}
3d407d2
+
3d407d2
+      /*
3d407d2
+       * The space being allocated for a chunk should at least be able to
3d407d2
+       * contain one chunk item.
3d407d2
+       */
3d407d2
+      if (chsize < sizeof (struct grub_btrfs_chunk_item))
3d407d2
+       {
3d407d2
+         grub_dprintf ("btrfs", "chunk-size too small\n");
3d407d2
+         return grub_error (GRUB_ERR_BAD_FS,
3d407d2
+                            "got an invalid chunk size");
3d407d2
+       }
3d407d2
       chunk = grub_malloc (chsize);
3d407d2
       if (!chunk)
3d407d2
 	return grub_errno;
3d407d2
@@ -1194,6 +1205,13 @@ grub_btrfs_read_logical (struct grub_btrfs_data *data, grub_disk_addr_t addr,
3d407d2
 	if (csize > (grub_uint64_t) size)
3d407d2
 	  csize = size;
3d407d2
 
3d407d2
+	/*
3d407d2
+	 * The space for a chunk stripe is limited to the space provide in the super-block's
3d407d2
+	 * bootstrap mapping with an initial btrfs key at the start of each chunk.
3d407d2
+	 */
3d407d2
+	grub_size_t avail_stripes = sizeof (data->sblock.bootstrap_mapping) /
3d407d2
+	  (sizeof (struct grub_btrfs_key) + sizeof (struct grub_btrfs_chunk_stripe));
3d407d2
+
3d407d2
 	for (j = 0; j < 2; j++)
3d407d2
 	  {
3d407d2
 	    grub_size_t est_chunk_alloc = 0;
3d407d2
@@ -1220,6 +1238,12 @@ grub_btrfs_read_logical (struct grub_btrfs_data *data, grub_disk_addr_t addr,
3d407d2
 		break;
3d407d2
 	      }
3d407d2
 
3d407d2
+	   if (grub_le_to_cpu16 (chunk->nstripes) > avail_stripes)
3d407d2
+             {
3d407d2
+               err = GRUB_ERR_BAD_FS;
3d407d2
+               break;
3d407d2
+             }
3d407d2
+
3d407d2
 	    if (is_raid56)
3d407d2
 	      {
3d407d2
 		err = btrfs_read_from_chunk (data, chunk, stripen,