Merge branch 'dmi-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jdelvar...
[linux-2.6-microblaze.git] / fs / xfs / libxfs / xfs_rmap.c
index c0644f1..d4460b0 100644 (file)
@@ -1,19 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * Copyright (c) 2014 Red Hat, Inc.
  * All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it would be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write the Free Software Foundation,
- * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  */
 #include "xfs.h"
 #include "xfs_fs.h"
@@ -39,6 +27,7 @@
 #include "xfs_extent_busy.h"
 #include "xfs_bmap.h"
 #include "xfs_inode.h"
+#include "xfs_ialloc.h"
 
 /*
  * Lookup the first record less than or equal to [bno, len, owner, offset]
@@ -203,6 +192,8 @@ xfs_rmap_get_rec(
        struct xfs_rmap_irec    *irec,
        int                     *stat)
 {
+       struct xfs_mount        *mp = cur->bc_mp;
+       xfs_agnumber_t          agno = cur->bc_private.a.agno;
        union xfs_btree_rec     *rec;
        int                     error;
 
@@ -210,7 +201,43 @@ xfs_rmap_get_rec(
        if (error || !*stat)
                return error;
 
-       return xfs_rmap_btrec_to_irec(rec, irec);
+       if (xfs_rmap_btrec_to_irec(rec, irec))
+               goto out_bad_rec;
+
+       if (irec->rm_blockcount == 0)
+               goto out_bad_rec;
+       if (irec->rm_startblock <= XFS_AGFL_BLOCK(mp)) {
+               if (irec->rm_owner != XFS_RMAP_OWN_FS)
+                       goto out_bad_rec;
+               if (irec->rm_blockcount != XFS_AGFL_BLOCK(mp) + 1)
+                       goto out_bad_rec;
+       } else {
+               /* check for valid extent range, including overflow */
+               if (!xfs_verify_agbno(mp, agno, irec->rm_startblock))
+                       goto out_bad_rec;
+               if (irec->rm_startblock >
+                               irec->rm_startblock + irec->rm_blockcount)
+                       goto out_bad_rec;
+               if (!xfs_verify_agbno(mp, agno,
+                               irec->rm_startblock + irec->rm_blockcount - 1))
+                       goto out_bad_rec;
+       }
+
+       if (!(xfs_verify_ino(mp, irec->rm_owner) ||
+             (irec->rm_owner <= XFS_RMAP_OWN_FS &&
+              irec->rm_owner >= XFS_RMAP_OWN_MIN)))
+               goto out_bad_rec;
+
+       return 0;
+out_bad_rec:
+       xfs_warn(mp,
+               "Reverse Mapping BTree record corruption in AG %d detected!",
+               agno);
+       xfs_warn(mp,
+               "Owner 0x%llx, flags 0x%x, start block 0x%x block count 0x%x",
+               irec->rm_owner, irec->rm_flags, irec->rm_startblock,
+               irec->rm_blockcount);
+       return -EFSCORRUPTED;
 }
 
 struct xfs_find_left_neighbor_info {