]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/commitdiff
libxfs: sanitize agcount on load
authorEric Sandeen <sandeen@sandeen.net>
Thu, 26 Jan 2017 02:02:43 +0000 (20:02 -0600)
committerEric Sandeen <sandeen@redhat.com>
Thu, 26 Jan 2017 02:02:43 +0000 (20:02 -0600)
Before we get into libxfs_initialize_perag and try to blindly
allocate a perag struct for every (possibly corrupted number of)
AGs, see if we can read the last one.  If not, assume it's corrupt,
and load only the first AG.

Do this only for an arbitrarily high-ish agcount, so that normal-ish
geometry on a possibly truncated file or device will still do
its best to make all readable AGs available.

Set xfs_db's exitcode to 1 if this happens.

Also teach metadump to detect this and exit appropriately if
truncated, as it resets exitcode to 0 for its own purposes internally.

Signed-off-by: Eric Sandeen <sandeen@redhat.com>
Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>
Signed-off-by: Eric Sandeen <sandeen@sandeen.net>
db/init.c
db/metadump.c
libxfs/init.c

index ec1e274c41b5e1f92bc29e7792c1d46876c7ba6a..59fc3e0c3e1c3e2cdb665ed43c47d1387fc7f739 100644 (file)
--- a/db/init.c
+++ b/db/init.c
@@ -58,6 +58,7 @@ init(
 {
        struct xfs_sb   *sbp;
        struct xfs_buf  *bp;
+       unsigned int    agcount;
        int             c;
 
        setlocale(LC_ALL, "");
@@ -148,6 +149,7 @@ init(
                }
        }
 
+       agcount = sbp->sb_agcount;
        mp = libxfs_mount(&xmount, sbp, x.ddev, x.logdev, x.rtdev,
                          LIBXFS_MOUNT_DEBUGGER);
        if (!mp) {
@@ -159,6 +161,10 @@ init(
        mp->m_log = &xlog;
        blkbb = 1 << mp->m_blkbb_log;
 
+       /* Did we limit a broken agcount in libxfs_mount? */
+       if (sbp->sb_agcount != agcount)
+               exitcode = 1;
+
        /*
         * xfs_check needs corrected incore superblock values
         */
index 1ba6b3853221c27122f0ada74c1f4effad2dab3b..38519f1be3bf38806cacf44eba370702d38fb408 100644 (file)
@@ -2760,6 +2760,16 @@ metadump_f(
                return 0;
        }
 
+       /*
+        * on load, we sanity-checked agcount and possibly set to 1
+        * if it was corrupted and large.
+        */
+       if (mp->m_sb.sb_agcount == 1 &&
+           XFS_MAX_DBLOCKS(&mp->m_sb) < mp->m_sb.sb_dblocks) {
+               print_warning("truncated agcount, giving up");
+               return 0;
+       }
+
        while ((c = getopt(argc, argv, "aegm:ow")) != EOF) {
                switch (c) {
                        case 'a':
index a08575a755a5809ccb2271fa90a9d0f3fd163aaf..85e0d159194a7ea77161a53011b018310a67fdb2 100644 (file)
@@ -817,6 +817,29 @@ libxfs_mount(
                        return NULL;
        }
 
+       /*
+        * libxfs_initialize_perag will allocate a perag structure for each ag.
+        * If agcount is corrupted and insanely high, this will OOM the box.
+        * If the agount seems (arbitrarily) high, try to read what would be
+        * the last AG, and if that fails for a relatively high agcount, just
+        * read the first one and let the user know to check the geometry.
+        */
+       if (sbp->sb_agcount > 1000000) {
+               bp = libxfs_readbuf(mp->m_dev,
+                               XFS_AG_DADDR(mp, sbp->sb_agcount - 1, 0), 1,
+                               !(flags & LIBXFS_MOUNT_DEBUGGER), NULL);
+               if (bp->b_error) {
+                       fprintf(stderr, _("%s: read of AG %u failed\n"),
+                                               progname, sbp->sb_agcount);
+                       if (!(flags & LIBXFS_MOUNT_DEBUGGER))
+                               return NULL;
+                       fprintf(stderr, _("%s: limiting reads to AG 0\n"),
+                                                               progname);
+                       sbp->sb_agcount = 1;
+               }
+               libxfs_putbuf(bp);
+       }
+
        error = libxfs_initialize_perag(mp, sbp->sb_agcount, &mp->m_maxagi);
        if (error) {
                fprintf(stderr, _("%s: perag init failed\n"),