nalika / rpms / grub2

Forked from rpms/grub2 2 years ago
Clone

Blame SOURCES/0221-fs-xfs-Fix-unreadable-filesystem-with-v4-superblock.patch

5593c8
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
5593c8
From: Erwan Velu <erwanaliasr1@gmail.com>
5593c8
Date: Wed, 25 Aug 2021 15:31:52 +0200
5593c8
Subject: [PATCH] fs/xfs: Fix unreadable filesystem with v4 superblock
5593c8
5593c8
The commit 8b1e5d193 (fs/xfs: Add bigtime incompat feature support)
5593c8
introduced the bigtime support by adding some features in v3 inodes.
5593c8
This change extended grub_xfs_inode struct by 76 bytes but also changed
5593c8
the computation of XFS_V2_INODE_SIZE and XFS_V3_INODE_SIZE. Prior this
5593c8
commit, XFS_V2_INODE_SIZE was 100 bytes. After the commit it's 84 bytes
5593c8
XFS_V2_INODE_SIZE becomes 16 bytes too small.
5593c8
5593c8
As a result, the data structures aren't properly aligned and the GRUB
5593c8
generates "attempt to read or write outside of partition" errors when
5593c8
trying to read the XFS filesystem:
5593c8
5593c8
                             GNU GRUB  version 2.11
5593c8
	....
5593c8
	grub> set debug=efi,gpt,xfs
5593c8
	grub> insmod part_gpt
5593c8
	grub> ls (hd0,gpt1)/
5593c8
	partmap/gpt.c:93: Read a valid GPT header
5593c8
	partmap/gpt.c:115: GPT entry 0: start=4096, length=1953125
5593c8
	fs/xfs.c:931: Reading sb
5593c8
	fs/xfs.c:270: Validating superblock
5593c8
	fs/xfs.c:295: XFS v4 superblock detected
5593c8
	fs/xfs.c:962: Reading root ino 128
5593c8
	fs/xfs.c:515: Reading inode (128) - 64, 0
5593c8
	fs/xfs.c:515: Reading inode (739521961424144223) - 344365866970255880, 3840
5593c8
	error: attempt to read or write outside of partition.
5593c8
5593c8
This commit change the XFS_V2_INODE_SIZE computation by subtracting 76
5593c8
bytes instead of 92 bytes from the actual size of grub_xfs_inode struct.
5593c8
This 76 bytes value comes from added members:
5593c8
	20 grub_uint8_t   unused5
5593c8
	 1 grub_uint64_t  flags2
5593c8
        48 grub_uint8_t   unused6
5593c8
5593c8
This patch explicitly splits the v2 and v3 parts of the structure.
5593c8
The unused4 is still ending of the v2 structures and the v3 starts
5593c8
at unused5. Thanks to this we will avoid future corruptions of v2
5593c8
or v3 inodes.
5593c8
5593c8
The XFS_V2_INODE_SIZE is returning to its expected size and the
5593c8
filesystem is back to a readable state:
5593c8
5593c8
                      GNU GRUB  version 2.11
5593c8
	....
5593c8
	grub> set debug=efi,gpt,xfs
5593c8
	grub> insmod part_gpt
5593c8
	grub> ls (hd0,gpt1)/
5593c8
	partmap/gpt.c:93: Read a valid GPT header
5593c8
	partmap/gpt.c:115: GPT entry 0: start=4096, length=1953125
5593c8
	fs/xfs.c:931: Reading sb
5593c8
	fs/xfs.c:270: Validating superblock
5593c8
	fs/xfs.c:295: XFS v4 superblock detected
5593c8
	fs/xfs.c:962: Reading root ino 128
5593c8
	fs/xfs.c:515: Reading inode (128) - 64, 0
5593c8
	fs/xfs.c:515: Reading inode (128) - 64, 0
5593c8
	fs/xfs.c:931: Reading sb
5593c8
	fs/xfs.c:270: Validating superblock
5593c8
	fs/xfs.c:295: XFS v4 superblock detected
5593c8
	fs/xfs.c:962: Reading root ino 128
5593c8
	fs/xfs.c:515: Reading inode (128) - 64, 0
5593c8
	fs/xfs.c:515: Reading inode (128) - 64, 0
5593c8
	fs/xfs.c:515: Reading inode (128) - 64, 0
5593c8
	fs/xfs.c:515: Reading inode (131) - 64, 768
5593c8
	efi/ fs/xfs.c:515: Reading inode (3145856) - 1464904, 0
5593c8
	grub2/ fs/xfs.c:515: Reading inode (132) - 64, 1024
5593c8
	grub/ fs/xfs.c:515: Reading inode (139) - 64, 2816
5593c8
	grub>
5593c8
5593c8
Fixes: 8b1e5d193 (fs/xfs: Add bigtime incompat feature support)
5593c8
5593c8
Signed-off-by: Erwan Velu <e.velu@criteo.com>
5593c8
Tested-by: Carlos Maiolino <cmaiolino@redhat.com>
5593c8
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
5593c8
(cherry picked from commit a4b495520e4dc41a896a8b916a64eda9970c50ea)
5593c8
---
5593c8
 grub-core/fs/xfs.c | 14 ++++++++++----
5593c8
 1 file changed, 10 insertions(+), 4 deletions(-)
5593c8
5593c8
diff --git a/grub-core/fs/xfs.c b/grub-core/fs/xfs.c
d3c3ab
index 0f524c3a8a6..e3816d1ec4a 100644
5593c8
--- a/grub-core/fs/xfs.c
5593c8
+++ b/grub-core/fs/xfs.c
5593c8
@@ -192,6 +192,11 @@ struct grub_xfs_time_legacy
5593c8
   grub_uint32_t nanosec;
5593c8
 } GRUB_PACKED;
5593c8
 
5593c8
+/*
5593c8
+ * The struct grub_xfs_inode layout was taken from the
5593c8
+ * struct xfs_dinode_core which is described here:
5593c8
+ * https://mirrors.edge.kernel.org/pub/linux/utils/fs/xfs/docs/xfs_filesystem_structure.pdf
5593c8
+ */
5593c8
 struct grub_xfs_inode
5593c8
 {
5593c8
   grub_uint8_t magic[2];
5593c8
@@ -208,14 +213,15 @@ struct grub_xfs_inode
5593c8
   grub_uint32_t nextents;
5593c8
   grub_uint16_t unused3;
5593c8
   grub_uint8_t fork_offset;
5593c8
-  grub_uint8_t unused4[37];
5593c8
+  grub_uint8_t unused4[17]; /* Last member of inode v2. */
5593c8
+  grub_uint8_t unused5[20]; /* First member of inode v3. */
5593c8
   grub_uint64_t flags2;
5593c8
-  grub_uint8_t unused5[48];
5593c8
+  grub_uint8_t unused6[48]; /* Last member of inode v3. */
5593c8
 } GRUB_PACKED;
5593c8
 
5593c8
 #define XFS_V3_INODE_SIZE	sizeof(struct grub_xfs_inode)
5593c8
-/* Size of struct grub_xfs_inode until fork_offset (included). */
5593c8
-#define XFS_V2_INODE_SIZE	(XFS_V3_INODE_SIZE - 92)
5593c8
+/* Size of struct grub_xfs_inode v2, up to unused4 member included. */
5593c8
+#define XFS_V2_INODE_SIZE	(XFS_V3_INODE_SIZE - 76)
5593c8
 
5593c8
 struct grub_xfs_dirblock_tail
5593c8
 {