Fix a bug in fsck_ffs(8) triggered by corrupted filesystems.

Reported-by:  Robert Morris
PR:           271378
Sponsored-by: The FreeBSD Foundation

(cherry picked from commit 101a9ac071)
This commit is contained in:
Kirk McKusick 2023-05-27 17:09:02 -07:00
parent fbfbd0638a
commit 3035f98d56
4 changed files with 30 additions and 11 deletions

View file

@ -471,6 +471,7 @@ void check_blkcnt(struct inode *ip);
int check_cgmagic(int cg, struct bufarea *cgbp);
void rebuild_cg(int cg, struct bufarea *cgbp);
void check_dirdepth(struct inoinfo *inp);
int chkfilesize(mode_t mode, u_int64_t filesize);
int chkrange(ufs2_daddr_t blk, int cnt);
void ckfini(int markclean);
int ckinode(union dinode *dp, struct inodesc *);

View file

@ -1206,6 +1206,31 @@ std_checkblkavail(ufs2_daddr_t blkno, long frags)
return (0);
}
/*
* Check whether a file size is within the limits for the filesystem.
* Return 1 when valid and 0 when too big.
*
* This should match the file size limit in ffs_mountfs().
*/
int
chkfilesize(mode_t mode, u_int64_t filesize)
{
u_int64_t kernmaxfilesize;
if (sblock.fs_magic == FS_UFS1_MAGIC)
kernmaxfilesize = (off_t)0x40000000 * sblock.fs_bsize - 1;
else
kernmaxfilesize = sblock.fs_maxfilesize;
if (filesize > kernmaxfilesize ||
filesize > sblock.fs_maxfilesize ||
(mode == IFDIR && filesize > MAXDIRSIZE)) {
if (debug)
printf("bad file size %ju:", (uintmax_t)filesize);
return (0);
}
return (1);
}
/*
* Slow down IO so as to leave some disk bandwidth for other processes
*/

View file

@ -256,7 +256,6 @@ checkinode(ino_t inumber, struct inodesc *idesc, int rebuiltcg)
{
struct inode ip;
union dinode *dp;
off_t kernmaxfilesize;
ufs2_daddr_t ndb;
mode_t mode;
intmax_t size, fixsize;
@ -293,16 +292,7 @@ checkinode(ino_t inumber, struct inodesc *idesc, int rebuiltcg)
return (1);
}
lastino = inumber;
/* This should match the file size limit in ffs_mountfs(). */
if (sblock.fs_magic == FS_UFS1_MAGIC)
kernmaxfilesize = (off_t)0x40000000 * sblock.fs_bsize - 1;
else
kernmaxfilesize = sblock.fs_maxfilesize;
if (DIP(dp, di_size) > kernmaxfilesize ||
DIP(dp, di_size) > sblock.fs_maxfilesize ||
(mode == IFDIR && DIP(dp, di_size) > MAXDIRSIZE)) {
if (debug)
printf("bad size %ju:", (uintmax_t)DIP(dp, di_size));
if (chkfilesize(mode, DIP(dp, di_size)) == 0) {
pfatal("BAD FILE SIZE");
goto unknown;
}

View file

@ -1963,6 +1963,9 @@ ino_build_trunc(struct jtrncrec *rec)
printf("ino_build_trunc: op %d ino %ju, size %jd\n",
rec->jt_op, (uintmax_t)rec->jt_ino,
(uintmax_t)rec->jt_size);
if (chkfilesize(IFREG, rec->jt_size) == 0)
err_suj("ino_build: truncation size too large %ju\n",
(intmax_t)rec->jt_size);
sino = ino_lookup(rec->jt_ino, 1);
if (rec->jt_op == JOP_SYNC) {
sino->si_trunc = NULL;