]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/commitdiff
metadump: be careful zeroing corrupt inode forks
authorDave Chinner <dchinner@redhat.com>
Fri, 27 May 2022 20:36:14 +0000 (16:36 -0400)
committerEric Sandeen <sandeen@sandeen.net>
Fri, 27 May 2022 20:36:14 +0000 (16:36 -0400)
When a corrupt inode fork is encountered, we can zero beyond the end
of the inode if the fork pointers are sufficiently trashed. We
should not trust the fork pointers when corruption is detected and
skip the zeroing in this case. We want metadump to capture the
corruption and so skipping the zeroing will give us the best chance
of preserving the corruption in a meaningful state for diagnosis.

Reported-by: Sean Caron <scaron@umich.edu>
Signed-off-by: Dave Chinner <dchinner@redhat.com>
Reviewed-by: Darrick J. Wong <djwong@kernel.org>
Signed-off-by: Eric Sandeen <sandeen@sandeen.net>
db/metadump.c

index bef01b6609ccf65dc841fad604d85eb534d092a8..f0c78167d14deea30f5f3e1b17de3eb998359a13 100644 (file)
@@ -2308,18 +2308,34 @@ process_inode_data(
 {
        switch (dip->di_format) {
                case XFS_DINODE_FMT_LOCAL:
-                       if (obfuscate || zero_stale_data)
-                               switch (itype) {
-                                       case TYP_DIR2:
-                                               process_sf_dir(dip);
-                                               break;
+                       if (!(obfuscate || zero_stale_data))
+                               break;
+
+                       /*
+                        * If the fork size is invalid, we can't safely do
+                        * anything with this fork. Leave it alone to preserve
+                        * the information for diagnostic purposes.
+                        */
+                       if (XFS_DFORK_DSIZE(dip, mp) > XFS_LITINO(mp)) {
+                               print_warning(
+"Invalid data fork size (%d) in inode %llu, preserving contents!",
+                                               XFS_DFORK_DSIZE(dip, mp),
+                                               (long long)cur_ino);
+                               break;
+                       }
 
-                                       case TYP_SYMLINK:
-                                               process_sf_symlink(dip);
-                                               break;
+                       switch (itype) {
+                               case TYP_DIR2:
+                                       process_sf_dir(dip);
+                                       break;
 
-                                       default: ;
-                               }
+                               case TYP_SYMLINK:
+                                       process_sf_symlink(dip);
+                                       break;
+
+                               default:
+                                       break;
+                       }
                        break;
 
                case XFS_DINODE_FMT_EXTENTS:
@@ -2341,6 +2357,19 @@ process_dev_inode(
                                      (unsigned long long)cur_ino);
                return;
        }
+
+       /*
+        * If the fork size is invalid, we can't safely do anything with
+        * this fork. Leave it alone to preserve the information for diagnostic
+        * purposes.
+        */
+       if (XFS_DFORK_DSIZE(dip, mp) > XFS_LITINO(mp)) {
+               print_warning(
+"Invalid data fork size (%d) in inode %llu, preserving contents!",
+                               XFS_DFORK_DSIZE(dip, mp), (long long)cur_ino);
+               return;
+       }
+
        if (zero_stale_data) {
                unsigned int    size = sizeof(xfs_dev_t);