diff mbox

[v9,1/5] xfs_db: sanitize agcount on load

Message ID 886473a5-c0ff-a5b7-38bc-13d4d5d13c3c@sandeen.net (mailing list archive)
State Superseded, archived
Headers show

Commit Message

Eric Sandeen Jan. 26, 2017, 1:05 a.m. UTC
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.

Teach metadump to detect this and exit appropriately if truncated.

Signed-off-by: Eric Sandeen <sandeen@redhat.com>
---

v1->v6: Tale of woe.
v7: blow it all up
v8: use bare libxfs_readbuf so verifiers don't matter,
    "ours goes to 1 million!"
v9: Fix printf format, exit metadump with error if things look wonky.


--
To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/db/metadump.c b/db/metadump.c
index 1ba6b38..d307771 100644
--- a/db/metadump.c
+++ b/db/metadump.c
@@ -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':
diff --git a/libxfs/init.c b/libxfs/init.c
index a08575a..85e0d15 100644
--- a/libxfs/init.c
+++ b/libxfs/init.c
@@ -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"),