grub-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH 1/1] xfs: Fix issues found while fuzzing the XFS filesystem


From: Lidong Chen
Subject: [PATCH 1/1] xfs: Fix issues found while fuzzing the XFS filesystem
Date: Mon, 22 May 2023 23:53:48 +0000

From: Darren Kenny <darren.kenny@oracle.com>

While performing fuzz testing with XFS filesystem images with ASAN
enabled, several issues were found where the memory accesses are made
beyond the data that is allocated into the struct grub_xfs_data
structure's data field.

The existing stucture didn't store the size of the memory allocted into
the buffer in the data field and had no way to check it. To resolve
these issues, the data size is stored to enable accesses into the data
buffer.

With these checks in place, the fuzzing corpus no longer cause any
crashes.

Signed-off-by: Darren Kenny <darren.kenny@oracle.com>
Signed-off-by: Robbie Harwood <rharwood@pm.me>
Signed-off-by: Marta Lewandowska <mlewando@redhat.com>
Signed-off-by: Lidong Chen <lidong.chen@oracle.com>
---
 grub-core/fs/xfs.c | 32 ++++++++++++++++++++++++++++++++
 1 file changed, 32 insertions(+)

diff --git a/grub-core/fs/xfs.c b/grub-core/fs/xfs.c
index d6de7f1a2..a0aaa3aa8 100644
--- a/grub-core/fs/xfs.c
+++ b/grub-core/fs/xfs.c
@@ -239,6 +239,7 @@ struct grub_fshelp_node
 
 struct grub_xfs_data
 {
+  grub_size_t datasize;
   struct grub_xfs_sblock sblock;
   grub_disk_t disk;
   int pos;
@@ -608,8 +609,20 @@ grub_xfs_read_block (grub_fshelp_node_t node, 
grub_disk_addr_t fileblock)
     }
   else if (node->inode.format == XFS_INODE_FORMAT_EXT)
     {
+      grub_addr_t exts_end = 0;
+      grub_addr_t data_end = 0;
+
       nrec = grub_be_to_cpu32 (node->inode.nextents);
       exts = (struct grub_xfs_extent *) grub_xfs_inode_data(&node->inode);
+
+      if (grub_mul(sizeof(struct grub_xfs_extent), nrec, &exts_end) ||
+         grub_add((grub_addr_t)node->data, exts_end, &exts_end) ||
+         grub_add((grub_addr_t)node->data, node->data->datasize, &data_end) ||
+         exts_end > data_end)
+        {
+         grub_error (GRUB_ERR_BAD_FS, "Invalid number of XFS exts");
+         return 0;
+        }
     }
   else
     {
@@ -799,6 +812,12 @@ grub_xfs_iterate_dir (grub_fshelp_node_t dir,
            grub_uint8_t *inopos = grub_xfs_inline_de_inopos(dir->data, de);
            grub_uint8_t c;
 
+           if ((inopos + (smallino?4:8)) >
+               (grub_uint8_t*)dir + grub_xfs_fshelp_size(dir->data))
+             {
+               return grub_error (GRUB_ERR_BAD_FS, "not a correct XFS inode");
+             }
+
            /* inopos might be unaligned.  */
            if (smallino)
              ino = (((grub_uint32_t) inopos[0]) << 24)
@@ -825,6 +844,12 @@ grub_xfs_iterate_dir (grub_fshelp_node_t dir,
            de->name[de->len] = c;
 
            de = grub_xfs_inline_next_de(dir->data, head, de);
+
+           if ((grub_uint8_t*)de >= (grub_uint8_t*)dir + 
grub_xfs_fshelp_size(dir->data))
+             {
+               return grub_error (GRUB_ERR_BAD_FS, "invalid XFS directory 
entry");
+             }
+
          }
        break;
       }
@@ -890,6 +915,10 @@ grub_xfs_iterate_dir (grub_fshelp_node_t dir,
                  }
 
                filename = (char *)(direntry + 1);
+               if (filename + direntry->len - 1 > (char *) tail)
+                 {
+                   return grub_error (GRUB_ERR_BAD_FS, "invalid XFS directory 
entry");
+                 }
                /* The byte after the filename is for the filetype, padding, or
                   tag, which is not used by GRUB.  So it can be overwritten. */
                filename[direntry->len] = '\0';
@@ -934,6 +963,8 @@ grub_xfs_mount (grub_disk_t disk)
   if (!data)
     return 0;
 
+  data->datasize = sizeof (struct grub_xfs_data);
+
   grub_dprintf("xfs", "Reading sb\n");
   /* Read the superblock.  */
   if (grub_disk_read (disk, 0, 0,
@@ -955,6 +986,7 @@ grub_xfs_mount (grub_disk_t disk)
   if (! data)
     goto fail;
 
+  data->datasize = sz;
   data->diropen.data = data;
   data->diropen.ino = grub_be_to_cpu64(data->sblock.rootino);
   data->diropen.inode_read = 1;
-- 
2.39.1




reply via email to

[Prev in Thread] Current Thread [Next in Thread]