Blame SOURCES/0535-fs-f2fs-Do-not-read-past-the-end-of-nat-bitmap.patch

b9d01e
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
b9d01e
From: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
b9d01e
Date: Wed, 6 Apr 2022 18:49:09 +0530
b9d01e
Subject: [PATCH] fs/f2fs: Do not read past the end of nat bitmap
b9d01e
b9d01e
A corrupt f2fs filesystem could have a block offset or a bitmap
b9d01e
offset that would cause us to read beyond the bounds of the nat
b9d01e
bitmap.
b9d01e
b9d01e
Introduce the nat_bitmap_size member in grub_f2fs_data which holds
b9d01e
the size of nat bitmap.
b9d01e
b9d01e
Set the size when loading the nat bitmap in nat_bitmap_ptr(), and
b9d01e
catch when an invalid offset would create a pointer past the end of
b9d01e
the allocated space.
b9d01e
b9d01e
Check against the bitmap size in grub_f2fs_test_bit() test bit to avoid
b9d01e
reading past the end of the nat bitmap.
b9d01e
b9d01e
Signed-off-by: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
b9d01e
Signed-off-by: Daniel Axtens <dja@axtens.net>
b9d01e
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
b9d01e
(cherry picked from commit 62d63d5e38c67a6e349148bf7cb87c560e935a7e)
b9d01e
(cherry picked from commit 92219e6d379b5b4d30b05361830b72ab1d95d281)
b9d01e
(cherry picked from commit c23d97e3b56594bf0f802d94062e14b221143115)
b9d01e
---
b9d01e
 grub-core/fs/f2fs.c | 33 +++++++++++++++++++++++++++------
b9d01e
 1 file changed, 27 insertions(+), 6 deletions(-)
b9d01e
b9d01e
diff --git a/grub-core/fs/f2fs.c b/grub-core/fs/f2fs.c
b9d01e
index 09dc932420..33e565b180 100644
b9d01e
--- a/grub-core/fs/f2fs.c
b9d01e
+++ b/grub-core/fs/f2fs.c
b9d01e
@@ -122,6 +122,7 @@ GRUB_MOD_LICENSE ("GPLv3+");
b9d01e
 #define F2FS_INLINE_DOTS          0x10  /* File having implicit dot dentries. */
b9d01e
 
b9d01e
 #define MAX_VOLUME_NAME           512
b9d01e
+#define MAX_NAT_BITMAP_SIZE       3900
b9d01e
 
b9d01e
 enum FILE_TYPE
b9d01e
 {
b9d01e
@@ -183,7 +184,7 @@ struct grub_f2fs_checkpoint
b9d01e
   grub_uint32_t                   checksum_offset;
b9d01e
   grub_uint64_t                   elapsed_time;
b9d01e
   grub_uint8_t                    alloc_type[MAX_ACTIVE_LOGS];
b9d01e
-  grub_uint8_t                    sit_nat_version_bitmap[3900];
b9d01e
+  grub_uint8_t                    sit_nat_version_bitmap[MAX_NAT_BITMAP_SIZE];
b9d01e
   grub_uint32_t                   checksum;
b9d01e
 } GRUB_PACKED;
b9d01e
 
b9d01e
@@ -302,6 +303,7 @@ struct grub_f2fs_data
b9d01e
 
b9d01e
   struct grub_f2fs_nat_journal    nat_j;
b9d01e
   char                            *nat_bitmap;
b9d01e
+  grub_uint32_t                   nat_bitmap_size;
b9d01e
 
b9d01e
   grub_disk_t                     disk;
b9d01e
   struct grub_f2fs_node           *inode;
b9d01e
@@ -377,15 +379,20 @@ sum_blk_addr (struct grub_f2fs_data *data, int base, int type)
b9d01e
 }
b9d01e
 
b9d01e
 static void *
