xfs
[Top] [All Lists]

[PATCH] xfs_repair: validate on-disk extent count better

To: xfs@xxxxxxxxxxx
Subject: [PATCH] xfs_repair: validate on-disk extent count better
From: Dave Chinner <david@xxxxxxxxxxxxx>
Date: Fri, 12 Apr 2013 23:57:02 +1000
Delivered-to: xfs@xxxxxxxxxxx
From: Dave Chinner <dchinner@xxxxxxxxxx>

When scanning a btree format inode, we trust the extent count to be
in range.  However, values of the range 2^31 <= cnt < 2^32 are
invalid and can cause problems with signed range checks. This
results in assert failures which validating the extent count such
as:

xfs_repair: dinode.c:768: process_bmbt_reclist_int: Assertion `i < *numrecs' 
failed.

Validate the extent count is at least within the positive range of a
singed 32 bit integer before using it.

Signed-off-by: Dave Chinner <dchinner@xxxxxxxxxx>
---
 repair/dinode.c |   25 +++++++++++++++++++++++--
 1 file changed, 23 insertions(+), 2 deletions(-)

diff --git a/repair/dinode.c b/repair/dinode.c
index 5a2da39..239bb7b 100644
--- a/repair/dinode.c
+++ b/repair/dinode.c
@@ -1293,7 +1293,7 @@ process_exinode(
        xfs_bmbt_rec_t          *rp;
        xfs_dfiloff_t           first_key;
        xfs_dfiloff_t           last_key;
-       int                     numrecs;
+       int32_t                 numrecs;
        int                     ret;
 
        lino = XFS_AGINO_TO_INO(mp, agno, ino);
@@ -1302,6 +1302,15 @@ process_exinode(
        numrecs = XFS_DFORK_NEXTENTS(dip, whichfork);
 
        /*
+        * We've already decided on the maximum number of extents on the inode,
+        * and numrecs may be corrupt. Hence make sure we only allow numrecs to
+        * be in the range of valid on-disk numbers, which is:
+        *      0 < numrecs < 2^31 - 1
+        */
+       if (numrecs < 0)
+               numrecs = *nex;
+
+       /*
         * XXX - if we were going to fix up the btree record,
         * we'd do it right here.  For now, if there's a problem,
         * we'll bail out and presumably clear the inode.
@@ -2038,11 +2047,23 @@ process_inode_data_fork(
 {
        xfs_ino_t       lino = XFS_AGINO_TO_INO(mp, agno, ino);
        int             err = 0;
+       int             nex;
+
+       /*
+        * extent count on disk is only valid for positive values. The kernel
+        * uses negative values in memory. hence if we see negative numbers
+        * here, trash it!
+        */
+       nex = be32_to_cpu(dino->di_nextents);
+       if (nex < 0)
+               *nextents = 1;
+       else
+               *nextents = nex;
 
-       *nextents = be32_to_cpu(dino->di_nextents);
        if (*nextents > be64_to_cpu(dino->di_nblocks))
                *nextents = 1;
 
+
        if (dino->di_format != XFS_DINODE_FMT_LOCAL && type != XR_INO_RTDATA)
                *dblkmap = blkmap_alloc(*nextents, XFS_DATA_FORK);
        *nextents = 0;
-- 
1.7.10.4

<Prev in Thread] Current Thread [Next in Thread>
  • [PATCH] xfs_repair: validate on-disk extent count better, Dave Chinner <=