0209-fs-xfs-Fix-unreadable-filesystem-with-v4-superblock.patch 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
  2. From: Erwan Velu <erwanaliasr1@gmail.com>
  3. Date: Wed, 25 Aug 2021 15:31:52 +0200
  4. Subject: [PATCH] fs/xfs: Fix unreadable filesystem with v4 superblock
  5. The commit 8b1e5d193 (fs/xfs: Add bigtime incompat feature support)
  6. introduced the bigtime support by adding some features in v3 inodes.
  7. This change extended grub_xfs_inode struct by 76 bytes but also changed
  8. the computation of XFS_V2_INODE_SIZE and XFS_V3_INODE_SIZE. Prior this
  9. commit, XFS_V2_INODE_SIZE was 100 bytes. After the commit it's 84 bytes
  10. XFS_V2_INODE_SIZE becomes 16 bytes too small.
  11. As a result, the data structures aren't properly aligned and the GRUB
  12. generates "attempt to read or write outside of partition" errors when
  13. trying to read the XFS filesystem:
  14. GNU GRUB version 2.11
  15. ....
  16. grub> set debug=efi,gpt,xfs
  17. grub> insmod part_gpt
  18. grub> ls (hd0,gpt1)/
  19. partmap/gpt.c:93: Read a valid GPT header
  20. partmap/gpt.c:115: GPT entry 0: start=4096, length=1953125
  21. fs/xfs.c:931: Reading sb
  22. fs/xfs.c:270: Validating superblock
  23. fs/xfs.c:295: XFS v4 superblock detected
  24. fs/xfs.c:962: Reading root ino 128
  25. fs/xfs.c:515: Reading inode (128) - 64, 0
  26. fs/xfs.c:515: Reading inode (739521961424144223) - 344365866970255880, 3840
  27. error: attempt to read or write outside of partition.
  28. This commit change the XFS_V2_INODE_SIZE computation by subtracting 76
  29. bytes instead of 92 bytes from the actual size of grub_xfs_inode struct.
  30. This 76 bytes value comes from added members:
  31. 20 grub_uint8_t unused5
  32. 1 grub_uint64_t flags2
  33. 48 grub_uint8_t unused6
  34. This patch explicitly splits the v2 and v3 parts of the structure.
  35. The unused4 is still ending of the v2 structures and the v3 starts
  36. at unused5. Thanks to this we will avoid future corruptions of v2
  37. or v3 inodes.
  38. The XFS_V2_INODE_SIZE is returning to its expected size and the
  39. filesystem is back to a readable state:
  40. GNU GRUB version 2.11
  41. ....
  42. grub> set debug=efi,gpt,xfs
  43. grub> insmod part_gpt
  44. grub> ls (hd0,gpt1)/
  45. partmap/gpt.c:93: Read a valid GPT header
  46. partmap/gpt.c:115: GPT entry 0: start=4096, length=1953125
  47. fs/xfs.c:931: Reading sb
  48. fs/xfs.c:270: Validating superblock
  49. fs/xfs.c:295: XFS v4 superblock detected
  50. fs/xfs.c:962: Reading root ino 128
  51. fs/xfs.c:515: Reading inode (128) - 64, 0
  52. fs/xfs.c:515: Reading inode (128) - 64, 0
  53. fs/xfs.c:931: Reading sb
  54. fs/xfs.c:270: Validating superblock
  55. fs/xfs.c:295: XFS v4 superblock detected
  56. fs/xfs.c:962: Reading root ino 128
  57. fs/xfs.c:515: Reading inode (128) - 64, 0
  58. fs/xfs.c:515: Reading inode (128) - 64, 0
  59. fs/xfs.c:515: Reading inode (128) - 64, 0
  60. fs/xfs.c:515: Reading inode (131) - 64, 768
  61. efi/ fs/xfs.c:515: Reading inode (3145856) - 1464904, 0
  62. grub2/ fs/xfs.c:515: Reading inode (132) - 64, 1024
  63. grub/ fs/xfs.c:515: Reading inode (139) - 64, 2816
  64. grub>
  65. Fixes: 8b1e5d193 (fs/xfs: Add bigtime incompat feature support)
  66. Signed-off-by: Erwan Velu <e.velu@criteo.com>
  67. Tested-by: Carlos Maiolino <cmaiolino@redhat.com>
  68. Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
  69. (cherry picked from commit a4b495520e4dc41a896a8b916a64eda9970c50ea)
  70. ---
  71. grub-core/fs/xfs.c | 14 ++++++++++----
  72. 1 file changed, 10 insertions(+), 4 deletions(-)
  73. diff --git a/grub-core/fs/xfs.c b/grub-core/fs/xfs.c
  74. index 0f524c3a8a6..e3816d1ec4a 100644
  75. --- a/grub-core/fs/xfs.c
  76. +++ b/grub-core/fs/xfs.c
  77. @@ -192,6 +192,11 @@ struct grub_xfs_time_legacy
  78. grub_uint32_t nanosec;
  79. } GRUB_PACKED;
  80. +/*
  81. + * The struct grub_xfs_inode layout was taken from the
  82. + * struct xfs_dinode_core which is described here:
  83. + * https://mirrors.edge.kernel.org/pub/linux/utils/fs/xfs/docs/xfs_filesystem_structure.pdf
  84. + */
  85. struct grub_xfs_inode
  86. {
  87. grub_uint8_t magic[2];
  88. @@ -208,14 +213,15 @@ struct grub_xfs_inode
  89. grub_uint32_t nextents;
  90. grub_uint16_t unused3;
  91. grub_uint8_t fork_offset;
  92. - grub_uint8_t unused4[37];
  93. + grub_uint8_t unused4[17]; /* Last member of inode v2. */
  94. + grub_uint8_t unused5[20]; /* First member of inode v3. */
  95. grub_uint64_t flags2;
  96. - grub_uint8_t unused5[48];
  97. + grub_uint8_t unused6[48]; /* Last member of inode v3. */
  98. } GRUB_PACKED;
  99. #define XFS_V3_INODE_SIZE sizeof(struct grub_xfs_inode)
  100. -/* Size of struct grub_xfs_inode until fork_offset (included). */
  101. -#define XFS_V2_INODE_SIZE (XFS_V3_INODE_SIZE - 92)
  102. +/* Size of struct grub_xfs_inode v2, up to unused4 member included. */
  103. +#define XFS_V2_INODE_SIZE (XFS_V3_INODE_SIZE - 76)
  104. struct grub_xfs_dirblock_tail
  105. {