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);