Skip to contentSkip to conversation

xfs_repair: fix verify_ag_bno() overflow

PATCH In review Eric Sandeen 2 participants 4 messages Jul 1, 2009 – Jul 2, 2009

lore
Share & tools
lore
#0 lore raw

PATCH 1/1 xfs_repair: fix verify_ag_bno() overflow

The last test in verify_ag_bno() may overflow:

return (agbno >= (sbp->sb_dblocks -

		((sbp->sb_agcount - 1) * sbp->sb_agblocks)));

because sb_agcount & sb_agblocks are 32-bit integers; this may then miss corrupt agbnos for the last ag, which can in turn lead to out of bounds memory accesses later, for example when the block nr is used to offset in set_agbno_state():

	addr = ba_bmap[(agno)] + (ag_blockno)/XR_BB_NUM;

Also make the first test simpler; agbno > sb_agblocks is -always- bad, regardless of the agno. This may even speed it up a tiny bit.

---

repair/dinode.c +7 -4
index fdf52db..f50f1ad 100644
@@ -315,11 +315,14 @@ verify_ag_bno(xfs_sb_t *sbp,
 		xfs_agnumber_t agno,
 		xfs_agblock_t agbno)
 {
-	if (agno < (sbp->sb_agcount - 1)) 
-		return (agbno >= sbp->sb_agblocks);
-	if (agno == (sbp->sb_agcount - 1)) 
+	/* in all cases bno >= agblocks is bad */
+	if (agbno >= sbp->sb_agblocks)
+		return 1;
+	/* last ag may be smaller */
+	if (agno == (sbp->sb_agcount - 1))
 		return (agbno >= (sbp->sb_dblocks -
-				((sbp->sb_agcount - 1) * sbp->sb_agblocks)));
+				((xfs_drfsbno_t)(sbp->sb_agcount - 1) *
+				 sbp->sb_agblocks)));
 	return 1;
 }
 

_______________________________________________
xfs mailing list
[email protected]
http://oss.sgi.com/mailman/listinfo/xfs

#1 lore raw

Argh self-nak on that one, stupid thinko; it always returns 1 for a non-last AG :/ Just add the cast and don't get fancy!

V2 below:

-------

The last test in verify_ag_bno() may overflow:

return (agbno >= (sbp->sb_dblocks -

		((sbp->sb_agcount - 1) * sbp->sb_agblocks)));

because sb_agcount & sb_agblocks are 32-bit integers; this may then miss corrupt agbnos for the last ag, which can in turn lead to out of bounds memory accesses later, for example when the block nr is used to offset in set_agbno_state():

	addr = ba_bmap[(agno)] + (ag_blockno)/XR_BB_NUM;

---

repair/dinode.c +2 -1
index fdf52db..84e1d05 100644
@@ -319,7 +319,8 @@ verify_ag_bno(xfs_sb_t *sbp,
 		return (agbno >= sbp->sb_agblocks);
 	if (agno == (sbp->sb_agcount - 1)) 
 		return (agbno >= (sbp->sb_dblocks -
-				((sbp->sb_agcount - 1) * sbp->sb_agblocks)));
+				((xfs_drfsbno_t)(sbp->sb_agcount - 1) *
+				 sbp->sb_agblocks)));
 	return 1;
 }
 

_______________________________________________
xfs mailing list
[email protected]
http://oss.sgi.com/mailman/listinfo/xfs

#2 lore raw

PATCH v3 1/1 xfs_repair: fix agcount*agblocks overflows

(V3: found another spot with this problem)

The last test in verify_ag_bno() may overflow:

return (agbno >= (sbp->sb_dblocks -

		((sbp->sb_agcount - 1) * sbp->sb_agblocks)));

because sb_agcount & sb_agblocks are 32-bit integers; this may then miss corrupt agbnos for the last ag, which can in turn lead to out of bounds memory accesses later, for example when the block nr is used to offset in set_agbno_state():

	addr = ba_bmap[(agno)] + (ag_blockno)/XR_BB_NUM;

Similar problems in mk_incore_fstree

---

repair/dinode.c +2 -1
index fdf52db..84e1d05 100644
@@ -319,7 +319,8 @@ verify_ag_bno(xfs_sb_t *sbp,
 		return (agbno >= sbp->sb_agblocks);
 	if (agno == (sbp->sb_agcount - 1)) 
 		return (agbno >= (sbp->sb_dblocks -
-				((sbp->sb_agcount - 1) * sbp->sb_agblocks)));
+				((xfs_drfsbno_t)(sbp->sb_agcount - 1) *
+				 sbp->sb_agblocks)));
 	return 1;
 }
 
repair/phase5.c +2 -1
index 2c243b6..77c7363 100644
@@ -113,7 +113,8 @@ mk_incore_fstree(xfs_mount_t *mp, xfs_agnumber_t agno)
 		ag_end = mp->m_sb.sb_agblocks;
 	else
 		ag_end = mp->m_sb.sb_dblocks -
-			mp->m_sb.sb_agblocks * (mp->m_sb.sb_agcount - 1);
+			(xfs_drfsbno_t)mp->m_sb.sb_agblocks *
+                        (mp->m_sb.sb_agcount - 1);
 
 	/*
 	 * ok, now find the number of extents, keep track of the

_______________________________________________
xfs mailing list
[email protected]
http://oss.sgi.com/mailman/listinfo/xfs

Reviewed-by on v3 1/1
#3 lore raw

Re: [PATCH V3] xfs_repair: fix agcount*agblocks overflows

Quoted 12 lines · Eric Sandeen

(V3: found another spot with this problem)

The last test in verify_ag_bno() may overflow:

return (agbno >= (sbp->sb_dblocks -

		((sbp->sb_agcount - 1) * sbp->sb_agblocks)));

because sb_agcount & sb_agblocks are 32-bit integers; this may then miss corrupt agbnos for the last ag, which can in turn lead to out of bounds memory accesses later, for example when the block nr is used to offset in set_agbno_state():

Quoted 6 lines
	addr = ba_bmap[(agno)] + (ag_blockno)/XR_BB_NUM;

Similar problems in mk_incore_fstree

Quoted 33 lines

---

repair/dinode.c +2 -1
index fdf52db..84e1d05 100644
@@ -319,7 +319,8 @@ verify_ag_bno(xfs_sb_t *sbp,
 		return (agbno >= sbp->sb_agblocks);
 	if (agno == (sbp->sb_agcount - 1))
 		return (agbno >= (sbp->sb_dblocks -
-				((sbp->sb_agcount - 1) * sbp->sb_agblocks)));
+				((xfs_drfsbno_t)(sbp->sb_agcount - 1) *
+				 sbp->sb_agblocks)));
 	return 1;
 }
 
repair/phase5.c +2 -1
index 2c243b6..77c7363 100644
@@ -113,7 +113,8 @@ mk_incore_fstree(xfs_mount_t *mp, xfs_agnumber_t  
 agno)
 		ag_end = mp->m_sb.sb_agblocks;
 	else
 		ag_end = mp->m_sb.sb_dblocks -
-			mp->m_sb.sb_agblocks * (mp->m_sb.sb_agcount - 1);
+			(xfs_drfsbno_t)mp->m_sb.sb_agblocks *
+                        (mp->m_sb.sb_agcount - 1);
 
 	/*

* ok, now find the number of extents, keep track of the

Quoted 4 lines

_______________________________________________
xfs mailing list
[email protected]
http://oss.sgi.com/mailman/listinfo/xfs

_______________________________________________
xfs mailing list
[email protected]
http://oss.sgi.com/mailman/listinfo/xfs