git: dc37121d3210 - main - ffs_reallocblks(): ensure that pref cg is valid
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Mon, 13 Jan 2025 19:23:31 UTC
The branch main has been updated by kib:
URL: https://cgit.FreeBSD.org/src/commit/?id=dc37121d3210d08c96a883ebfed780660e7e2b39
commit dc37121d3210d08c96a883ebfed780660e7e2b39
Author: Konstantin Belousov <kib@FreeBSD.org>
AuthorDate: 2025-01-05 22:51:23 +0000
Commit: Konstantin Belousov <kib@FreeBSD.org>
CommitDate: 2025-01-13 19:22:54 +0000
ffs_reallocblks(): ensure that pref cg is valid
ffs_blkpref_ufsX() must return in-range pref frag number, otherwise
calculated cg index is out of range for fs, causing out of range
accesses to the structures sized by the number of cg, e.g. the
fs_maxcluster[] array in ffs_clusteralloc().
The easiest way to trigger it is to overflow the volume.
In collaboration with: pho
Reviewed by: mckusick
Sponsored by: The FreeBSD Foundation
MFC afer: 1 week
Differential revision: https://reviews.freebsd.org/D48378
---
sys/ufs/ffs/ffs_alloc.c | 27 +++++++++++++++++++++++----
1 file changed, 23 insertions(+), 4 deletions(-)
diff --git a/sys/ufs/ffs/ffs_alloc.c b/sys/ufs/ffs/ffs_alloc.c
index 01bfdb85c2e6..265daef14812 100644
--- a/sys/ufs/ffs/ffs_alloc.c
+++ b/sys/ufs/ffs/ffs_alloc.c
@@ -681,6 +681,7 @@ ffs_reallocblks_ufs1(
* groups that we will search.
*/
cg = dtog(fs, pref);
+ MPASS(cg < fs->fs_ncg);
for (i = min(maxclustersearch, fs->fs_ncg); i > 0; i--) {
if ((newblk = ffs_clusteralloc(ip, cg, pref, len)) != 0)
break;
@@ -947,6 +948,7 @@ ffs_reallocblks_ufs2(
* groups that we will search.
*/
cg = dtog(fs, pref);
+ MPASS(cg < fs->fs_ncg);
for (i = min(maxclustersearch, fs->fs_ncg); i > 0; i--) {
if ((newblk = ffs_clusteralloc(ip, cg, pref, len)) != 0)
break;
@@ -1438,8 +1440,11 @@ ffs_blkpref_ufs1(struct inode *ip,
* place it immediately following the last direct block.
*/
if (indx == -1 && lbn < UFS_NDADDR + NINDIR(fs) &&
- ip->i_din1->di_db[UFS_NDADDR - 1] != 0)
+ ip->i_din1->di_db[UFS_NDADDR - 1] != 0) {
pref = ip->i_din1->di_db[UFS_NDADDR - 1] + fs->fs_frag;
+ if (dtog(fs, pref) >= fs->fs_ncg)
+ pref = 0;
+ }
return (pref);
}
/*
@@ -1450,8 +1455,11 @@ ffs_blkpref_ufs1(struct inode *ip,
if (lbn == UFS_NDADDR) {
pref = ip->i_din1->di_ib[0];
if (pref != 0 && pref >= cgdata(fs, inocg) &&
- pref < cgbase(fs, inocg + 1))
+ pref < cgbase(fs, inocg + 1)) {
+ if (dtog(fs, pref + fs->fs_frag) >= fs->fs_ncg)
+ return (0);
return (pref + fs->fs_frag);
+ }
}
/*
* If we are at the beginning of a file, or we have already allocated
@@ -1506,6 +1514,8 @@ ffs_blkpref_ufs1(struct inode *ip,
/*
* Otherwise, we just always try to lay things out contiguously.
*/
+ if (dtog(fs, prevbn + fs->fs_frag) >= fs->fs_ncg)
+ return (0);
return (prevbn + fs->fs_frag);
}
@@ -1550,8 +1560,11 @@ ffs_blkpref_ufs2(struct inode *ip,
* place it immediately following the last direct block.
*/
if (indx == -1 && lbn < UFS_NDADDR + NINDIR(fs) &&
- ip->i_din2->di_db[UFS_NDADDR - 1] != 0)
+ ip->i_din2->di_db[UFS_NDADDR - 1] != 0) {
pref = ip->i_din2->di_db[UFS_NDADDR - 1] + fs->fs_frag;
+ if (dtog(fs, pref) >= fs->fs_ncg)
+ pref = 0;
+ }
return (pref);
}
/*
@@ -1562,8 +1575,11 @@ ffs_blkpref_ufs2(struct inode *ip,
if (lbn == UFS_NDADDR) {
pref = ip->i_din2->di_ib[0];
if (pref != 0 && pref >= cgdata(fs, inocg) &&
- pref < cgbase(fs, inocg + 1))
+ pref < cgbase(fs, inocg + 1)) {
+ if (dtog(fs, pref + fs->fs_frag) >= fs->fs_ncg)
+ return (0);
return (pref + fs->fs_frag);
+ }
}
/*
* If we are at the beginning of a file, or we have already allocated
@@ -1618,6 +1634,8 @@ ffs_blkpref_ufs2(struct inode *ip,
/*
* Otherwise, we just always try to lay things out contiguously.
*/
+ if (dtog(fs, prevbn + fs->fs_frag) >= fs->fs_ncg)
+ return (0);
return (prevbn + fs->fs_frag);
}
@@ -1968,6 +1986,7 @@ ffs_clusteralloc(struct inode *ip,
ump = ITOUMP(ip);
fs = ump->um_fs;
+ MPASS(cg < fs->fs_ncg);
if (fs->fs_maxcluster[cg] < len)
return (0);
UFS_UNLOCK(ump);