]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/commitdiff
xfs_repair: validate on-disk extent count better
authorDave Chinner <dchinner@redhat.com>
Thu, 2 May 2013 12:59:20 +0000 (07:59 -0500)
committerRich Johnston <rjohnston@sgi.com>
Thu, 2 May 2013 13:04:54 +0000 (08:04 -0500)
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
signed 32 bit integer before using it.

Signed-off-by: Dave Chinner <dchinner@redhat.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Mark Tinguely <tinguely@sgi.com>
Signed-off-by: Rich Johnston <rjohnston@sgi.com>
repair/dinode.c

index 5a2da395e874cfbadc6b10a713e11d97312906c2..239bb7b47f311ede8d488aee0b6d30bd95e1365d 100644 (file)
@@ -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);
@@ -1301,6 +1301,15 @@ process_exinode(
        *tot = 0;
        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,
@@ -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;