b9d01e
-nat_bitmap_ptr (struct grub_f2fs_data *data)
b9d01e
+nat_bitmap_ptr (struct grub_f2fs_data *data, grub_uint32_t *nat_bitmap_size)
b9d01e
 {
b9d01e
   struct grub_f2fs_checkpoint *ckpt = &data->ckpt;
b9d01e
   grub_uint32_t offset;
b9d01e
+  *nat_bitmap_size = MAX_NAT_BITMAP_SIZE;
b9d01e
 
b9d01e
   if (grub_le_to_cpu32 (data->sblock.cp_payload) > 0)
b9d01e
     return ckpt->sit_nat_version_bitmap;
b9d01e
 
b9d01e
   offset = grub_le_to_cpu32 (ckpt->sit_ver_bitmap_bytesize);
b9d01e
+  if (offset >= MAX_NAT_BITMAP_SIZE)
b9d01e
+     return NULL;
b9d01e
+
b9d01e
+  *nat_bitmap_size = *nat_bitmap_size - offset;
b9d01e
 
b9d01e
   return ckpt->sit_nat_version_bitmap + offset;
b9d01e
 }
b9d01e
@@ -438,11 +445,15 @@ grub_f2fs_crc_valid (grub_uint32_t blk_crc, void *buf, const grub_uint32_t len)
b9d01e
 }
b9d01e
 
b9d01e
 static int
b9d01e
-grub_f2fs_test_bit (grub_uint32_t nr, const char *p)
b9d01e
+grub_f2fs_test_bit (grub_uint32_t nr, const char *p, grub_uint32_t len)
b9d01e
 {
b9d01e
   int mask;
b9d01e
+  grub_uint32_t shifted_nr = (nr >> 3);
b9d01e
 
b9d01e
-  p += (nr >> 3);
b9d01e
+  if (shifted_nr >= len)
b9d01e
+    return -1;
b9d01e
+
b9d01e
+  p += shifted_nr;
b9d01e
   mask = 1 << (7 - (nr & 0x07));
b9d01e
 
b9d01e
   return mask & *p;
b9d01e
@@ -662,6 +673,7 @@ get_node_blkaddr (struct grub_f2fs_data *data, grub_uint32_t nid)
b9d01e
   grub_uint32_t seg_off, block_off, entry_off, block_addr;
b9d01e
   grub_uint32_t blkaddr = 0;
b9d01e
   grub_err_t err;
b9d01e
+  int result_bit;
b9d01e
 
b9d01e
   err = get_blkaddr_from_nat_journal (data, nid, &blkaddr);
b9d01e
   if (err != GRUB_ERR_NONE)
b9d01e
@@ -682,8 +694,15 @@ get_node_blkaddr (struct grub_f2fs_data *data, grub_uint32_t nid)
b9d01e
         ((seg_off * data->blocks_per_seg) << 1) +
b9d01e
         (block_off & (data->blocks_per_seg - 1));
b9d01e
 
b9d01e
-  if (grub_f2fs_test_bit (block_off, data->nat_bitmap))
b9d01e
+  result_bit = grub_f2fs_test_bit (block_off, data->nat_bitmap,
b9d01e
+                                   data->nat_bitmap_size);
b9d01e
+  if (result_bit > 0)
b9d01e
     block_addr += data->blocks_per_seg;
b9d01e
+  else if (result_bit == -1)
b9d01e
+    {
b9d01e
+      grub_free (nat_block);
b9d01e
+      return 0;
b9d01e
+    }
b9d01e
 
b9d01e
   err = grub_f2fs_block_read (data, block_addr, nat_block);
b9d01e
   if (err)
b9d01e
@@ -832,7 +851,9 @@ grub_f2fs_mount (grub_disk_t disk)
b9d01e
   if (err)
b9d01e
     goto fail;
b9d01e
 
b9d01e
-  data->nat_bitmap = nat_bitmap_ptr (data);
b9d01e
+  data->nat_bitmap = nat_bitmap_ptr (data, &data->nat_bitmap_size);
b9d01e
+  if (data->nat_bitmap == NULL)
b9d01e
+    goto fail;
b9d01e
 
b9d01e
   err = get_nat_journal (data);
b9d01e
   if (err)