From a529cc7f0e5bd1632e5169d015c54e3a6122ee0f Mon Sep 17 00:00:00 2001 From: Eric Sandeen Date: Sat, 9 Mar 2013 15:21:55 +0000 Subject: [PATCH] xfsprogs: skip freelist scans of corrupt agf If an agf has bad values in the freelist, this can wreak havoc if, for example, first > last and the loop never exits; we index agfl->agfl_bno[i] off into the weeds. If they're off, warn about it and skip the scan. This is done both in xfs_check and xfs_db's freespace cmd. Also fix uninit'd variable "i" from previous, similar fix for xfs_repair. Signed-off-by: Eric Sandeen Reviewed-by: Dave Chinner Signed-off-by: Rich Johnston --- db/check.c | 10 ++++++++++ db/freesp.c | 10 ++++++++++ repair/scan.c | 2 +- 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/db/check.c b/db/check.c index e601e0af0..35325b797 100644 --- a/db/check.c +++ b/db/check.c @@ -4112,6 +4112,16 @@ scan_freelist( return; } i = be32_to_cpu(agf->agf_flfirst); + + /* verify agf values before proceeding */ + if (be32_to_cpu(agf->agf_flfirst) >= XFS_AGFL_SIZE(mp) || + be32_to_cpu(agf->agf_fllast) >= XFS_AGFL_SIZE(mp)) { + dbprintf(_("agf %d freelist blocks bad, skipping " + "freelist scan\n"), i); + pop_cur(); + return; + } + count = 0; for (;;) { bno = be32_to_cpu(agfl->agfl_bno[i]); diff --git a/db/freesp.c b/db/freesp.c index c4dabad16..472b1f7bc 100644 --- a/db/freesp.c +++ b/db/freesp.c @@ -239,6 +239,16 @@ scan_freelist( XFS_FSS_TO_BB(mp, 1), DB_RING_IGN, NULL); agfl = iocur_top->data; i = be32_to_cpu(agf->agf_flfirst); + + /* verify agf values before proceeding */ + if (be32_to_cpu(agf->agf_flfirst) >= XFS_AGFL_SIZE(mp) || + be32_to_cpu(agf->agf_fllast) >= XFS_AGFL_SIZE(mp)) { + dbprintf(_("agf %d freelist blocks bad, skipping " + "freelist scan\n"), i); + pop_cur(); + return; + } + for (;;) { bno = be32_to_cpu(agfl->agfl_bno[i]); addtohist(seqno, bno, 1); diff --git a/repair/scan.c b/repair/scan.c index 1d39bdc7d..6a62dfff0 100644 --- a/repair/scan.c +++ b/repair/scan.c @@ -1066,6 +1066,7 @@ scan_freelist( return; } agfl = XFS_BUF_TO_AGFL(agflbuf); + i = be32_to_cpu(agf->agf_flfirst); if (no_modify) { /* agf values not fixed in verify_set_agf, so recheck */ @@ -1078,7 +1079,6 @@ scan_freelist( } else /* should have been fixed in verify_set_agf() */ ASSERT(0); - i = be32_to_cpu(agf->agf_flfirst); count = 0; for (;;) { bno = be32_to_cpu(agfl->agfl_bno[i]); -- 2.47.2